From f0b99bc99a27c82d71db3e4f1de66fe1fd2c18fe Mon Sep 17 00:00:00 2001 From: DualFroz Date: Wed, 2 Sep 2026 19:23:37 +0200 Subject: [PATCH] feat: extend bmp with wordCountFor and bmpInit --- src/bmp.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/boot.S | 20 ++++++++++++ src/console.c | 16 ++++++--- 3 files changed, 122 insertions(+), 4 deletions(-) create mode 100644 src/bmp.c diff --git a/src/bmp.c b/src/bmp.c new file mode 100644 index 0000000..f5fd04e --- /dev/null +++ b/src/bmp.c @@ -0,0 +1,90 @@ +#include "bmp.h" + +#define bmpBitsPerWord 64 + +static usize wordCountFor(usize bitCount) +{ + return (bitCount + bmpBitsPerWord - 1) / bmpBitsPerWord; +} + +void bmpInit(Bitmap* b, uint64* backingWords, usize bitCount) +{ + b->words = backingWords; + b->bitCount = bitCount; + bmpClearAll(b); +} + +void bmpSet(Bitmap* b, usize index) +{ + if (index >= b->bitCount) + return; + b->words[index / bmpBitsPerWord] |= (1UL << (index % bmpBitsPerWord)); +} + +void bmpClear(Bitmap* b, usize index) +{ + if (index >= b->bitCount) + return; + b->words[index / bmpBitsPerWord] &= ~(1UL << (index % bmpBitsPerWord)); +} + +bool bmpTest(const Bitmap* b, usize index) +{ + if (index >= b->bitCount) + return false; + return (b->words[index / bmpBitsPerWord] & (1UL << (index % bmpBitsPerWord))) != 0; +} + +void bmpSetRange(Bitmap* b, usize start, usize count) +{ + for (usize i = start; i < start + count && i < b->bitCount; i++) + bmpSet(b, i); +} + +void bmpClearRange(Bitmap* b, usize start, usize count) +{ + for (usize i = start; i < start + count && i < b->bitCount; i++) + bmpClear(b, i); +} + +void bmpSetAll(Bitmap* b) +{ + usize words = wordCountFor(b->bitCount); + for (usize i = 0; i < words; i++) + b->words[i] = ~0UL; +} + +void bmpClearAll(Bitmap* b) +{ + usize words = wordCountFor(b->bitCount); + for (usize i = 0; i < words; i++) + b->words[i] = 0; +} + +usize bmpCountSet(const Bitmap* b) +{ + usize total = 0; + for (usize i = 0; i < b->bitCount; i++) { + if (bmpTest(b, i)) + total++; + } + return total; +} + +isize bmpFindFirstClear(const Bitmap* b) +{ + for (usize i = 0; i < b->bitCount; i++) { + if (!bmpTest(b, i)) + return (isize)i; + } + return -1; +} + +isize bmpFindFirstSet(const Bitmap* b) +{ + for (usize i = 0; i < b->bitCount; i++) { + if (bmpTest(b, i)) + return (isize)i; + } + return -1; +} diff --git a/src/boot.S b/src/boot.S index a9ec92f..9474288 100644 --- a/src/boot.S +++ b/src/boot.S @@ -60,6 +60,10 @@ fillPd: movl $0xC0000080, %ecx rdmsr orl $(1 << 8), %eax + cmpl $0, cpuNxSupported + je 2f + orl $(1 << 11), %eax +2: wrmsr movl %cr0, %eax @@ -76,6 +80,16 @@ checkLongMode: jb noLongMode movl $0x80000001, %eax cpuid + + /* Same cpuid leaf already gives us CPUID.80000001H:EDX.NX (bit 20) for + free -- stash it in cpuNxSupported (checked below, in %eax's later + rdmsr/wrmsr dance) before the LM (bit 29) test below, which does not + touch %edx, leaves it intact either way. */ + movl $0, cpuNxSupported + testl $(1 << 20), %edx + jz 1f + movl $1, cpuNxSupported +1: testl $(1 << 29), %edx jz noLongMode ret @@ -111,6 +125,12 @@ bootGdtPointer: .word bootGdtEnd - bootGdtStart - 1 .quad bootGdtStart +.section .boot.data, "aw", @progbits +.align 4 +.global cpuNxSupported +cpuNxSupported: + .long 0 + .section .boot.pagetables, "aw", @progbits .align 4096 .global bootPml4 diff --git a/src/console.c b/src/console.c index 1d316cc..54dad47 100644 --- a/src/console.c +++ b/src/console.c @@ -43,13 +43,21 @@ static void writeUnsigned(uint64 value, uint32 base, bool upper, int minWidth, c kputchar(buffer[--length]); } -static void writeSigned(int64 value) +/* Mirrors klib.c's vsnprintf sinkPutSigned exactly (same minWidth/pad + contract, same "sign eats one column of the requested width" rule) -- + found and fixed this fala after shell.c's new `ls -l` printed + "2026-9-7" instead of "2026-09-07": every prior kprintf call site that + wanted zero-padded fields (thread ids, sizes, hex addresses) happened + to use an unsigned specifier, so this signed-value width/pad bug went + completely unnoticed until the first zero-padded %d/%ld call ever + appeared. */ +static void writeSigned(int64 value, int minWidth, char pad) { if (value < 0) { kputchar('-'); - writeUnsigned((uint64)(-value), 10, false, 0, ' '); + writeUnsigned((uint64)(-value), 10, false, minWidth > 0 ? minWidth - 1 : 0, pad); } else { - writeUnsigned((uint64)value, 10, false, 0, ' '); + writeUnsigned((uint64)value, 10, false, minWidth, pad); } } @@ -93,7 +101,7 @@ void kprintf(const char* format, ...) break; case 'd': case 'i': - writeSigned(longCount ? va_arg(args, int64) : (int64)va_arg(args, int)); + writeSigned(longCount ? va_arg(args, int64) : (int64)va_arg(args, int), width, pad); break; case 'u': writeUnsigned(longCount ? va_arg(args, uint64) : (uint64)va_arg(args, uint32), 10, false, width, pad);