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

This commit is contained in:
maksw committed 2026-06-09 18:02:28 +02:00
1 parent 27b31f62b6
commit 325149006c
45 files changed
+2038 -707

No files matched your search

Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1,5 +1,5 @@
[kernel] [kernel]
; bitmask: 1 = debug prints, 2 = self check, 4 = write debug prints to file ; bitmask: 1 = debug prints, 2 = self check, 4 = write debug prints to file
debug = 4 debug = 1
[init] [init]
commandline = apps/shell_native.exe commandline = apps/shell_native.exe
+16 -14
View File
@@ -36,7 +36,7 @@ static const Driver_Target STANDALONE_DRIVERS[] = {
void create_layout() { void create_layout() {
const char *dirs[] = { const char *dirs[] = {
"obj", "bin", "obj\\boot", "obj\\kernel", "obj\\lwip", "obj\\hal", "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\\shell_win32", "obj\\shell_posix", "obj\\shell_native",
"obj\\async_apc", "obj\\async_cancel", "obj\\edit", "obj\\httpget", "obj\\async_apc", "obj\\async_cancel", "obj\\edit", "obj\\httpget",
"obj\\tcpserve", "obj\\udp", "obj\\resolve", "obj\\ping", "obj\\doom", "obj\\video" "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), 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", "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 // 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), 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 // Subsystem DLLs
"link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:bin\\syscall.dll obj\\syscall\\stubs.obj", "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 /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 /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\\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++) { 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 // Queue Subsystem Applications
const char *apps[][4] = { const char *apps[][4] = {
// Folder, Libs, Name, Optional Extra Link Args // 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_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_posix", "bin\\posix.lib obj\\libc.obj", "shell_posix", "/ENTRY:main"},
{"apps\\shell_native", "bin\\syscall.lib obj\\libc.obj", "shell_native", "/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", "async_apc", "/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", "async_cancel", "/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", "edit", "/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", "httpget", "/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", "tcpserve", "/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", "udp", "/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", "resolve", "/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", "ping", "/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", "doom", "/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"} {"apps\\video", "bin\\win32.lib obj\\libc.obj code\\user\\apps\\video\\bink2w64.lib", "video", "/ENTRY:main"}
}; };
+1 -1
View File
@@ -115,7 +115,7 @@ KSTATUS UsbMapMmio(const HAL_API* hal, uint64_t physBase,
for (uint32_t i = 0; i < pages; i++) { for (uint32_t i = 0; i < pages; i++) {
PHYSICAL_ADDRESS phys = pageBase + (uint64_t)i * PAGE_SIZE; PHYSICAL_ADDRESS phys = pageBase + (uint64_t)i * PAGE_SIZE;
uintptr_t virt = (uintptr_t)hal->PhysToVirt(phys); 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) if (st == STATUS_ALREADY_EXISTS)
st = MmSetPageProtect(virt, PAGE_SIZE, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE); st = MmSetPageProtect(virt, PAGE_SIZE, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE);
if (!KSUCCESS(st)) { if (!KSUCCESS(st)) {
+1 -1
View File
@@ -41,7 +41,7 @@ KSTATUS Rtl8139MapMmio(uint64_t physBase, volatile uint8_t** outMmio) {
for (uint32_t i = 0; i < RTL8139_MMIO_PAGES; i++) { for (uint32_t i = 0; i < RTL8139_MMIO_PAGES; i++) {
PHYSICAL_ADDRESS phys = pageBase + (uint64_t)i * PAGE_SIZE; PHYSICAL_ADDRESS phys = pageBase + (uint64_t)i * PAGE_SIZE;
uintptr_t virt = (uintptr_t)gHal->PhysToVirt(phys); 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) if (st == STATUS_ALREADY_EXISTS)
st = MmSetPageProtect(virt, PAGE_SIZE, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE); st = MmSetPageProtect(virt, PAGE_SIZE, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE);
if (!KSUCCESS(st)) if (!KSUCCESS(st))
+1 -1
View File
@@ -54,7 +54,7 @@ KSTATUS RtlMapMmio(uint64_t physBase, volatile uint8_t** outMmio) {
for (uint32_t i = 0; i < RTL_MMIO_PAGES; i++) { for (uint32_t i = 0; i < RTL_MMIO_PAGES; i++) {
PHYSICAL_ADDRESS phys = pageBase + (uint64_t)i * PAGE_SIZE; PHYSICAL_ADDRESS phys = pageBase + (uint64_t)i * PAGE_SIZE;
uintptr_t virt = (uintptr_t)gHal->PhysToVirt(phys); 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) if (st == STATUS_ALREADY_EXISTS)
st = MmSetPageProtect(virt, PAGE_SIZE, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE); st = MmSetPageProtect(virt, PAGE_SIZE, PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE);
if (!KSUCCESS(st)) if (!KSUCCESS(st))
+1 -1
View File
@@ -6,7 +6,7 @@ KSTATUS ahci_map_mmio(uint64_t physBase) {
uint64_t phys = physBase + (uint64_t)i * 4096; uint64_t phys = physBase + (uint64_t)i * 4096;
uintptr_t virt = (uintptr_t)g_hal->PhysToVirt(phys); uintptr_t virt = (uintptr_t)g_hal->PhysToVirt(phys);
uint64_t flags = PAGE_PRESENT | PAGE_WRITE | PAGE_NOCACHE; 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 // Ignore STATUS_ALREADY_EXISTS - a prior mapping with different flags
// is possible for the first page if the bootloader was overly generous. // is possible for the first page if the bootloader was overly generous.
// Use MmSetPageProtect to force NOCACHE in that case. // Use MmSetPageProtect to force NOCACHE in that case.
+1 -1
View File
@@ -93,7 +93,7 @@ static int gS5Found = 0;
int debugEnabled = 0; int debugEnabled = 0;
int _fltused; // MSVC floating-point helper anchor int _fltused; // MSVC floating-point helper anchor
static void hal_putchar(char c) { static void hal_putchar(char c) {
gApi.Screen.PrintChar(c, 0x00FF00, 0x000000); gApi.Screen.PrintChar(c, 0xCCCCCC, 0x012456);
} }
void HalDbgPrint(const char* fmt, ...) { void HalDbgPrint(const char* fmt, ...) {
if (!debugEnabled) return; if (!debugEnabled) return;
+20 -9
View File
@@ -19,6 +19,9 @@ static int gCursorX = 0, gCursorY = 0;
#define FONT_W 8 #define FONT_W 8
#define FONT_H 16 #define FONT_H 16
#define SCREEN_DEFAULT_FG 0xCCCCCCu
#define SCREEN_DEFAULT_BG 0x012456u
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// 8x16 VGA font - printable ASCII only (glyph 0 = space = 0x20) // 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 ScreenGetSize(int* w, int* h) { *w = gWidth; *h = gHeight; }
static void ScreenScroll(int lines) { 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); size_t rowBytes = (size_t)gStride * sizeof(uint32_t);
uint32_t* shadow = gBackbuffer ? gBackbuffer : gFb; uint32_t* shadow = gBackbuffer ? gBackbuffer : gFb;
memmove(shadow, shadow + lines * gStride, memmove(shadow, shadow + lines * gStride,
(size_t)(gHeight - lines) * rowBytes); (size_t)(gHeight - lines) * rowBytes);
// Clear the revealed rows at the bottom.
memset(shadow + (gHeight - lines) * gStride, 0, // Fill the revealed rows with the console background. Do not memset here:
(size_t)lines * rowBytes); // 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); ScreenFlushRows(0, gHeight);
} }
static void ScreenPutChar(char c, int x, int y, uint32_t fg, uint32_t bg) { 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 + ((uint8_t)c * 16);
const uint8_t* glyph = Font8x16 + ((unsigned char)c - 0x20) * 16;
for (int row = 0; row < 16; row++) { for (int row = 0; row < 16; row++) {
uint8_t bits = glyph[row]; uint8_t bits = glyph[row];
for (int col = 0; col < 8; col++) { 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 uint32_t color = (bits & (0x80u >> col)) ? fg : bg;
// i shouldn't have to wonder why but the font is backwards unless we do this terriblness
PutPixelRaw(x + col, y + row, color); 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->PrintChar = ScreenPrintChar;
out->DrawCursor = HalScreenDrawCursor; out->DrawCursor = HalScreenDrawCursor;
out->EraseCursor = HalScreenEraseCursor; out->EraseCursor = HalScreenEraseCursor;
ScreenClear(0x000000); ScreenClear(SCREEN_DEFAULT_BG);
} }
+10 -4
View File
@@ -175,6 +175,13 @@ static uint32_t CalibrateApicTimerViaHpet(uintptr_t hpetPhys) {
return elapsed / 10; // APIC ticks per ms 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) { KSTATUS HalTimerInitialize(uintptr_t lapicPhys, uintptr_t hpetPhys, HAL_TIMER *out) {
gLapic = (volatile uint32_t *)gApi.PhysToVirt(lapicPhys); gLapic = (volatile uint32_t *)gApi.PhysToVirt(lapicPhys);
HalDbgPrint("HAL: lapicPhys=0x%016llX, lapicVirt=0x%016llX, hpetPhys=0x%016llX\n", lapicPhys, (uintptr_t)gLapic, hpetPhys); 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); HalDbgPrint("HAL: APIC timer: %u ticks/ms\n", ticksPerMs);
// Configure LAPIC timer in periodic mode // Configure this CPU's LAPIC timer; APs call HalTimerConfigureCurrentCpu()
LAPIC_REG(LAPIC_TIMER_DIV) = TIMER_DIV16; // after enabling their local APIC.
LAPIC_REG(LAPIC_TIMER_LVT) = TIMER_PERIODIC | TIMER_VECTOR; HalTimerConfigureCurrentCpu();
LAPIC_REG(LAPIC_TIMER_INIT) = gApicTicksPerQuantum;
out->QueryTicks = QueryTicks; out->QueryTicks = QueryTicks;
out->Stall = Stall; out->Stall = Stall;
+515 -193
View File
@@ -1,199 +1,521 @@
#pragma once #pragma once
// font8x16.h - embedded 8x16 VGA bitmap font, printable ASCII (0x20-0x7E) // font8x16.h - embedded 8x16 CP437 bitmap font.
// 95 glyphs × 16 bytes = 1520 bytes total. // Source: PC Face oldschool-vga-8x16 fontlist.js.
// Each byte is one scanline; bit 7 = leftmost pixel. // Converted from: oldschool-vga-8x16-fontlist.js
// Layout: 256 glyphs * 16 scanlines. Bit 7 is the leftmost pixel.
#include <stdint.h> #include <stdint.h>
static const uint8_t Font8x16[95 * 16] = { static const uint8_t Font8x16[256 * 16] = {
// 0x20 ' ' // 0x00
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x21 '!' // 0x01
0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x7E,0x81,0xA5,0x81,0x81,0xBD,0x99,0x81,0x81,0x7E,0x00,0x00,0x00,0x00,
// 0x22 '"' // 0x02
0x00,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x7E,0xFF,0xDB,0xFF,0xFF,0xC3,0xE7,0xFF,0xFF,0x7E,0x00,0x00,0x00,0x00,
// 0x23 '#' // 0x03
0x00,0x36,0x36,0x7F,0x36,0x36,0x36,0x7F,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x6C,0xFE,0xFE,0xFE,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,
// 0x24 '$' // 0x04
0x18,0x18,0x3E,0x63,0x03,0x03,0x1E,0x30,0x30,0x63,0x3E,0x18,0x18,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x10,0x38,0x7C,0xFE,0x7C,0x38,0x10,0x00,0x00,0x00,0x00,0x00,
// 0x25 '%' // 0x05
0x00,0x00,0x63,0x33,0x18,0x0C,0x06,0x31,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x18,0x3C,0x3C,0xE7,0xE7,0xE7,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
// 0x26 '&' // 0x06
0x00,0x1C,0x36,0x1C,0x0E,0x3B,0x33,0x33,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x18,0x3C,0x7E,0xFF,0xFF,0x7E,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,
// 0x27 '\'' // 0x07
0x00,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x28 '(' // 0x08
0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE7,0xC3,0xC3,0xE7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
// 0x29 ')' // 0x09
0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x3C,0x66,0x42,0x42,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,
// 0x2A '*' // 0x0A
0x00,0x00,0x00,0x33,0x1E,0xFF,0x1E,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0xFF,0xFF,0xFF,0xFF,0xFF,0xC3,0x99,0xBD,0xBD,0x99,0xC3,0xFF,0xFF,0xFF,0xFF,0xFF,
// 0x2B '+' // 0x0B
0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x1E,0x0E,0x1A,0x32,0x78,0xCC,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00,
// 0x2C ',' // 0x0C
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,
// 0x2D '-' // 0x0D
0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x3F,0x33,0x3F,0x30,0x30,0x30,0x30,0x70,0xF0,0xE0,0x00,0x00,0x00,0x00,
// 0x2E '.' // 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, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x2F '/' // 0xFA
0x00,0x60,0x30,0x18,0x0C,0x06,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x30 '0' // 0xFB
0x00,0x3C,0x66,0x66,0x76,0x6E,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x0F,0x0C,0x0C,0x0C,0x0C,0x0C,0xEC,0x6C,0x6C,0x3C,0x1C,0x00,0x00,0x00,0x00,
// 0x31 '1' // 0xFC
0x00,0x18,0x1C,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0xD8,0x6C,0x6C,0x6C,0x6C,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x32 '2' // 0xFD
0x00,0x3C,0x66,0x60,0x30,0x18,0x0C,0x66,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x70,0xD8,0x30,0x60,0xC8,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x33 '3' // 0xFE
0x00,0x3C,0x66,0x60,0x38,0x60,0x60,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x7C,0x00,0x00,0x00,0x00,0x00,
// 0x34 '4' // 0xFF
0x00,0x30,0x38,0x3C,0x36,0x33,0x7F,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,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,
}; };
@@ -34,4 +34,5 @@ __declspec(dllexport) void HalApicEnableCurrentCpu(void);
__declspec(dllexport) void HalApicSendPanicIpi(void); __declspec(dllexport) void HalApicSendPanicIpi(void);
__declspec(dllexport) void HalApicSendRescheduleIpi(uint32_t lapicId); __declspec(dllexport) void HalApicSendRescheduleIpi(uint32_t lapicId);
__declspec(dllexport) void HalApicSendTlbShootdownIpi(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); __declspec(dllexport) KSTATUS HalStartApplicationProcessor(uint32_t lapicId, uint8_t startupVector);
-1
View File
@@ -31,7 +31,6 @@ KSTATUS LdrResolveImports(uintptr_t imageBase);
KSTATUS LdrResolveImportsForProcess(struct PROCESS* process, uintptr_t imageBase); KSTATUS LdrResolveImportsForProcess(struct PROCESS* process, uintptr_t imageBase);
// Apply final page permissions for a loaded image after relocations/imports. // 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); KSTATUS LdrProtectImageForProcess(struct PROCESS* process, uintptr_t imageBase, bool user);
// Load a DLL for a specific process, resolve it against that process's // Load a DLL for a specific process, resolve it against that process's
+11 -1
View File
@@ -1,6 +1,6 @@
#pragma once #pragma once
// mm_phys.h - physical memory manager (PMM) // 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 <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
@@ -11,6 +11,15 @@
typedef uint64_t PHYSICAL_ADDRESS; 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. // Called once by KernelMain with the MEMORY_MAP from BOOT_INFO.
bool MmInitializePhysical(const MEMORY_MAP* map, bool MmInitializePhysical(const MEMORY_MAP* map,
uint64_t physicalWindowBase); uint64_t physicalWindowBase);
@@ -29,3 +38,4 @@ __declspec(dllexport) PHYSICAL_ADDRESS MmAllocateContiguous(size_t count);
size_t MmFreeFrameCount(void); size_t MmFreeFrameCount(void);
size_t MmTotalFrameCount(void); size_t MmTotalFrameCount(void);
void MmQueryPhysicalStats(MM_PHYSICAL_STATS* out);
+8 -2
View File
@@ -1,6 +1,6 @@
#pragma once #pragma once
// mm_virt.h - virtual memory manager (VMM) // 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 <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <kernel/mm_phys.h> #include <kernel/mm_phys.h>
@@ -9,6 +9,11 @@
struct PROCESS; struct PROCESS;
typedef struct PROCESS PROCESS; typedef struct PROCESS PROCESS;
typedef enum MM_MAP_MODE {
MmMapFailIfPresent = 0,
MmMapReplaceExisting = 1,
} MM_MAP_MODE;
typedef enum USER_REGION_TYPE { typedef enum USER_REGION_TYPE {
UserRegionGeneric = 0, UserRegionGeneric = 0,
UserRegionHeap, UserRegionHeap,
@@ -59,7 +64,7 @@ void MmActivate(void);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Page mapping // 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); __declspec(dllexport) KSTATUS MmUnmapPage(uintptr_t virt);
// Modify protection flags on an already-mapped virtual range. // 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 MmProtectUserRegion(PROCESS* process, void* base, size_t size, uint64_t pageFlags);
KSTATUS MmDestroyUserRegion(PROCESS* process, void* base); KSTATUS MmDestroyUserRegion(PROCESS* process, void* base);
void MmDestroyAllUserRegions(PROCESS* process); 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 MmGetUserRegionSize(PROCESS* process, const void* base);
size_t MmGetUserRegionSizeByBase(const void* base); size_t MmGetUserRegionSizeByBase(const void* base);
+76 -74
View File
@@ -23,78 +23,80 @@
#define SYS_SLEEP 14 #define SYS_SLEEP 14
#define SYS_SET_USER_APC_DISPATCHER 15 #define SYS_SET_USER_APC_DISPATCHER 15
#define SYS_APC_RETURN 16 #define SYS_APC_RETURN 16
#define SYS_ALLOC 17 #define SYS_VM_ALLOC 17
#define SYS_FREE 18 #define SYS_VM_FREE 18
#define SYS_REALLOC 19 #define SYS_VM_PROTECT 19
#define SYS_CLOSE_HANDLE 20 #define SYS_VM_QUERY 20
#define SYS_MUTEX_CREATE 21 #define SYS_CLOSE_HANDLE 21
#define SYS_MUTEX_ACQUIRE 22 #define SYS_MUTEX_CREATE 22
#define SYS_MUTEX_TRY_ACQUIRE 23 #define SYS_MUTEX_ACQUIRE 23
#define SYS_MUTEX_RELEASE 24 #define SYS_MUTEX_TRY_ACQUIRE 24
#define SYS_SEM_CREATE 25 #define SYS_MUTEX_RELEASE 25
#define SYS_SEM_WAIT 26 #define SYS_SEM_CREATE 26
#define SYS_SEM_TRY_WAIT 27 #define SYS_SEM_WAIT 27
#define SYS_SEM_SIGNAL 28 #define SYS_SEM_TRY_WAIT 28
#define SYS_EVENT_CREATE 29 #define SYS_SEM_SIGNAL 29
#define SYS_EVENT_SIGNAL 30 #define SYS_EVENT_CREATE 30
#define SYS_EVENT_CLEAR 31 #define SYS_EVENT_SIGNAL 31
#define SYS_EVENT_WAIT 32 #define SYS_EVENT_CLEAR 32
#define SYS_QUEUE_CREATE 33 #define SYS_EVENT_WAIT 33
#define SYS_QUEUE_SEND 34 #define SYS_QUEUE_CREATE 34
#define SYS_QUEUE_RECV 35 #define SYS_QUEUE_SEND 35
#define SYS_PUBLISH_QUEUE 36 #define SYS_QUEUE_RECV 36
#define SYS_OPEN_NAMED_QUEUE 37 #define SYS_PUBLISH_QUEUE 37
#define SYS_QUEUE_DUPLICATE 38 #define SYS_OPEN_NAMED_QUEUE 38
#define SYS_NAMED_QUEUE_OWNER_PID 39 #define SYS_QUEUE_DUPLICATE 39
#define SYS_OPEN_FILE 40 #define SYS_NAMED_QUEUE_OWNER_PID 40
#define SYS_CREATE_FILE 41 #define SYS_OPEN_FILE 41
#define SYS_READ_FILE 42 #define SYS_CREATE_FILE 42
#define SYS_WRITE_FILE 43 #define SYS_READ_FILE 43
#define SYS_READ_FILE_ASYNC 44 #define SYS_WRITE_FILE 44
#define SYS_WRITE_FILE_ASYNC 45 #define SYS_READ_FILE_ASYNC 45
#define SYS_CANCEL_IO 46 #define SYS_WRITE_FILE_ASYNC 46
#define SYS_SEEK_FILE 47 #define SYS_CANCEL_IO 47
#define SYS_GET_FILE_POS 48 #define SYS_SEEK_FILE 48
#define SYS_GET_FILE_SIZE 49 #define SYS_GET_FILE_POS 49
#define SYS_TRUNCATE_FILE 50 #define SYS_GET_FILE_SIZE 50
#define SYS_DELETE_FILE 51 #define SYS_TRUNCATE_FILE 51
#define SYS_RENAME_FILE 52 #define SYS_DELETE_FILE 52
#define SYS_OPEN_DIR 53 #define SYS_RENAME_FILE 53
#define SYS_READ_DIR 54 #define SYS_OPEN_DIR 54
#define SYS_CREATE_DIR 55 #define SYS_READ_DIR 55
#define SYS_REMOVE_DIR 56 #define SYS_CREATE_DIR 56
#define SYS_SET_CWD 57 #define SYS_REMOVE_DIR 57
#define SYS_GET_CWD 58 #define SYS_SET_CWD 58
#define SYS_WRITE_CONSOLE 59 #define SYS_GET_CWD 59
#define SYS_SCREEN_BLIT 60 #define SYS_WRITE_CONSOLE 60
#define SYS_SCREEN_CLEAR 61 #define SYS_SCREEN_BLIT 61
#define SYS_SCREEN_GET_SIZE 62 #define SYS_SCREEN_CLEAR 62
#define SYS_SCREEN_PUT_CHAR 63 #define SYS_SCREEN_GET_SIZE 63
#define SYS_KB_POLL 64 #define SYS_SCREEN_PUT_CHAR 64
#define SYS_KB_IS_KEY_DOWN 65 #define SYS_KB_POLL 65
#define SYS_KB_READ_CHAR 66 #define SYS_KB_IS_KEY_DOWN 66
#define SYS_KB_READ_KEY 67 #define SYS_KB_READ_CHAR 67
#define SYS_KB_GET_MODIFIERS 68 #define SYS_KB_READ_KEY 68
#define SYS_MOUSE_POLL 69 #define SYS_KB_GET_MODIFIERS 69
#define SYS_MOUSE_READ 70 #define SYS_MOUSE_POLL 70
#define SYS_MOUSE_GET_POS 71 #define SYS_MOUSE_READ 71
#define SYS_GET_TICK 72 #define SYS_MOUSE_GET_POS 72
#define SYS_DEBUG_PRINT 73 #define SYS_GET_TICK 73
#define SYS_QUERY_TRAP_FRAME 74 #define SYS_DEBUG_PRINT 74
#define SYS_SOCKET 75 #define SYS_QUERY_TRAP_FRAME 75
#define SYS_BIND 76 #define SYS_SOCKET 76
#define SYS_LISTEN 77 #define SYS_BIND 77
#define SYS_ACCEPT 78 #define SYS_LISTEN 78
#define SYS_CONNECT 79 #define SYS_ACCEPT 79
#define SYS_SEND 80 #define SYS_CONNECT 80
#define SYS_RECV 81 #define SYS_SEND 81
#define SYS_SHUTDOWN 82 #define SYS_RECV 82
#define SYS_SEND_TO 83 #define SYS_SHUTDOWN 83
#define SYS_RECV_FROM 84 #define SYS_SEND_TO 84
#define SYS_RESOLVE_HOST 85 #define SYS_RECV_FROM 85
#define SYS_SET_SOCKET_OPTION 86 #define SYS_RESOLVE_HOST 86
#define SYS_GET_SOCKET_OPTION 87 #define SYS_SET_SOCKET_OPTION 87
#define SYS_POLL 88 #define SYS_GET_SOCKET_OPTION 88
#define SYS_GET_MEMORY_STATUS 89 #define SYS_POLL 89
#define SYS_GET_MEMORY_STATUS 90
#define SYS_QUERY_KERNEL_STATS 91
#define SYS_MAX 90 #define SYS_MAX 92
+5 -6
View File
@@ -57,7 +57,7 @@ static void KiDebugConsoleWrite(const char* text, size_t len) {
if (!PrintChar || !text) if (!PrintChar || !text)
return; return;
for (size_t i = 0; i < len; i++) for (size_t i = 0; i < len; i++)
PrintChar(text[i], 0x00FF00, 0x000000); PrintChar(text[i], 0xCCCCCC, 0x012456);
} }
static volatile long gPanicInProgress = 0; static volatile long gPanicInProgress = 0;
@@ -88,7 +88,7 @@ __declspec(dllexport) int KeHandleNmiIpi(void) {
} }
void KiKernelPutChar(char c) { void KiKernelPutChar(char c) {
PrintChar(c, 0x00FF00, 0x000000); PrintChar(c, 0xCCCCCC, 0x012456);
} }
void KeInitDebug(void (*PrintPtr)(char, uint32_t, uint32_t), uint32_t flags) { 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(); for (;;) __halt();
} }
// KePrintConsole - write user-visible console text in white-on-black. // KePrintConsole - write user-visible console text using the default console palette.
// Used by SYS_WRITE_CONSOLE so user programs get a distinct color from // Panic output keeps a distinct color so fatal paths remain visually obvious.
// kernel debug output (green) and panic output (red).
__declspec(dllexport) void KePrintConsole(const char* buf, size_t len) { __declspec(dllexport) void KePrintConsole(const char* buf, size_t len) {
if (!buf || !PrintChar) return; if (!buf || !PrintChar) return;
for (size_t i = 0; i < len; i++) for (size_t i = 0; i < len; i++)
PrintChar(buf[i], 0xFFFFFF, 0x000000); PrintChar(buf[i], 0xCCCCCC, 0x012456);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
+8
View File
@@ -5,6 +5,8 @@
#include <kernel/ke_idt.h> #include <kernel/ke_idt.h>
#include <kernel/ke_irql.h> #include <kernel/ke_irql.h>
#include <kernel/ke_dpc.h> #include <kernel/ke_dpc.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_process.h>
#include <ntlite/ddi/hal_api.h> #include <ntlite/ddi/hal_api.h>
#include <kernel/ke_debug.h> #include <kernel/ke_debug.h>
@@ -115,6 +117,12 @@ void KiExitInterrupt(void) {
// code, leave the request pending instead of switching out of a spinlock or // code, leave the request pending instead of switching out of a spinlock or
// high-IRQL region. // high-IRQL region.
if (cpu->InterruptDepth == 0 && KeGetCurrentIrql() == PASSIVE_LEVEL) { 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(); KiDrainDpcQueue();
if (KeGetCurrentIrql() == PASSIVE_LEVEL) if (KeGetCurrentIrql() == PASSIVE_LEVEL)
KiScheduleFromInterrupt(); KiScheduleFromInterrupt();
+17 -5
View File
@@ -8,6 +8,8 @@
#include <kernel/ke_userenv.h> #include <kernel/ke_userenv.h>
#include <kernel/mm_virt.h> #include <kernel/mm_virt.h>
#include <kernel/ob_object.h> #include <kernel/ob_object.h>
#include <kernel/ke_cpu.h>
#include <kernel/hal/hal_apic.h>
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Global process list // Global process list
@@ -382,16 +384,26 @@ KSTATUS KeTerminateProcess(PROCESS* process, int exitCode) {
process->ExitCode = exitCode; process->ExitCode = exitCode;
_InterlockedExchange(&process->Terminating, 1); _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); uintptr_t flags = KeAcquireSpinlock(&process->HandleLock);
LIST_ENTRY* head = &process->ThreadList; 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) { for (LIST_ENTRY* node = head->Fwd; node != head; node = node->Fwd) {
THREAD* t = CONTAINING_RECORD(node, THREAD, ProcessLink); THREAD* t = CONTAINING_RECORD(node, THREAD, ProcessLink);
if (t != KeGetCurrentThread()) if (t == self)
continue;
(void)KeAlertThread(t); (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); KeReleaseSpinlock(&process->HandleLock, flags);
+10
View File
@@ -29,6 +29,10 @@ static uint64_t KiDefaultThreadAffinityMask(void) {
return 1ULL; 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) { static int KiThreadCanRunOnCpuLocked(const THREAD* thread, const KCPU* cpu) {
if (!thread || !cpu) return 0; if (!thread || !cpu) return 0;
if (thread->IsIdleThread) return thread == cpu->IdleThread; 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 // 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 // lone CPU-bound thread gets alternated with the idle thread on every timer
// tick, effectively turning a periodic preemption check into a 50% throttle. // 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 != idle && cur->State == ThreadRunning && !KiAnyRunnableForCpuLocked(cpu)) {
if (cur->QuantumRemaining == 0) if (cur->QuantumRemaining == 0)
KiRefillQuantumLocked(cur); KiRefillQuantumLocked(cur);
@@ -635,6 +643,8 @@ void KeSchedulerTick(void) {
if (cur == idle) { if (cur == idle) {
if (KiAnyRunnableForCpuLocked(cpu)) if (KiAnyRunnableForCpuLocked(cpu))
requestReschedule = 1; requestReschedule = 1;
} else if (KiThreadIsKilledLocked(cur)) {
requestReschedule = 1;
} else { } else {
cur->CpuBurstTicks++; cur->CpuBurstTicks++;
cur->QuantaConsumed = cur->CpuBurstTicks; cur->QuantaConsumed = cur->CpuBurstTicks;
+24 -1
View File
@@ -298,13 +298,29 @@ _Noreturn void KiApKernelEntry(KCPU* cpu) {
idle->RunningCpu = cpu->CpuIndex; idle->RunningCpu = cpu->CpuIndex;
idle->Queued = 0; idle->Queued = 0;
cpu->Parked = 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); _InterlockedExchange(&cpu->SchedulerActive, 1);
_enable(); _enable();
KeStartInitialThread(idle); 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(); _ReadWriteBarrier();
_InterlockedExchange(&cpu->SchedulerCommand, 1); _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; int active = 0;
for (uint32_t spin = 0; spin < AP_SCHED_TIMEOUT_SPINS; spin++) { for (uint32_t spin = 0; spin < AP_SCHED_TIMEOUT_SPINS; spin++) {
if (_InterlockedCompareExchange(&cpu->SchedulerActive, 0, 0) != 0) { if (_InterlockedCompareExchange(&cpu->SchedulerActive, 0, 0) != 0) {
+316 -92
View File
@@ -34,6 +34,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <kernel/ke_thread.h> #include <kernel/ke_thread.h>
#include <kernel/ke_cpu.h>
#include <kernel/ke_sched.h> #include <kernel/ke_sched.h>
#include <kernel/ke_process.h> #include <kernel/ke_process.h>
#include <kernel/ke_mutex.h> #include <kernel/ke_mutex.h>
@@ -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, static KSTATUS KiVmProtectToPageFlags(uint32_t protect, uint64_t* flagsOut) {
uint64_t a3, uint64_t a4, uint64_t a5) { if (!flagsOut) return STATUS_INVALID_PARAMETER;
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5; switch (protect) {
if (!a0) return 0; case SYS_VM_NOACCESS:
return (uint64_t)(uintptr_t)MmAllocateUserMemory((size_t)a0); *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;
}
} }
// --------------------------------------------------------------------------- static uint32_t KiPageFlagsToVmProtect(uint64_t flags) {
// SYS_FREE a0 = ptr if (!(flags & PAGE_PRESENT)) return SYS_VM_NOACCESS;
// --------------------------------------------------------------------------- bool writable = (flags & PAGE_WRITE) != 0;
static uint64_t SyscallFree(uint64_t a0, uint64_t a1, uint64_t a2, 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) { uint64_t a3, uint64_t a4, uint64_t a5) {
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5; (void)a5;
if (a0) MmFreeUserMemory((void*)(uintptr_t)a0); 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; return STATUS_SUCCESS;
} }
// --------------------------------------------------------------------------- static uint64_t SyscallVmFree(uint64_t a0, uint64_t a1, uint64_t a2,
// SYS_REALLOC (10) a0 = ptr, a1 = newSize -> void* uint64_t a3, uint64_t a4, uint64_t a5) {
// --------------------------------------------------------------------------- (void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
static uint64_t SyscallRealloc(uint64_t a0, uint64_t a1, uint64_t a2, 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, &regionBase, &regionSize, &oldFlags, &type, &regionFlags);
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) { uint64_t a3, uint64_t a4, uint64_t a5) {
(void)a2; (void)a3; (void)a4; (void)a5; (void)a2; (void)a3; (void)a4; (void)a5;
return (uint64_t)(uintptr_t)MmReallocateUserMemory( if (!a0 || !a1) return STATUS_INVALID_PARAMETER;
(void*)(uintptr_t)a0, (size_t)a1);
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, &regionFlags);
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)); 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. // Dispatch table - index must match SYS_* in syscall_nr.h exactly.
// =========================================================================== // ===========================================================================
@@ -2589,79 +2797,81 @@ static const SYSCALL_HANDLER gSyscallTable[SYS_MAX] = {
/* 14 SYS_SLEEP */ SyscallSleep, /* 14 SYS_SLEEP */ SyscallSleep,
/* 15 SYS_SET_USER_APC_DISPATCHER */ SyscallSetUserApcDispatcher, /* 15 SYS_SET_USER_APC_DISPATCHER */ SyscallSetUserApcDispatcher,
/* 16 SYS_APC_RETURN */ SyscallApcReturn, /* 16 SYS_APC_RETURN */ SyscallApcReturn,
/* 17 SYS_ALLOC */ SyscallAlloc, /* 17 SYS_VM_ALLOC */ SyscallVmAlloc,
/* 18 SYS_FREE */ SyscallFree, /* 18 SYS_VM_FREE */ SyscallVmFree,
/* 19 SYS_REALLOC */ SyscallRealloc, /* 19 SYS_VM_PROTECT */ SyscallVmProtect,
/* 20 SYS_CLOSE_HANDLE */ SyscallCloseHandle, /* 20 SYS_VM_QUERY */ SyscallVmQuery,
/* 21 SYS_MUTEX_CREATE */ SyscallMutexCreate, /* 21 SYS_CLOSE_HANDLE */ SyscallCloseHandle,
/* 22 SYS_MUTEX_ACQUIRE */ SyscallMutexAcquire, /* 22 SYS_MUTEX_CREATE */ SyscallMutexCreate,
/* 23 SYS_MUTEX_TRY_ACQUIRE */ SyscallMutexTryAcquire, /* 23 SYS_MUTEX_ACQUIRE */ SyscallMutexAcquire,
/* 24 SYS_MUTEX_RELEASE */ SyscallMutexRelease, /* 24 SYS_MUTEX_TRY_ACQUIRE */ SyscallMutexTryAcquire,
/* 25 SYS_SEM_CREATE */ SyscallSemCreate, /* 25 SYS_MUTEX_RELEASE */ SyscallMutexRelease,
/* 26 SYS_SEM_WAIT */ SyscallSemWait, /* 26 SYS_SEM_CREATE */ SyscallSemCreate,
/* 27 SYS_SEM_TRY_WAIT */ SyscallSemTryWait, /* 27 SYS_SEM_WAIT */ SyscallSemWait,
/* 28 SYS_SEM_SIGNAL */ SyscallSemSignal, /* 28 SYS_SEM_TRY_WAIT */ SyscallSemTryWait,
/* 29 SYS_EVENT_CREATE */ SyscallEventCreate, /* 29 SYS_SEM_SIGNAL */ SyscallSemSignal,
/* 30 SYS_EVENT_SIGNAL */ SyscallEventSignal, /* 30 SYS_EVENT_CREATE */ SyscallEventCreate,
/* 31 SYS_EVENT_CLEAR */ SyscallEventClear, /* 31 SYS_EVENT_SIGNAL */ SyscallEventSignal,
/* 32 SYS_EVENT_WAIT */ SyscallEventWait, /* 32 SYS_EVENT_CLEAR */ SyscallEventClear,
/* 33 SYS_QUEUE_CREATE */ SyscallQueueCreate, /* 33 SYS_EVENT_WAIT */ SyscallEventWait,
/* 34 SYS_QUEUE_SEND */ SyscallQueueSend, /* 34 SYS_QUEUE_CREATE */ SyscallQueueCreate,
/* 35 SYS_QUEUE_RECV */ SyscallQueueRecv, /* 35 SYS_QUEUE_SEND */ SyscallQueueSend,
/* 36 SYS_PUBLISH_QUEUE */ SyscallPublishQueue, /* 36 SYS_QUEUE_RECV */ SyscallQueueRecv,
/* 37 SYS_OPEN_NAMED_QUEUE */ SyscallOpenNamedQueue, /* 37 SYS_PUBLISH_QUEUE */ SyscallPublishQueue,
/* 38 SYS_QUEUE_DUPLICATE */ SyscallQueueDuplicate, /* 38 SYS_OPEN_NAMED_QUEUE */ SyscallOpenNamedQueue,
/* 39 SYS_NAMED_QUEUE_OWNER_PID */ SyscallNamedQueueOwnerPid, /* 39 SYS_QUEUE_DUPLICATE */ SyscallQueueDuplicate,
/* 40 SYS_OPEN_FILE */ SyscallOpenFile, /* 40 SYS_NAMED_QUEUE_OWNER_PID */ SyscallNamedQueueOwnerPid,
/* 41 SYS_CREATE_FILE */ SyscallCreateFile, /* 41 SYS_OPEN_FILE */ SyscallOpenFile,
/* 42 SYS_READ_FILE */ SyscallReadFile, /* 42 SYS_CREATE_FILE */ SyscallCreateFile,
/* 43 SYS_WRITE_FILE */ SyscallWriteFile, /* 43 SYS_READ_FILE */ SyscallReadFile,
/* 44 SYS_READ_FILE_ASYNC */ SyscallReadFileAsync, /* 44 SYS_WRITE_FILE */ SyscallWriteFile,
/* 45 SYS_WRITE_FILE_ASYNC */ SyscallWriteFileAsync, /* 45 SYS_READ_FILE_ASYNC */ SyscallReadFileAsync,
/* 46 SYS_CANCEL_IO */ SyscallCancelIo, /* 46 SYS_WRITE_FILE_ASYNC */ SyscallWriteFileAsync,
/* 47 SYS_SEEK_FILE */ SyscallSeekFile, /* 47 SYS_CANCEL_IO */ SyscallCancelIo,
/* 48 SYS_GET_FILE_POS */ SyscallGetFilePos, /* 48 SYS_SEEK_FILE */ SyscallSeekFile,
/* 49 SYS_GET_FILE_SIZE */ SyscallGetFileSize, /* 49 SYS_GET_FILE_POS */ SyscallGetFilePos,
/* 50 SYS_TRUNCATE_FILE */ SyscallTruncateFile, /* 50 SYS_GET_FILE_SIZE */ SyscallGetFileSize,
/* 51 SYS_DELETE_FILE */ SyscallDeleteFile, /* 51 SYS_TRUNCATE_FILE */ SyscallTruncateFile,
/* 52 SYS_RENAME_FILE */ SyscallRenameFile, /* 52 SYS_DELETE_FILE */ SyscallDeleteFile,
/* 53 SYS_OPEN_DIR */ SyscallOpenDir, /* 53 SYS_RENAME_FILE */ SyscallRenameFile,
/* 54 SYS_READ_DIR */ SyscallReadDir, /* 54 SYS_OPEN_DIR */ SyscallOpenDir,
/* 55 SYS_CREATE_DIR */ SyscallCreateDir, /* 55 SYS_READ_DIR */ SyscallReadDir,
/* 56 SYS_REMOVE_DIR */ SyscallRemoveDir, /* 56 SYS_CREATE_DIR */ SyscallCreateDir,
/* 57 SYS_SET_CWD */ SyscallSetCwd, /* 57 SYS_REMOVE_DIR */ SyscallRemoveDir,
/* 58 SYS_GET_CWD */ SyscallGetCwd, /* 58 SYS_SET_CWD */ SyscallSetCwd,
/* 59 SYS_WRITE_CONSOLE */ SyscallWriteConsole, /* 59 SYS_GET_CWD */ SyscallGetCwd,
/* 60 SYS_SCREEN_BLIT */ SyscallScreenBlit, /* 60 SYS_WRITE_CONSOLE */ SyscallWriteConsole,
/* 61 SYS_SCREEN_CLEAR */ SyscallScreenClear, /* 61 SYS_SCREEN_BLIT */ SyscallScreenBlit,
/* 62 SYS_SCREEN_GET_SIZE */ SyscallScreenGetSize, /* 62 SYS_SCREEN_CLEAR */ SyscallScreenClear,
/* 63 SYS_SCREEN_PUT_CHAR */ SyscallScreenPutChar, /* 63 SYS_SCREEN_GET_SIZE */ SyscallScreenGetSize,
/* 64 SYS_KB_POLL */ SyscallKbPoll, /* 64 SYS_SCREEN_PUT_CHAR */ SyscallScreenPutChar,
/* 65 SYS_KB_IS_KEY_DOWN */ SyscallKbIsKeyDown, /* 65 SYS_KB_POLL */ SyscallKbPoll,
/* 66 SYS_KB_READ_CHAR */ SyscallKbReadChar, /* 66 SYS_KB_IS_KEY_DOWN */ SyscallKbIsKeyDown,
/* 67 SYS_KB_READ_KEY */ SyscallKbReadKey, /* 67 SYS_KB_READ_CHAR */ SyscallKbReadChar,
/* 68 SYS_KB_GET_MODIFIERS */ SyscallKbGetModifiers, /* 68 SYS_KB_READ_KEY */ SyscallKbReadKey,
/* 69 SYS_MOUSE_POLL */ SyscallMousePoll, /* 69 SYS_KB_GET_MODIFIERS */ SyscallKbGetModifiers,
/* 70 SYS_MOUSE_READ */ SyscallMouseRead, /* 70 SYS_MOUSE_POLL */ SyscallMousePoll,
/* 71 SYS_MOUSE_GET_POS */ SyscallMouseGetPos, /* 71 SYS_MOUSE_READ */ SyscallMouseRead,
/* 72 SYS_GET_TICK */ SyscallGetTick, /* 72 SYS_MOUSE_GET_POS */ SyscallMouseGetPos,
/* 73 SYS_DEBUG_PRINT */ SyscallDebugPrint, /* 73 SYS_GET_TICK */ SyscallGetTick,
/* 74 SYS_QUERY_TRAP_FRAME */ SyscallQueryTrapFrame, /* 74 SYS_DEBUG_PRINT */ SyscallDebugPrint,
/* 75 SYS_SOCKET */ SyscallSocket, /* 75 SYS_QUERY_TRAP_FRAME */ SyscallQueryTrapFrame,
/* 76 SYS_BIND */ SyscallBind, /* 76 SYS_SOCKET */ SyscallSocket,
/* 77 SYS_LISTEN */ SyscallListen, /* 77 SYS_BIND */ SyscallBind,
/* 78 SYS_ACCEPT */ SyscallAccept, /* 78 SYS_LISTEN */ SyscallListen,
/* 79 SYS_CONNECT */ SyscallConnect, /* 79 SYS_ACCEPT */ SyscallAccept,
/* 80 SYS_SEND */ SyscallSend, /* 80 SYS_CONNECT */ SyscallConnect,
/* 81 SYS_RECV */ SyscallRecv, /* 81 SYS_SEND */ SyscallSend,
/* 82 SYS_SHUTDOWN */ SyscallShutdown, /* 82 SYS_RECV */ SyscallRecv,
/* 83 SYS_SEND_TO */ SyscallSendTo, /* 83 SYS_SHUTDOWN */ SyscallShutdown,
/* 84 SYS_RECV_FROM */ SyscallRecvFrom, /* 84 SYS_SEND_TO */ SyscallSendTo,
/* 85 SYS_RESOLVE_HOST */ SyscallResolveHost, /* 85 SYS_RECV_FROM */ SyscallRecvFrom,
/* 86 SYS_SET_SOCKET_OPTION */ SyscallSetSocketOption, /* 86 SYS_RESOLVE_HOST */ SyscallResolveHost,
/* 87 SYS_GET_SOCKET_OPTION */ SyscallGetSocketOption, /* 87 SYS_SET_SOCKET_OPTION */ SyscallSetSocketOption,
/* 88 SYS_POLL */ SyscallPoll, /* 88 SYS_GET_SOCKET_OPTION */ SyscallGetSocketOption,
/* 89 SYS_GET_MEMORY_STATUS */ SyscallGetMemoryStatus /* 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; 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;
} }
+1 -1
View File
@@ -409,7 +409,7 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
.FramebufferHeight = bootInfo->FramebufferHeight, .FramebufferHeight = bootInfo->FramebufferHeight,
.FramebufferStride = bootInfo->FramebufferStride, .FramebufferStride = bootInfo->FramebufferStride,
.RsdpPhysical = bootInfo->RsdpPhysical, .RsdpPhysical = bootInfo->RsdpPhysical,
.Debug = bootInfo->Debug, .Debug = bootInfo->Debug & 1, // bitmask 1 debug prints
.AllocatePool = MmAllocatePool .AllocatePool = MmAllocatePool
}; };
+1 -3
View File
@@ -325,6 +325,7 @@ static void KiFreeLoadedImage(uintptr_t imageBase, bool user) {
KSTATUS LdrProtectImageForProcess(PROCESS* process, uintptr_t imageBase, bool user) { KSTATUS LdrProtectImageForProcess(PROCESS* process, uintptr_t imageBase, bool user) {
if (!imageBase) return STATUS_INVALID_PARAMETER; if (!imageBase) return STATUS_INVALID_PARAMETER;
if (user && !process) return STATUS_INVALID_PARAMETER;
size_t mappedSize = user ? LdrGetMappedImageSize(process, imageBase) : LdrGetImageSize(imageBase); size_t mappedSize = user ? LdrGetMappedImageSize(process, imageBase) : LdrGetImageSize(imageBase);
if (!mappedSize) return STATUS_FAILURE; if (!mappedSize) return STATUS_FAILURE;
@@ -387,9 +388,6 @@ KSTATUS LdrProtectImageForProcess(PROCESS* process, uintptr_t imageBase, bool us
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
KSTATUS LdrProtectImage(uintptr_t imageBase, bool user) {
return LdrProtectImageForProcess(user ? (PROCESS*)0 : (PROCESS*)0, imageBase, user);
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Entry point lookup // Entry point lookup
+248 -138
View File
@@ -1,13 +1,12 @@
// mm_phys.c - physical memory manager // mm_phys.c - physical memory manager
// //
// The free-frame stack is a flat array of PHYSICAL_ADDRESS values carved out of // Bitmap allocator over 4 KB physical frames. One bitmap records which PFNs
// the first suitable usable region before any allocation is served. All access // exist in usable RAM, and one bitmap records which usable PFNs are currently
// to physical memory goes through the direct physical window established by the // free. This keeps single-frame allocation simple while making contiguous
// bootloader at PhysicalWindowBase (always 0xFFFF880000000000). // allocation and memory visualization deterministic.
//
// Lock: a single spinlock guards Push/Pop. O(1) for both operations.
#include <kernel/mm_phys.h> #include <kernel/mm_phys.h>
#include <kernel/ke_spinlock.h> #include <kernel/ke_spinlock.h>
#include <string.h>
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Physical-to-virtual translation via the direct map window. // 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 { typedef struct {
PHYSICAL_ADDRESS* Stack; // pointer into physical window uint8_t* Usable; // bit = 1 when PFN belongs to usable RAM
size_t Top; // index of next free slot (stack grows up) uint8_t* Free; // bit = 1 when PFN is currently free
size_t Capacity; size_t BitmapBytes;
size_t Total; // total frames ever pushed size_t MaxPfn;
size_t TotalFrames; // usable frames available to the allocator
size_t FreeFrames;
SPINLOCK Lock; SPINLOCK Lock;
} FRAME_STACK; } FRAME_BITMAP;
static FRAME_STACK gFrameStack; static FRAME_BITMAP gFrameBitmap;
// Push a physical frame address onto the stack. static inline PHYSICAL_ADDRESS KiAlignUp(PHYSICAL_ADDRESS value) {
static void KiPushFrame(PHYSICAL_ADDRESS frame) { return (value + PAGE_SIZE - 1) & PAGE_MASK;
uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock); }
if (gFrameStack.Top < gFrameStack.Capacity) {
gFrameStack.Stack[gFrameStack.Top++] = frame; static inline PHYSICAL_ADDRESS KiAlignDown(PHYSICAL_ADDRESS value) {
gFrameStack.Total++; 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 // Initialisation
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
bool MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) { bool MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) {
if (!map) return false;
gPhysBase = physicalWindowBase; gPhysBase = physicalWindowBase;
// --- Phase 0: Count total usable frames so we can size the stack PHYSICAL_ADDRESS maxEnd = 0;
// 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);
for (uint32_t i = 0; i < map->RegionCount; i++) { for (uint32_t i = 0; i < map->RegionCount; i++) {
const MEMORY_REGION* r = &map->Regions[i]; const MEMORY_REGION* r = &map->Regions[i];
if (r->Type != MemoryUsable) continue; if (r->Type != MemoryUsable) continue;
PHYSICAL_ADDRESS base = r->Base; PHYSICAL_ADDRESS base = KiAlignUp(r->Base);
PHYSICAL_ADDRESS end = r->Base + r->Length; 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) { size_t maxPfn = (size_t)(maxEnd / PAGE_SIZE);
if (frame >= stackPhys && frame < stackEnd) continue; if (!maxPfn) return false;
KiPushFrame(frame);
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; return true;
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Public API // 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 MmAllocateFrameInRange(PHYSICAL_ADDRESS minInclusive,
PHYSICAL_ADDRESS maxExclusive) { PHYSICAL_ADDRESS maxExclusive) {
minInclusive = (minInclusive + PAGE_SIZE - 1) & PAGE_MASK; minInclusive = KiAlignUp(minInclusive);
maxExclusive &= PAGE_MASK; maxExclusive = KiAlignDown(maxExclusive);
if (maxExclusive <= minInclusive) return (PHYSICAL_ADDRESS)0;
if (maxExclusive <= minInclusive) size_t firstPfn = (size_t)(minInclusive / PAGE_SIZE);
return (PHYSICAL_ADDRESS)0; 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 for (size_t pfn = limitPfn; pfn > firstPfn; pfn--) {
// such as the AP trampoline this naturally prefers the traditional size_t candidate = pfn - 1;
// 0x70000-0x9f000 area and avoids consuming lower real-mode space first. if (KiPfnFreeLocked(candidate)) {
for (size_t i = gFrameStack.Top; i > 0; i--) { KiBitClear(gFrameBitmap.Free, candidate);
size_t idx = i - 1; if (gFrameBitmap.FreeFrames) gFrameBitmap.FreeFrames--;
PHYSICAL_ADDRESS frame = gFrameStack.Stack[idx]; KeReleaseSpinlock(&gFrameBitmap.Lock, flags);
if (frame >= minInclusive && frame < maxExclusive && return (PHYSICAL_ADDRESS)candidate * PAGE_SIZE;
!(frame & (PAGE_SIZE - 1))) {
frame = KiPopFrameAtIndexLocked(idx);
KeReleaseSpinlock(&gFrameStack.Lock, flags);
return frame;
} }
} }
KeReleaseSpinlock(&gFrameStack.Lock, flags); KeReleaseSpinlock(&gFrameBitmap.Lock, flags);
return (PHYSICAL_ADDRESS)0; return (PHYSICAL_ADDRESS)0;
} }
@@ -143,74 +218,109 @@ PHYSICAL_ADDRESS MmAllocateFrameBelow(PHYSICAL_ADDRESS maxExclusive) {
} }
__declspec(dllexport) PHYSICAL_ADDRESS MmAllocateFrame(void) { __declspec(dllexport) PHYSICAL_ADDRESS MmAllocateFrame(void) {
uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock); return MmAllocateFrameInRange(PAGE_SIZE, (PHYSICAL_ADDRESS)gFrameBitmap.MaxPfn * PAGE_SIZE);
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;
} }
void MmFreeFrame(PHYSICAL_ADDRESS frame) { void MmFreeFrame(PHYSICAL_ADDRESS frame) {
if (!frame || (frame & (PAGE_SIZE - 1))) return; if (!frame || (frame & (PAGE_SIZE - 1))) return;
uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock); size_t pfn = (size_t)(frame / PAGE_SIZE);
if (gFrameStack.Top < gFrameStack.Capacity)
gFrameStack.Stack[gFrameStack.Top++] = frame; uintptr_t flags = KeAcquireSpinlock(&gFrameBitmap.Lock);
// else: stack full - leak rather than corrupt if (KiPfnUsableLocked(pfn) && !KiBitTest(gFrameBitmap.Free, pfn)) {
KeReleaseSpinlock(&gFrameStack.Lock, flags); KiBitSet(gFrameBitmap.Free, pfn);
gFrameBitmap.FreeFrames++;
}
KeReleaseSpinlock(&gFrameBitmap.Lock, flags);
} }
__declspec(dllexport) PHYSICAL_ADDRESS MmAllocateContiguous(size_t count) { __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) { size_t runStart = 0;
KeReleaseSpinlock(&gFrameStack.Lock, flags); 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;
}
}
KeReleaseSpinlock(&gFrameBitmap.Lock, flags);
return (PHYSICAL_ADDRESS)0; 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;
}
}
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;
}
size_t MmFreeFrameCount(void) { 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) { 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;
}
+50 -7
View File
@@ -11,7 +11,8 @@
// //
// User heap: // User heap:
// A single best-fit free list in the lower half. // 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 <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <intrin.h> #include <intrin.h>
@@ -164,7 +165,7 @@ int MmHandleTlbShootdownNmi(void) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Public mapping // 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; unsigned userFlag = (flags & PAGE_USER) ? PAGE_USER : 0;
uintptr_t lockFlags = KeAcquireSpinlock(&gPageTableLock); 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)); uint64_t* pte = KiPtePtr(pt, PT_IDX(virt));
if ((*pte & PAGE_PRESENT) && mode == MmMapFailIfPresent) {
KeReleaseSpinlock(&gPageTableLock, lockFlags);
return STATUS_ALREADY_EXISTS;
}
*pte = phys | flags; *pte = phys | flags;
KeReleaseSpinlock(&gPageTableLock, lockFlags); KeReleaseSpinlock(&gPageTableLock, lockFlags);
@@ -525,7 +530,7 @@ static int KiHeapEnsureMapped(HEAP* h, uintptr_t start, size_t size) {
PHYSICAL_ADDRESS frame = MmAllocateFrame(); PHYSICAL_ADDRESS frame = MmAllocateFrame();
if (!frame) return 0; if (!frame) return 0;
KSTATUS ms = MmMapPage(va, frame, h->MapFlags); KSTATUS ms = MmMapPage(va, frame, h->MapFlags, MmMapFailIfPresent);
if (!KSUCCESS(ms)) { if (!KSUCCESS(ms)) {
MmFreeFrame(frame); MmFreeFrame(frame);
return 0; 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) { for (uintptr_t va = h->Brk; va < h->Brk + grow; va += PAGE_SIZE) {
PHYSICAL_ADDRESS frame = MmAllocateFrame(); PHYSICAL_ADDRESS frame = MmAllocateFrame();
if (!frame) return 0; if (!frame) return 0;
if (!KSUCCESS(MmMapPage(va, frame, h->MapFlags))) { if (!KSUCCESS(MmMapPage(va, frame, h->MapFlags, MmMapFailIfPresent))) {
MmFreeFrame(frame); MmFreeFrame(frame);
return 0; return 0;
} }
@@ -965,7 +970,7 @@ KSTATUS MmCreateUserRegion(PROCESS* process, size_t size, size_t alignment,
s = STATUS_NO_MEMORY; s = STATUS_NO_MEMORY;
break; break;
} }
s = MmMapPage(va, frame, pageFlags); s = MmMapPage(va, frame, pageFlags, MmMapFailIfPresent);
if (!KSUCCESS(s)) { if (!KSUCCESS(s)) {
MmFreeFrame(frame); MmFreeFrame(frame);
break; break;
@@ -1036,7 +1041,7 @@ KSTATUS MmEnsureUserRegionMapped(PROCESS* process, void* base, size_t size, uint
PHYSICAL_ADDRESS frame = MmAllocateFrame(); PHYSICAL_ADDRESS frame = MmAllocateFrame();
if (!frame) return STATUS_NO_MEMORY; if (!frame) return STATUS_NO_MEMORY;
KSTATUS ms = MmMapPage(va, frame, flags); KSTATUS ms = MmMapPage(va, frame, flags, MmMapFailIfPresent);
if (!KSUCCESS(ms)) { if (!KSUCCESS(ms)) {
MmFreeFrame(frame); MmFreeFrame(frame);
return ms; return ms;
@@ -1073,6 +1078,16 @@ KSTATUS MmProtectUserRegion(PROCESS* process, void* base, size_t size, uint64_t
return STATUS_NOT_FOUND; 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; uint64_t finalFlags = pageFlags | PAGE_PRESENT | PAGE_USER;
for (uintptr_t va = alignedStart; va < alignedEnd; va += PAGE_SIZE) { 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)) { if (!KSUCCESS(qs) || !(existingFlags & PAGE_PRESENT)) {
PHYSICAL_ADDRESS frame = MmAllocateFrame(); PHYSICAL_ADDRESS frame = MmAllocateFrame();
if (!frame) return STATUS_NO_MEMORY; 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)) { if (!KSUCCESS(ms)) {
MmFreeFrame(frame); MmFreeFrame(frame);
return ms; 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) { size_t MmGetUserRegionSize(PROCESS* process, const void* base) {
if (!process || !base) return 0; if (!process || !base) return 0;
uintptr_t procFlags = KeAcquireSpinlock(&process->UserRegionLock); uintptr_t procFlags = KeAcquireSpinlock(&process->UserRegionLock);
+81 -4
View File
@@ -13,6 +13,8 @@
#define SYS_STATUS_TIMEOUT 3u #define SYS_STATUS_TIMEOUT 3u
#define SYS_STATUS_PENDING 4u #define SYS_STATUS_PENDING 4u
#define SYS_STATUS_ALERTED 5u #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_KERNEL_APC 6u
#define SYS_STATUS_USER_APC 7u #define SYS_STATUS_USER_APC 7u
#define SYS_STATUS_CANCELLED 0x33u #define SYS_STATUS_CANCELLED 0x33u
@@ -205,11 +207,33 @@ uint32_t SysSetUserApcDispatcher(void* dispatcher);
uint32_t SysApcReturn(const SYS_USER_APC_FRAME* frame); uint32_t SysApcReturn(const SYS_USER_APC_FRAME* frame);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Memory and handles // Virtual memory and handles
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
void* SysAlloc(size_t size); typedef enum SYS_VM_PROTECTION {
uint32_t SysFree(void* ptr); SYS_VM_NOACCESS = 0,
void* SysRealloc(void* ptr, size_t newSize); 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); uint32_t SysCloseHandle(uint32_t handle);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -382,6 +406,58 @@ typedef struct SYS_MEMORY_STATUS {
uint64_t UserHeapBytes; uint64_t UserHeapBytes;
} SYS_MEMORY_STATUS; } 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 // 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 SysQueryTrapFrame(SYS_TRAP_FRAME_INFO* info);
uint32_t SysGetMemoryStatus(SYS_MEMORY_STATUS* statusOut); uint32_t SysGetMemoryStatus(SYS_MEMORY_STATUS* statusOut);
uint32_t SysQueryKernelStats(uint32_t classId, void* buffer, size_t bufferSize, size_t* requiredSizeOut);
+5 -4
View File
@@ -4,6 +4,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <intrin.h> #include <intrin.h>
@@ -28,7 +29,7 @@ static void doom_print_wrapper(const char* msg)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
static void* doom_malloc_wrapper(int size) static void* doom_malloc_wrapper(int size)
{ {
void* p = SysAlloc(size); void* p = malloc(size);
if (!p) SysExitProcess(1); if (!p) SysExitProcess(1);
return p; return p;
} }
@@ -37,7 +38,7 @@ static void doom_free_wrapper(void* ptr)
{ {
if (!ptr) return; 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; 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) { if (!f) {
SysCloseHandle(handle); SysCloseHandle(handle);
return 0; return 0;
@@ -79,7 +80,7 @@ static void doom_close_wrapper(void* handle)
if (!handle) return; if (!handle) return;
DOOM_FILE_HANDLE* f = (DOOM_FILE_HANDLE*)handle; DOOM_FILE_HANDLE* f = (DOOM_FILE_HANDLE*)handle;
SysCloseHandle(f->Handle); SysCloseHandle(f->Handle);
SysFree(f); free(f);
} }
static int doom_read_wrapper(void* handle, void* buf, int count) static int doom_read_wrapper(void* handle, void* buf, int count)
+75 -18
View File
@@ -18,6 +18,8 @@
#define MAX_LINE 256 #define MAX_LINE 256
#define PATH_MAX2 260 #define PATH_MAX2 260
#define MSG_MAX 160 #define MSG_MAX 160
#define MAX_SCREEN_COLS 256
#define MAX_SCREEN_ROWS 128
#define COL_BG 0x000000u #define COL_BG 0x000000u
#define COL_FG 0xC8C8C8u #define COL_FG 0xC8C8C8u
@@ -61,8 +63,55 @@ static bool gQuitArmed = false;
static char gFilename[PATH_MAX2] = "untitled.txt"; static char gFilename[PATH_MAX2] = "untitled.txt";
static char gMessage[MSG_MAX] = "ready"; 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) { 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) { static void clear_row(int row, uint32_t bg) {
@@ -151,13 +200,7 @@ static void ensure_visible(void) {
} }
static void render(void) { static void render(void) {
int pxW = 0, pxH = 0; update_screen_size();
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;
}
clamp_cursor(); clamp_cursor();
ensure_visible(); ensure_visible();
@@ -172,28 +215,40 @@ static void render(void) {
append_str(status, sizeof(status), &p, ", Col "); append_str(status, sizeof(status), &p, ", Col ");
append_u32(status, sizeof(status), &p, (uint32_t)(gCx + 1)); append_u32(status, sizeof(status), &p, (uint32_t)(gCx + 1));
clear_row(0, COL_STATUS); size_t statusLen = p;
draw_text(0, 0, status, COL_STATUSF, COL_STATUS); 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; int textRows = gRows - 2;
for (int sy = 0; sy < textRows; sy++) { for (int sy = 0; sy < textRows; sy++) {
int row = sy + 1; int row = sy + 1;
int li = gTop + sy; int li = gTop + sy;
clear_row(row, COL_BG);
if (li >= gLineCount) continue;
LINE* ln = &gLines[li];
for (int sx = 0; sx < gCols; sx++) { for (int sx = 0; sx < gCols; sx++) {
int ci = gLeft + sx; int ci = gLeft + sx;
char c = (ci < ln->len) ? ln->text[ci] : ' '; char c = ' ';
bool atCursor = (li == gCy && ci == gCx); 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, put_cell(sx, row, c, atCursor ? COL_CURSORF : COL_FG,
atCursor ? COL_CURSOR : COL_BG); atCursor ? COL_CURSOR : COL_BG);
} }
} }
clear_row(gRows - 1, COL_STATUS); size_t messageLen = strlen(gMessage);
draw_text(0, gRows - 1, gMessage, COL_STATUSF, COL_STATUS); 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) { static void insert_char_at_cursor(char c) {
@@ -481,8 +536,10 @@ int main(void) {
parse_filename_from_cmdline(); parse_filename_from_cmdline();
load_file(); load_file();
SysScreenClear(COL_BG); SysScreenClear(COL_BG);
invalidate_screen_cache();
editor_loop(); editor_loop();
SysScreenClear(COL_BG); SysScreenClear(0x012456);
invalidate_screen_cache();
print("edit: goodbye\n"); print("edit: goodbye\n");
SysExitProcess(0); SysExitProcess(0);
return 0; return 0;
+93 -1
View File
@@ -95,6 +95,7 @@ static void cmd_help() {
print("Available commands:\n" print("Available commands:\n"
" help - Show this list\n" " help - Show this list\n"
" mem - Show memory usage\n" " mem - Show memory usage\n"
" stats - Show scheduler/CPU/PMM telemetry\n"
" ps - List running process IDs\n" " ps - List running process IDs\n"
" dir [path] - List directory contents\n" " dir [path] - List directory contents\n"
" cd <path> - Change directory\n" " cd <path> - Change directory\n"
@@ -110,6 +111,96 @@ static void printSizeKiB(uint64_t bytes) {
print(" KiB"); 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) { static void cmd_mem(void) {
SYS_MEMORY_STATUS st; SYS_MEMORY_STATUS st;
if (SysGetMemoryStatus(&st) != 0) { if (SysGetMemoryStatus(&st) != 0) {
@@ -240,7 +331,7 @@ static int runCommand(const char* cmd) {
if (!cmd || *cmd == '\0') return 0; if (!cmd || *cmd == '\0') return 0;
if (strcmp(cmd, "exit") == 0) return 1; if (strcmp(cmd, "exit") == 0) return 1;
if (strcmp(cmd, "help") == 0) { cmd_help(); return 0; } 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) { if (strncmp(cmd, "crash", 5) == 0) {
// Check the sub-option trailing "crash " (offset 6) // Check the sub-option trailing "crash " (offset 6)
if (strcmp(cmd + 6, "void") == 0) { 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, "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, "ps") == 0) { cmd_ps(); return 0; }
if (strcmp(cmd, "dir") == 0) { cmd_dir("."); return 0; } if (strcmp(cmd, "dir") == 0) { cmd_dir("."); return 0; }
if (strncmp(cmd, "dir ", 4) == 0) { cmd_dir(cmd + 4); return 0; } if (strncmp(cmd, "dir ", 4) == 0) { cmd_dir(cmd + 4); return 0; }
+4 -3
View File
@@ -1,6 +1,7 @@
// posix_dir.c - chdir, getcwd, opendir, readdir, closedir // posix_dir.c - chdir, getcwd, opendir, readdir, closedir
#include <string.h> #include <string.h>
#include <ntlite/syscall.h> #include <ntlite/syscall.h>
#include <stdlib.h>
#include "posix.h" #include "posix.h"
#include "posix_path.h" #include "posix_path.h"
@@ -38,8 +39,8 @@ __declspec(dllexport) DIR* opendir(const char* path) {
uint32_t s = SysOpenDir(&req); uint32_t s = SysOpenDir(&req);
if (s != 0) { errno = ENOENT; return (DIR*)0; } if (s != 0) { errno = ENOENT; return (DIR*)0; }
// Allocate DIR on the kernel heap (SysAlloc) so it outlives the stack. // Allocate DIR on the kernel heap (malloc) so it outlives the stack.
DIR* d = (DIR*)SysAlloc(sizeof(DIR)); DIR* d = (DIR*)malloc(sizeof(DIR));
if (!d) { SysCloseHandle(kh); errno = ENOMEM; return (DIR*)0; } if (!d) { SysCloseHandle(kh); errno = ENOMEM; return (DIR*)0; }
d->KHandle = kh; d->KHandle = kh;
d->Valid = false; d->Valid = false;
@@ -64,6 +65,6 @@ __declspec(dllexport) struct dirent* readdir(DIR* d) {
__declspec(dllexport) int closedir(DIR* d) { __declspec(dllexport) int closedir(DIR* d) {
if (!d) { errno = EBADF; return -1; } if (!d) { errno = EBADF; return -1; }
SysCloseHandle(d->KHandle); SysCloseHandle(d->KHandle);
SysFree(d); free(d);
return 0; return 0;
} }
+1 -1
View File
@@ -7,7 +7,7 @@
#include "posix_path.h" #include "posix_path.h"
__declspec(dllexport) void clearscreen(void) { __declspec(dllexport) void clearscreen(void) {
SysScreenClear(0x00000000); SysScreenClear(0x012456);
} }
__declspec(dllexport) void clearkeyboard(void) { __declspec(dllexport) void clearkeyboard(void) {
+6 -5
View File
@@ -1,5 +1,6 @@
// posix_socket.c - POSIX-ish socket wrappers over native Sys* sockets. // posix_socket.c - POSIX-ish socket wrappers over native Sys* sockets.
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <ntlite/syscall.h> #include <ntlite/syscall.h>
@@ -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) { __declspec(dllexport) int poll(struct pollfd* fds, nfds_t nfds, int timeout) {
if (!fds || nfds == 0 || nfds > 64) { errno = EINVAL; return -1; } 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; } if (!kfds) { errno = ENOMEM; return -1; }
for (nfds_t i = 0; i < nfds; i++) { 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 timeoutMs = timeout < 0 ? SYS_POLL_TIMEOUT_INFINITE : (uint32_t)timeout;
uint32_t s = SysPoll(kfds, nfds, timeoutMs, &ready); uint32_t s = SysPoll(kfds, nfds, timeoutMs, &ready);
if (s != 0) { if (s != 0) {
SysFree(kfds); free(kfds);
errno = PosixStatusToErrno(s); errno = PosixStatusToErrno(s);
return -1; return -1;
} }
@@ -365,7 +366,7 @@ __declspec(dllexport) int poll(struct pollfd* fds, nfds_t nfds, int timeout) {
if (re) out++; if (re) out++;
} }
SysFree(kfds); free(kfds);
return out; return out;
} }
@@ -446,7 +447,7 @@ __declspec(dllexport) int getaddrinfo(const char* node, const char* service,
a.Port = service ? ParsePort(service) : 0; a.Port = service ? ParsePort(service) : 0;
size_t total = sizeof(struct addrinfo) + sizeof(struct sockaddr_in); 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; if (!ai) return ENOMEM;
memset(ai, 0, total); 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) { __declspec(dllexport) void freeaddrinfo(struct addrinfo* res) {
if (res) SysFree(res); if (res) free(res);
} }
+4 -3
View File
@@ -1,5 +1,6 @@
// posix_thread.c - pthread_create, pthread_join, pthread_exit, pthread_mutex_* // posix_thread.c - pthread_create, pthread_join, pthread_exit, pthread_mutex_*
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
#include <ntlite/syscall.h> #include <ntlite/syscall.h>
#include "posix.h" #include "posix.h"
@@ -56,7 +57,7 @@ static void PthreadTrampoline(uintptr_t raw) {
PTHREAD_SLOT* slot = PthreadSlotFind(pid, tid); PTHREAD_SLOT* slot = PthreadSlotFind(pid, tid);
if (!slot) slot = PthreadSlotAlloc(pid, tid); if (!slot) slot = PthreadSlotAlloc(pid, tid);
SysFree(tr); free(tr);
void* retval = fn(arg); 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(); 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; if (!tr) return ENOMEM;
tr->Fn = fn; tr->Fn = fn;
tr->Arg = arg; 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, uint32_t s = SysCreateThread((uint64_t)PthreadTrampoline,
(uint64_t)tr, 1 /*PriorityNormal*/, &tid); (uint64_t)tr, 1 /*PriorityNormal*/, &tid);
if (s != 0) { if (s != 0) {
SysFree(tr); free(tr);
return EAGAIN; return EAGAIN;
} }
// The trampoline allocates the retval slot itself after it knows its real // The trampoline allocates the retval slot itself after it knows its real
+5 -4
View File
@@ -1,6 +1,7 @@
// gdi32.c // gdi32.c
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
#include <ntlite/syscall.h> #include <ntlite/syscall.h>
#if defined(__SSE2__) || defined(_M_X64) || defined(_M_IX86) #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 // Only reallocate if the new size is LARGER than what we already have
int requiredPixels = DestWidth * DestHeight; int requiredPixels = DestWidth * DestHeight;
if (requiredPixels > currentDestCapacity) { if (requiredPixels > currentDestCapacity) {
SysFree(destBuffer); free(destBuffer);
destBuffer = (uint32_t*)SysAlloc(requiredPixels * sizeof(uint32_t)); destBuffer = (uint32_t*)malloc(requiredPixels * sizeof(uint32_t));
currentDestCapacity = requiredPixels; currentDestCapacity = requiredPixels;
} }
if (DestWidth > currentXMapCapacity) { if (DestWidth > currentXMapCapacity) {
SysFree(srcX_map); free(srcX_map);
srcX_map = (int*)SysAlloc(DestWidth * sizeof(int)); srcX_map = (int*)malloc(DestWidth * sizeof(int));
currentXMapCapacity = DestWidth; currentXMapCapacity = DestWidth;
} }
+70 -23
View File
@@ -9,7 +9,7 @@
// HANDLE_TO_KH / KH_TO_HANDLE do that conversion in one place. // HANDLE_TO_KH / KH_TO_HANDLE do that conversion in one place.
// - INVALID_HANDLE_VALUE maps to kernel handle 0 (the always-invalid slot). // - INVALID_HANDLE_VALUE maps to kernel handle 0 (the always-invalid slot).
// - HeapAlloc / HeapFree / HeapReAlloc ignore the HANDLE heap argument and // - 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. // 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 // - Win32 per-thread state lives behind SYS_TEB::SubsystemData so the native
// TEB ABI stays subsystem-neutral. // TEB ABI stays subsystem-neutral.
@@ -21,6 +21,7 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <intrin.h> #include <intrin.h>
@@ -66,6 +67,31 @@ typedef struct _MEMORY_BASIC_INFORMATION {
DWORD Type; DWORD Type;
} MEMORY_BASIC_INFORMATION; } 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 // File-find structures
typedef struct _FILETIME { typedef struct _FILETIME {
DWORD dwLowDateTime; DWORD dwLowDateTime;
@@ -228,7 +254,7 @@ static WIN32_THREAD_ENV* K32ThreadEnv(void) {
WIN32_THREAD_ENV* env = (WIN32_THREAD_ENV*)teb->SubsystemData; WIN32_THREAD_ENV* env = (WIN32_THREAD_ENV*)teb->SubsystemData;
if (!env) { if (!env) {
env = (WIN32_THREAD_ENV*)SysAlloc(sizeof(WIN32_THREAD_ENV)); env = (WIN32_THREAD_ENV*)malloc(sizeof(WIN32_THREAD_ENV));
if (!env) return &gFallbackThreadEnv; if (!env) return &gFallbackThreadEnv;
memset(env, 0, sizeof(*env)); memset(env, 0, sizeof(*env));
teb->SubsystemData = 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) { __declspec(dllexport) void* HeapAlloc(void* heap, DWORD flags, size_t size) {
(void)heap; (void)heap; (void)flags;
if (!size) return NULL; if (!size) return NULL;
void* ptr = SysAlloc(size); void* ptr = malloc(size);
if (!ptr) gLastError = 8; // ERROR_NOT_ENOUGH_MEMORY if (!ptr) gLastError = 8; // ERROR_NOT_ENOUGH_MEMORY
return ptr; return ptr;
} }
__declspec(dllexport) BOOL HeapFree(void* heap, DWORD flags, void* ptr) { __declspec(dllexport) BOOL HeapFree(void* heap, DWORD flags, void* ptr) {
(void)heap; (void)flags; (void)heap; (void)flags;
// Win32's HeapFree doesn't need the size; we pass 0 and the kernel's // Win32's HeapFree doesn't need the size; we pass 0 and the user-mode heap carries the block size.
// allocator handles it (the block header carries the size). if (ptr) free(ptr);
if (ptr) SysFree(ptr);
return TRUE; return TRUE;
} }
__declspec(dllexport) void* HeapReAlloc(void* heap, DWORD flags, __declspec(dllexport) void* HeapReAlloc(void* heap, DWORD flags,
void* ptr, size_t size) { void* ptr, size_t size) {
(void)heap; (void)flags; (void)heap; (void)flags;
void* newptr = SysRealloc(ptr, size); void* newptr = realloc(ptr, size);
if (!newptr && size) gLastError = 8; if (!newptr && size) gLastError = 8;
return newptr; return newptr;
} }
@@ -400,23 +425,37 @@ __declspec(dllexport) void* GetProcessHeap(void) {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
__declspec(dllexport) void* VirtualAlloc(void* lpAddress, size_t dwSize, __declspec(dllexport) void* VirtualAlloc(void* lpAddress, size_t dwSize,
DWORD flAllocationType, DWORD flProtect) { DWORD flAllocationType, DWORD flProtect) {
(void)lpAddress; (void)flAllocationType; (void)flProtect; (void)flAllocationType;
if (!dwSize) return NULL; if (!dwSize) return NULL;
void* ptr = SysAlloc(dwSize);
if (!ptr) gLastError = 8; // ERROR_NOT_ENOUGH_MEMORY size_t pages = (dwSize + 4095u) / 4096u;
return ptr; 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) { __declspec(dllexport) BOOL VirtualFree(void* lpAddress, size_t dwSize, DWORD dwFreeType) {
(void)dwSize; (void)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; return TRUE;
} }
__declspec(dllexport) BOOL VirtualProtect(void* lpAddress, size_t dwSize, __declspec(dllexport) BOOL VirtualProtect(void* lpAddress, size_t dwSize,
DWORD flNewProtect, DWORD* lpflOldProtect) { DWORD flNewProtect, DWORD* lpflOldProtect) {
(void)lpAddress; (void)dwSize; (void)flNewProtect; if (!lpAddress || !dwSize) { gLastError = 87; return FALSE; }
if (lpflOldProtect) *lpflOldProtect = PAGE_EXECUTE_READWRITE; 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; return TRUE;
} }
@@ -427,13 +466,21 @@ __declspec(dllexport) size_t VirtualQuery(const void* lpAddress,
gLastError = 87; // ERROR_INVALID_PARAMETER gLastError = 87; // ERROR_INVALID_PARAMETER
return 0; return 0;
} }
uintptr_t base = (uintptr_t)lpAddress & ~(uintptr_t)0xFFF;
lpBuffer->BaseAddress = (void*)base; SYS_VM_REGION_INFO info;
lpBuffer->AllocationBase = (void*)base; uint32_t s = SysVmQuery((void*)lpAddress, &info);
lpBuffer->AllocationProtect = PAGE_EXECUTE_READWRITE; if (s != SYS_STATUS_SUCCESS) {
lpBuffer->RegionSize = 0x1000; 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->State = MEM_COMMIT;
lpBuffer->Protect = PAGE_EXECUTE_READWRITE; lpBuffer->Protect = protect;
lpBuffer->Type = MEM_PRIVATE; lpBuffer->Type = MEM_PRIVATE;
return sizeof(MEMORY_BASIC_INFORMATION); return sizeof(MEMORY_BASIC_INFORMATION);
} }
@@ -512,7 +559,7 @@ __declspec(dllexport) BOOL FlushConsoleInputBuffer(HANDLE hConsoleInput) {
// !Made-up! clear console api. // !Made-up! clear console api.
__declspec(dllexport) BOOL ClearConsoleScreenBuffer(HANDLE hConsole) { __declspec(dllexport) BOOL ClearConsoleScreenBuffer(HANDLE hConsole) {
SysScreenClear(0x00000000); SysScreenClear(0x012456);
return TRUE; return TRUE;
} }
+2 -1
View File
@@ -2,6 +2,7 @@
// No COM infrastructure at this stage; all functions fail gracefully. // No COM infrastructure at this stage; all functions fail gracefully.
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
#include <ntlite/syscall.h> #include <ntlite/syscall.h>
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -65,7 +66,7 @@ __declspec(dllexport) HRESULT CoCreateInstance(const GUID* clsid, IUnknown* oute
// Memory // Memory
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
__declspec(dllexport) void CoTaskMemFree(void* pv) { __declspec(dllexport) void CoTaskMemFree(void* pv) {
if (pv) SysFree(pv); if (pv) free(pv);
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
+226
View File
@@ -0,0 +1,226 @@
// heap.c - user-mode page-backed heap
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <intrin.h>
#include <ntlite/syscall.h>
#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;
}
+34
View File
@@ -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);
}
+76 -74
View File
@@ -17,78 +17,80 @@ SYS_YIELD EQU 13
SYS_SLEEP EQU 14 SYS_SLEEP EQU 14
SYS_SET_USER_APC_DISPATCHER EQU 15 SYS_SET_USER_APC_DISPATCHER EQU 15
SYS_APC_RETURN EQU 16 SYS_APC_RETURN EQU 16
SYS_ALLOC EQU 17 SYS_VM_ALLOC EQU 17
SYS_FREE EQU 18 SYS_VM_FREE EQU 18
SYS_REALLOC EQU 19 SYS_VM_PROTECT EQU 19
SYS_CLOSE_HANDLE EQU 20 SYS_VM_QUERY EQU 20
SYS_MUTEX_CREATE EQU 21 SYS_CLOSE_HANDLE EQU 21
SYS_MUTEX_ACQUIRE EQU 22 SYS_MUTEX_CREATE EQU 22
SYS_MUTEX_TRY_ACQUIRE EQU 23 SYS_MUTEX_ACQUIRE EQU 23
SYS_MUTEX_RELEASE EQU 24 SYS_MUTEX_TRY_ACQUIRE EQU 24
SYS_SEM_CREATE EQU 25 SYS_MUTEX_RELEASE EQU 25
SYS_SEM_WAIT EQU 26 SYS_SEM_CREATE EQU 26
SYS_SEM_TRY_WAIT EQU 27 SYS_SEM_WAIT EQU 27
SYS_SEM_SIGNAL EQU 28 SYS_SEM_TRY_WAIT EQU 28
SYS_EVENT_CREATE EQU 29 SYS_SEM_SIGNAL EQU 29
SYS_EVENT_SIGNAL EQU 30 SYS_EVENT_CREATE EQU 30
SYS_EVENT_CLEAR EQU 31 SYS_EVENT_SIGNAL EQU 31
SYS_EVENT_WAIT EQU 32 SYS_EVENT_CLEAR EQU 32
SYS_QUEUE_CREATE EQU 33 SYS_EVENT_WAIT EQU 33
SYS_QUEUE_SEND EQU 34 SYS_QUEUE_CREATE EQU 34
SYS_QUEUE_RECV EQU 35 SYS_QUEUE_SEND EQU 35
SYS_PUBLISH_QUEUE EQU 36 SYS_QUEUE_RECV EQU 36
SYS_OPEN_NAMED_QUEUE EQU 37 SYS_PUBLISH_QUEUE EQU 37
SYS_QUEUE_DUPLICATE EQU 38 SYS_OPEN_NAMED_QUEUE EQU 38
SYS_NAMED_QUEUE_OWNER_PID EQU 39 SYS_QUEUE_DUPLICATE EQU 39
SYS_OPEN_FILE EQU 40 SYS_NAMED_QUEUE_OWNER_PID EQU 40
SYS_CREATE_FILE EQU 41 SYS_OPEN_FILE EQU 41
SYS_READ_FILE EQU 42 SYS_CREATE_FILE EQU 42
SYS_WRITE_FILE EQU 43 SYS_READ_FILE EQU 43
SYS_READ_FILE_ASYNC EQU 44 SYS_WRITE_FILE EQU 44
SYS_WRITE_FILE_ASYNC EQU 45 SYS_READ_FILE_ASYNC EQU 45
SYS_CANCEL_IO EQU 46 SYS_WRITE_FILE_ASYNC EQU 46
SYS_SEEK_FILE EQU 47 SYS_CANCEL_IO EQU 47
SYS_GET_FILE_POS EQU 48 SYS_SEEK_FILE EQU 48
SYS_GET_FILE_SIZE EQU 49 SYS_GET_FILE_POS EQU 49
SYS_TRUNCATE_FILE EQU 50 SYS_GET_FILE_SIZE EQU 50
SYS_DELETE_FILE EQU 51 SYS_TRUNCATE_FILE EQU 51
SYS_RENAME_FILE EQU 52 SYS_DELETE_FILE EQU 52
SYS_OPEN_DIR EQU 53 SYS_RENAME_FILE EQU 53
SYS_READ_DIR EQU 54 SYS_OPEN_DIR EQU 54
SYS_CREATE_DIR EQU 55 SYS_READ_DIR EQU 55
SYS_REMOVE_DIR EQU 56 SYS_CREATE_DIR EQU 56
SYS_SET_CWD EQU 57 SYS_REMOVE_DIR EQU 57
SYS_GET_CWD EQU 58 SYS_SET_CWD EQU 58
SYS_WRITE_CONSOLE EQU 59 SYS_GET_CWD EQU 59
SYS_SCREEN_BLIT EQU 60 SYS_WRITE_CONSOLE EQU 60
SYS_SCREEN_CLEAR EQU 61 SYS_SCREEN_BLIT EQU 61
SYS_SCREEN_GET_SIZE EQU 62 SYS_SCREEN_CLEAR EQU 62
SYS_SCREEN_PUT_CHAR EQU 63 SYS_SCREEN_GET_SIZE EQU 63
SYS_KB_POLL EQU 64 SYS_SCREEN_PUT_CHAR EQU 64
SYS_KB_IS_KEY_DOWN EQU 65 SYS_KB_POLL EQU 65
SYS_KB_READ_CHAR EQU 66 SYS_KB_IS_KEY_DOWN EQU 66
SYS_KB_READ_KEY EQU 67 SYS_KB_READ_CHAR EQU 67
SYS_KB_GET_MODIFIERS EQU 68 SYS_KB_READ_KEY EQU 68
SYS_MOUSE_POLL EQU 69 SYS_KB_GET_MODIFIERS EQU 69
SYS_MOUSE_READ EQU 70 SYS_MOUSE_POLL EQU 70
SYS_MOUSE_GET_POS EQU 71 SYS_MOUSE_READ EQU 71
SYS_GET_TICK EQU 72 SYS_MOUSE_GET_POS EQU 72
SYS_DEBUG_PRINT EQU 73 SYS_GET_TICK EQU 73
SYS_QUERY_TRAP_FRAME EQU 74 SYS_DEBUG_PRINT EQU 74
SYS_SOCKET EQU 75 SYS_QUERY_TRAP_FRAME EQU 75
SYS_BIND EQU 76 SYS_SOCKET EQU 76
SYS_LISTEN EQU 77 SYS_BIND EQU 77
SYS_ACCEPT EQU 78 SYS_LISTEN EQU 78
SYS_CONNECT EQU 79 SYS_ACCEPT EQU 79
SYS_SEND EQU 80 SYS_CONNECT EQU 80
SYS_RECV EQU 81 SYS_SEND EQU 81
SYS_SHUTDOWN EQU 82 SYS_RECV EQU 82
SYS_SEND_TO EQU 83 SYS_SHUTDOWN EQU 83
SYS_RECV_FROM EQU 84 SYS_SEND_TO EQU 84
SYS_RESOLVE_HOST EQU 85 SYS_RECV_FROM EQU 85
SYS_SET_SOCKET_OPTION EQU 86 SYS_RESOLVE_HOST EQU 86
SYS_GET_SOCKET_OPTION EQU 87 SYS_SET_SOCKET_OPTION EQU 87
SYS_POLL EQU 88 SYS_GET_SOCKET_OPTION EQU 88
SYS_GET_MEMORY_STATUS EQU 89 SYS_POLL EQU 89
SYS_GET_MEMORY_STATUS EQU 90
SYS_QUERY_KERNEL_STATS EQU 91
SYS_MAX EQU 90 SYS_MAX EQU 92
+6 -4
View File
@@ -108,11 +108,12 @@ SysUserApcDispatcher_Failed:
SysUserApcDispatcher ENDP SysUserApcDispatcher ENDP
; --------------------------------------------------------------------------- ; ---------------------------------------------------------------------------
; Memory and handles ; Virtual memory and handles
; --------------------------------------------------------------------------- ; ---------------------------------------------------------------------------
SYSCALL_STUB2 Alloc, SYS_ALLOC SYSCALL_STUB6 VmAlloc, SYS_VM_ALLOC
SYSCALL_STUB2 Free, SYS_FREE SYSCALL_STUB2 VmFree, SYS_VM_FREE
SYSCALL_STUB2 Realloc, SYS_REALLOC SYSCALL_STUB2 VmProtect, SYS_VM_PROTECT
SYSCALL_STUB2 VmQuery, SYS_VM_QUERY
SYSCALL_STUB2 CloseHandle, SYS_CLOSE_HANDLE SYSCALL_STUB2 CloseHandle, SYS_CLOSE_HANDLE
; --------------------------------------------------------------------------- ; ---------------------------------------------------------------------------
@@ -216,5 +217,6 @@ SYSCALL_STUB2 GetSocketOption, SYS_GET_SOCKET_OPTION
SYSCALL_STUB2 Poll, SYS_POLL SYSCALL_STUB2 Poll, SYS_POLL
SYSCALL_STUB2 GetMemoryStatus, SYS_GET_MEMORY_STATUS SYSCALL_STUB2 GetMemoryStatus, SYS_GET_MEMORY_STATUS
SYSCALL_STUB2 QueryKernelStats, SYS_QUERY_KERNEL_STATS
END END
+3 -2
View File
@@ -1,5 +1,6 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <intrin.h> #include <intrin.h>
#include <ntlite/syscall.h> #include <ntlite/syscall.h>
@@ -82,7 +83,7 @@ int main(void) {
SysExitProcess(1); SysExitProcess(1);
} }
uint8_t* buffer = (uint8_t*)SysAlloc(512); uint8_t* buffer = (uint8_t*)malloc(512);
if (!buffer) { if (!buffer) {
print("async_apc: allocation failed\n"); print("async_apc: allocation failed\n");
SysExitProcess(1); SysExitProcess(1);
@@ -141,7 +142,7 @@ int main(void) {
SysCloseHandle(event); SysCloseHandle(event);
SysCloseHandle(file); SysCloseHandle(file);
SysFree(buffer); free(buffer);
if (!ok) { if (!ok) {
print("async_apc: FAIL\n"); print("async_apc: FAIL\n");
+3 -2
View File
@@ -1,5 +1,6 @@
#include <stdint.h> #include <stdint.h>
#include <stddef.h> #include <stddef.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <ntlite/syscall.h> #include <ntlite/syscall.h>
@@ -51,7 +52,7 @@ int main(void) {
SysExitProcess(1); SysExitProcess(1);
} }
uint8_t* buffer = (uint8_t*)SysAlloc(512); uint8_t* buffer = (uint8_t*)malloc(512);
if (!buffer) { if (!buffer) {
print("async_cancel: alloc failed\n"); print("async_cancel: alloc failed\n");
SysExitProcess(1); SysExitProcess(1);
@@ -101,7 +102,7 @@ int main(void) {
SysCloseHandle(request); SysCloseHandle(request);
SysCloseHandle(event); SysCloseHandle(event);
SysCloseHandle(file); SysCloseHandle(file);
SysFree(buffer); free(buffer);
if (!ok) { if (!ok) {
print("async_cancel: FAIL\n"); print("async_cancel: FAIL\n");
+1 -1
View File
@@ -291,7 +291,7 @@ Q: Does it run Doom?
A: `doom.exe` A: `doom.exe`
Q: Does USB work? 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? Q: If I write a program now, will it run in the future?
A: Not a chance. WE DO - in fact - BREAK USERSPACE. A: Not a chance. WE DO - in fact - BREAK USERSPACE.