From 325149006cc34316a016b954895deaa66828a5cd Mon Sep 17 00:00:00 2001 From: Maksymilian Wilczynski Date: Tue, 9 Jun 2026 16:01:12 +0200 Subject: [PATCH] completely redesign how user mode memory is allocated, fix a few smp and scheduler bugs, terminating a process now terminates the process, telemetry, optimize text editor, new font, new color scheme --- OVMF/OVMF_VARS_4M.fd | Bin 540672 -> 540672 bytes OVMF/OVMF_VARS_4M_d.fd | Bin 540672 -> 540672 bytes code/boot.ini | 2 +- code/build/build.c | 30 +- code/drivers/bus/usb/usb_xhci.c | 2 +- code/drivers/net/rtl8139/rtl8139_pci.c | 2 +- code/drivers/net/rtl816x/rtl816x_pci.c | 2 +- code/drivers/storage/ahci/ahci_port.c | 2 +- code/kernel/hal/hal_main.c | 2 +- code/kernel/hal/hal_screen.c | 29 +- code/kernel/hal/hal_timer.c | 14 +- code/kernel/include/kernel/hal/font8x16.h | 708 ++++++++++++++----- code/kernel/include/kernel/hal/hal_apic.h | 1 + code/kernel/include/kernel/ldr_image.h | 1 - code/kernel/include/kernel/mm_phys.h | 12 +- code/kernel/include/kernel/mm_virt.h | 10 +- code/kernel/include/kernel/syscall_nr.h | 184 ++--- code/kernel/ke_debug.c | 11 +- code/kernel/ke_irq.c | 8 + code/kernel/ke_process.c | 24 +- code/kernel/ke_sched.c | 10 + code/kernel/ke_smp.c | 25 +- code/kernel/ke_syscall.c | 446 +++++++++--- code/kernel/kmain.c | 2 +- code/kernel/ldr_image.c | 4 +- code/kernel/mm_phys.c | 384 ++++++---- code/kernel/mm_virt.c | 57 +- code/public/ntlite/syscall.h | 85 ++- code/user/apps/doom/doom.c | 9 +- code/user/apps/edit/edit.c | 93 ++- code/user/apps/shell_native/shell_native.c | 94 ++- code/user/personalities/posix/posix_dir.c | 7 +- code/user/personalities/posix/posix_io.c | 2 +- code/user/personalities/posix/posix_socket.c | 11 +- code/user/personalities/posix/posix_thread.c | 7 +- code/user/personalities/win32/gdi32.c | 9 +- code/user/personalities/win32/kernel32.c | 93 ++- code/user/personalities/win32/ole32.c | 3 +- code/user/runtime/heap.c | 226 ++++++ code/user/runtime/heap_exports.c | 34 + code/user/syscall/syscall_nr.inc | 184 ++--- code/user/syscall/syscall_stubs.asm | 10 +- code/user/tests/async_apc/async_apc.c | 5 +- code/user/tests/async_cancel/async_cancel.c | 5 +- readme.md | 2 +- 45 files changed, 2091 insertions(+), 760 deletions(-) create mode 100644 code/user/runtime/heap.c create mode 100644 code/user/runtime/heap_exports.c diff --git a/OVMF/OVMF_VARS_4M.fd b/OVMF/OVMF_VARS_4M.fd index 7ab8cfce74b31067a952fd6bd2c6d92fa79c8548..9ddd15448bd41534a095f15b5d45bf832af6caa4 100644 GIT binary patch delta 73 zcmZo@P;3CA7RD`1Y;KeNf}FN{xG`Pg+Wane7b~ON=7~X`0@K;tn4B2hf$WQ1?NWhE b+ob}T&&_QUU}+OzZ4+Q?6JTE^z+nIYw7eIk delta 56 zcmZo@P;3CA7RD`1Y;M!#(wUsLd$=)O;%YZ4V%lz0#C&e<_55 zsT`B*bT3R+vsIdWpj?4bcKSj)M(s(3FE%$A^e{5BGcZi%H*#f^+YS_V<_GaNU*Exq zkdVhEp@2(55lw;xXePsC0~Hmp{Yu*(Hb5E|XeMuAnd8%|^dVy5ke6PeG~ qwL45?-0m=u$(3iD0LulI?F}L<2Hb55ENu#`Z3=8{3hc`iI1~Uo;7g(a delta 984 zcmZo@P;6*W+~A=#*+5%~(P(n8_IF0(&E7iVjEp9elXZVHnof?_yFNLtSdFo7vZ1!( zGl0!I^Opn;piiy6^O{)jMHf**&PPY5*xZ1)1&{Lirr(~Tf6envIO&;;UY1ucj^ z;#~X%VF*qaeYUlH2Xp(RK*wX&7g>n1G7N#q8+XPrHuxwWl bWqH6gsWqTYfu&7>wM~JoO@V!x0*3+sFR%TW diff --git a/code/boot.ini b/code/boot.ini index 1d0fb60..5cc5468 100644 --- a/code/boot.ini +++ b/code/boot.ini @@ -1,5 +1,5 @@ [kernel] ; bitmask: 1 = debug prints, 2 = self check, 4 = write debug prints to file -debug = 4 +debug = 1 [init] commandline = apps/shell_native.exe diff --git a/code/build/build.c b/code/build/build.c index 20aa019..51e745e 100644 --- a/code/build/build.c +++ b/code/build/build.c @@ -36,7 +36,7 @@ static const Driver_Target STANDALONE_DRIVERS[] = { void create_layout() { const char *dirs[] = { "obj", "bin", "obj\\boot", "obj\\kernel", "obj\\lwip", "obj\\hal", - "obj\\syscall", "obj\\win32", "obj\\posix", "obj\\drivers", "obj\\init", + "obj\\syscall", "obj\\runtime", "obj\\win32", "obj\\posix", "obj\\drivers", "obj\\init", "obj\\shell_win32", "obj\\shell_posix", "obj\\shell_native", "obj\\async_apc", "obj\\async_cancel", "obj\\edit", "obj\\httpget", "obj\\tcpserve", "obj\\udp", "obj\\resolve", "obj\\ping", "obj\\doom", "obj\\video" @@ -86,6 +86,8 @@ int main(int argc, char **argv) { nob_temp_sprintf("cl %s /MP /c /Foobj\\ code\\common\\printf.c code\\common\\ini_parser.c", CFLAGS), "cl /nologo /c /Foobj\\libc.obj code\\common\\libc.c", + nob_temp_sprintf("cl %s /c /Foobj\\runtime\\user_heap.obj code\\user\\runtime\\heap.c", CFLAGS), + nob_temp_sprintf("cl %s /c /Foobj\\runtime\\user_heap_exports.obj code\\user\\runtime\\heap_exports.c", CFLAGS), // Bootloader nob_temp_sprintf("cl %s /MP /c /Icode\\boot\\uefi\\include /Foobj\\boot\\ code\\boot\\uefi\\*.c && link %s /FORCE:MULTIPLE /SUBSYSTEM:EFI_APPLICATION /ENTRY:UefiMain /OUT:bin\\bootx64.efi obj\\libc.obj obj\\ini_parser.obj code\\boot\\uefi\\efilib.lib obj\\boot\\*.obj", CFLAGS, LFLAGS), @@ -98,8 +100,8 @@ int main(int argc, char **argv) { // Subsystem DLLs "link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\syscall.dll obj\\syscall\\stubs.obj", - nob_temp_sprintf("cl %s /MP /c /Foobj\\win32\\ code\\user\\personalities\\win32\\*.c && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\win32.dll bin\\syscall.lib obj\\libc.obj obj\\win32\\*.obj", CFLAGS), - nob_temp_sprintf("cl %s /MP /c /Foobj\\posix\\ code\\user\\personalities\\posix\\*.c && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\posix.dll bin\\syscall.lib obj\\libc.obj obj\\posix\\*.obj", CFLAGS) + nob_temp_sprintf("cl %s /DUSER_HEAP_EXPORTS /MP /c /Foobj\\win32\\ code\\user\\runtime\\heap.c code\\user\\runtime\\heap_exports.c code\\user\\personalities\\win32\\*.c && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\win32.dll bin\\syscall.lib obj\\libc.obj obj\\win32\\*.obj", CFLAGS), + nob_temp_sprintf("cl %s /DUSER_HEAP_EXPORTS /MP /c /Foobj\\posix\\ code\\user\\runtime\\heap.c code\\user\\runtime\\heap_exports.c code\\user\\personalities\\posix\\*.c && link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\posix.dll bin\\syscall.lib obj\\libc.obj obj\\posix\\*.obj", CFLAGS) }; for (size_t i = 0; i < NOB_ARRAY_LEN(core_tasks); i++) { @@ -140,19 +142,19 @@ int main(int argc, char **argv) { // Queue Subsystem Applications const char *apps[][4] = { // Folder, Libs, Name, Optional Extra Link Args - {"system\\init", "bin\\syscall.lib obj\\libc.obj", "init", "/ENTRY:_start"}, + {"system\\init", "bin\\syscall.lib obj\\libc.obj obj\\runtime\\user_heap.obj obj\\runtime\\user_heap_exports.obj", "init", "/ENTRY:_start"}, {"apps\\shell_win32", "bin\\win32.lib obj\\libc.obj", "shell_win32", "/ENTRY:main"}, {"apps\\shell_posix", "bin\\posix.lib obj\\libc.obj", "shell_posix", "/ENTRY:main"}, - {"apps\\shell_native", "bin\\syscall.lib obj\\libc.obj", "shell_native", "/ENTRY:main"}, - {"tests\\async_apc", "bin\\syscall.lib obj\\libc.obj", "async_apc", "/ENTRY:main"}, - {"tests\\async_cancel", "bin\\syscall.lib obj\\libc.obj", "async_cancel", "/ENTRY:main"}, - {"apps\\edit", "bin\\syscall.lib obj\\libc.obj", "edit", "/ENTRY:main"}, - {"apps\\httpget", "bin\\syscall.lib obj\\libc.obj", "httpget", "/ENTRY:main"}, - {"apps\\tcpserve", "bin\\syscall.lib obj\\libc.obj", "tcpserve", "/ENTRY:main"}, - {"apps\\udp", "bin\\syscall.lib obj\\libc.obj", "udp", "/ENTRY:main"}, - {"apps\\resolve", "bin\\syscall.lib obj\\libc.obj", "resolve", "/ENTRY:main"}, - {"apps\\ping", "bin\\syscall.lib obj\\libc.obj", "ping", "/ENTRY:main"}, - {"apps\\doom", "bin\\syscall.lib obj\\libc.obj", "doom", "/ENTRY:main"}, + {"apps\\shell_native", "bin\\syscall.lib obj\\libc.obj obj\\runtime\\user_heap.obj obj\\runtime\\user_heap_exports.obj", "shell_native", "/ENTRY:main"}, + {"tests\\async_apc", "bin\\syscall.lib obj\\libc.obj obj\\runtime\\user_heap.obj obj\\runtime\\user_heap_exports.obj", "async_apc", "/ENTRY:main"}, + {"tests\\async_cancel", "bin\\syscall.lib obj\\libc.obj obj\\runtime\\user_heap.obj obj\\runtime\\user_heap_exports.obj", "async_cancel", "/ENTRY:main"}, + {"apps\\edit", "bin\\syscall.lib obj\\libc.obj obj\\runtime\\user_heap.obj obj\\runtime\\user_heap_exports.obj", "edit", "/ENTRY:main"}, + {"apps\\httpget", "bin\\syscall.lib obj\\libc.obj obj\\runtime\\user_heap.obj obj\\runtime\\user_heap_exports.obj", "httpget", "/ENTRY:main"}, + {"apps\\tcpserve", "bin\\syscall.lib obj\\libc.obj obj\\runtime\\user_heap.obj obj\\runtime\\user_heap_exports.obj", "tcpserve", "/ENTRY:main"}, + {"apps\\udp", "bin\\syscall.lib obj\\libc.obj obj\\runtime\\user_heap.obj obj\\runtime\\user_heap_exports.obj", "udp", "/ENTRY:main"}, + {"apps\\resolve", "bin\\syscall.lib obj\\libc.obj obj\\runtime\\user_heap.obj obj\\runtime\\user_heap_exports.obj", "resolve", "/ENTRY:main"}, + {"apps\\ping", "bin\\syscall.lib obj\\libc.obj obj\\runtime\\user_heap.obj obj\\runtime\\user_heap_exports.obj", "ping", "/ENTRY:main"}, + {"apps\\doom", "bin\\syscall.lib obj\\libc.obj obj\\runtime\\user_heap.obj obj\\runtime\\user_heap_exports.obj", "doom", "/ENTRY:main"}, {"apps\\video", "bin\\win32.lib obj\\libc.obj code\\user\\apps\\video\\bink2w64.lib", "video", "/ENTRY:main"} }; diff --git a/code/drivers/bus/usb/usb_xhci.c b/code/drivers/bus/usb/usb_xhci.c index 9d593c2..c615665 100644 --- a/code/drivers/bus/usb/usb_xhci.c +++ b/code/drivers/bus/usb/usb_xhci.c @@ -115,7 +115,7 @@ KSTATUS UsbMapMmio(const HAL_API* hal, uint64_t physBase, for (uint32_t i = 0; i < pages; i++) { PHYSICAL_ADDRESS phys = pageBase + (uint64_t)i * PAGE_SIZE; uintptr_t virt = (uintptr_t)hal->PhysToVirt(phys); - KSTATUS st = MmMapPage(virt, phys, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE); + KSTATUS st = MmMapPage(virt, phys, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE, MmMapFailIfPresent); if (st == STATUS_ALREADY_EXISTS) st = MmSetPageProtect(virt, PAGE_SIZE, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE); if (!KSUCCESS(st)) { diff --git a/code/drivers/net/rtl8139/rtl8139_pci.c b/code/drivers/net/rtl8139/rtl8139_pci.c index 7179817..32cc6f3 100644 --- a/code/drivers/net/rtl8139/rtl8139_pci.c +++ b/code/drivers/net/rtl8139/rtl8139_pci.c @@ -41,7 +41,7 @@ KSTATUS Rtl8139MapMmio(uint64_t physBase, volatile uint8_t** outMmio) { for (uint32_t i = 0; i < RTL8139_MMIO_PAGES; i++) { PHYSICAL_ADDRESS phys = pageBase + (uint64_t)i * PAGE_SIZE; uintptr_t virt = (uintptr_t)gHal->PhysToVirt(phys); - KSTATUS st = MmMapPage(virt, phys, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE); + KSTATUS st = MmMapPage(virt, phys, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE, MmMapFailIfPresent); if (st == STATUS_ALREADY_EXISTS) st = MmSetPageProtect(virt, PAGE_SIZE, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE); if (!KSUCCESS(st)) diff --git a/code/drivers/net/rtl816x/rtl816x_pci.c b/code/drivers/net/rtl816x/rtl816x_pci.c index 58f89a2..5446aa0 100644 --- a/code/drivers/net/rtl816x/rtl816x_pci.c +++ b/code/drivers/net/rtl816x/rtl816x_pci.c @@ -54,7 +54,7 @@ KSTATUS RtlMapMmio(uint64_t physBase, volatile uint8_t** outMmio) { for (uint32_t i = 0; i < RTL_MMIO_PAGES; i++) { PHYSICAL_ADDRESS phys = pageBase + (uint64_t)i * PAGE_SIZE; uintptr_t virt = (uintptr_t)gHal->PhysToVirt(phys); - KSTATUS st = MmMapPage(virt, phys, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE); + KSTATUS st = MmMapPage(virt, phys, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE, MmMapFailIfPresent); if (st == STATUS_ALREADY_EXISTS) st = MmSetPageProtect(virt, PAGE_SIZE, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE); if (!KSUCCESS(st)) diff --git a/code/drivers/storage/ahci/ahci_port.c b/code/drivers/storage/ahci/ahci_port.c index 6936bb3..c71a44e 100644 --- a/code/drivers/storage/ahci/ahci_port.c +++ b/code/drivers/storage/ahci/ahci_port.c @@ -6,7 +6,7 @@ KSTATUS ahci_map_mmio(uint64_t physBase) { uint64_t phys = physBase + (uint64_t)i * 4096; uintptr_t virt = (uintptr_t)g_hal->PhysToVirt(phys); uint64_t flags = PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE; - KSTATUS st = MmMapPage(virt, phys, flags); + KSTATUS st = MmMapPage(virt, phys, flags, MmMapFailIfPresent); // Ignore STATUS_ALREADY_EXISTS - a prior mapping with different flags // is possible for the first page if the bootloader was overly generous. // Use MmSetPageProtect to force NOCACHE in that case. diff --git a/code/kernel/hal/hal_main.c b/code/kernel/hal/hal_main.c index 18a0a9d..54ec30e 100644 --- a/code/kernel/hal/hal_main.c +++ b/code/kernel/hal/hal_main.c @@ -93,7 +93,7 @@ static int gS5Found = 0; int debugEnabled = 0; int _fltused; // MSVC floating-point helper anchor static void hal_putchar(char c) { - gApi.Screen.PrintChar(c, 0x00FF00, 0x000000); + gApi.Screen.PrintChar(c, 0xCCCCCC, 0x012456); } void HalDbgPrint(const char* fmt, ...) { if (!debugEnabled) return; diff --git a/code/kernel/hal/hal_screen.c b/code/kernel/hal/hal_screen.c index 1a83193..e7d097e 100644 --- a/code/kernel/hal/hal_screen.c +++ b/code/kernel/hal/hal_screen.c @@ -19,6 +19,9 @@ static int gCursorX = 0, gCursorY = 0; #define FONT_W 8 #define FONT_H 16 +#define SCREEN_DEFAULT_FG 0xCCCCCCu +#define SCREEN_DEFAULT_BG 0x012456u + // --------------------------------------------------------------------------- // 8x16 VGA font - printable ASCII only (glyph 0 = space = 0x20) // --------------------------------------------------------------------------- @@ -113,28 +116,36 @@ static void ScreenBlit(int x, int y, int w, int h, const uint32_t* pixels) { static void ScreenGetSize(int* w, int* h) { *w = gWidth; *h = gHeight; } static void ScreenScroll(int lines) { - if (lines <= 0 || lines >= gHeight) { ScreenClear(0); return; } + if (lines <= 0) + return; + if (lines >= gHeight) { + ScreenClear(SCREEN_DEFAULT_BG); + return; + } size_t rowBytes = (size_t)gStride * sizeof(uint32_t); uint32_t* shadow = gBackbuffer ? gBackbuffer : gFb; memmove(shadow, shadow + lines * gStride, (size_t)(gHeight - lines) * rowBytes); - // Clear the revealed rows at the bottom. - memset(shadow + (gHeight - lines) * gStride, 0, - (size_t)lines * rowBytes); + + // Fill the revealed rows with the console background. Do not memset here: + // the background color is not zero. + uint32_t* fill = shadow + (gHeight - lines) * gStride; + for (int y = 0; y < lines; y++) { + for (int x = 0; x < gWidth; x++) + fill[y * gStride + x] = SCREEN_DEFAULT_BG; + } ScreenFlushRows(0, gHeight); } static void ScreenPutChar(char c, int x, int y, uint32_t fg, uint32_t bg) { - if ((unsigned char)c < 0x20 || (unsigned char)c > 0x7E) c = '?'; - const uint8_t* glyph = Font8x16 + ((unsigned char)c - 0x20) * 16; + const uint8_t* glyph = Font8x16 + ((uint8_t)c * 16); for (int row = 0; row < 16; row++) { uint8_t bits = glyph[row]; for (int col = 0; col < 8; col++) { - uint32_t color = (bits & (1 << col)) ? fg : bg; // i don't know why, i don't want to know why - // i shouldn't have to wonder why but the font is backwards unless we do this terriblness + uint32_t color = (bits & (0x80u >> col)) ? fg : bg; PutPixelRaw(x + col, y + row, color); } } @@ -321,5 +332,5 @@ void HalScreenInitialize(void* (*AllocatePool)(size_t size), uintptr_t fb, int w out->PrintChar = ScreenPrintChar; out->DrawCursor = HalScreenDrawCursor; out->EraseCursor = HalScreenEraseCursor; - ScreenClear(0x000000); + ScreenClear(SCREEN_DEFAULT_BG); } diff --git a/code/kernel/hal/hal_timer.c b/code/kernel/hal/hal_timer.c index 5cb7d8e..fbf7b3b 100644 --- a/code/kernel/hal/hal_timer.c +++ b/code/kernel/hal/hal_timer.c @@ -175,6 +175,13 @@ static uint32_t CalibrateApicTimerViaHpet(uintptr_t hpetPhys) { return elapsed / 10; // APIC ticks per ms } +__declspec(dllexport) void HalTimerConfigureCurrentCpu(void) { + if (!gLapic || !gApicTicksPerQuantum) return; + LAPIC_REG(LAPIC_TIMER_DIV) = TIMER_DIV16; + LAPIC_REG(LAPIC_TIMER_LVT) = TIMER_PERIODIC | TIMER_VECTOR; + LAPIC_REG(LAPIC_TIMER_INIT) = gApicTicksPerQuantum; +} + KSTATUS HalTimerInitialize(uintptr_t lapicPhys, uintptr_t hpetPhys, HAL_TIMER *out) { gLapic = (volatile uint32_t *)gApi.PhysToVirt(lapicPhys); HalDbgPrint("HAL: lapicPhys=0x%016llX, lapicVirt=0x%016llX, hpetPhys=0x%016llX\n", lapicPhys, (uintptr_t)gLapic, hpetPhys); @@ -205,10 +212,9 @@ KSTATUS HalTimerInitialize(uintptr_t lapicPhys, uintptr_t hpetPhys, HAL_TIMER *o HalDbgPrint("HAL: APIC timer: %u ticks/ms\n", ticksPerMs); - // Configure LAPIC timer in periodic mode - LAPIC_REG(LAPIC_TIMER_DIV) = TIMER_DIV16; - LAPIC_REG(LAPIC_TIMER_LVT) = TIMER_PERIODIC | TIMER_VECTOR; - LAPIC_REG(LAPIC_TIMER_INIT) = gApicTicksPerQuantum; + // Configure this CPU's LAPIC timer; APs call HalTimerConfigureCurrentCpu() + // after enabling their local APIC. + HalTimerConfigureCurrentCpu(); out->QueryTicks = QueryTicks; out->Stall = Stall; diff --git a/code/kernel/include/kernel/hal/font8x16.h b/code/kernel/include/kernel/hal/font8x16.h index ccc0a0b..e7e332b 100644 --- a/code/kernel/include/kernel/hal/font8x16.h +++ b/code/kernel/include/kernel/hal/font8x16.h @@ -1,199 +1,521 @@ #pragma once -// font8x16.h - embedded 8x16 VGA bitmap font, printable ASCII (0x20-0x7E) -// 95 glyphs × 16 bytes = 1520 bytes total. -// Each byte is one scanline; bit 7 = leftmost pixel. +// font8x16.h - embedded 8x16 CP437 bitmap font. +// Source: PC Face oldschool-vga-8x16 fontlist.js. +// Converted from: oldschool-vga-8x16-fontlist.js +// Layout: 256 glyphs * 16 scanlines. Bit 7 is the leftmost pixel. #include -static const uint8_t Font8x16[95 * 16] = { - // 0x20 ' ' +static const uint8_t Font8x16[256 * 16] = { + // 0x00 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x21 '!' - 0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00, - // 0x22 '"' - 0x00,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x23 '#' - 0x00,0x36,0x36,0x7F,0x36,0x36,0x36,0x7F,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x24 '$' - 0x18,0x18,0x3E,0x63,0x03,0x03,0x1E,0x30,0x30,0x63,0x3E,0x18,0x18,0x00,0x00,0x00, - // 0x25 '%' - 0x00,0x00,0x63,0x33,0x18,0x0C,0x06,0x31,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x26 '&' - 0x00,0x1C,0x36,0x1C,0x0E,0x3B,0x33,0x33,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x27 '\'' - 0x00,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x28 '(' - 0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x29 ')' - 0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x2A '*' - 0x00,0x00,0x00,0x33,0x1E,0xFF,0x1E,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x2B '+' - 0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x2C ',' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x2D '-' - 0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x2E '.' + // 0x01 + 0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00, + // 0x02 + 0x00,0x00,0x7E,0xFF,0xDB,0xFF,0xFF,0xC3,0xE7,0xFF,0xFF,0x7E,0x00,0x00,0x00,0x00, + // 0x03 + 0x00,0x00,0x00,0x00,0x6C,0xFE,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00, + // 0x04 + 0x00,0x00,0x00,0x00,0x10,0x38,0x7C,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00, + // 0x05 + 0x00,0x00,0x00,0x18,0x3C,0x3C,0xE7,0xE7,0xE7,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, + // 0x06 + 0x00,0x00,0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x7E,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, + // 0x07 + 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00, + // 0x08 + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xC3,0xC3,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + // 0x09 + 0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x42,0x42,0x66,0x3C,0x00,0x00,0x00,0x00,0x00, + // 0x0A + 0xFF,0xFF,0xFF,0xFF,0xFF,0xC3,0x99,0xBD,0xBD,0x99,0xC3,0xFF,0xFF,0xFF,0xFF,0xFF, + // 0x0B + 0x00,0x00,0x1E,0x0E,0x1A,0x32,0x78,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00, + // 0x0C + 0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00, + // 0x0D + 0x00,0x00,0x3F,0x33,0x3F,0x30,0x30,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0x00, + // 0x0E + 0x00,0x00,0x7F,0x63,0x7F,0x63,0x63,0x63,0x63,0x67,0xE7,0xE6,0xC0,0x00,0x00,0x00, + // 0x0F + 0x00,0x00,0x00,0x18,0x18,0xDB,0x3C,0xE7,0x3C,0xDB,0x18,0x18,0x00,0x00,0x00,0x00, + // 0x10 + 0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFE,0xF8,0xF0,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00, + // 0x11 + 0x00,0x02,0x06,0x0E,0x1E,0x3E,0xFE,0x3E,0x1E,0x0E,0x06,0x02,0x00,0x00,0x00,0x00, + // 0x12 + 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00,0x00, + // 0x13 + 0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x66,0x00,0x00,0x00,0x00, + // 0x14 + 0x00,0x00,0x7F,0xDB,0xDB,0xDB,0x7B,0x1B,0x1B,0x1B,0x1B,0x1B,0x00,0x00,0x00,0x00, + // 0x15 + 0x00,0x7C,0xC6,0x60,0x38,0x6C,0xC6,0xC6,0x6C,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00, + // 0x16 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFE,0xFE,0xFE,0x00,0x00,0x00,0x00, + // 0x17 + 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x7E,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00, + // 0x18 + 0x00,0x00,0x18,0x3C,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, + // 0x19 + 0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x3C,0x18,0x00,0x00,0x00,0x00, + // 0x1A + 0x00,0x00,0x00,0x00,0x00,0x18,0x0C,0xFE,0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00, + // 0x1B + 0x00,0x00,0x00,0x00,0x00,0x30,0x60,0xFE,0x60,0x30,0x00,0x00,0x00,0x00,0x00,0x00, + // 0x1C + 0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xC0,0xFE,0x00,0x00,0x00,0x00,0x00,0x00, + // 0x1D + 0x00,0x00,0x00,0x00,0x00,0x28,0x6C,0xFE,0x6C,0x28,0x00,0x00,0x00,0x00,0x00,0x00, + // 0x1E + 0x00,0x00,0x00,0x00,0x10,0x38,0x38,0x7C,0x7C,0xFE,0xFE,0x00,0x00,0x00,0x00,0x00, + // 0x1F + 0x00,0x00,0x00,0x00,0xFE,0xFE,0x7C,0x7C,0x38,0x38,0x10,0x00,0x00,0x00,0x00,0x00, + // 0x20 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0x21 + 0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00, + // 0x22 + 0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0x23 + 0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00, + // 0x24 + 0x18,0x18,0x7C,0xC6,0xC2,0xC0,0x7C,0x06,0x06,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00, + // 0x25 + 0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00, + // 0x26 + 0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, + // 0x27 + 0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0x28 + 0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00, + // 0x29 + 0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00, + // 0x2A + 0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00, + // 0x2B + 0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00, + // 0x2C + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00, + // 0x2D + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0x2E + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00, + // 0x2F + 0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00, + // 0x30 + 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xD6,0xD6,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00, + // 0x31 + 0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00, + // 0x32 + 0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00, + // 0x33 + 0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x34 + 0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00, + // 0x35 + 0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x36 + 0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x37 + 0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00, + // 0x38 + 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x39 + 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00, + // 0x3A + 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00, + // 0x3B + 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00, + // 0x3C + 0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00, + // 0x3D + 0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0x3E + 0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00, + // 0x3F + 0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00, + // 0x40 + 0x00,0x00,0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0x7C,0x00,0x00,0x00,0x00, + // 0x41 + 0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, + // 0x42 + 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00, + // 0x43 + 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00, + // 0x44 + 0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00, + // 0x45 + 0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00, + // 0x46 + 0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, + // 0x47 + 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00, + // 0x48 + 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, + // 0x49 + 0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, + // 0x4A + 0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00, + // 0x4B + 0x00,0x00,0xE6,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00, + // 0x4C + 0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00, + // 0x4D + 0x00,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, + // 0x4E + 0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, + // 0x4F + 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x50 + 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, + // 0x51 + 0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00, + // 0x52 + 0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00, + // 0x53 + 0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x54 + 0x00,0x00,0x7E,0x7E,0x5A,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, + // 0x55 + 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x56 + 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00, + // 0x57 + 0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00, + // 0x58 + 0x00,0x00,0xC6,0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00, + // 0x59 + 0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, + // 0x5A + 0x00,0x00,0xFE,0xC6,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00, + // 0x5B + 0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00, + // 0x5C + 0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00, + // 0x5D + 0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00, + // 0x5E + 0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0x5F + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00, + // 0x60 + 0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0x61 + 0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, + // 0x62 + 0x00,0x00,0xE0,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00, + // 0x63 + 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x64 + 0x00,0x00,0x1C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, + // 0x65 + 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x66 + 0x00,0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, + // 0x67 + 0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0xCC,0x78,0x00, + // 0x68 + 0x00,0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00, + // 0x69 + 0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, + // 0x6A + 0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x66,0x3C,0x00, + // 0x6B + 0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00, + // 0x6C + 0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, + // 0x6D + 0x00,0x00,0x00,0x00,0x00,0xEC,0xFE,0xD6,0xD6,0xD6,0xD6,0xC6,0x00,0x00,0x00,0x00, + // 0x6E + 0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00, + // 0x6F + 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x70 + 0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00, + // 0x71 + 0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00, + // 0x72 + 0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x66,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00, + // 0x73 + 0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x74 + 0x00,0x00,0x10,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00, + // 0x75 + 0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, + // 0x76 + 0x00,0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00, + // 0x77 + 0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00, + // 0x78 + 0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00, + // 0x79 + 0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00, + // 0x7A + 0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00, + // 0x7B + 0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00, + // 0x7C + 0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, + // 0x7D + 0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00, + // 0x7E + 0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0x7F + 0x00,0x00,0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xC6,0xFE,0x00,0x00,0x00,0x00,0x00, + // 0x80 + 0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x0C,0x06,0x7C,0x00,0x00, + // 0x81 + 0x00,0x00,0xCC,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, + // 0x82 + 0x00,0x0C,0x18,0x30,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x83 + 0x00,0x10,0x38,0x6C,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, + // 0x84 + 0x00,0x00,0xCC,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, + // 0x85 + 0x00,0x60,0x30,0x18,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, + // 0x86 + 0x00,0x38,0x6C,0x38,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, + // 0x87 + 0x00,0x00,0x00,0x00,0x3C,0x66,0x60,0x60,0x66,0x3C,0x0C,0x06,0x3C,0x00,0x00,0x00, + // 0x88 + 0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x89 + 0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x8A + 0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x8B + 0x00,0x00,0x66,0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, + // 0x8C + 0x00,0x18,0x3C,0x66,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, + // 0x8D + 0x00,0x60,0x30,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, + // 0x8E + 0x00,0xC6,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, + // 0x8F + 0x38,0x6C,0x38,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, + // 0x90 + 0x18,0x30,0x60,0x00,0xFE,0x66,0x60,0x7C,0x60,0x60,0x66,0xFE,0x00,0x00,0x00,0x00, + // 0x91 + 0x00,0x00,0x00,0x00,0x00,0xCC,0x76,0x36,0x7E,0xD8,0xD8,0x6E,0x00,0x00,0x00,0x00, + // 0x92 + 0x00,0x00,0x3E,0x6C,0xCC,0xCC,0xFE,0xCC,0xCC,0xCC,0xCC,0xCE,0x00,0x00,0x00,0x00, + // 0x93 + 0x00,0x10,0x38,0x6C,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x94 + 0x00,0x00,0xC6,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x95 + 0x00,0x60,0x30,0x18,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x96 + 0x00,0x30,0x78,0xCC,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, + // 0x97 + 0x00,0x60,0x30,0x18,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, + // 0x98 + 0x00,0x00,0xC6,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0x78,0x00, + // 0x99 + 0x00,0xC6,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x9A + 0x00,0xC6,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0x9B + 0x00,0x18,0x18,0x3C,0x66,0x60,0x60,0x60,0x66,0x3C,0x18,0x18,0x00,0x00,0x00,0x00, + // 0x9C + 0x00,0x38,0x6C,0x64,0x60,0xF0,0x60,0x60,0x60,0x60,0xE6,0xFC,0x00,0x00,0x00,0x00, + // 0x9D + 0x00,0x00,0x66,0x66,0x3C,0x18,0x7E,0x18,0x7E,0x18,0x18,0x18,0x00,0x00,0x00,0x00, + // 0x9E + 0x00,0xF8,0xCC,0xCC,0xF8,0xC4,0xCC,0xDE,0xCC,0xCC,0xCC,0xC6,0x00,0x00,0x00,0x00, + // 0x9F + 0x00,0x0E,0x1B,0x18,0x18,0x18,0x7E,0x18,0x18,0x18,0x18,0x18,0xD8,0x70,0x00,0x00, + // 0xA0 + 0x00,0x18,0x30,0x60,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, + // 0xA1 + 0x00,0x0C,0x18,0x30,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00, + // 0xA2 + 0x00,0x18,0x30,0x60,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0xA3 + 0x00,0x18,0x30,0x60,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00, + // 0xA4 + 0x00,0x00,0x76,0xDC,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00, + // 0xA5 + 0x76,0xDC,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, + // 0xA6 + 0x00,0x3C,0x6C,0x6C,0x3E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xA7 + 0x00,0x38,0x6C,0x6C,0x38,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xA8 + 0x00,0x00,0x30,0x30,0x00,0x30,0x30,0x60,0xC0,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00, + // 0xA9 + 0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00, + // 0xAA + 0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00, + // 0xAB + 0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x60,0xDC,0x86,0x0C,0x18,0x3E,0x00,0x00, + // 0xAC + 0x00,0xC0,0xC0,0xC2,0xC6,0xCC,0x18,0x30,0x66,0xCE,0x9E,0x3E,0x06,0x06,0x00,0x00, + // 0xAD + 0x00,0x00,0x18,0x18,0x00,0x18,0x18,0x18,0x3C,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00, + // 0xAE + 0x00,0x00,0x00,0x00,0x00,0x36,0x6C,0xD8,0x6C,0x36,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xAF + 0x00,0x00,0x00,0x00,0x00,0xD8,0x6C,0x36,0x6C,0xD8,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xB0 + 0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44,0x11,0x44, + // 0xB1 + 0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA,0x55,0xAA, + // 0xB2 + 0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77,0xDD,0x77, + // 0xB3 + 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + // 0xB4 + 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + // 0xB5 + 0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + // 0xB6 + 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, + // 0xB7 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, + // 0xB8 + 0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + // 0xB9 + 0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, + // 0xBA + 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, + // 0xBB + 0x00,0x00,0x00,0x00,0x00,0xFE,0x06,0xF6,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, + // 0xBC + 0x36,0x36,0x36,0x36,0x36,0xF6,0x06,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xBD + 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xBE + 0x18,0x18,0x18,0x18,0x18,0xF8,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xBF + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + // 0xC0 + 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xC1 + 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xC2 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + // 0xC3 + 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + // 0xC4 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xC5 + 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + // 0xC6 + 0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + // 0xC7 + 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, + // 0xC8 + 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xC9 + 0x00,0x00,0x00,0x00,0x00,0x3F,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, + // 0xCA + 0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xCB + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, + // 0xCC + 0x36,0x36,0x36,0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, + // 0xCD + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xCE + 0x36,0x36,0x36,0x36,0x36,0xF7,0x00,0xF7,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, + // 0xCF + 0x18,0x18,0x18,0x18,0x18,0xFF,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xD0 + 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xD1 + 0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + // 0xD2 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, + // 0xD3 + 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xD4 + 0x18,0x18,0x18,0x18,0x18,0x1F,0x18,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xD5 + 0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + // 0xD6 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, + // 0xD7 + 0x36,0x36,0x36,0x36,0x36,0x36,0x36,0xFF,0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36, + // 0xD8 + 0x18,0x18,0x18,0x18,0x18,0xFF,0x18,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + // 0xD9 + 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xDA + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + // 0xDB + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + // 0xDC + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + // 0xDD + 0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0, + // 0xDE + 0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F,0x0F, + // 0xDF + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xE0 + 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0xD8,0xD8,0xD8,0xDC,0x76,0x00,0x00,0x00,0x00, + // 0xE1 + 0x00,0x00,0x78,0xCC,0xCC,0xCC,0xD8,0xCC,0xC6,0xC6,0xC6,0xCC,0x00,0x00,0x00,0x00, + // 0xE2 + 0x00,0x00,0xFE,0xC6,0xC6,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x00,0x00,0x00,0x00, + // 0xE3 + 0x00,0x00,0x00,0x00,0xFE,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00, + // 0xE4 + 0x00,0x00,0x00,0xFE,0xC6,0x60,0x30,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00, + // 0xE5 + 0x00,0x00,0x00,0x00,0x00,0x7E,0xD8,0xD8,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00, + // 0xE6 + 0x00,0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xC0,0x00,0x00,0x00, + // 0xE7 + 0x00,0x00,0x00,0x00,0x76,0xDC,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00, + // 0xE8 + 0x00,0x00,0x00,0x7E,0x18,0x3C,0x66,0x66,0x66,0x3C,0x18,0x7E,0x00,0x00,0x00,0x00, + // 0xE9 + 0x00,0x00,0x00,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0x6C,0x38,0x00,0x00,0x00,0x00, + // 0xEA + 0x00,0x00,0x38,0x6C,0xC6,0xC6,0xC6,0x6C,0x6C,0x6C,0x6C,0xEE,0x00,0x00,0x00,0x00, + // 0xEB + 0x00,0x00,0x1E,0x30,0x18,0x0C,0x3E,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00, + // 0xEC + 0x00,0x00,0x00,0x00,0x00,0x7E,0xDB,0xDB,0xDB,0x7E,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xED + 0x00,0x00,0x00,0x03,0x06,0x7E,0xDB,0xDB,0xF3,0x7E,0x60,0xC0,0x00,0x00,0x00,0x00, + // 0xEE + 0x00,0x00,0x1C,0x30,0x60,0x60,0x7C,0x60,0x60,0x60,0x30,0x1C,0x00,0x00,0x00,0x00, + // 0xEF + 0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00, + // 0xF0 + 0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00, + // 0xF1 + 0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0xFF,0x00,0x00,0x00,0x00, + // 0xF2 + 0x00,0x00,0x00,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x00,0x7E,0x00,0x00,0x00,0x00, + // 0xF3 + 0x00,0x00,0x00,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x00,0x7E,0x00,0x00,0x00,0x00, + // 0xF4 + 0x00,0x00,0x0E,0x1B,0x1B,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, + // 0xF5 + 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xD8,0xD8,0xD8,0x70,0x00,0x00,0x00,0x00, + // 0xF6 + 0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x7E,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00, + // 0xF7 + 0x00,0x00,0x00,0x00,0x00,0x76,0xDC,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xF8 + 0x00,0x38,0x6C,0x6C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xF9 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x2F '/' - 0x00,0x60,0x30,0x18,0x0C,0x06,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x30 '0' - 0x00,0x3C,0x66,0x66,0x76,0x6E,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x31 '1' - 0x00,0x18,0x1C,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x32 '2' - 0x00,0x3C,0x66,0x60,0x30,0x18,0x0C,0x66,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x33 '3' - 0x00,0x3C,0x66,0x60,0x38,0x60,0x60,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x34 '4' - 0x00,0x30,0x38,0x3C,0x36,0x33,0x7F,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x35 '5' - 0x00,0x7E,0x06,0x06,0x3E,0x60,0x60,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x36 '6' - 0x00,0x38,0x0C,0x06,0x3E,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x37 '7' - 0x00,0x7E,0x60,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x38 '8' - 0x00,0x3C,0x66,0x66,0x3C,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x39 '9' - 0x00,0x3C,0x66,0x66,0x7C,0x60,0x30,0x18,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x3A ':' - 0x00,0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x3B ';' - 0x00,0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x3C '<' - 0x00,0x60,0x30,0x18,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x3D '=' - 0x00,0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x3E '>' - 0x00,0x06,0x0C,0x18,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x3F '?' - 0x00,0x3C,0x66,0x60,0x30,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x40 '@' - 0x00,0x3E,0x63,0x7B,0x7B,0x7B,0x3B,0x03,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x41 'A' - 0x00,0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x42 'B' - 0x00,0x3E,0x66,0x66,0x3E,0x66,0x66,0x66,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x43 'C' - 0x00,0x3C,0x66,0x06,0x06,0x06,0x06,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x44 'D' - 0x00,0x1E,0x36,0x66,0x66,0x66,0x66,0x36,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x45 'E' - 0x00,0x7E,0x06,0x06,0x3E,0x06,0x06,0x06,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x46 'F' - 0x00,0x7E,0x06,0x06,0x3E,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x47 'G' - 0x00,0x3C,0x66,0x06,0x06,0x76,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x48 'H' - 0x00,0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x49 'I' - 0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x4A 'J' - 0x00,0x78,0x30,0x30,0x30,0x30,0x36,0x36,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x4B 'K' - 0x00,0x66,0x36,0x1E,0x0E,0x1E,0x36,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x4C 'L' - 0x00,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x4D 'M' - 0x00,0x63,0x77,0x7F,0x6B,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x4E 'N' - 0x00,0x63,0x67,0x6F,0x7B,0x73,0x63,0x63,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x4F 'O' - 0x00,0x3C,0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x50 'P' - 0x00,0x3E,0x66,0x66,0x3E,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x51 'Q' - 0x00,0x3C,0x66,0x66,0x66,0x66,0x6E,0x3C,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x52 'R' - 0x00,0x3E,0x66,0x66,0x3E,0x36,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x53 'S' - 0x00,0x3C,0x66,0x06,0x1C,0x30,0x60,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x54 'T' - 0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x55 'U' - 0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x56 'V' - 0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x57 'W' - 0x00,0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x58 'X' - 0x00,0x66,0x66,0x3C,0x18,0x3C,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x59 'Y' - 0x00,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x5A 'Z' - 0x00,0x7E,0x60,0x30,0x18,0x0C,0x06,0x06,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x5B '[' - 0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x5C '\' - 0x00,0x03,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x5D ']' - 0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x5E '^' - 0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x5F '_' - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x60 '`' - 0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x61-0x7A lowercase - condensed to save space, using same shapes as upper offset by 32 - // 0x61 'a' - 0x00,0x00,0x00,0x1C,0x30,0x3C,0x33,0x33,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x62 'b' - 0x00,0x06,0x06,0x1E,0x36,0x66,0x66,0x66,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x63 'c' - 0x00,0x00,0x00,0x3C,0x06,0x06,0x06,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x64 'd' - 0x00,0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x65 'e' - 0x00,0x00,0x00,0x3C,0x66,0x7E,0x06,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x66 'f' - 0x00,0x38,0x0C,0x0C,0x3E,0x0C,0x0C,0x0C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x67 'g' - 0x00,0x00,0x7C,0x66,0x66,0x66,0x7C,0x60,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x68 'h' - 0x00,0x06,0x06,0x3E,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x69 'i' - 0x00,0x18,0x00,0x1C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x6A 'j' - 0x00,0x30,0x00,0x38,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x6B 'k' - 0x00,0x06,0x06,0x66,0x36,0x1E,0x36,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x6C 'l' - 0x00,0x1C,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x6D 'm' - 0x00,0x00,0x00,0x37,0x7F,0x6B,0x6B,0x6B,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x6E 'n' - 0x00,0x00,0x00,0x1E,0x36,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x6F 'o' - 0x00,0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x70 'p' - 0x00,0x00,0x3E,0x66,0x66,0x3E,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x71 'q' - 0x00,0x00,0x7C,0x66,0x66,0x7C,0x60,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x72 'r' - 0x00,0x00,0x00,0x3E,0x06,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x73 's' - 0x00,0x00,0x00,0x3C,0x06,0x1C,0x30,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x74 't' - 0x00,0x0C,0x0C,0x3E,0x0C,0x0C,0x0C,0x0C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x75 'u' - 0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x76 'v' - 0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x77 'w' - 0x00,0x00,0x00,0x63,0x6B,0x6B,0x7F,0x77,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x78 'x' - 0x00,0x00,0x00,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x79 'y' - 0x00,0x00,0x66,0x66,0x66,0x7C,0x60,0x30,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x7A 'z' - 0x00,0x00,0x00,0x7E,0x30,0x18,0x0C,0x06,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x7B '{' - 0x00,0x30,0x18,0x18,0x0C,0x18,0x18,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x7C '|' - 0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x7D '}' - 0x00,0x0C,0x18,0x18,0x30,0x18,0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - // 0x7E '~' - 0x00,0x6E,0x3B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xFA + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xFB + 0x00,0x0F,0x0C,0x0C,0x0C,0x0C,0x0C,0xEC,0x6C,0x6C,0x3C,0x1C,0x00,0x00,0x00,0x00, + // 0xFC + 0x00,0xD8,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xFD + 0x00,0x70,0xD8,0x30,0x60,0xC8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + // 0xFE + 0x00,0x00,0x00,0x00,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x00,0x00,0x00,0x00,0x00, + // 0xFF + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, }; diff --git a/code/kernel/include/kernel/hal/hal_apic.h b/code/kernel/include/kernel/hal/hal_apic.h index e68c7c5..38dad95 100644 --- a/code/kernel/include/kernel/hal/hal_apic.h +++ b/code/kernel/include/kernel/hal/hal_apic.h @@ -34,4 +34,5 @@ __declspec(dllexport) void HalApicEnableCurrentCpu(void); __declspec(dllexport) void HalApicSendPanicIpi(void); __declspec(dllexport) void HalApicSendRescheduleIpi(uint32_t lapicId); __declspec(dllexport) void HalApicSendTlbShootdownIpi(uint32_t lapicId); +__declspec(dllexport) void HalTimerConfigureCurrentCpu(void); __declspec(dllexport) KSTATUS HalStartApplicationProcessor(uint32_t lapicId, uint8_t startupVector); diff --git a/code/kernel/include/kernel/ldr_image.h b/code/kernel/include/kernel/ldr_image.h index c40eb87..f72d6b3 100644 --- a/code/kernel/include/kernel/ldr_image.h +++ b/code/kernel/include/kernel/ldr_image.h @@ -31,7 +31,6 @@ KSTATUS LdrResolveImports(uintptr_t imageBase); KSTATUS LdrResolveImportsForProcess(struct PROCESS* process, uintptr_t imageBase); // Apply final page permissions for a loaded image after relocations/imports. -KSTATUS LdrProtectImage(uintptr_t imageBase, bool user); KSTATUS LdrProtectImageForProcess(struct PROCESS* process, uintptr_t imageBase, bool user); // Load a DLL for a specific process, resolve it against that process's diff --git a/code/kernel/include/kernel/mm_phys.h b/code/kernel/include/kernel/mm_phys.h index 2f95c81..16bb887 100644 --- a/code/kernel/include/kernel/mm_phys.h +++ b/code/kernel/include/kernel/mm_phys.h @@ -1,6 +1,6 @@ #pragma once // mm_phys.h - physical memory manager (PMM) -// Stack allocator over 4 KB frames, seeded from MEMORY_MAP. +// Bitmap allocator over 4 KB frames, seeded from MEMORY_MAP. #include #include #include @@ -11,6 +11,15 @@ typedef uint64_t PHYSICAL_ADDRESS; +typedef struct MM_PHYSICAL_STATS { + uint64_t TotalFrames; + uint64_t FreeFrames; + uint64_t UsedFrames; + uint64_t LargestFreeRun; + uint64_t FreeRunCount; + uint64_t FreeRunHistogram[8]; +} MM_PHYSICAL_STATS; + // Called once by KernelMain with the MEMORY_MAP from BOOT_INFO. bool MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase); @@ -29,3 +38,4 @@ __declspec(dllexport) PHYSICAL_ADDRESS MmAllocateContiguous(size_t count); size_t MmFreeFrameCount(void); size_t MmTotalFrameCount(void); +void MmQueryPhysicalStats(MM_PHYSICAL_STATS* out); diff --git a/code/kernel/include/kernel/mm_virt.h b/code/kernel/include/kernel/mm_virt.h index 13dafaf..cb34d9c 100644 --- a/code/kernel/include/kernel/mm_virt.h +++ b/code/kernel/include/kernel/mm_virt.h @@ -1,6 +1,6 @@ #pragma once // mm_virt.h - virtual memory manager (VMM) -// Manages the single shared PML4, kernel pool, and user heap. +// Manages the single shared PML4, kernel pool, and page-granular user VM regions. #include #include #include @@ -9,6 +9,11 @@ struct PROCESS; typedef struct PROCESS PROCESS; +typedef enum MM_MAP_MODE { + MmMapFailIfPresent = 0, + MmMapReplaceExisting = 1, +} MM_MAP_MODE; + typedef enum USER_REGION_TYPE { UserRegionGeneric = 0, UserRegionHeap, @@ -59,7 +64,7 @@ void MmActivate(void); // --------------------------------------------------------------------------- // Page mapping // --------------------------------------------------------------------------- -__declspec(dllexport) KSTATUS MmMapPage(uintptr_t virt, PHYSICAL_ADDRESS phys, uint64_t flags); +__declspec(dllexport) KSTATUS MmMapPage(uintptr_t virt, PHYSICAL_ADDRESS phys, uint64_t flags, MM_MAP_MODE mode); __declspec(dllexport) KSTATUS MmUnmapPage(uintptr_t virt); // Modify protection flags on an already-mapped virtual range. @@ -120,6 +125,7 @@ KSTATUS MmEnsureUserRegionMapped(PROCESS* process, void* base, size_t size, uint KSTATUS MmProtectUserRegion(PROCESS* process, void* base, size_t size, uint64_t pageFlags); KSTATUS MmDestroyUserRegion(PROCESS* process, void* base); void MmDestroyAllUserRegions(PROCESS* process); +KSTATUS MmQueryUserRegion(PROCESS* process, const void* address, void** baseOut, size_t* sizeOut, uint64_t* pageFlagsOut, USER_REGION_TYPE* typeOut, uint32_t* regionFlagsOut); size_t MmGetUserRegionSize(PROCESS* process, const void* base); size_t MmGetUserRegionSizeByBase(const void* base); diff --git a/code/kernel/include/kernel/syscall_nr.h b/code/kernel/include/kernel/syscall_nr.h index cf83049..0263304 100644 --- a/code/kernel/include/kernel/syscall_nr.h +++ b/code/kernel/include/kernel/syscall_nr.h @@ -6,95 +6,97 @@ // R10, R11 = args 4-5 (loaded by SYSCALL_STUB6) // RAX = return value -#define SYS_EXIT_PROCESS 0 -#define SYS_EXIT_THREAD 1 -#define SYS_CREATE_PROCESS 2 -#define SYS_WAIT_FOR_PROCESS 3 -#define SYS_GET_PROCESS_EXIT_CODE 4 -#define SYS_KILL_PROCESS 5 -#define SYS_GET_PROCESS_LIST 6 -#define SYS_GET_PROCESS_PID 7 -#define SYS_CREATE_THREAD 8 -#define SYS_WAIT_THREAD 9 -#define SYS_GET_CURRENT_TID 10 -#define SYS_GET_CURRENT_PID 11 -#define SYS_SET_THREAD_PRIORITY 12 -#define SYS_YIELD 13 -#define SYS_SLEEP 14 -#define SYS_SET_USER_APC_DISPATCHER 15 -#define SYS_APC_RETURN 16 -#define SYS_ALLOC 17 -#define SYS_FREE 18 -#define SYS_REALLOC 19 -#define SYS_CLOSE_HANDLE 20 -#define SYS_MUTEX_CREATE 21 -#define SYS_MUTEX_ACQUIRE 22 -#define SYS_MUTEX_TRY_ACQUIRE 23 -#define SYS_MUTEX_RELEASE 24 -#define SYS_SEM_CREATE 25 -#define SYS_SEM_WAIT 26 -#define SYS_SEM_TRY_WAIT 27 -#define SYS_SEM_SIGNAL 28 -#define SYS_EVENT_CREATE 29 -#define SYS_EVENT_SIGNAL 30 -#define SYS_EVENT_CLEAR 31 -#define SYS_EVENT_WAIT 32 -#define SYS_QUEUE_CREATE 33 -#define SYS_QUEUE_SEND 34 -#define SYS_QUEUE_RECV 35 -#define SYS_PUBLISH_QUEUE 36 -#define SYS_OPEN_NAMED_QUEUE 37 -#define SYS_QUEUE_DUPLICATE 38 -#define SYS_NAMED_QUEUE_OWNER_PID 39 -#define SYS_OPEN_FILE 40 -#define SYS_CREATE_FILE 41 -#define SYS_READ_FILE 42 -#define SYS_WRITE_FILE 43 -#define SYS_READ_FILE_ASYNC 44 -#define SYS_WRITE_FILE_ASYNC 45 -#define SYS_CANCEL_IO 46 -#define SYS_SEEK_FILE 47 -#define SYS_GET_FILE_POS 48 -#define SYS_GET_FILE_SIZE 49 -#define SYS_TRUNCATE_FILE 50 -#define SYS_DELETE_FILE 51 -#define SYS_RENAME_FILE 52 -#define SYS_OPEN_DIR 53 -#define SYS_READ_DIR 54 -#define SYS_CREATE_DIR 55 -#define SYS_REMOVE_DIR 56 -#define SYS_SET_CWD 57 -#define SYS_GET_CWD 58 -#define SYS_WRITE_CONSOLE 59 -#define SYS_SCREEN_BLIT 60 -#define SYS_SCREEN_CLEAR 61 -#define SYS_SCREEN_GET_SIZE 62 -#define SYS_SCREEN_PUT_CHAR 63 -#define SYS_KB_POLL 64 -#define SYS_KB_IS_KEY_DOWN 65 -#define SYS_KB_READ_CHAR 66 -#define SYS_KB_READ_KEY 67 -#define SYS_KB_GET_MODIFIERS 68 -#define SYS_MOUSE_POLL 69 -#define SYS_MOUSE_READ 70 -#define SYS_MOUSE_GET_POS 71 -#define SYS_GET_TICK 72 -#define SYS_DEBUG_PRINT 73 -#define SYS_QUERY_TRAP_FRAME 74 -#define SYS_SOCKET 75 -#define SYS_BIND 76 -#define SYS_LISTEN 77 -#define SYS_ACCEPT 78 -#define SYS_CONNECT 79 -#define SYS_SEND 80 -#define SYS_RECV 81 -#define SYS_SHUTDOWN 82 -#define SYS_SEND_TO 83 -#define SYS_RECV_FROM 84 -#define SYS_RESOLVE_HOST 85 -#define SYS_SET_SOCKET_OPTION 86 -#define SYS_GET_SOCKET_OPTION 87 -#define SYS_POLL 88 -#define SYS_GET_MEMORY_STATUS 89 +#define SYS_EXIT_PROCESS 0 +#define SYS_EXIT_THREAD 1 +#define SYS_CREATE_PROCESS 2 +#define SYS_WAIT_FOR_PROCESS 3 +#define SYS_GET_PROCESS_EXIT_CODE 4 +#define SYS_KILL_PROCESS 5 +#define SYS_GET_PROCESS_LIST 6 +#define SYS_GET_PROCESS_PID 7 +#define SYS_CREATE_THREAD 8 +#define SYS_WAIT_THREAD 9 +#define SYS_GET_CURRENT_TID 10 +#define SYS_GET_CURRENT_PID 11 +#define SYS_SET_THREAD_PRIORITY 12 +#define SYS_YIELD 13 +#define SYS_SLEEP 14 +#define SYS_SET_USER_APC_DISPATCHER 15 +#define SYS_APC_RETURN 16 +#define SYS_VM_ALLOC 17 +#define SYS_VM_FREE 18 +#define SYS_VM_PROTECT 19 +#define SYS_VM_QUERY 20 +#define SYS_CLOSE_HANDLE 21 +#define SYS_MUTEX_CREATE 22 +#define SYS_MUTEX_ACQUIRE 23 +#define SYS_MUTEX_TRY_ACQUIRE 24 +#define SYS_MUTEX_RELEASE 25 +#define SYS_SEM_CREATE 26 +#define SYS_SEM_WAIT 27 +#define SYS_SEM_TRY_WAIT 28 +#define SYS_SEM_SIGNAL 29 +#define SYS_EVENT_CREATE 30 +#define SYS_EVENT_SIGNAL 31 +#define SYS_EVENT_CLEAR 32 +#define SYS_EVENT_WAIT 33 +#define SYS_QUEUE_CREATE 34 +#define SYS_QUEUE_SEND 35 +#define SYS_QUEUE_RECV 36 +#define SYS_PUBLISH_QUEUE 37 +#define SYS_OPEN_NAMED_QUEUE 38 +#define SYS_QUEUE_DUPLICATE 39 +#define SYS_NAMED_QUEUE_OWNER_PID 40 +#define SYS_OPEN_FILE 41 +#define SYS_CREATE_FILE 42 +#define SYS_READ_FILE 43 +#define SYS_WRITE_FILE 44 +#define SYS_READ_FILE_ASYNC 45 +#define SYS_WRITE_FILE_ASYNC 46 +#define SYS_CANCEL_IO 47 +#define SYS_SEEK_FILE 48 +#define SYS_GET_FILE_POS 49 +#define SYS_GET_FILE_SIZE 50 +#define SYS_TRUNCATE_FILE 51 +#define SYS_DELETE_FILE 52 +#define SYS_RENAME_FILE 53 +#define SYS_OPEN_DIR 54 +#define SYS_READ_DIR 55 +#define SYS_CREATE_DIR 56 +#define SYS_REMOVE_DIR 57 +#define SYS_SET_CWD 58 +#define SYS_GET_CWD 59 +#define SYS_WRITE_CONSOLE 60 +#define SYS_SCREEN_BLIT 61 +#define SYS_SCREEN_CLEAR 62 +#define SYS_SCREEN_GET_SIZE 63 +#define SYS_SCREEN_PUT_CHAR 64 +#define SYS_KB_POLL 65 +#define SYS_KB_IS_KEY_DOWN 66 +#define SYS_KB_READ_CHAR 67 +#define SYS_KB_READ_KEY 68 +#define SYS_KB_GET_MODIFIERS 69 +#define SYS_MOUSE_POLL 70 +#define SYS_MOUSE_READ 71 +#define SYS_MOUSE_GET_POS 72 +#define SYS_GET_TICK 73 +#define SYS_DEBUG_PRINT 74 +#define SYS_QUERY_TRAP_FRAME 75 +#define SYS_SOCKET 76 +#define SYS_BIND 77 +#define SYS_LISTEN 78 +#define SYS_ACCEPT 79 +#define SYS_CONNECT 80 +#define SYS_SEND 81 +#define SYS_RECV 82 +#define SYS_SHUTDOWN 83 +#define SYS_SEND_TO 84 +#define SYS_RECV_FROM 85 +#define SYS_RESOLVE_HOST 86 +#define SYS_SET_SOCKET_OPTION 87 +#define SYS_GET_SOCKET_OPTION 88 +#define SYS_POLL 89 +#define SYS_GET_MEMORY_STATUS 90 +#define SYS_QUERY_KERNEL_STATS 91 -#define SYS_MAX 90 +#define SYS_MAX 92 diff --git a/code/kernel/ke_debug.c b/code/kernel/ke_debug.c index a23c57f..3f4114e 100644 --- a/code/kernel/ke_debug.c +++ b/code/kernel/ke_debug.c @@ -57,7 +57,7 @@ static void KiDebugConsoleWrite(const char* text, size_t len) { if (!PrintChar || !text) return; for (size_t i = 0; i < len; i++) - PrintChar(text[i], 0x00FF00, 0x000000); + PrintChar(text[i], 0xCCCCCC, 0x012456); } static volatile long gPanicInProgress = 0; @@ -88,7 +88,7 @@ __declspec(dllexport) int KeHandleNmiIpi(void) { } void KiKernelPutChar(char c) { - PrintChar(c, 0x00FF00, 0x000000); + PrintChar(c, 0xCCCCCC, 0x012456); } void KeInitDebug(void (*PrintPtr)(char, uint32_t, uint32_t), uint32_t flags) { @@ -231,13 +231,12 @@ __declspec(dllexport) _Noreturn void KePanic(int code, const char* fmt, ...) { for (;;) __halt(); } -// KePrintConsole - write user-visible console text in white-on-black. -// Used by SYS_WRITE_CONSOLE so user programs get a distinct color from -// kernel debug output (green) and panic output (red). +// KePrintConsole - write user-visible console text using the default console palette. +// Panic output keeps a distinct color so fatal paths remain visually obvious. __declspec(dllexport) void KePrintConsole(const char* buf, size_t len) { if (!buf || !PrintChar) return; for (size_t i = 0; i < len; i++) - PrintChar(buf[i], 0xFFFFFF, 0x000000); + PrintChar(buf[i], 0xCCCCCC, 0x012456); } // --------------------------------------------------------------------------- diff --git a/code/kernel/ke_irq.c b/code/kernel/ke_irq.c index fe19393..24abff8 100644 --- a/code/kernel/ke_irq.c +++ b/code/kernel/ke_irq.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include @@ -115,6 +117,12 @@ void KiExitInterrupt(void) { // code, leave the request pending instead of switching out of a spinlock or // high-IRQL region. if (cpu->InterruptDepth == 0 && KeGetCurrentIrql() == PASSIVE_LEVEL) { + THREAD* current = cpu->CurrentThread; + if (current && !current->IsIdleThread && current->Owner && KeIsProcessTerminating(current->Owner)) { + KeExitThread(current, current->Owner->ExitCode); + while (true) ; + } + KiDrainDpcQueue(); if (KeGetCurrentIrql() == PASSIVE_LEVEL) KiScheduleFromInterrupt(); diff --git a/code/kernel/ke_process.c b/code/kernel/ke_process.c index ac20ea8..09460b2 100644 --- a/code/kernel/ke_process.c +++ b/code/kernel/ke_process.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include // --------------------------------------------------------------------------- // Global process list @@ -382,16 +384,26 @@ KSTATUS KeTerminateProcess(PROCESS* process, int exitCode) { process->ExitCode = exitCode; _InterlockedExchange(&process->Terminating, 1); - // Wake alertable waiters so they can notice Terminating at the syscall/ - // wait boundary. This is intentionally conservative: fully asynchronous - // forced thread teardown needs object-specific wait-list locking and is a - // larger process-lifecycle project. uintptr_t flags = KeAcquireSpinlock(&process->HandleLock); LIST_ENTRY* head = &process->ThreadList; + THREAD* self = KeGetCurrentThread(); + KCPU* selfCpu = KeGetCurrentCpu(); + uint32_t selfIndex = selfCpu ? selfCpu->CpuIndex : KE_INVALID_CPU; + for (LIST_ENTRY* node = head->Fwd; node != head; node = node->Fwd) { THREAD* t = CONTAINING_RECORD(node, THREAD, ProcessLink); - if (t != KeGetCurrentThread()) - (void)KeAlertThread(t); + if (t == self) + continue; + + (void)KeAlertThread(t); + + if (t->RunningCpu != KE_INVALID_CPU && t->RunningCpu != selfIndex && t->RunningCpu < gCpuCount) { + KCPU* cpu = &gCpus[t->RunningCpu]; + if (cpu->Present && cpu->Started && cpu->Online) { + _InterlockedExchange(&cpu->ReschedulePending, 1); + HalApicSendRescheduleIpi(cpu->LapicId); + } + } } KeReleaseSpinlock(&process->HandleLock, flags); diff --git a/code/kernel/ke_sched.c b/code/kernel/ke_sched.c index b6d285e..e22bd30 100644 --- a/code/kernel/ke_sched.c +++ b/code/kernel/ke_sched.c @@ -29,6 +29,10 @@ static uint64_t KiDefaultThreadAffinityMask(void) { return 1ULL; } +static int KiThreadIsKilledLocked(const THREAD* thread) { + return thread && !thread->IsIdleThread && thread->Owner && KeIsProcessTerminating(thread->Owner); +} + static int KiThreadCanRunOnCpuLocked(const THREAD* thread, const KCPU* cpu) { if (!thread || !cpu) return 0; if (thread->IsIdleThread) return thread == cpu->IdleThread; @@ -494,6 +498,10 @@ static void KiSchedule(void) { // still runnable and nobody else is ready, keep executing it. Otherwise a // lone CPU-bound thread gets alternated with the idle thread on every timer // tick, effectively turning a periodic preemption check into a 50% throttle. + if (cur != idle && KiThreadIsKilledLocked(cur)) { + cur->State = ThreadDead; + } + if (cur != idle && cur->State == ThreadRunning && !KiAnyRunnableForCpuLocked(cpu)) { if (cur->QuantumRemaining == 0) KiRefillQuantumLocked(cur); @@ -635,6 +643,8 @@ void KeSchedulerTick(void) { if (cur == idle) { if (KiAnyRunnableForCpuLocked(cpu)) requestReschedule = 1; + } else if (KiThreadIsKilledLocked(cur)) { + requestReschedule = 1; } else { cur->CpuBurstTicks++; cur->QuantaConsumed = cur->CpuBurstTicks; diff --git a/code/kernel/ke_smp.c b/code/kernel/ke_smp.c index 780d201..27947f1 100644 --- a/code/kernel/ke_smp.c +++ b/code/kernel/ke_smp.c @@ -298,13 +298,29 @@ _Noreturn void KiApKernelEntry(KCPU* cpu) { idle->RunningCpu = cpu->CpuIndex; idle->Queued = 0; cpu->Parked = 0; + + // Do not arm the AP's periodic LAPIC timer while it is still in + // the raw park loop. Timer IRQs are scheduler-owned events; + // the AP may take them only after it has a current idle thread. + HalTimerConfigureCurrentCpu(); + _InterlockedExchange(&cpu->SchedulerActive, 1); _enable(); KeStartInitialThread(idle); } } - _mm_pause(); + // The BSP admits parked APs by storing SchedulerCommand and sending a + // wake IPI. Avoid the classic lost wakeup where the command appears + // between the poll and HLT: check once with interrupts disabled, then + // STI;HLT as a single sleep transition. + _disable(); + if (_InterlockedCompareExchange(&cpu->SchedulerCommand, 0, 0) != 0) { + _enable(); + continue; + } + _enable(); + __halt(); } } @@ -766,6 +782,13 @@ KSTATUS KeAdmitApplicationProcessorsToScheduler(void) { _ReadWriteBarrier(); _InterlockedExchange(&cpu->SchedulerCommand, 1); + // Parked APs sleep with HLT and have no LAPIC timer armed yet. The + // command store alone is not sufficient; send a fixed-vector IPI only + // to wake the parked loop. ReschedulePending is intentionally left + // clear, so the interrupt exit path will not try to schedule before + // the AP has installed its idle thread. + HalApicSendRescheduleIpi(cpu->LapicId); + int active = 0; for (uint32_t spin = 0; spin < AP_SCHED_TIMEOUT_SPINS; spin++) { if (_InterlockedCompareExchange(&cpu->SchedulerActive, 0, 0) != 0) { diff --git a/code/kernel/ke_syscall.c b/code/kernel/ke_syscall.c index 0927192..a511bbc 100644 --- a/code/kernel/ke_syscall.c +++ b/code/kernel/ke_syscall.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -354,33 +355,147 @@ static uint64_t SyscallSetThreadPriority(uint64_t a0, uint64_t a1, uint64_t a2, } // --------------------------------------------------------------------------- -// SYS_ALLOC (8) a0 = size -> void* +// SYS_VM_* page-granular user virtual memory // --------------------------------------------------------------------------- -static uint64_t SyscallAlloc(uint64_t a0, uint64_t a1, uint64_t a2, - uint64_t a3, uint64_t a4, uint64_t a5) { - (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; - if (!a0) return 0; - return (uint64_t)(uintptr_t)MmAllocateUserMemory((size_t)a0); +static KSTATUS KiVmProtectToPageFlags(uint32_t protect, uint64_t* flagsOut) { + if (!flagsOut) return STATUS_INVALID_PARAMETER; + switch (protect) { + case SYS_VM_NOACCESS: + *flagsOut = 0; + return STATUS_SUCCESS; + case SYS_VM_READ: + *flagsOut = PAGE_PRESENT | PAGE_USER | PAGE_NX; + return STATUS_SUCCESS; + case SYS_VM_READWRITE: + *flagsOut = PAGE_PRESENT | PAGE_USER | PAGE_WRITE | PAGE_NX; + return STATUS_SUCCESS; + case SYS_VM_EXECUTE: + case SYS_VM_EXECUTE_READ: + *flagsOut = PAGE_PRESENT | PAGE_USER; + return STATUS_SUCCESS; + case SYS_VM_EXECUTE_READWRITE: + *flagsOut = PAGE_PRESENT | PAGE_USER | PAGE_WRITE; + return STATUS_SUCCESS; + default: + return STATUS_INVALID_PARAMETER; + } } -// --------------------------------------------------------------------------- -// SYS_FREE a0 = ptr -// --------------------------------------------------------------------------- -static uint64_t SyscallFree(uint64_t a0, uint64_t a1, uint64_t a2, - uint64_t a3, uint64_t a4, uint64_t a5) { - (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; - if (a0) MmFreeUserMemory((void*)(uintptr_t)a0); +static uint32_t KiPageFlagsToVmProtect(uint64_t flags) { + if (!(flags & PAGE_PRESENT)) return SYS_VM_NOACCESS; + bool writable = (flags & PAGE_WRITE) != 0; + bool executable = (flags & PAGE_NX) == 0; + if (executable && writable) return SYS_VM_EXECUTE_READWRITE; + if (executable) return SYS_VM_EXECUTE_READ; + if (writable) return SYS_VM_READWRITE; + return SYS_VM_READ; +} + +static uint64_t SyscallVmAlloc(uint64_t a0, uint64_t a1, uint64_t a2, + uint64_t a3, uint64_t a4, uint64_t a5) { + (void)a5; + void* preferredBase = (void*)(uintptr_t)a0; + size_t pageCount = (size_t)a1; + uint32_t protect = (uint32_t)a2; + uint32_t flags = (uint32_t)a3; + void** baseOut = (void**)(uintptr_t)a4; + + if (!pageCount || !baseOut) return STATUS_INVALID_PARAMETER; + if (pageCount > ((size_t)-1) / PAGE_SIZE) return STATUS_NO_MEMORY; + if (preferredBase || (flags & SYS_VM_FLAG_FIXED)) return STATUS_NOT_SUPPORTED; + + uint64_t pageFlags = 0; + KSTATUS s = KiVmProtectToPageFlags(protect, &pageFlags); + if (!KSUCCESS(s)) return s; + + PROCESS* process = KeGetCurrentProcess(); + if (!process) return STATUS_FAILURE; + + void* base = (void*)0; + s = MmCreateUserRegion(process, pageCount * PAGE_SIZE, PAGE_SIZE, + pageFlags ? pageFlags : (PAGE_PRESENT | PAGE_WRITE | PAGE_USER | PAGE_NX), + USER_REGION_ZERO, + UserRegionGeneric, + &base); + if (!KSUCCESS(s)) return s; + + if (protect == SYS_VM_NOACCESS) { + s = MmProtectUserRegion(process, base, pageCount * PAGE_SIZE, 0); + if (!KSUCCESS(s)) { + MmDestroyUserRegion(process, base); + return s; + } + } + + s = CopyToUser(baseOut, &base, sizeof(base)); + if (!KSUCCESS(s)) { + MmDestroyUserRegion(process, base); + return s; + } return STATUS_SUCCESS; } -// --------------------------------------------------------------------------- -// SYS_REALLOC (10) a0 = ptr, a1 = newSize -> void* -// --------------------------------------------------------------------------- -static uint64_t SyscallRealloc(uint64_t a0, uint64_t a1, uint64_t a2, - uint64_t a3, uint64_t a4, uint64_t a5) { +static uint64_t SyscallVmFree(uint64_t a0, uint64_t a1, uint64_t a2, + uint64_t a3, uint64_t a4, uint64_t a5) { + (void)a1; (void)a2; (void)a3; (void)a4; (void)a5; + PROCESS* process = KeGetCurrentProcess(); + if (!process || !a0) return STATUS_INVALID_PARAMETER; + return MmDestroyUserRegion(process, (void*)(uintptr_t)a0); +} + +static uint64_t SyscallVmProtect(uint64_t a0, uint64_t a1, uint64_t a2, + uint64_t a3, uint64_t a4, uint64_t a5) { + (void)a4; (void)a5; + if (!a0 || !a1) return STATUS_INVALID_PARAMETER; + if ((size_t)a1 > ((size_t)-1) / PAGE_SIZE) return STATUS_NO_MEMORY; + + uint64_t pageFlags = 0; + KSTATUS s = KiVmProtectToPageFlags((uint32_t)a2, &pageFlags); + if (!KSUCCESS(s)) return s; + + PROCESS* process = KeGetCurrentProcess(); + if (!process) return STATUS_FAILURE; + + if (a3) { + void* regionBase = (void*)0; + size_t regionSize = 0; + uint64_t oldFlags = 0; + USER_REGION_TYPE type = UserRegionGeneric; + uint32_t regionFlags = 0; + s = MmQueryUserRegion(process, (void*)(uintptr_t)a0, ®ionBase, ®ionSize, &oldFlags, &type, ®ionFlags); + if (!KSUCCESS(s)) return s; + uint32_t oldProtect = KiPageFlagsToVmProtect(oldFlags); + s = CopyToUser((void*)(uintptr_t)a3, &oldProtect, sizeof(oldProtect)); + if (!KSUCCESS(s)) return s; + } + + return MmProtectUserRegion(process, (void*)(uintptr_t)a0, (size_t)a1 * PAGE_SIZE, pageFlags); +} + +static uint64_t SyscallVmQuery(uint64_t a0, uint64_t a1, uint64_t a2, + uint64_t a3, uint64_t a4, uint64_t a5) { (void)a2; (void)a3; (void)a4; (void)a5; - return (uint64_t)(uintptr_t)MmReallocateUserMemory( - (void*)(uintptr_t)a0, (size_t)a1); + if (!a0 || !a1) return STATUS_INVALID_PARAMETER; + + PROCESS* process = KeGetCurrentProcess(); + if (!process) return STATUS_FAILURE; + + void* base = (void*)0; + size_t size = 0; + uint64_t pageFlags = 0; + USER_REGION_TYPE type = UserRegionGeneric; + uint32_t regionFlags = 0; + KSTATUS s = MmQueryUserRegion(process, (void*)(uintptr_t)a0, &base, &size, &pageFlags, &type, ®ionFlags); + if (!KSUCCESS(s)) return s; + + SYS_VM_REGION_INFO info; + info.Base = base; + info.PageCount = size / PAGE_SIZE; + info.Protect = KiPageFlagsToVmProtect(pageFlags); + info.Flags = regionFlags; + info.Type = (uint32_t)type; + info.OwnerPid = process->ProcessId; + return CopyToUser((void*)(uintptr_t)a1, &info, sizeof(info)); } // --------------------------------------------------------------------------- @@ -2565,6 +2680,99 @@ static uint64_t SyscallGetMemoryStatus(uint64_t a0, uint64_t a1, uint64_t a2, return CopyToUser((void*)(uintptr_t)a0, &status, sizeof(status)); } + +// --------------------------------------------------------------------------- +// SYS_QUERY_KERNEL_STATS a0=classId a1=buffer a2=bufferSize a3=*requiredSizeOut +// --------------------------------------------------------------------------- +static KSTATUS KiReturnKernelStats(uint64_t bufferArg, size_t bufferSize, + uint64_t requiredArg, + const void* src, size_t size) { + if (requiredArg) { + KSTATUS s = KiCopySizeToUser(requiredArg, size); + if (!KSUCCESS(s)) return s; + } + + if (!bufferArg) + return STATUS_SUCCESS; + + if (bufferSize < size) + return STATUS_BUFFER_TOO_SMALL; + + return CopyToUser((void*)(uintptr_t)bufferArg, src, size); +} + +static uint64_t SyscallQueryKernelStats(uint64_t a0, uint64_t a1, uint64_t a2, + uint64_t a3, uint64_t a4, uint64_t a5) { + (void)a4; (void)a5; + + switch ((uint32_t)a0) { + case SYS_KERNEL_STATS_SCHEDULER: { + KE_SCHED_STATS ks; + SYS_SCHEDULER_STATS us; + KeGetSchedulerStats(&ks); + memset(&us, 0, sizeof(us)); + us.Ticks = ks.Ticks; + us.ContextSwitches = ks.ContextSwitches; + us.KeepCurrentDecisions = ks.KeepCurrentDecisions; + us.IdleSelections = ks.IdleSelections; + us.Demotions = ks.Demotions; + us.AgingPromotions = ks.AgingPromotions; + us.QuantumExpirations = ks.QuantumExpirations; + us.PriorityPreemptions = ks.PriorityPreemptions; + us.VoluntaryBlocks = ks.VoluntaryBlocks; + us.CpuBurstDemotions = ks.CpuBurstDemotions; + us.SmtSiblingDeferrals = ks.SmtSiblingDeferrals; + us.SmtPrimaryPokes = ks.SmtPrimaryPokes; + return KiReturnKernelStats(a1, (size_t)a2, a3, &us, sizeof(us)); + } + + case SYS_KERNEL_STATS_PMM: { + MM_PHYSICAL_STATS km; + SYS_PMM_STATS um; + MmQueryPhysicalStats(&km); + memset(&um, 0, sizeof(um)); + um.TotalFrames = km.TotalFrames; + um.FreeFrames = km.FreeFrames; + um.UsedFrames = km.UsedFrames; + um.LargestFreeRun = km.LargestFreeRun; + um.FreeRunCount = km.FreeRunCount; + for (size_t i = 0; i < 8; i++) + um.FreeRunHistogram[i] = km.FreeRunHistogram[i]; + return KiReturnKernelStats(a1, (size_t)a2, a3, &um, sizeof(um)); + } + + case SYS_KERNEL_STATS_CPU: { + SYS_CPU_STATS stats; + memset(&stats, 0, sizeof(stats)); + stats.CpuCount = gCpuCount; + uint32_t n = gCpuCount; + if (n > SYS_KERNEL_STATS_MAX_CPUS) + n = SYS_KERNEL_STATS_MAX_CPUS; + + for (uint32_t i = 0; i < n; i++) { + KCPU* cpu = &gCpus[i]; + SYS_CPU_STAT* out = &stats.Cpu[i]; + out->CpuIndex = cpu->CpuIndex; + out->LapicId = cpu->LapicId; + if (cpu->Present) out->Flags |= SYS_CPU_FLAG_PRESENT; + if (cpu->Started) out->Flags |= SYS_CPU_FLAG_STARTED; + if (cpu->Parked) out->Flags |= SYS_CPU_FLAG_PARKED; + if (cpu->Online) out->Flags |= SYS_CPU_FLAG_ONLINE; + if (cpu->IsBsp) out->Flags |= SYS_CPU_FLAG_BSP; + if (cpu->IsPrimaryThread) out->Flags |= SYS_CPU_FLAG_PRIMARY; + out->CurrentTid = cpu->CurrentThread ? cpu->CurrentThread->ThreadId : 0; + out->SchedulerTicks = cpu->SchedulerTicks; + out->ContextSwitches = cpu->ContextSwitches; + } + + return KiReturnKernelStats(a1, (size_t)a2, a3, &stats, sizeof(stats)); + } + + default: + return STATUS_INVALID_PARAMETER; + } +} + // =========================================================================== // Dispatch table - index must match SYS_* in syscall_nr.h exactly. // =========================================================================== @@ -2572,96 +2780,98 @@ typedef uint64_t (*SYSCALL_HANDLER)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); static const SYSCALL_HANDLER gSyscallTable[SYS_MAX] = { - /* 00 SYS_EXIT_PROCESS */ SyscallExitProcess, - /* 01 SYS_EXIT_THREAD */ SyscallExitThread, - /* 02 SYS_CREATE_PROCESS */ SyscallCreateProcess, - /* 03 SYS_WAIT_FOR_PROCESS */ SyscallWaitForProcess, - /* 04 SYS_GET_PROCESS_EXIT_CODE */ SyscallGetProcessExitCode, - /* 05 SYS_KILL_PROCESS */ SyscallKillProcess, - /* 06 SYS_GET_PROCESS_LIST */ SyscallGetProcessList, - /* 07 SYS_GET_PROCESS_PID */ SyscallGetProcessPid, - /* 08 SYS_CREATE_THREAD */ SyscallCreateThread, - /* 09 SYS_WAIT_THREAD */ SyscallWaitThread, - /* 10 SYS_GET_CURRENT_TID */ SyscallGetCurrentTid, - /* 11 SYS_GET_CURRENT_PID */ SyscallGetCurrentPid, - /* 12 SYS_SET_THREAD_PRIORITY */ SyscallSetThreadPriority, - /* 13 SYS_YIELD */ SyscallYield, - /* 14 SYS_SLEEP */ SyscallSleep, - /* 15 SYS_SET_USER_APC_DISPATCHER */ SyscallSetUserApcDispatcher, - /* 16 SYS_APC_RETURN */ SyscallApcReturn, - /* 17 SYS_ALLOC */ SyscallAlloc, - /* 18 SYS_FREE */ SyscallFree, - /* 19 SYS_REALLOC */ SyscallRealloc, - /* 20 SYS_CLOSE_HANDLE */ SyscallCloseHandle, - /* 21 SYS_MUTEX_CREATE */ SyscallMutexCreate, - /* 22 SYS_MUTEX_ACQUIRE */ SyscallMutexAcquire, - /* 23 SYS_MUTEX_TRY_ACQUIRE */ SyscallMutexTryAcquire, - /* 24 SYS_MUTEX_RELEASE */ SyscallMutexRelease, - /* 25 SYS_SEM_CREATE */ SyscallSemCreate, - /* 26 SYS_SEM_WAIT */ SyscallSemWait, - /* 27 SYS_SEM_TRY_WAIT */ SyscallSemTryWait, - /* 28 SYS_SEM_SIGNAL */ SyscallSemSignal, - /* 29 SYS_EVENT_CREATE */ SyscallEventCreate, - /* 30 SYS_EVENT_SIGNAL */ SyscallEventSignal, - /* 31 SYS_EVENT_CLEAR */ SyscallEventClear, - /* 32 SYS_EVENT_WAIT */ SyscallEventWait, - /* 33 SYS_QUEUE_CREATE */ SyscallQueueCreate, - /* 34 SYS_QUEUE_SEND */ SyscallQueueSend, - /* 35 SYS_QUEUE_RECV */ SyscallQueueRecv, - /* 36 SYS_PUBLISH_QUEUE */ SyscallPublishQueue, - /* 37 SYS_OPEN_NAMED_QUEUE */ SyscallOpenNamedQueue, - /* 38 SYS_QUEUE_DUPLICATE */ SyscallQueueDuplicate, - /* 39 SYS_NAMED_QUEUE_OWNER_PID */ SyscallNamedQueueOwnerPid, - /* 40 SYS_OPEN_FILE */ SyscallOpenFile, - /* 41 SYS_CREATE_FILE */ SyscallCreateFile, - /* 42 SYS_READ_FILE */ SyscallReadFile, - /* 43 SYS_WRITE_FILE */ SyscallWriteFile, - /* 44 SYS_READ_FILE_ASYNC */ SyscallReadFileAsync, - /* 45 SYS_WRITE_FILE_ASYNC */ SyscallWriteFileAsync, - /* 46 SYS_CANCEL_IO */ SyscallCancelIo, - /* 47 SYS_SEEK_FILE */ SyscallSeekFile, - /* 48 SYS_GET_FILE_POS */ SyscallGetFilePos, - /* 49 SYS_GET_FILE_SIZE */ SyscallGetFileSize, - /* 50 SYS_TRUNCATE_FILE */ SyscallTruncateFile, - /* 51 SYS_DELETE_FILE */ SyscallDeleteFile, - /* 52 SYS_RENAME_FILE */ SyscallRenameFile, - /* 53 SYS_OPEN_DIR */ SyscallOpenDir, - /* 54 SYS_READ_DIR */ SyscallReadDir, - /* 55 SYS_CREATE_DIR */ SyscallCreateDir, - /* 56 SYS_REMOVE_DIR */ SyscallRemoveDir, - /* 57 SYS_SET_CWD */ SyscallSetCwd, - /* 58 SYS_GET_CWD */ SyscallGetCwd, - /* 59 SYS_WRITE_CONSOLE */ SyscallWriteConsole, - /* 60 SYS_SCREEN_BLIT */ SyscallScreenBlit, - /* 61 SYS_SCREEN_CLEAR */ SyscallScreenClear, - /* 62 SYS_SCREEN_GET_SIZE */ SyscallScreenGetSize, - /* 63 SYS_SCREEN_PUT_CHAR */ SyscallScreenPutChar, - /* 64 SYS_KB_POLL */ SyscallKbPoll, - /* 65 SYS_KB_IS_KEY_DOWN */ SyscallKbIsKeyDown, - /* 66 SYS_KB_READ_CHAR */ SyscallKbReadChar, - /* 67 SYS_KB_READ_KEY */ SyscallKbReadKey, - /* 68 SYS_KB_GET_MODIFIERS */ SyscallKbGetModifiers, - /* 69 SYS_MOUSE_POLL */ SyscallMousePoll, - /* 70 SYS_MOUSE_READ */ SyscallMouseRead, - /* 71 SYS_MOUSE_GET_POS */ SyscallMouseGetPos, - /* 72 SYS_GET_TICK */ SyscallGetTick, - /* 73 SYS_DEBUG_PRINT */ SyscallDebugPrint, - /* 74 SYS_QUERY_TRAP_FRAME */ SyscallQueryTrapFrame, - /* 75 SYS_SOCKET */ SyscallSocket, - /* 76 SYS_BIND */ SyscallBind, - /* 77 SYS_LISTEN */ SyscallListen, - /* 78 SYS_ACCEPT */ SyscallAccept, - /* 79 SYS_CONNECT */ SyscallConnect, - /* 80 SYS_SEND */ SyscallSend, - /* 81 SYS_RECV */ SyscallRecv, - /* 82 SYS_SHUTDOWN */ SyscallShutdown, - /* 83 SYS_SEND_TO */ SyscallSendTo, - /* 84 SYS_RECV_FROM */ SyscallRecvFrom, - /* 85 SYS_RESOLVE_HOST */ SyscallResolveHost, - /* 86 SYS_SET_SOCKET_OPTION */ SyscallSetSocketOption, - /* 87 SYS_GET_SOCKET_OPTION */ SyscallGetSocketOption, - /* 88 SYS_POLL */ SyscallPoll, - /* 89 SYS_GET_MEMORY_STATUS */ SyscallGetMemoryStatus + /* 00 SYS_EXIT_PROCESS */ SyscallExitProcess, + /* 01 SYS_EXIT_THREAD */ SyscallExitThread, + /* 02 SYS_CREATE_PROCESS */ SyscallCreateProcess, + /* 03 SYS_WAIT_FOR_PROCESS */ SyscallWaitForProcess, + /* 04 SYS_GET_PROCESS_EXIT_CODE */ SyscallGetProcessExitCode, + /* 05 SYS_KILL_PROCESS */ SyscallKillProcess, + /* 06 SYS_GET_PROCESS_LIST */ SyscallGetProcessList, + /* 07 SYS_GET_PROCESS_PID */ SyscallGetProcessPid, + /* 08 SYS_CREATE_THREAD */ SyscallCreateThread, + /* 09 SYS_WAIT_THREAD */ SyscallWaitThread, + /* 10 SYS_GET_CURRENT_TID */ SyscallGetCurrentTid, + /* 11 SYS_GET_CURRENT_PID */ SyscallGetCurrentPid, + /* 12 SYS_SET_THREAD_PRIORITY */ SyscallSetThreadPriority, + /* 13 SYS_YIELD */ SyscallYield, + /* 14 SYS_SLEEP */ SyscallSleep, + /* 15 SYS_SET_USER_APC_DISPATCHER */ SyscallSetUserApcDispatcher, + /* 16 SYS_APC_RETURN */ SyscallApcReturn, + /* 17 SYS_VM_ALLOC */ SyscallVmAlloc, + /* 18 SYS_VM_FREE */ SyscallVmFree, + /* 19 SYS_VM_PROTECT */ SyscallVmProtect, + /* 20 SYS_VM_QUERY */ SyscallVmQuery, + /* 21 SYS_CLOSE_HANDLE */ SyscallCloseHandle, + /* 22 SYS_MUTEX_CREATE */ SyscallMutexCreate, + /* 23 SYS_MUTEX_ACQUIRE */ SyscallMutexAcquire, + /* 24 SYS_MUTEX_TRY_ACQUIRE */ SyscallMutexTryAcquire, + /* 25 SYS_MUTEX_RELEASE */ SyscallMutexRelease, + /* 26 SYS_SEM_CREATE */ SyscallSemCreate, + /* 27 SYS_SEM_WAIT */ SyscallSemWait, + /* 28 SYS_SEM_TRY_WAIT */ SyscallSemTryWait, + /* 29 SYS_SEM_SIGNAL */ SyscallSemSignal, + /* 30 SYS_EVENT_CREATE */ SyscallEventCreate, + /* 31 SYS_EVENT_SIGNAL */ SyscallEventSignal, + /* 32 SYS_EVENT_CLEAR */ SyscallEventClear, + /* 33 SYS_EVENT_WAIT */ SyscallEventWait, + /* 34 SYS_QUEUE_CREATE */ SyscallQueueCreate, + /* 35 SYS_QUEUE_SEND */ SyscallQueueSend, + /* 36 SYS_QUEUE_RECV */ SyscallQueueRecv, + /* 37 SYS_PUBLISH_QUEUE */ SyscallPublishQueue, + /* 38 SYS_OPEN_NAMED_QUEUE */ SyscallOpenNamedQueue, + /* 39 SYS_QUEUE_DUPLICATE */ SyscallQueueDuplicate, + /* 40 SYS_NAMED_QUEUE_OWNER_PID */ SyscallNamedQueueOwnerPid, + /* 41 SYS_OPEN_FILE */ SyscallOpenFile, + /* 42 SYS_CREATE_FILE */ SyscallCreateFile, + /* 43 SYS_READ_FILE */ SyscallReadFile, + /* 44 SYS_WRITE_FILE */ SyscallWriteFile, + /* 45 SYS_READ_FILE_ASYNC */ SyscallReadFileAsync, + /* 46 SYS_WRITE_FILE_ASYNC */ SyscallWriteFileAsync, + /* 47 SYS_CANCEL_IO */ SyscallCancelIo, + /* 48 SYS_SEEK_FILE */ SyscallSeekFile, + /* 49 SYS_GET_FILE_POS */ SyscallGetFilePos, + /* 50 SYS_GET_FILE_SIZE */ SyscallGetFileSize, + /* 51 SYS_TRUNCATE_FILE */ SyscallTruncateFile, + /* 52 SYS_DELETE_FILE */ SyscallDeleteFile, + /* 53 SYS_RENAME_FILE */ SyscallRenameFile, + /* 54 SYS_OPEN_DIR */ SyscallOpenDir, + /* 55 SYS_READ_DIR */ SyscallReadDir, + /* 56 SYS_CREATE_DIR */ SyscallCreateDir, + /* 57 SYS_REMOVE_DIR */ SyscallRemoveDir, + /* 58 SYS_SET_CWD */ SyscallSetCwd, + /* 59 SYS_GET_CWD */ SyscallGetCwd, + /* 60 SYS_WRITE_CONSOLE */ SyscallWriteConsole, + /* 61 SYS_SCREEN_BLIT */ SyscallScreenBlit, + /* 62 SYS_SCREEN_CLEAR */ SyscallScreenClear, + /* 63 SYS_SCREEN_GET_SIZE */ SyscallScreenGetSize, + /* 64 SYS_SCREEN_PUT_CHAR */ SyscallScreenPutChar, + /* 65 SYS_KB_POLL */ SyscallKbPoll, + /* 66 SYS_KB_IS_KEY_DOWN */ SyscallKbIsKeyDown, + /* 67 SYS_KB_READ_CHAR */ SyscallKbReadChar, + /* 68 SYS_KB_READ_KEY */ SyscallKbReadKey, + /* 69 SYS_KB_GET_MODIFIERS */ SyscallKbGetModifiers, + /* 70 SYS_MOUSE_POLL */ SyscallMousePoll, + /* 71 SYS_MOUSE_READ */ SyscallMouseRead, + /* 72 SYS_MOUSE_GET_POS */ SyscallMouseGetPos, + /* 73 SYS_GET_TICK */ SyscallGetTick, + /* 74 SYS_DEBUG_PRINT */ SyscallDebugPrint, + /* 75 SYS_QUERY_TRAP_FRAME */ SyscallQueryTrapFrame, + /* 76 SYS_SOCKET */ SyscallSocket, + /* 77 SYS_BIND */ SyscallBind, + /* 78 SYS_LISTEN */ SyscallListen, + /* 79 SYS_ACCEPT */ SyscallAccept, + /* 80 SYS_CONNECT */ SyscallConnect, + /* 81 SYS_SEND */ SyscallSend, + /* 82 SYS_RECV */ SyscallRecv, + /* 83 SYS_SHUTDOWN */ SyscallShutdown, + /* 84 SYS_SEND_TO */ SyscallSendTo, + /* 85 SYS_RECV_FROM */ SyscallRecvFrom, + /* 86 SYS_RESOLVE_HOST */ SyscallResolveHost, + /* 87 SYS_SET_SOCKET_OPTION */ SyscallSetSocketOption, + /* 88 SYS_GET_SOCKET_OPTION */ SyscallGetSocketOption, + /* 89 SYS_POLL */ SyscallPoll, + /* 90 SYS_GET_MEMORY_STATUS */ SyscallGetMemoryStatus, + /* 91 SYS_QUERY_KERNEL_STATS */ SyscallQueryKernelStats }; // --------------------------------------------------------------------------- @@ -2681,5 +2891,19 @@ uint64_t KeSyscallDispatch(uint64_t nr, uint64_t a0, uint64_t a1, } if (nr >= SYS_MAX || !gSyscallTable[nr]) return STATUS_NOT_SUPPORTED; - return gSyscallTable[nr](a0, a1, a2, a3, a4, a5); + + uint64_t result = gSyscallTable[nr](a0, a1, a2, a3, a4, a5); + + // A process may be terminated while one of its threads is already inside a + // syscall. Do not allow that thread to return to userspace after the owner + // has been marked terminating. + owner = self ? self->Owner : (PROCESS*)0; + if (owner && KeIsProcessTerminating(owner) && + nr != SYS_EXIT_PROCESS && nr != SYS_EXIT_THREAD) { + int exitCode = owner->ExitCode; + KeExitThread(self, exitCode); + while (true) ; + } + + return result; } diff --git a/code/kernel/kmain.c b/code/kernel/kmain.c index 06398c5..1719835 100644 --- a/code/kernel/kmain.c +++ b/code/kernel/kmain.c @@ -409,7 +409,7 @@ extern void KernelMain(BOOT_INFO* bootInfo) { .FramebufferHeight = bootInfo->FramebufferHeight, .FramebufferStride = bootInfo->FramebufferStride, .RsdpPhysical = bootInfo->RsdpPhysical, - .Debug = bootInfo->Debug, + .Debug = bootInfo->Debug & 1, // bitmask 1 debug prints .AllocatePool = MmAllocatePool }; diff --git a/code/kernel/ldr_image.c b/code/kernel/ldr_image.c index b455eeb..a1d805f 100644 --- a/code/kernel/ldr_image.c +++ b/code/kernel/ldr_image.c @@ -325,6 +325,7 @@ static void KiFreeLoadedImage(uintptr_t imageBase, bool user) { KSTATUS LdrProtectImageForProcess(PROCESS* process, uintptr_t imageBase, bool user) { if (!imageBase) return STATUS_INVALID_PARAMETER; + if (user && !process) return STATUS_INVALID_PARAMETER; size_t mappedSize = user ? LdrGetMappedImageSize(process, imageBase) : LdrGetImageSize(imageBase); if (!mappedSize) return STATUS_FAILURE; @@ -387,9 +388,6 @@ KSTATUS LdrProtectImageForProcess(PROCESS* process, uintptr_t imageBase, bool us return STATUS_SUCCESS; } -KSTATUS LdrProtectImage(uintptr_t imageBase, bool user) { - return LdrProtectImageForProcess(user ? (PROCESS*)0 : (PROCESS*)0, imageBase, user); -} // --------------------------------------------------------------------------- // Entry point lookup diff --git a/code/kernel/mm_phys.c b/code/kernel/mm_phys.c index 8c70abb..79763b6 100644 --- a/code/kernel/mm_phys.c +++ b/code/kernel/mm_phys.c @@ -1,13 +1,12 @@ // mm_phys.c - physical memory manager // -// The free-frame stack is a flat array of PHYSICAL_ADDRESS values carved out of -// the first suitable usable region before any allocation is served. All access -// to physical memory goes through the direct physical window established by the -// bootloader at PhysicalWindowBase (always 0xFFFF880000000000). -// -// Lock: a single spinlock guards Push/Pop. O(1) for both operations. +// Bitmap allocator over 4 KB physical frames. One bitmap records which PFNs +// exist in usable RAM, and one bitmap records which usable PFNs are currently +// free. This keeps single-frame allocation simple while making contiguous +// allocation and memory visualization deterministic. #include #include +#include // --------------------------------------------------------------------------- // Physical-to-virtual translation via the direct map window. @@ -19,122 +18,198 @@ static inline void* KiPhysToVirt(PHYSICAL_ADDRESS phys) { } // --------------------------------------------------------------------------- -// Frame stack +// Frame bitmap // --------------------------------------------------------------------------- typedef struct { - PHYSICAL_ADDRESS* Stack; // pointer into physical window - size_t Top; // index of next free slot (stack grows up) - size_t Capacity; - size_t Total; // total frames ever pushed - SPINLOCK Lock; -} FRAME_STACK; + uint8_t* Usable; // bit = 1 when PFN belongs to usable RAM + uint8_t* Free; // bit = 1 when PFN is currently free + size_t BitmapBytes; + size_t MaxPfn; + size_t TotalFrames; // usable frames available to the allocator + size_t FreeFrames; + SPINLOCK Lock; +} FRAME_BITMAP; -static FRAME_STACK gFrameStack; +static FRAME_BITMAP gFrameBitmap; -// Push a physical frame address onto the stack. -static void KiPushFrame(PHYSICAL_ADDRESS frame) { - uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock); - if (gFrameStack.Top < gFrameStack.Capacity) { - gFrameStack.Stack[gFrameStack.Top++] = frame; - gFrameStack.Total++; +static inline PHYSICAL_ADDRESS KiAlignUp(PHYSICAL_ADDRESS value) { + return (value + PAGE_SIZE - 1) & PAGE_MASK; +} + +static inline PHYSICAL_ADDRESS KiAlignDown(PHYSICAL_ADDRESS value) { + return value & PAGE_MASK; +} + +static inline int KiBitTest(const uint8_t* bits, size_t index) { + return (bits[index >> 3] & (uint8_t)(1u << (index & 7))) != 0; +} + +static inline void KiBitSet(uint8_t* bits, size_t index) { + bits[index >> 3] |= (uint8_t)(1u << (index & 7)); +} + +static inline void KiBitClear(uint8_t* bits, size_t index) { + bits[index >> 3] &= (uint8_t)~(1u << (index & 7)); +} + +static inline int KiPfnUsableLocked(size_t pfn) { + return pfn < gFrameBitmap.MaxPfn && KiBitTest(gFrameBitmap.Usable, pfn); +} + +static inline int KiPfnFreeLocked(size_t pfn) { + return KiPfnUsableLocked(pfn) && KiBitTest(gFrameBitmap.Free, pfn); +} + +static void KiMarkUsableFreeRange(size_t firstPfn, size_t count) { + for (size_t i = 0; i < count; i++) { + size_t pfn = firstPfn + i; + if (pfn >= gFrameBitmap.MaxPfn) break; + if (!KiBitTest(gFrameBitmap.Usable, pfn)) { + KiBitSet(gFrameBitmap.Usable, pfn); + gFrameBitmap.TotalFrames++; + } + if (!KiBitTest(gFrameBitmap.Free, pfn)) { + KiBitSet(gFrameBitmap.Free, pfn); + gFrameBitmap.FreeFrames++; + } + } +} + +static void KiRemoveUsablePfn(size_t pfn) { + if (pfn >= gFrameBitmap.MaxPfn) return; + if (KiBitTest(gFrameBitmap.Free, pfn)) { + KiBitClear(gFrameBitmap.Free, pfn); + if (gFrameBitmap.FreeFrames) gFrameBitmap.FreeFrames--; + } + if (KiBitTest(gFrameBitmap.Usable, pfn)) { + KiBitClear(gFrameBitmap.Usable, pfn); + if (gFrameBitmap.TotalFrames) gFrameBitmap.TotalFrames--; } - KeReleaseSpinlock(&gFrameStack.Lock, flags); } // --------------------------------------------------------------------------- // Initialisation // --------------------------------------------------------------------------- bool MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) { + if (!map) return false; gPhysBase = physicalWindowBase; - // --- Phase 0: Count total usable frames so we can size the stack - // dynamically instead of capping at a hardcoded 1 GB. --- - uint64_t totalUsableBytes = 0; - for (uint32_t i = 0; i < map->RegionCount; i++) { - if (map->Regions[i].Type == MemoryUsable) - totalUsableBytes += map->Regions[i].Length; - } - const size_t maxFrames = (size_t)(totalUsableBytes / PAGE_SIZE); - const size_t stackBytes = maxFrames * sizeof(PHYSICAL_ADDRESS); - - // --- Phase 1: Find a usable region large enough to hold the stack. --- - PHYSICAL_ADDRESS stackPhys = 0; - for (uint32_t i = 0; i < map->RegionCount; i++) { - const MEMORY_REGION* r = &map->Regions[i]; - if (r->Type == MemoryUsable && r->Length >= stackBytes + PAGE_SIZE) { - stackPhys = r->Base; - break; - } - } - - if (!stackPhys) { - return false; - } - - gFrameStack.Stack = (PHYSICAL_ADDRESS *)KiPhysToVirt(stackPhys); - gFrameStack.Top = 0; - gFrameStack.Capacity = maxFrames; - gFrameStack.Total = 0; - gFrameStack.Lock = (SPINLOCK)SPINLOCK_INIT; - - // --- Phase 2: Push all free 4 KB frames, skipping the stack pages. --- - const PHYSICAL_ADDRESS stackEnd = - stackPhys + ((stackBytes + PAGE_SIZE - 1) & PAGE_MASK); - + PHYSICAL_ADDRESS maxEnd = 0; for (uint32_t i = 0; i < map->RegionCount; i++) { const MEMORY_REGION* r = &map->Regions[i]; if (r->Type != MemoryUsable) continue; - PHYSICAL_ADDRESS base = r->Base; - PHYSICAL_ADDRESS end = r->Base + r->Length; + PHYSICAL_ADDRESS base = KiAlignUp(r->Base); + PHYSICAL_ADDRESS end = r->Base + r->Length; + if (end < r->Base) end = (PHYSICAL_ADDRESS)-1; + end = KiAlignDown(end); + if (end <= base) continue; + if (end > maxEnd) maxEnd = end; + } - for (PHYSICAL_ADDRESS frame = base; frame < end; frame += PAGE_SIZE) { - if (frame >= stackPhys && frame < stackEnd) continue; - KiPushFrame(frame); + size_t maxPfn = (size_t)(maxEnd / PAGE_SIZE); + if (!maxPfn) return false; + + size_t bitmapBytes = (maxPfn + 7) / 8; + size_t metadataBytes = bitmapBytes * 2; + size_t metadataPages = (metadataBytes + PAGE_SIZE - 1) / PAGE_SIZE; + PHYSICAL_ADDRESS metadataSize = (PHYSICAL_ADDRESS)metadataPages * PAGE_SIZE; + + // Keep allocator metadata out of low memory. The bitmap is much smaller + // than the old free-frame stack, so a first-fit search can otherwise choose + // a conventional-memory hole below 1 MiB. That range is still useful for + // AP startup/legacy scratch, and stealing it makes early boot failures + // unnecessarily silent because PMM initializes before normal debug output. + const PHYSICAL_ADDRESS metadataMin = 0x100000ULL; + PHYSICAL_ADDRESS metadataPhys = 0; + int metadataFound = 0; + for (uint32_t i = 0; i < map->RegionCount; i++) { + const MEMORY_REGION* r = &map->Regions[i]; + if (r->Type != MemoryUsable) continue; + + PHYSICAL_ADDRESS base = KiAlignUp(r->Base); + if (base < metadataMin) base = metadataMin; + PHYSICAL_ADDRESS end = r->Base + r->Length; + if (end < r->Base) end = (PHYSICAL_ADDRESS)-1; + end = KiAlignDown(end); + if (end <= base) continue; + if (end - base >= metadataSize) { + metadataPhys = base; + metadataFound = 1; + break; } } + if (!metadataFound) return false; + + gFrameBitmap.BitmapBytes = bitmapBytes; + gFrameBitmap.MaxPfn = maxPfn; + gFrameBitmap.TotalFrames = 0; + gFrameBitmap.FreeFrames = 0; + gFrameBitmap.Lock = (SPINLOCK)SPINLOCK_INIT; + gFrameBitmap.Usable = (uint8_t*)KiPhysToVirt(metadataPhys); + gFrameBitmap.Free = gFrameBitmap.Usable + bitmapBytes; + + memset(gFrameBitmap.Usable, 0, metadataBytes); + + // Mark page-aligned usable RAM as free. Unaligned tails are ignored rather + // than handing malformed frame addresses to the rest of the kernel. + for (uint32_t i = 0; i < map->RegionCount; i++) { + const MEMORY_REGION* r = &map->Regions[i]; + if (r->Type != MemoryUsable) continue; + + PHYSICAL_ADDRESS base = KiAlignUp(r->Base); + PHYSICAL_ADDRESS end = r->Base + r->Length; + if (end < r->Base) end = (PHYSICAL_ADDRESS)-1; + end = KiAlignDown(end); + if (end <= base) continue; + + size_t firstPfn = (size_t)(base / PAGE_SIZE); + size_t count = (size_t)((end - base) / PAGE_SIZE); + KiMarkUsableFreeRange(firstPfn, count); + } + + // PFN 0 is never a valid allocation result because 0 is the failure value. + KiRemoveUsablePfn(0); + + // Hide the PMM metadata pages from the allocator entirely. They are not + // merely allocated; they are structural storage that must not become free if + // some caller accidentally passes their PFNs to MmFreeFrame(). + size_t metadataFirstPfn = (size_t)(metadataPhys / PAGE_SIZE); + for (size_t i = 0; i < metadataPages; i++) + KiRemoveUsablePfn(metadataFirstPfn + i); + return true; } // --------------------------------------------------------------------------- // Public API // --------------------------------------------------------------------------- -static PHYSICAL_ADDRESS KiPopFrameAtIndexLocked(size_t idx) { - PHYSICAL_ADDRESS frame = gFrameStack.Stack[idx]; - size_t tail = gFrameStack.Top - idx - 1; - for (size_t j = 0; j < tail; j++) - gFrameStack.Stack[idx + j] = gFrameStack.Stack[idx + 1 + j]; - gFrameStack.Top--; - return frame; -} - PHYSICAL_ADDRESS MmAllocateFrameInRange(PHYSICAL_ADDRESS minInclusive, PHYSICAL_ADDRESS maxExclusive) { - minInclusive = (minInclusive + PAGE_SIZE - 1) & PAGE_MASK; - maxExclusive &= PAGE_MASK; + minInclusive = KiAlignUp(minInclusive); + maxExclusive = KiAlignDown(maxExclusive); + if (maxExclusive <= minInclusive) return (PHYSICAL_ADDRESS)0; - if (maxExclusive <= minInclusive) - return (PHYSICAL_ADDRESS)0; + size_t firstPfn = (size_t)(minInclusive / PAGE_SIZE); + size_t limitPfn = (size_t)(maxExclusive / PAGE_SIZE); + if (limitPfn > gFrameBitmap.MaxPfn) limitPfn = gFrameBitmap.MaxPfn; + if (firstPfn >= limitPfn) return (PHYSICAL_ADDRESS)0; - uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock); + uintptr_t flags = KeAcquireSpinlock(&gFrameBitmap.Lock); - // Search high-to-low within the requested window. For low-memory users - // such as the AP trampoline this naturally prefers the traditional - // 0x70000-0x9f000 area and avoids consuming lower real-mode space first. - for (size_t i = gFrameStack.Top; i > 0; i--) { - size_t idx = i - 1; - PHYSICAL_ADDRESS frame = gFrameStack.Stack[idx]; - if (frame >= minInclusive && frame < maxExclusive && - !(frame & (PAGE_SIZE - 1))) { - frame = KiPopFrameAtIndexLocked(idx); - KeReleaseSpinlock(&gFrameStack.Lock, flags); - return frame; + for (size_t pfn = limitPfn; pfn > firstPfn; pfn--) { + size_t candidate = pfn - 1; + if (KiPfnFreeLocked(candidate)) { + KiBitClear(gFrameBitmap.Free, candidate); + if (gFrameBitmap.FreeFrames) gFrameBitmap.FreeFrames--; + KeReleaseSpinlock(&gFrameBitmap.Lock, flags); + return (PHYSICAL_ADDRESS)candidate * PAGE_SIZE; } } - KeReleaseSpinlock(&gFrameStack.Lock, flags); + KeReleaseSpinlock(&gFrameBitmap.Lock, flags); return (PHYSICAL_ADDRESS)0; } @@ -143,74 +218,109 @@ PHYSICAL_ADDRESS MmAllocateFrameBelow(PHYSICAL_ADDRESS maxExclusive) { } __declspec(dllexport) PHYSICAL_ADDRESS MmAllocateFrame(void) { - uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock); - if (gFrameStack.Top == 0) { - KeReleaseSpinlock(&gFrameStack.Lock, flags); - return (PHYSICAL_ADDRESS)0; - } - PHYSICAL_ADDRESS frame = gFrameStack.Stack[--gFrameStack.Top]; - KeReleaseSpinlock(&gFrameStack.Lock, flags); - return frame; + return MmAllocateFrameInRange(PAGE_SIZE, (PHYSICAL_ADDRESS)gFrameBitmap.MaxPfn * PAGE_SIZE); } void MmFreeFrame(PHYSICAL_ADDRESS frame) { if (!frame || (frame & (PAGE_SIZE - 1))) return; - uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock); - if (gFrameStack.Top < gFrameStack.Capacity) - gFrameStack.Stack[gFrameStack.Top++] = frame; - // else: stack full - leak rather than corrupt - KeReleaseSpinlock(&gFrameStack.Lock, flags); + size_t pfn = (size_t)(frame / PAGE_SIZE); + + uintptr_t flags = KeAcquireSpinlock(&gFrameBitmap.Lock); + if (KiPfnUsableLocked(pfn) && !KiBitTest(gFrameBitmap.Free, pfn)) { + KiBitSet(gFrameBitmap.Free, pfn); + gFrameBitmap.FreeFrames++; + } + KeReleaseSpinlock(&gFrameBitmap.Lock, flags); } __declspec(dllexport) PHYSICAL_ADDRESS MmAllocateContiguous(size_t count) { - if (!count) return (PHYSICAL_ADDRESS)0; + if (!count || count > gFrameBitmap.MaxPfn) return (PHYSICAL_ADDRESS)0; - uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock); + uintptr_t flags = KeAcquireSpinlock(&gFrameBitmap.Lock); - if (gFrameStack.Top < count) { - KeReleaseSpinlock(&gFrameStack.Lock, flags); - return (PHYSICAL_ADDRESS)0; - } - - // Frames are pushed in ascending address order by MmInitializePhysical, - // so physically consecutive pages sit at consecutive stack indices. - // Scan from bottom upward for a run of 'count' adjacent frames. - size_t run = (size_t)-1; - for (size_t i = 0; i + count <= gFrameStack.Top; i++) { - int ok = 1; - for (size_t j = 1; j < count; j++) { - if (gFrameStack.Stack[i + j] != gFrameStack.Stack[i] + j * PAGE_SIZE) { - ok = 0; - // Skip past this broken run; the next candidate can't start - // before the frame that broke the sequence. - i += j - 1; // outer loop adds 1 more - break; + size_t runStart = 0; + size_t runLength = 0; + for (size_t pfn = 1; pfn < gFrameBitmap.MaxPfn; pfn++) { + if (KiPfnFreeLocked(pfn)) { + if (!runLength) runStart = pfn; + runLength++; + if (runLength == count) { + for (size_t i = 0; i < count; i++) + KiBitClear(gFrameBitmap.Free, runStart + i); + if (gFrameBitmap.FreeFrames >= count) gFrameBitmap.FreeFrames -= count; + else gFrameBitmap.FreeFrames = 0; + KeReleaseSpinlock(&gFrameBitmap.Lock, flags); + return (PHYSICAL_ADDRESS)runStart * PAGE_SIZE; } + } else { + runLength = 0; } - if (ok) { run = i; break; } } - if (run == (size_t)-1) { - KeReleaseSpinlock(&gFrameStack.Lock, flags); - return (PHYSICAL_ADDRESS)0; - } - - PHYSICAL_ADDRESS base = gFrameStack.Stack[run]; - - // Splice out the 'count' entries by sliding the tail down. - size_t tail = gFrameStack.Top - run - count; - for (size_t i = 0; i < tail; i++) - gFrameStack.Stack[run + i] = gFrameStack.Stack[run + count + i]; - gFrameStack.Top -= count; - - KeReleaseSpinlock(&gFrameStack.Lock, flags); - return base; + KeReleaseSpinlock(&gFrameBitmap.Lock, flags); + return (PHYSICAL_ADDRESS)0; } size_t MmFreeFrameCount(void) { - return gFrameStack.Top; + uintptr_t flags = KeAcquireSpinlock(&gFrameBitmap.Lock); + size_t count = gFrameBitmap.FreeFrames; + KeReleaseSpinlock(&gFrameBitmap.Lock, flags); + return count; } size_t MmTotalFrameCount(void) { - return gFrameStack.Total; + return gFrameBitmap.TotalFrames; } +void MmQueryPhysicalStats(MM_PHYSICAL_STATS* out) { + if (!out) return; + + MM_PHYSICAL_STATS stats; + memset(&stats, 0, sizeof(stats)); + + uintptr_t flags = KeAcquireSpinlock(&gFrameBitmap.Lock); + + stats.TotalFrames = (uint64_t)gFrameBitmap.TotalFrames; + stats.FreeFrames = (uint64_t)gFrameBitmap.FreeFrames; + stats.UsedFrames = stats.TotalFrames - stats.FreeFrames; + + uint64_t run = 0; + for (size_t pfn = 1; pfn < gFrameBitmap.MaxPfn; pfn++) { + if (KiPfnFreeLocked(pfn)) { + run++; + continue; + } + + if (run) { + stats.FreeRunCount++; + if (run > stats.LargestFreeRun) + stats.LargestFreeRun = run; + if (run == 1) stats.FreeRunHistogram[0]++; + else if (run <= 3) stats.FreeRunHistogram[1]++; + else if (run <= 7) stats.FreeRunHistogram[2]++; + else if (run <= 15) stats.FreeRunHistogram[3]++; + else if (run <= 63) stats.FreeRunHistogram[4]++; + else if (run <= 255) stats.FreeRunHistogram[5]++; + else if (run <= 1023) stats.FreeRunHistogram[6]++; + else stats.FreeRunHistogram[7]++; + run = 0; + } + } + + if (run) { + stats.FreeRunCount++; + if (run > stats.LargestFreeRun) + stats.LargestFreeRun = run; + if (run == 1) stats.FreeRunHistogram[0]++; + else if (run <= 3) stats.FreeRunHistogram[1]++; + else if (run <= 7) stats.FreeRunHistogram[2]++; + else if (run <= 15) stats.FreeRunHistogram[3]++; + else if (run <= 63) stats.FreeRunHistogram[4]++; + else if (run <= 255) stats.FreeRunHistogram[5]++; + else if (run <= 1023) stats.FreeRunHistogram[6]++; + else stats.FreeRunHistogram[7]++; + } + + KeReleaseSpinlock(&gFrameBitmap.Lock, flags); + *out = stats; +} + diff --git a/code/kernel/mm_virt.c b/code/kernel/mm_virt.c index b514100..3d1b0ae 100644 --- a/code/kernel/mm_virt.c +++ b/code/kernel/mm_virt.c @@ -11,7 +11,8 @@ // // User heap: // A single best-fit free list in the lower half. -// Backed on demand from the PMM. No per-process heaps. +// Page-granular lower-half regions owned by PROCESS metadata. Sub-page +// allocation is a user-mode runtime concern. #include #include #include @@ -164,7 +165,7 @@ int MmHandleTlbShootdownNmi(void) { // --------------------------------------------------------------------------- // Public mapping // --------------------------------------------------------------------------- -__declspec(dllexport) KSTATUS MmMapPage(uintptr_t virt, PHYSICAL_ADDRESS phys, uint64_t flags) { +__declspec(dllexport) KSTATUS MmMapPage(uintptr_t virt, PHYSICAL_ADDRESS phys, uint64_t flags, MM_MAP_MODE mode) { unsigned userFlag = (flags & PAGE_USER) ? PAGE_USER : 0; uintptr_t lockFlags = KeAcquireSpinlock(&gPageTableLock); @@ -186,6 +187,10 @@ __declspec(dllexport) KSTATUS MmMapPage(uintptr_t virt, PHYSICAL_ADDRESS phys, u } uint64_t* pte = KiPtePtr(pt, PT_IDX(virt)); + if ((*pte & PAGE_PRESENT) && mode == MmMapFailIfPresent) { + KeReleaseSpinlock(&gPageTableLock, lockFlags); + return STATUS_ALREADY_EXISTS; + } *pte = phys | flags; KeReleaseSpinlock(&gPageTableLock, lockFlags); @@ -525,7 +530,7 @@ static int KiHeapEnsureMapped(HEAP* h, uintptr_t start, size_t size) { PHYSICAL_ADDRESS frame = MmAllocateFrame(); if (!frame) return 0; - KSTATUS ms = MmMapPage(va, frame, h->MapFlags); + KSTATUS ms = MmMapPage(va, frame, h->MapFlags, MmMapFailIfPresent); if (!KSUCCESS(ms)) { MmFreeFrame(frame); return 0; @@ -544,7 +549,7 @@ static int KiHeapGrow(HEAP* h, size_t need) { for (uintptr_t va = h->Brk; va < h->Brk + grow; va += PAGE_SIZE) { PHYSICAL_ADDRESS frame = MmAllocateFrame(); if (!frame) return 0; - if (!KSUCCESS(MmMapPage(va, frame, h->MapFlags))) { + if (!KSUCCESS(MmMapPage(va, frame, h->MapFlags, MmMapFailIfPresent))) { MmFreeFrame(frame); return 0; } @@ -965,7 +970,7 @@ KSTATUS MmCreateUserRegion(PROCESS* process, size_t size, size_t alignment, s = STATUS_NO_MEMORY; break; } - s = MmMapPage(va, frame, pageFlags); + s = MmMapPage(va, frame, pageFlags, MmMapFailIfPresent); if (!KSUCCESS(s)) { MmFreeFrame(frame); break; @@ -1036,7 +1041,7 @@ KSTATUS MmEnsureUserRegionMapped(PROCESS* process, void* base, size_t size, uint PHYSICAL_ADDRESS frame = MmAllocateFrame(); if (!frame) return STATUS_NO_MEMORY; - KSTATUS ms = MmMapPage(va, frame, flags); + KSTATUS ms = MmMapPage(va, frame, flags, MmMapFailIfPresent); if (!KSUCCESS(ms)) { MmFreeFrame(frame); return ms; @@ -1073,6 +1078,16 @@ KSTATUS MmProtectUserRegion(PROCESS* process, void* base, size_t size, uint64_t return STATUS_NOT_FOUND; } + if (pageFlags == 0) { + for (uintptr_t va = alignedStart; va < alignedEnd; va += PAGE_SIZE) { + if (va < regionBase || va >= regionEnd) return STATUS_ACCESS_DENIED; + PHYSICAL_ADDRESS phys = MmGetPhysicalAddress(va); + if (phys && KSUCCESS(MmUnmapPage(va))) + MmFreeFrame(phys); + } + return STATUS_SUCCESS; + } + uint64_t finalFlags = pageFlags | PAGE_PRESENT | PAGE_USER; for (uintptr_t va = alignedStart; va < alignedEnd; va += PAGE_SIZE) { @@ -1091,7 +1106,7 @@ KSTATUS MmProtectUserRegion(PROCESS* process, void* base, size_t size, uint64_t if (!KSUCCESS(qs) || !(existingFlags & PAGE_PRESENT)) { PHYSICAL_ADDRESS frame = MmAllocateFrame(); if (!frame) return STATUS_NO_MEMORY; - KSTATUS ms = MmMapPage(va, frame, PAGE_PRESENT | PAGE_WRITE | PAGE_USER | PAGE_NX); + KSTATUS ms = MmMapPage(va, frame, PAGE_PRESENT | PAGE_WRITE | PAGE_USER | PAGE_NX, MmMapFailIfPresent); if (!KSUCCESS(ms)) { MmFreeFrame(frame); return ms; @@ -1161,6 +1176,34 @@ void MmDestroyAllUserRegions(PROCESS* process) { } } +KSTATUS MmQueryUserRegion(PROCESS* process, const void* address, void** baseOut, size_t* sizeOut, + uint64_t* pageFlagsOut, USER_REGION_TYPE* typeOut, uint32_t* regionFlagsOut) { + if (!process || !address) return STATUS_INVALID_PARAMETER; + uintptr_t addr = (uintptr_t)address; + + uintptr_t procFlags = KeAcquireSpinlock(&process->UserRegionLock); + for (LIST_ENTRY* node = process->UserRegions.Fwd; node != &process->UserRegions; node = node->Fwd) { + USER_VA_REGION* r = CONTAINING_RECORD(node, USER_VA_REGION, ProcessLink); + uintptr_t end = r->Base + r->CommittedSize; + if (addr >= r->Base && addr < end) { + if (baseOut) *baseOut = (void*)r->Base; + if (sizeOut) *sizeOut = r->CommittedSize; + if (pageFlagsOut) { + PHYSICAL_ADDRESS phys = 0; + uint64_t flags = 0; + KSTATUS qs = MmQueryPage(addr & PAGE_MASK, &phys, &flags); + *pageFlagsOut = KSUCCESS(qs) ? flags : 0; + } + if (typeOut) *typeOut = r->Type; + if (regionFlagsOut) *regionFlagsOut = r->Flags; + KeReleaseSpinlock(&process->UserRegionLock, procFlags); + return STATUS_SUCCESS; + } + } + KeReleaseSpinlock(&process->UserRegionLock, procFlags); + return STATUS_NOT_FOUND; +} + size_t MmGetUserRegionSize(PROCESS* process, const void* base) { if (!process || !base) return 0; uintptr_t procFlags = KeAcquireSpinlock(&process->UserRegionLock); diff --git a/code/public/ntlite/syscall.h b/code/public/ntlite/syscall.h index 5cc800b..e02b773 100644 --- a/code/public/ntlite/syscall.h +++ b/code/public/ntlite/syscall.h @@ -13,6 +13,8 @@ #define SYS_STATUS_TIMEOUT 3u #define SYS_STATUS_PENDING 4u #define SYS_STATUS_ALERTED 5u +#define SYS_STATUS_INVALID_PARAMETER 0x10u +#define SYS_STATUS_NO_MEMORY 0x20u #define SYS_STATUS_KERNEL_APC 6u #define SYS_STATUS_USER_APC 7u #define SYS_STATUS_CANCELLED 0x33u @@ -205,11 +207,33 @@ uint32_t SysSetUserApcDispatcher(void* dispatcher); uint32_t SysApcReturn(const SYS_USER_APC_FRAME* frame); // --------------------------------------------------------------------------- -// Memory and handles +// Virtual memory and handles // --------------------------------------------------------------------------- -void* SysAlloc(size_t size); -uint32_t SysFree(void* ptr); -void* SysRealloc(void* ptr, size_t newSize); +typedef enum SYS_VM_PROTECTION { + SYS_VM_NOACCESS = 0, + SYS_VM_READ = 1, + SYS_VM_READWRITE = 2, + SYS_VM_EXECUTE = 3, + SYS_VM_EXECUTE_READ = 4, + SYS_VM_EXECUTE_READWRITE = 5, +} SYS_VM_PROTECTION; + +#define SYS_VM_FLAG_NONE 0u +#define SYS_VM_FLAG_FIXED 1u + +typedef struct SYS_VM_REGION_INFO { + void* Base; + size_t PageCount; + uint32_t Protect; + uint32_t Flags; + uint32_t Type; + uint32_t OwnerPid; +} SYS_VM_REGION_INFO; + +uint32_t SysVmAlloc(void* preferredBase, size_t pageCount, uint32_t protect, uint32_t flags, void** baseOut); +uint32_t SysVmFree(void* base); +uint32_t SysVmProtect(void* base, size_t pageCount, uint32_t protect, uint32_t* oldProtectOut); +uint32_t SysVmQuery(void* address, SYS_VM_REGION_INFO* out); uint32_t SysCloseHandle(uint32_t handle); // --------------------------------------------------------------------------- @@ -382,6 +406,58 @@ typedef struct SYS_MEMORY_STATUS { uint64_t UserHeapBytes; } SYS_MEMORY_STATUS; +#define SYS_KERNEL_STATS_SCHEDULER 1u +#define SYS_KERNEL_STATS_PMM 2u +#define SYS_KERNEL_STATS_CPU 3u + +#define SYS_KERNEL_STATS_MAX_CPUS 32u + +typedef struct SYS_SCHEDULER_STATS { + uint64_t Ticks; + uint64_t ContextSwitches; + uint64_t KeepCurrentDecisions; + uint64_t IdleSelections; + uint64_t Demotions; + uint64_t AgingPromotions; + uint64_t QuantumExpirations; + uint64_t PriorityPreemptions; + uint64_t VoluntaryBlocks; + uint64_t CpuBurstDemotions; + uint64_t SmtSiblingDeferrals; + uint64_t SmtPrimaryPokes; +} SYS_SCHEDULER_STATS; + +typedef struct SYS_PMM_STATS { + uint64_t TotalFrames; + uint64_t FreeFrames; + uint64_t UsedFrames; + uint64_t LargestFreeRun; + uint64_t FreeRunCount; + uint64_t FreeRunHistogram[8]; +} SYS_PMM_STATS; + +typedef struct SYS_CPU_STAT { + uint32_t CpuIndex; + uint32_t LapicId; + uint32_t Flags; + uint32_t CurrentTid; + uint64_t SchedulerTicks; + uint64_t ContextSwitches; +} SYS_CPU_STAT; + +typedef struct SYS_CPU_STATS { + uint32_t CpuCount; + uint32_t Reserved; + SYS_CPU_STAT Cpu[SYS_KERNEL_STATS_MAX_CPUS]; +} SYS_CPU_STATS; + +#define SYS_CPU_FLAG_PRESENT 0x00000001u +#define SYS_CPU_FLAG_STARTED 0x00000002u +#define SYS_CPU_FLAG_PARKED 0x00000004u +#define SYS_CPU_FLAG_ONLINE 0x00000008u +#define SYS_CPU_FLAG_BSP 0x00000010u +#define SYS_CPU_FLAG_PRIMARY 0x00000020u + // --------------------------------------------------------------------------- // Time and diagnostics // --------------------------------------------------------------------------- @@ -390,3 +466,4 @@ uint32_t SysDebugPrint(const SYS_DEBUG_PRINT_REQUEST* request); uint32_t SysQueryTrapFrame(SYS_TRAP_FRAME_INFO* info); uint32_t SysGetMemoryStatus(SYS_MEMORY_STATUS* statusOut); +uint32_t SysQueryKernelStats(uint32_t classId, void* buffer, size_t bufferSize, size_t* requiredSizeOut); diff --git a/code/user/apps/doom/doom.c b/code/user/apps/doom/doom.c index ed45a8f..f5effe1 100644 --- a/code/user/apps/doom/doom.c +++ b/code/user/apps/doom/doom.c @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -28,7 +29,7 @@ static void doom_print_wrapper(const char* msg) // --------------------------------------------------------------------------- static void* doom_malloc_wrapper(int size) { - void* p = SysAlloc(size); + void* p = malloc(size); if (!p) SysExitProcess(1); return p; } @@ -37,7 +38,7 @@ static void doom_free_wrapper(void* ptr) { if (!ptr) return; - SysFree(ptr); + free(ptr); } // --------------------------------------------------------------------------- @@ -62,7 +63,7 @@ static void* doom_open_wrapper(const char* path, const char* mode) } if (result != 0) return 0; - DOOM_FILE_HANDLE* f = (DOOM_FILE_HANDLE*)SysAlloc(sizeof(DOOM_FILE_HANDLE)); + DOOM_FILE_HANDLE* f = (DOOM_FILE_HANDLE*)malloc(sizeof(DOOM_FILE_HANDLE)); if (!f) { SysCloseHandle(handle); return 0; @@ -79,7 +80,7 @@ static void doom_close_wrapper(void* handle) if (!handle) return; DOOM_FILE_HANDLE* f = (DOOM_FILE_HANDLE*)handle; SysCloseHandle(f->Handle); - SysFree(f); + free(f); } static int doom_read_wrapper(void* handle, void* buf, int count) diff --git a/code/user/apps/edit/edit.c b/code/user/apps/edit/edit.c index b0f3d2d..c33f977 100644 --- a/code/user/apps/edit/edit.c +++ b/code/user/apps/edit/edit.c @@ -18,6 +18,8 @@ #define MAX_LINE 256 #define PATH_MAX2 260 #define MSG_MAX 160 +#define MAX_SCREEN_COLS 256 +#define MAX_SCREEN_ROWS 128 #define COL_BG 0x000000u #define COL_FG 0xC8C8C8u @@ -61,8 +63,55 @@ static bool gQuitArmed = false; static char gFilename[PATH_MAX2] = "untitled.txt"; static char gMessage[MSG_MAX] = "ready"; +typedef struct SCREEN_CELL { + char c; + uint32_t fg; + uint32_t bg; +} SCREEN_CELL; + +static SCREEN_CELL gScreenCache[MAX_SCREEN_COLS * MAX_SCREEN_ROWS]; +static bool gScreenCacheValid = false; + +static void invalidate_screen_cache(void) { + gScreenCacheValid = false; +} + +static void update_screen_size(void) { + int pxW = 0, pxH = 0; + int oldCols = gCols; + int oldRows = gRows; + + if (SysScreenGetSize(&pxW, &pxH) == 0 && pxW > 0 && pxH > 0) { + gCols = pxW / GLYPH_W; + gRows = pxH / GLYPH_H; + + if (gCols < 20) gCols = 20; + if (gRows < 5) gRows = 5; + if (gCols > MAX_SCREEN_COLS) gCols = MAX_SCREEN_COLS; + if (gRows > MAX_SCREEN_ROWS) gRows = MAX_SCREEN_ROWS; + } + + if (gCols != oldCols || gRows != oldRows) + invalidate_screen_cache(); +} + static void put_cell(int col, int row, char c, uint32_t fg, uint32_t bg) { - SysScreenPutChar(c ? c : ' ', col * GLYPH_W, row * GLYPH_H, fg, bg); + if (col < 0 || row < 0 || col >= gCols || row >= gRows) + return; + + if (!c) c = ' '; + + if (col < MAX_SCREEN_COLS && row < MAX_SCREEN_ROWS) { + SCREEN_CELL* cell = &gScreenCache[row * MAX_SCREEN_COLS + col]; + if (gScreenCacheValid && cell->c == c && cell->fg == fg && cell->bg == bg) + return; + + cell->c = c; + cell->fg = fg; + cell->bg = bg; + } + + SysScreenPutChar(c, col * GLYPH_W, row * GLYPH_H, fg, bg); } static void clear_row(int row, uint32_t bg) { @@ -151,13 +200,7 @@ static void ensure_visible(void) { } static void render(void) { - int pxW = 0, pxH = 0; - if (SysScreenGetSize(&pxW, &pxH) == 0 && pxW > 0 && pxH > 0) { - gCols = pxW / GLYPH_W; - gRows = pxH / GLYPH_H; - if (gCols < 20) gCols = 20; - if (gRows < 5) gRows = 5; - } + update_screen_size(); clamp_cursor(); ensure_visible(); @@ -172,28 +215,40 @@ static void render(void) { append_str(status, sizeof(status), &p, ", Col "); append_u32(status, sizeof(status), &p, (uint32_t)(gCx + 1)); - clear_row(0, COL_STATUS); - draw_text(0, 0, status, COL_STATUSF, COL_STATUS); + size_t statusLen = p; + for (int sx = 0; sx < gCols; sx++) { + char c = ((size_t)sx < statusLen) ? status[sx] : ' '; + put_cell(sx, 0, c, COL_STATUSF, COL_STATUS); + } int textRows = gRows - 2; for (int sy = 0; sy < textRows; sy++) { int row = sy + 1; int li = gTop + sy; - clear_row(row, COL_BG); - if (li >= gLineCount) continue; - LINE* ln = &gLines[li]; for (int sx = 0; sx < gCols; sx++) { int ci = gLeft + sx; - char c = (ci < ln->len) ? ln->text[ci] : ' '; - bool atCursor = (li == gCy && ci == gCx); + char c = ' '; + bool atCursor = false; + + if (li < gLineCount) { + LINE* ln = &gLines[li]; + c = (ci < ln->len) ? ln->text[ci] : ' '; + atCursor = (li == gCy && ci == gCx); + } + put_cell(sx, row, c, atCursor ? COL_CURSORF : COL_FG, atCursor ? COL_CURSOR : COL_BG); } } - clear_row(gRows - 1, COL_STATUS); - draw_text(0, gRows - 1, gMessage, COL_STATUSF, COL_STATUS); + size_t messageLen = strlen(gMessage); + for (int sx = 0; sx < gCols; sx++) { + char c = ((size_t)sx < messageLen) ? gMessage[sx] : ' '; + put_cell(sx, gRows - 1, c, COL_STATUSF, COL_STATUS); + } + + gScreenCacheValid = true; } static void insert_char_at_cursor(char c) { @@ -481,8 +536,10 @@ int main(void) { parse_filename_from_cmdline(); load_file(); SysScreenClear(COL_BG); + invalidate_screen_cache(); editor_loop(); - SysScreenClear(COL_BG); + SysScreenClear(0x012456); + invalidate_screen_cache(); print("edit: goodbye\n"); SysExitProcess(0); return 0; diff --git a/code/user/apps/shell_native/shell_native.c b/code/user/apps/shell_native/shell_native.c index afc8970..d2f46f7 100644 --- a/code/user/apps/shell_native/shell_native.c +++ b/code/user/apps/shell_native/shell_native.c @@ -95,6 +95,7 @@ static void cmd_help() { print("Available commands:\n" " help - Show this list\n" " mem - Show memory usage\n" + " stats - Show scheduler/CPU/PMM telemetry\n" " ps - List running process IDs\n" " dir [path] - List directory contents\n" " cd - Change directory\n" @@ -110,6 +111,96 @@ static void printSizeKiB(uint64_t bytes) { print(" KiB"); } + +static void printPagesKiB(uint64_t pages) { + printUInt64(pages * 4u); + print(" KiB"); +} + +static void printCpuFlags(uint32_t flags) { + if (flags & SYS_CPU_FLAG_BSP) print("bsp "); + if (flags & SYS_CPU_FLAG_ONLINE) print("online "); + if (flags & SYS_CPU_FLAG_PARKED) print("parked "); + if (flags & SYS_CPU_FLAG_PRIMARY) print("primary "); + if (flags & SYS_CPU_FLAG_STARTED) print("started "); + if (flags & SYS_CPU_FLAG_PRESENT) print("present "); +} + +static void cmd_stats(void) { + SYS_SCHEDULER_STATS sched; + SYS_PMM_STATS pmm; + SYS_CPU_STATS cpu; + uint32_t status; + + status = SysQueryKernelStats(SYS_KERNEL_STATS_SCHEDULER, &sched, sizeof(sched), NULL); + if (status != 0) { + print("stats: scheduler query failed: "); + printUInt(status); + print("\n"); + return; + } + + status = SysQueryKernelStats(SYS_KERNEL_STATS_PMM, &pmm, sizeof(pmm), NULL); + if (status != 0) { + print("stats: pmm query failed: "); + printUInt(status); + print("\n"); + return; + } + + status = SysQueryKernelStats(SYS_KERNEL_STATS_CPU, &cpu, sizeof(cpu), NULL); + if (status != 0) { + print("stats: cpu query failed: "); + printUInt(status); + print("\n"); + return; + } + + print("Scheduler:\n"); + print(" ticks: "); printUInt64(sched.Ticks); print("\n"); + print(" context switches: "); printUInt64(sched.ContextSwitches); print("\n"); + print(" quantum expires: "); printUInt64(sched.QuantumExpirations); print("\n"); + print(" priority preempts: "); printUInt64(sched.PriorityPreemptions); print("\n"); + print(" idle selections: "); printUInt64(sched.IdleSelections); print("\n"); + print(" keep-current: "); printUInt64(sched.KeepCurrentDecisions); print("\n"); + print(" demotions: "); printUInt64(sched.Demotions); print("\n"); + print(" aging promotions: "); printUInt64(sched.AgingPromotions); print("\n"); + print(" voluntary blocks: "); printUInt64(sched.VoluntaryBlocks); print("\n"); + print(" SMT deferrals: "); printUInt64(sched.SmtSiblingDeferrals); print("\n"); + print(" SMT primary pokes: "); printUInt64(sched.SmtPrimaryPokes); print("\n"); + + print("CPUs:\n"); + uint32_t n = cpu.CpuCount; + if (n > SYS_KERNEL_STATS_MAX_CPUS) + n = SYS_KERNEL_STATS_MAX_CPUS; + for (uint32_t i = 0; i < n; i++) { + SYS_CPU_STAT* c = &cpu.Cpu[i]; + print(" cpu"); printUInt(c->CpuIndex); + print(" lapic="); printUInt(c->LapicId); + print(" tid="); printUInt(c->CurrentTid); + print(" ticks="); printUInt64(c->SchedulerTicks); + print(" switches="); printUInt64(c->ContextSwitches); + print(" flags="); printCpuFlags(c->Flags); + print("\n"); + } + + print("Physical memory:\n"); + print(" total: "); printPagesKiB(pmm.TotalFrames); print(" (frames="); printUInt64(pmm.TotalFrames); print(")\n"); + print(" used: "); printPagesKiB(pmm.UsedFrames); print(" (frames="); printUInt64(pmm.UsedFrames); print(")\n"); + print(" free: "); printPagesKiB(pmm.FreeFrames); print(" (frames="); printUInt64(pmm.FreeFrames); print(")\n"); + print(" largest free run: "); printPagesKiB(pmm.LargestFreeRun); print(" (frames="); printUInt64(pmm.LargestFreeRun); print(")\n"); + print(" free runs: "); printUInt64(pmm.FreeRunCount); print("\n"); + print(" run histogram:\n"); + print(" 1: "); printUInt64(pmm.FreeRunHistogram[0]); print("\n"); + print(" 2-3: "); printUInt64(pmm.FreeRunHistogram[1]); print("\n"); + print(" 4-7: "); printUInt64(pmm.FreeRunHistogram[2]); print("\n"); + print(" 8-15: "); printUInt64(pmm.FreeRunHistogram[3]); print("\n"); + print(" 16-63: "); printUInt64(pmm.FreeRunHistogram[4]); print("\n"); + print(" 64-255: "); printUInt64(pmm.FreeRunHistogram[5]); print("\n"); + print(" 256-1023: "); printUInt64(pmm.FreeRunHistogram[6]); print("\n"); + print(" 1024+: "); printUInt64(pmm.FreeRunHistogram[7]); print("\n"); +} + static void cmd_mem(void) { SYS_MEMORY_STATUS st; if (SysGetMemoryStatus(&st) != 0) { @@ -240,7 +331,7 @@ static int runCommand(const char* cmd) { if (!cmd || *cmd == '\0') return 0; if (strcmp(cmd, "exit") == 0) return 1; if (strcmp(cmd, "help") == 0) { cmd_help(); return 0; } - if (strcmp(cmd, "clear") == 0) { SysScreenClear(0); return 0; } + if (strcmp(cmd, "clear") == 0) { SysScreenClear(0x012456); return 0; } if (strncmp(cmd, "crash", 5) == 0) { // Check the sub-option trailing "crash " (offset 6) if (strcmp(cmd + 6, "void") == 0) { @@ -280,6 +371,7 @@ static int runCommand(const char* cmd) { } } if (strcmp(cmd, "mem") == 0) { cmd_mem(); return 0; } + if (strcmp(cmd, "stats") == 0 || strcmp(cmd, "telemetry") == 0) { cmd_stats(); return 0; } if (strcmp(cmd, "ps") == 0) { cmd_ps(); return 0; } if (strcmp(cmd, "dir") == 0) { cmd_dir("."); return 0; } if (strncmp(cmd, "dir ", 4) == 0) { cmd_dir(cmd + 4); return 0; } diff --git a/code/user/personalities/posix/posix_dir.c b/code/user/personalities/posix/posix_dir.c index 2fdab04..b573d98 100644 --- a/code/user/personalities/posix/posix_dir.c +++ b/code/user/personalities/posix/posix_dir.c @@ -1,6 +1,7 @@ // posix_dir.c - chdir, getcwd, opendir, readdir, closedir #include #include +#include #include "posix.h" #include "posix_path.h" @@ -38,8 +39,8 @@ __declspec(dllexport) DIR* opendir(const char* path) { uint32_t s = SysOpenDir(&req); if (s != 0) { errno = ENOENT; return (DIR*)0; } - // Allocate DIR on the kernel heap (SysAlloc) so it outlives the stack. - DIR* d = (DIR*)SysAlloc(sizeof(DIR)); + // Allocate DIR on the kernel heap (malloc) so it outlives the stack. + DIR* d = (DIR*)malloc(sizeof(DIR)); if (!d) { SysCloseHandle(kh); errno = ENOMEM; return (DIR*)0; } d->KHandle = kh; d->Valid = false; @@ -64,6 +65,6 @@ __declspec(dllexport) struct dirent* readdir(DIR* d) { __declspec(dllexport) int closedir(DIR* d) { if (!d) { errno = EBADF; return -1; } SysCloseHandle(d->KHandle); - SysFree(d); + free(d); return 0; } diff --git a/code/user/personalities/posix/posix_io.c b/code/user/personalities/posix/posix_io.c index 735a750..087ef2d 100644 --- a/code/user/personalities/posix/posix_io.c +++ b/code/user/personalities/posix/posix_io.c @@ -7,7 +7,7 @@ #include "posix_path.h" __declspec(dllexport) void clearscreen(void) { - SysScreenClear(0x00000000); + SysScreenClear(0x012456); } __declspec(dllexport) void clearkeyboard(void) { diff --git a/code/user/personalities/posix/posix_socket.c b/code/user/personalities/posix/posix_socket.c index 8ee04e2..fee7caa 100644 --- a/code/user/personalities/posix/posix_socket.c +++ b/code/user/personalities/posix/posix_socket.c @@ -1,5 +1,6 @@ // posix_socket.c - POSIX-ish socket wrappers over native Sys* sockets. #include +#include #include #include #include @@ -324,7 +325,7 @@ __declspec(dllexport) int getsockopt(int fd, int level, int optname, void* optva __declspec(dllexport) int poll(struct pollfd* fds, nfds_t nfds, int timeout) { if (!fds || nfds == 0 || nfds > 64) { errno = EINVAL; return -1; } - SYS_POLLFD* kfds = (SYS_POLLFD*)SysAlloc(sizeof(SYS_POLLFD) * nfds); + SYS_POLLFD* kfds = (SYS_POLLFD*)malloc(sizeof(SYS_POLLFD) * nfds); if (!kfds) { errno = ENOMEM; return -1; } for (nfds_t i = 0; i < nfds; i++) { @@ -348,7 +349,7 @@ __declspec(dllexport) int poll(struct pollfd* fds, nfds_t nfds, int timeout) { uint32_t timeoutMs = timeout < 0 ? SYS_POLL_TIMEOUT_INFINITE : (uint32_t)timeout; uint32_t s = SysPoll(kfds, nfds, timeoutMs, &ready); if (s != 0) { - SysFree(kfds); + free(kfds); errno = PosixStatusToErrno(s); return -1; } @@ -365,7 +366,7 @@ __declspec(dllexport) int poll(struct pollfd* fds, nfds_t nfds, int timeout) { if (re) out++; } - SysFree(kfds); + free(kfds); return out; } @@ -446,7 +447,7 @@ __declspec(dllexport) int getaddrinfo(const char* node, const char* service, a.Port = service ? ParsePort(service) : 0; size_t total = sizeof(struct addrinfo) + sizeof(struct sockaddr_in); - struct addrinfo* ai = (struct addrinfo*)SysAlloc(total); + struct addrinfo* ai = (struct addrinfo*)malloc(total); if (!ai) return ENOMEM; memset(ai, 0, total); @@ -467,5 +468,5 @@ __declspec(dllexport) int getaddrinfo(const char* node, const char* service, } __declspec(dllexport) void freeaddrinfo(struct addrinfo* res) { - if (res) SysFree(res); + if (res) free(res); } diff --git a/code/user/personalities/posix/posix_thread.c b/code/user/personalities/posix/posix_thread.c index 1bc9aee..d1a265e 100644 --- a/code/user/personalities/posix/posix_thread.c +++ b/code/user/personalities/posix/posix_thread.c @@ -1,5 +1,6 @@ // posix_thread.c - pthread_create, pthread_join, pthread_exit, pthread_mutex_* #include +#include #include #include "posix.h" @@ -56,7 +57,7 @@ static void PthreadTrampoline(uintptr_t raw) { PTHREAD_SLOT* slot = PthreadSlotFind(pid, tid); if (!slot) slot = PthreadSlotAlloc(pid, tid); - SysFree(tr); + free(tr); void* retval = fn(arg); @@ -76,7 +77,7 @@ __declspec(dllexport) int pthread_create(pthread_t* t, const pthread_attr_t* att uint32_t pid = SysGetCurrentPid(); - PTHREAD_TRAMP* tr = (PTHREAD_TRAMP*)SysAlloc(sizeof(PTHREAD_TRAMP)); + PTHREAD_TRAMP* tr = (PTHREAD_TRAMP*)malloc(sizeof(PTHREAD_TRAMP)); if (!tr) return ENOMEM; tr->Fn = fn; tr->Arg = arg; @@ -86,7 +87,7 @@ __declspec(dllexport) int pthread_create(pthread_t* t, const pthread_attr_t* att uint32_t s = SysCreateThread((uint64_t)PthreadTrampoline, (uint64_t)tr, 1 /*PriorityNormal*/, &tid); if (s != 0) { - SysFree(tr); + free(tr); return EAGAIN; } // The trampoline allocates the retval slot itself after it knows its real diff --git a/code/user/personalities/win32/gdi32.c b/code/user/personalities/win32/gdi32.c index d1087b5..c99f209 100644 --- a/code/user/personalities/win32/gdi32.c +++ b/code/user/personalities/win32/gdi32.c @@ -1,6 +1,7 @@ // gdi32.c #include #include +#include #include #if defined(__SSE2__) || defined(_M_X64) || defined(_M_IX86) @@ -92,14 +93,14 @@ __declspec(dllexport) int StretchDIBits( // Only reallocate if the new size is LARGER than what we already have int requiredPixels = DestWidth * DestHeight; if (requiredPixels > currentDestCapacity) { - SysFree(destBuffer); - destBuffer = (uint32_t*)SysAlloc(requiredPixels * sizeof(uint32_t)); + free(destBuffer); + destBuffer = (uint32_t*)malloc(requiredPixels * sizeof(uint32_t)); currentDestCapacity = requiredPixels; } if (DestWidth > currentXMapCapacity) { - SysFree(srcX_map); - srcX_map = (int*)SysAlloc(DestWidth * sizeof(int)); + free(srcX_map); + srcX_map = (int*)malloc(DestWidth * sizeof(int)); currentXMapCapacity = DestWidth; } diff --git a/code/user/personalities/win32/kernel32.c b/code/user/personalities/win32/kernel32.c index 06d6ede..2725163 100644 --- a/code/user/personalities/win32/kernel32.c +++ b/code/user/personalities/win32/kernel32.c @@ -9,7 +9,7 @@ // HANDLE_TO_KH / KH_TO_HANDLE do that conversion in one place. // - INVALID_HANDLE_VALUE maps to kernel handle 0 (the always-invalid slot). // - HeapAlloc / HeapFree / HeapReAlloc ignore the HANDLE heap argument and -// always use the single kernel user-heap. This is fine: we don't expose +// always use the single user-mode heap. This is fine: we don't expose // multiple heaps, and NULL is a legal (no-op) heap argument under Win32. // - Win32 per-thread state lives behind SYS_TEB::SubsystemData so the native // TEB ABI stays subsystem-neutral. @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -66,6 +67,31 @@ typedef struct _MEMORY_BASIC_INFORMATION { DWORD Type; } MEMORY_BASIC_INFORMATION; +static uint32_t WinProtectToSysVm(DWORD protect) { + switch (protect) { + case PAGE_NOACCESS: return SYS_VM_NOACCESS; + case PAGE_READONLY: return SYS_VM_READ; + case PAGE_READWRITE: + case PAGE_WRITECOPY: return SYS_VM_READWRITE; + case PAGE_EXECUTE: return SYS_VM_EXECUTE; + case PAGE_EXECUTE_READ: return SYS_VM_EXECUTE_READ; + case PAGE_EXECUTE_READWRITE: return SYS_VM_EXECUTE_READWRITE; + default: return SYS_VM_READWRITE; + } +} + +static DWORD SysVmProtectToWin(uint32_t protect) { + switch (protect) { + case SYS_VM_NOACCESS: return PAGE_NOACCESS; + case SYS_VM_READ: return PAGE_READONLY; + case SYS_VM_READWRITE: return PAGE_READWRITE; + case SYS_VM_EXECUTE: return PAGE_EXECUTE; + case SYS_VM_EXECUTE_READ: return PAGE_EXECUTE_READ; + case SYS_VM_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE; + default: return PAGE_NOACCESS; + } +} + // File-find structures typedef struct _FILETIME { DWORD dwLowDateTime; @@ -228,7 +254,7 @@ static WIN32_THREAD_ENV* K32ThreadEnv(void) { WIN32_THREAD_ENV* env = (WIN32_THREAD_ENV*)teb->SubsystemData; if (!env) { - env = (WIN32_THREAD_ENV*)SysAlloc(sizeof(WIN32_THREAD_ENV)); + env = (WIN32_THREAD_ENV*)malloc(sizeof(WIN32_THREAD_ENV)); if (!env) return &gFallbackThreadEnv; memset(env, 0, sizeof(*env)); teb->SubsystemData = env; @@ -363,28 +389,27 @@ __declspec(dllexport) uint64_t GetTickCount64(void) { } // --------------------------------------------------------------------------- -// Memory (heap argument is ignored - single kernel user-heap) +// Memory (heap argument is ignored - single user-mode heap) // --------------------------------------------------------------------------- __declspec(dllexport) void* HeapAlloc(void* heap, DWORD flags, size_t size) { - (void)heap; + (void)heap; (void)flags; if (!size) return NULL; - void* ptr = SysAlloc(size); + void* ptr = malloc(size); if (!ptr) gLastError = 8; // ERROR_NOT_ENOUGH_MEMORY return ptr; } __declspec(dllexport) BOOL HeapFree(void* heap, DWORD flags, void* ptr) { (void)heap; (void)flags; - // Win32's HeapFree doesn't need the size; we pass 0 and the kernel's - // allocator handles it (the block header carries the size). - if (ptr) SysFree(ptr); + // Win32's HeapFree doesn't need the size; we pass 0 and the user-mode heap carries the block size. + if (ptr) free(ptr); return TRUE; } __declspec(dllexport) void* HeapReAlloc(void* heap, DWORD flags, void* ptr, size_t size) { (void)heap; (void)flags; - void* newptr = SysRealloc(ptr, size); + void* newptr = realloc(ptr, size); if (!newptr && size) gLastError = 8; return newptr; } @@ -400,23 +425,37 @@ __declspec(dllexport) void* GetProcessHeap(void) { // --------------------------------------------------------------------------- __declspec(dllexport) void* VirtualAlloc(void* lpAddress, size_t dwSize, DWORD flAllocationType, DWORD flProtect) { - (void)lpAddress; (void)flAllocationType; (void)flProtect; + (void)flAllocationType; if (!dwSize) return NULL; - void* ptr = SysAlloc(dwSize); - if (!ptr) gLastError = 8; // ERROR_NOT_ENOUGH_MEMORY - return ptr; + + size_t pages = (dwSize + 4095u) / 4096u; + void* base = NULL; + uint32_t flags = lpAddress ? SYS_VM_FLAG_FIXED : SYS_VM_FLAG_NONE; + uint32_t s = SysVmAlloc(lpAddress, pages, WinProtectToSysVm(flProtect), flags, &base); + if (s != SYS_STATUS_SUCCESS) { + gLastError = (s == SYS_STATUS_NOT_FOUND || s == SYS_STATUS_INVALID_PARAMETER) ? 87 : 8; + return NULL; + } + return base; } __declspec(dllexport) BOOL VirtualFree(void* lpAddress, size_t dwSize, DWORD dwFreeType) { (void)dwSize; (void)dwFreeType; - if (lpAddress) SysFree(lpAddress); + if (!lpAddress) return TRUE; + uint32_t s = SysVmFree(lpAddress); + if (s != SYS_STATUS_SUCCESS) { gLastError = 87; return FALSE; } return TRUE; } __declspec(dllexport) BOOL VirtualProtect(void* lpAddress, size_t dwSize, DWORD flNewProtect, DWORD* lpflOldProtect) { - (void)lpAddress; (void)dwSize; (void)flNewProtect; - if (lpflOldProtect) *lpflOldProtect = PAGE_EXECUTE_READWRITE; + if (!lpAddress || !dwSize) { gLastError = 87; return FALSE; } + size_t pages = (dwSize + 4095u) / 4096u; + uint32_t oldSysProtect = 0; + uint32_t s = SysVmProtect(lpAddress, pages, WinProtectToSysVm(flNewProtect), + lpflOldProtect ? &oldSysProtect : NULL); + if (s != SYS_STATUS_SUCCESS) { gLastError = 87; return FALSE; } + if (lpflOldProtect) *lpflOldProtect = SysVmProtectToWin(oldSysProtect); return TRUE; } @@ -427,13 +466,21 @@ __declspec(dllexport) size_t VirtualQuery(const void* lpAddress, gLastError = 87; // ERROR_INVALID_PARAMETER return 0; } - uintptr_t base = (uintptr_t)lpAddress & ~(uintptr_t)0xFFF; - lpBuffer->BaseAddress = (void*)base; - lpBuffer->AllocationBase = (void*)base; - lpBuffer->AllocationProtect = PAGE_EXECUTE_READWRITE; - lpBuffer->RegionSize = 0x1000; + + SYS_VM_REGION_INFO info; + uint32_t s = SysVmQuery((void*)lpAddress, &info); + if (s != SYS_STATUS_SUCCESS) { + gLastError = 87; + return 0; + } + + DWORD protect = SysVmProtectToWin(info.Protect); + lpBuffer->BaseAddress = info.Base; + lpBuffer->AllocationBase = info.Base; + lpBuffer->AllocationProtect = protect; + lpBuffer->RegionSize = info.PageCount * 4096u; lpBuffer->State = MEM_COMMIT; - lpBuffer->Protect = PAGE_EXECUTE_READWRITE; + lpBuffer->Protect = protect; lpBuffer->Type = MEM_PRIVATE; return sizeof(MEMORY_BASIC_INFORMATION); } @@ -512,7 +559,7 @@ __declspec(dllexport) BOOL FlushConsoleInputBuffer(HANDLE hConsoleInput) { // !Made-up! clear console api. __declspec(dllexport) BOOL ClearConsoleScreenBuffer(HANDLE hConsole) { - SysScreenClear(0x00000000); + SysScreenClear(0x012456); return TRUE; } diff --git a/code/user/personalities/win32/ole32.c b/code/user/personalities/win32/ole32.c index 10cfff1..5bd9b71 100644 --- a/code/user/personalities/win32/ole32.c +++ b/code/user/personalities/win32/ole32.c @@ -2,6 +2,7 @@ // No COM infrastructure at this stage; all functions fail gracefully. #include #include +#include #include // --------------------------------------------------------------------------- @@ -65,7 +66,7 @@ __declspec(dllexport) HRESULT CoCreateInstance(const GUID* clsid, IUnknown* oute // Memory // --------------------------------------------------------------------------- __declspec(dllexport) void CoTaskMemFree(void* pv) { - if (pv) SysFree(pv); + if (pv) free(pv); } // --------------------------------------------------------------------------- diff --git a/code/user/runtime/heap.c b/code/user/runtime/heap.c new file mode 100644 index 0000000..1d30bfd --- /dev/null +++ b/code/user/runtime/heap.c @@ -0,0 +1,226 @@ +// heap.c - user-mode page-backed heap +#include +#include +#include +#include +#include + +#define USER_HEAP_PAGE_SIZE 4096u +#define USER_HEAP_MIN_PAGES 16u +#define USER_HEAP_ALIGN 16u +#define USER_HEAP_MAGIC 0x48424C4Bu /* KLBH */ + +/* + * Keep the mask pointer-sized. A 32-bit unsigned mask truncates high VA bits. + */ +#define ALIGN_UP(v, a) (((v) + ((uintptr_t)(a) - 1)) & ~((uintptr_t)(a) - 1)) + +typedef struct HEAP_BLOCK { + uint32_t Magic; + uint32_t Free; + size_t Size; + struct HEAP_BLOCK* Prev; + struct HEAP_BLOCK* Next; +} HEAP_BLOCK; + +typedef struct HEAP_SEGMENT { + struct HEAP_SEGMENT* Prev; + struct HEAP_SEGMENT* Next; + size_t PageCount; + size_t Size; + HEAP_BLOCK* First; +} HEAP_SEGMENT; + +static volatile long gHeapLock; +static HEAP_SEGMENT* gSegments; + +static void HeapLock(void) { + while (_InterlockedCompareExchange(&gHeapLock, 1, 0) != 0) + _mm_pause(); + _ReadWriteBarrier(); +} + +static void HeapUnlock(void) { + _ReadWriteBarrier(); + _InterlockedExchange(&gHeapLock, 0); +} + +static size_t AlignSize(size_t size) { + return ALIGN_UP(size ? size : 1, USER_HEAP_ALIGN); +} + +static void* BlockPayload(HEAP_BLOCK* block) { + return (void*)((uint8_t*)block + sizeof(HEAP_BLOCK)); +} + +static HEAP_BLOCK* PayloadBlock(void* ptr) { + return (HEAP_BLOCK*)((uint8_t*)ptr - sizeof(HEAP_BLOCK)); +} + +static HEAP_SEGMENT* SegmentForPointer(void* ptr) { + uintptr_t p = (uintptr_t)ptr; + for (HEAP_SEGMENT* seg = gSegments; seg; seg = seg->Next) { + uintptr_t base = (uintptr_t)seg; + uintptr_t end = base + seg->Size; + if (p > base && p < end) + return seg; + } + return (HEAP_SEGMENT*)0; +} + +static void SplitBlock(HEAP_BLOCK* block, size_t size) { + size_t aligned = AlignSize(size); + if (block->Size < aligned + sizeof(HEAP_BLOCK) + USER_HEAP_ALIGN) + return; + + HEAP_BLOCK* tail = (HEAP_BLOCK*)((uint8_t*)BlockPayload(block) + aligned); + tail->Magic = USER_HEAP_MAGIC; + tail->Free = 1; + tail->Size = block->Size - aligned - sizeof(HEAP_BLOCK); + tail->Prev = block; + tail->Next = block->Next; + if (tail->Next) tail->Next->Prev = tail; + + block->Size = aligned; + block->Next = tail; +} + +static void CoalesceBlock(HEAP_BLOCK* block) { + if (block->Next && block->Next->Magic == USER_HEAP_MAGIC && block->Next->Free) { + HEAP_BLOCK* next = block->Next; + block->Size += sizeof(HEAP_BLOCK) + next->Size; + block->Next = next->Next; + if (block->Next) block->Next->Prev = block; + } + + if (block->Prev && block->Prev->Magic == USER_HEAP_MAGIC && block->Prev->Free) { + HEAP_BLOCK* prev = block->Prev; + prev->Size += sizeof(HEAP_BLOCK) + block->Size; + prev->Next = block->Next; + if (prev->Next) prev->Next->Prev = prev; + } +} + +static HEAP_SEGMENT* AddSegment(size_t payloadSize) { + size_t need = sizeof(HEAP_SEGMENT) + sizeof(HEAP_BLOCK) + AlignSize(payloadSize); + size_t pages = (need + USER_HEAP_PAGE_SIZE - 1) / USER_HEAP_PAGE_SIZE; + if (pages < USER_HEAP_MIN_PAGES) pages = USER_HEAP_MIN_PAGES; + + void* base = 0; + uint32_t s = SysVmAlloc(0, pages, SYS_VM_READWRITE, SYS_VM_FLAG_NONE, &base); + if (s != SYS_STATUS_SUCCESS || !base) + return (HEAP_SEGMENT*)0; + + HEAP_SEGMENT* seg = (HEAP_SEGMENT*)base; + seg->Prev = 0; + seg->Next = gSegments; + if (gSegments) gSegments->Prev = seg; + gSegments = seg; + seg->PageCount = pages; + seg->Size = pages * USER_HEAP_PAGE_SIZE; + + uintptr_t blockAddr = ALIGN_UP((uintptr_t)(seg + 1), USER_HEAP_ALIGN); + HEAP_BLOCK* block = (HEAP_BLOCK*)blockAddr; + block->Magic = USER_HEAP_MAGIC; + block->Free = 1; + block->Size = seg->Size - (blockAddr - (uintptr_t)seg) - sizeof(HEAP_BLOCK); + block->Prev = 0; + block->Next = 0; + seg->First = block; + return seg; +} + +static void RemoveSegmentIfEmpty(HEAP_SEGMENT* seg) { + if (!seg || !seg->First || !seg->First->Free || seg->First->Prev || seg->First->Next) + return; + + if (seg->Prev) seg->Prev->Next = seg->Next; + else gSegments = seg->Next; + if (seg->Next) seg->Next->Prev = seg->Prev; + + SysVmFree(seg); +} + +void* _malloc(size_t size) { + if (!size) return 0; + size = AlignSize(size); + + HeapLock(); + for (;;) { + for (HEAP_SEGMENT* seg = gSegments; seg; seg = seg->Next) { + for (HEAP_BLOCK* block = seg->First; block; block = block->Next) { + if (block->Magic == USER_HEAP_MAGIC && block->Free && block->Size >= size) { + SplitBlock(block, size); + block->Free = 0; + void* out = BlockPayload(block); + HeapUnlock(); + return out; + } + } + } + + if (!AddSegment(size)) { + HeapUnlock(); + return 0; + } + } +} + +void _free(void* ptr) { + if (!ptr) return; + + HeapLock(); + HEAP_SEGMENT* seg = SegmentForPointer(ptr); + if (!seg) { + HeapUnlock(); + return; + } + + HEAP_BLOCK* block = PayloadBlock(ptr); + if (block->Magic != USER_HEAP_MAGIC || block->Free) { + HeapUnlock(); + return; + } + + block->Free = 1; + CoalesceBlock(block); + RemoveSegmentIfEmpty(seg); + HeapUnlock(); +} + +void* _calloc(size_t count, size_t size) { + if (count && size > ((size_t)-1) / count) + return 0; + size_t total = count * size; + void* ptr = _malloc(total); + if (ptr) memset(ptr, 0, total); + return ptr; +} + +void* _realloc(void* ptr, size_t newSize) { + if (!ptr) return _malloc(newSize); + if (!newSize) { + _free(ptr); + return 0; + } + + HeapLock(); + HEAP_BLOCK* block = PayloadBlock(ptr); + if (block->Magic != USER_HEAP_MAGIC || block->Free) { + HeapUnlock(); + return 0; + } + size_t oldSize = block->Size; + if (oldSize >= newSize) { + SplitBlock(block, newSize); + HeapUnlock(); + return ptr; + } + HeapUnlock(); + + void* newPtr = _malloc(newSize); + if (!newPtr) return 0; + memcpy(newPtr, ptr, oldSize); + _free(ptr); + return newPtr; +} diff --git a/code/user/runtime/heap_exports.c b/code/user/runtime/heap_exports.c new file mode 100644 index 0000000..126c0ae --- /dev/null +++ b/code/user/runtime/heap_exports.c @@ -0,0 +1,34 @@ +// heap_exports.c - public CRT allocator names +// Intentionally includes nothing. MSVC/UCRT headers declare malloc/free with +// compiler attributes that conflict with /Gz in this freestanding build. +// Keep the real heap implementation in heap.c under private names and expose +// only these tiny forwarding thunks here. + +#ifdef USER_HEAP_EXPORTS +#define HEAP_EXPORT __declspec(dllexport) +#else +#define HEAP_EXPORT +#endif + +typedef unsigned __int64 size_t; + +void* _malloc(size_t size); +void _free(void* ptr); +void* _calloc(size_t count, size_t size); +void* _realloc(void* ptr, size_t size); + +HEAP_EXPORT void* malloc(size_t size) { + return _malloc(size); +} + +HEAP_EXPORT void free(void* ptr) { + _free(ptr); +} + +HEAP_EXPORT void* calloc(size_t count, size_t size) { + return _calloc(count, size); +} + +HEAP_EXPORT void* realloc(void* ptr, size_t size) { + return _realloc(ptr, size); +} diff --git a/code/user/syscall/syscall_nr.inc b/code/user/syscall/syscall_nr.inc index 78c5aa0..586ffed 100644 --- a/code/user/syscall/syscall_nr.inc +++ b/code/user/syscall/syscall_nr.inc @@ -1,94 +1,96 @@ ; syscall_nr.inc -SYS_EXIT_PROCESS EQU 0 -SYS_EXIT_THREAD EQU 1 -SYS_CREATE_PROCESS EQU 2 -SYS_WAIT_FOR_PROCESS EQU 3 -SYS_GET_PROCESS_EXIT_CODE EQU 4 -SYS_KILL_PROCESS EQU 5 -SYS_GET_PROCESS_LIST EQU 6 -SYS_GET_PROCESS_PID EQU 7 -SYS_CREATE_THREAD EQU 8 -SYS_WAIT_THREAD EQU 9 -SYS_GET_CURRENT_TID EQU 10 -SYS_GET_CURRENT_PID EQU 11 -SYS_SET_THREAD_PRIORITY EQU 12 -SYS_YIELD EQU 13 -SYS_SLEEP EQU 14 -SYS_SET_USER_APC_DISPATCHER EQU 15 -SYS_APC_RETURN EQU 16 -SYS_ALLOC EQU 17 -SYS_FREE EQU 18 -SYS_REALLOC EQU 19 -SYS_CLOSE_HANDLE EQU 20 -SYS_MUTEX_CREATE EQU 21 -SYS_MUTEX_ACQUIRE EQU 22 -SYS_MUTEX_TRY_ACQUIRE EQU 23 -SYS_MUTEX_RELEASE EQU 24 -SYS_SEM_CREATE EQU 25 -SYS_SEM_WAIT EQU 26 -SYS_SEM_TRY_WAIT EQU 27 -SYS_SEM_SIGNAL EQU 28 -SYS_EVENT_CREATE EQU 29 -SYS_EVENT_SIGNAL EQU 30 -SYS_EVENT_CLEAR EQU 31 -SYS_EVENT_WAIT EQU 32 -SYS_QUEUE_CREATE EQU 33 -SYS_QUEUE_SEND EQU 34 -SYS_QUEUE_RECV EQU 35 -SYS_PUBLISH_QUEUE EQU 36 -SYS_OPEN_NAMED_QUEUE EQU 37 -SYS_QUEUE_DUPLICATE EQU 38 -SYS_NAMED_QUEUE_OWNER_PID EQU 39 -SYS_OPEN_FILE EQU 40 -SYS_CREATE_FILE EQU 41 -SYS_READ_FILE EQU 42 -SYS_WRITE_FILE EQU 43 -SYS_READ_FILE_ASYNC EQU 44 -SYS_WRITE_FILE_ASYNC EQU 45 -SYS_CANCEL_IO EQU 46 -SYS_SEEK_FILE EQU 47 -SYS_GET_FILE_POS EQU 48 -SYS_GET_FILE_SIZE EQU 49 -SYS_TRUNCATE_FILE EQU 50 -SYS_DELETE_FILE EQU 51 -SYS_RENAME_FILE EQU 52 -SYS_OPEN_DIR EQU 53 -SYS_READ_DIR EQU 54 -SYS_CREATE_DIR EQU 55 -SYS_REMOVE_DIR EQU 56 -SYS_SET_CWD EQU 57 -SYS_GET_CWD EQU 58 -SYS_WRITE_CONSOLE EQU 59 -SYS_SCREEN_BLIT EQU 60 -SYS_SCREEN_CLEAR EQU 61 -SYS_SCREEN_GET_SIZE EQU 62 -SYS_SCREEN_PUT_CHAR EQU 63 -SYS_KB_POLL EQU 64 -SYS_KB_IS_KEY_DOWN EQU 65 -SYS_KB_READ_CHAR EQU 66 -SYS_KB_READ_KEY EQU 67 -SYS_KB_GET_MODIFIERS EQU 68 -SYS_MOUSE_POLL EQU 69 -SYS_MOUSE_READ EQU 70 -SYS_MOUSE_GET_POS EQU 71 -SYS_GET_TICK EQU 72 -SYS_DEBUG_PRINT EQU 73 -SYS_QUERY_TRAP_FRAME EQU 74 -SYS_SOCKET EQU 75 -SYS_BIND EQU 76 -SYS_LISTEN EQU 77 -SYS_ACCEPT EQU 78 -SYS_CONNECT EQU 79 -SYS_SEND EQU 80 -SYS_RECV EQU 81 -SYS_SHUTDOWN EQU 82 -SYS_SEND_TO EQU 83 -SYS_RECV_FROM EQU 84 -SYS_RESOLVE_HOST EQU 85 -SYS_SET_SOCKET_OPTION EQU 86 -SYS_GET_SOCKET_OPTION EQU 87 -SYS_POLL EQU 88 -SYS_GET_MEMORY_STATUS EQU 89 +SYS_EXIT_PROCESS EQU 0 +SYS_EXIT_THREAD EQU 1 +SYS_CREATE_PROCESS EQU 2 +SYS_WAIT_FOR_PROCESS EQU 3 +SYS_GET_PROCESS_EXIT_CODE EQU 4 +SYS_KILL_PROCESS EQU 5 +SYS_GET_PROCESS_LIST EQU 6 +SYS_GET_PROCESS_PID EQU 7 +SYS_CREATE_THREAD EQU 8 +SYS_WAIT_THREAD EQU 9 +SYS_GET_CURRENT_TID EQU 10 +SYS_GET_CURRENT_PID EQU 11 +SYS_SET_THREAD_PRIORITY EQU 12 +SYS_YIELD EQU 13 +SYS_SLEEP EQU 14 +SYS_SET_USER_APC_DISPATCHER EQU 15 +SYS_APC_RETURN EQU 16 +SYS_VM_ALLOC EQU 17 +SYS_VM_FREE EQU 18 +SYS_VM_PROTECT EQU 19 +SYS_VM_QUERY EQU 20 +SYS_CLOSE_HANDLE EQU 21 +SYS_MUTEX_CREATE EQU 22 +SYS_MUTEX_ACQUIRE EQU 23 +SYS_MUTEX_TRY_ACQUIRE EQU 24 +SYS_MUTEX_RELEASE EQU 25 +SYS_SEM_CREATE EQU 26 +SYS_SEM_WAIT EQU 27 +SYS_SEM_TRY_WAIT EQU 28 +SYS_SEM_SIGNAL EQU 29 +SYS_EVENT_CREATE EQU 30 +SYS_EVENT_SIGNAL EQU 31 +SYS_EVENT_CLEAR EQU 32 +SYS_EVENT_WAIT EQU 33 +SYS_QUEUE_CREATE EQU 34 +SYS_QUEUE_SEND EQU 35 +SYS_QUEUE_RECV EQU 36 +SYS_PUBLISH_QUEUE EQU 37 +SYS_OPEN_NAMED_QUEUE EQU 38 +SYS_QUEUE_DUPLICATE EQU 39 +SYS_NAMED_QUEUE_OWNER_PID EQU 40 +SYS_OPEN_FILE EQU 41 +SYS_CREATE_FILE EQU 42 +SYS_READ_FILE EQU 43 +SYS_WRITE_FILE EQU 44 +SYS_READ_FILE_ASYNC EQU 45 +SYS_WRITE_FILE_ASYNC EQU 46 +SYS_CANCEL_IO EQU 47 +SYS_SEEK_FILE EQU 48 +SYS_GET_FILE_POS EQU 49 +SYS_GET_FILE_SIZE EQU 50 +SYS_TRUNCATE_FILE EQU 51 +SYS_DELETE_FILE EQU 52 +SYS_RENAME_FILE EQU 53 +SYS_OPEN_DIR EQU 54 +SYS_READ_DIR EQU 55 +SYS_CREATE_DIR EQU 56 +SYS_REMOVE_DIR EQU 57 +SYS_SET_CWD EQU 58 +SYS_GET_CWD EQU 59 +SYS_WRITE_CONSOLE EQU 60 +SYS_SCREEN_BLIT EQU 61 +SYS_SCREEN_CLEAR EQU 62 +SYS_SCREEN_GET_SIZE EQU 63 +SYS_SCREEN_PUT_CHAR EQU 64 +SYS_KB_POLL EQU 65 +SYS_KB_IS_KEY_DOWN EQU 66 +SYS_KB_READ_CHAR EQU 67 +SYS_KB_READ_KEY EQU 68 +SYS_KB_GET_MODIFIERS EQU 69 +SYS_MOUSE_POLL EQU 70 +SYS_MOUSE_READ EQU 71 +SYS_MOUSE_GET_POS EQU 72 +SYS_GET_TICK EQU 73 +SYS_DEBUG_PRINT EQU 74 +SYS_QUERY_TRAP_FRAME EQU 75 +SYS_SOCKET EQU 76 +SYS_BIND EQU 77 +SYS_LISTEN EQU 78 +SYS_ACCEPT EQU 79 +SYS_CONNECT EQU 80 +SYS_SEND EQU 81 +SYS_RECV EQU 82 +SYS_SHUTDOWN EQU 83 +SYS_SEND_TO EQU 84 +SYS_RECV_FROM EQU 85 +SYS_RESOLVE_HOST EQU 86 +SYS_SET_SOCKET_OPTION EQU 87 +SYS_GET_SOCKET_OPTION EQU 88 +SYS_POLL EQU 89 +SYS_GET_MEMORY_STATUS EQU 90 +SYS_QUERY_KERNEL_STATS EQU 91 -SYS_MAX EQU 90 +SYS_MAX EQU 92 diff --git a/code/user/syscall/syscall_stubs.asm b/code/user/syscall/syscall_stubs.asm index f01ae90..3a342a3 100644 --- a/code/user/syscall/syscall_stubs.asm +++ b/code/user/syscall/syscall_stubs.asm @@ -108,11 +108,12 @@ SysUserApcDispatcher_Failed: SysUserApcDispatcher ENDP ; --------------------------------------------------------------------------- -; Memory and handles +; Virtual memory and handles ; --------------------------------------------------------------------------- -SYSCALL_STUB2 Alloc, SYS_ALLOC -SYSCALL_STUB2 Free, SYS_FREE -SYSCALL_STUB2 Realloc, SYS_REALLOC +SYSCALL_STUB6 VmAlloc, SYS_VM_ALLOC +SYSCALL_STUB2 VmFree, SYS_VM_FREE +SYSCALL_STUB2 VmProtect, SYS_VM_PROTECT +SYSCALL_STUB2 VmQuery, SYS_VM_QUERY SYSCALL_STUB2 CloseHandle, SYS_CLOSE_HANDLE ; --------------------------------------------------------------------------- @@ -216,5 +217,6 @@ SYSCALL_STUB2 GetSocketOption, SYS_GET_SOCKET_OPTION SYSCALL_STUB2 Poll, SYS_POLL SYSCALL_STUB2 GetMemoryStatus, SYS_GET_MEMORY_STATUS +SYSCALL_STUB2 QueryKernelStats, SYS_QUERY_KERNEL_STATS END diff --git a/code/user/tests/async_apc/async_apc.c b/code/user/tests/async_apc/async_apc.c index fbd8962..39ac210 100644 --- a/code/user/tests/async_apc/async_apc.c +++ b/code/user/tests/async_apc/async_apc.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -82,7 +83,7 @@ int main(void) { SysExitProcess(1); } - uint8_t* buffer = (uint8_t*)SysAlloc(512); + uint8_t* buffer = (uint8_t*)malloc(512); if (!buffer) { print("async_apc: allocation failed\n"); SysExitProcess(1); @@ -141,7 +142,7 @@ int main(void) { SysCloseHandle(event); SysCloseHandle(file); - SysFree(buffer); + free(buffer); if (!ok) { print("async_apc: FAIL\n"); diff --git a/code/user/tests/async_cancel/async_cancel.c b/code/user/tests/async_cancel/async_cancel.c index abb800a..45adca6 100644 --- a/code/user/tests/async_cancel/async_cancel.c +++ b/code/user/tests/async_cancel/async_cancel.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -51,7 +52,7 @@ int main(void) { SysExitProcess(1); } - uint8_t* buffer = (uint8_t*)SysAlloc(512); + uint8_t* buffer = (uint8_t*)malloc(512); if (!buffer) { print("async_cancel: alloc failed\n"); SysExitProcess(1); @@ -101,7 +102,7 @@ int main(void) { SysCloseHandle(request); SysCloseHandle(event); SysCloseHandle(file); - SysFree(buffer); + free(buffer); if (!ok) { print("async_cancel: FAIL\n"); diff --git a/readme.md b/readme.md index 51ede1f..c6842cc 100644 --- a/readme.md +++ b/readme.md @@ -291,7 +291,7 @@ Q: Does it run Doom? A: `doom.exe` Q: Does USB work? -A: For me, my keyboard, mouse and thumbdrive. +A: It did for everything I threw at it. Q: If I write a program now, will it run in the future? A: Not a chance. WE DO - in fact - BREAK USERSPACE.