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
+2091 -760

No files matched your search

+5 -4
View File
@@ -4,6 +4,7 @@
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <intrin.h>
@@ -28,7 +29,7 @@ static void doom_print_wrapper(const char* msg)
// ---------------------------------------------------------------------------
static void* doom_malloc_wrapper(int size)
{
void* p = SysAlloc(size);
void* p = malloc(size);
if (!p) SysExitProcess(1);
return p;
}
@@ -37,7 +38,7 @@ static void doom_free_wrapper(void* ptr)
{
if (!ptr) return;
SysFree(ptr);
free(ptr);
}
// ---------------------------------------------------------------------------
@@ -62,7 +63,7 @@ static void* doom_open_wrapper(const char* path, const char* mode)
}
if (result != 0) return 0;
DOOM_FILE_HANDLE* f = (DOOM_FILE_HANDLE*)SysAlloc(sizeof(DOOM_FILE_HANDLE));
DOOM_FILE_HANDLE* f = (DOOM_FILE_HANDLE*)malloc(sizeof(DOOM_FILE_HANDLE));
if (!f) {
SysCloseHandle(handle);
return 0;
@@ -79,7 +80,7 @@ static void doom_close_wrapper(void* handle)
if (!handle) return;
DOOM_FILE_HANDLE* f = (DOOM_FILE_HANDLE*)handle;
SysCloseHandle(f->Handle);
SysFree(f);
free(f);
}
static int doom_read_wrapper(void* handle, void* buf, int count)
+75 -18
View File
@@ -18,6 +18,8 @@
#define MAX_LINE 256
#define PATH_MAX2 260
#define MSG_MAX 160
#define MAX_SCREEN_COLS 256
#define MAX_SCREEN_ROWS 128
#define COL_BG 0x000000u
#define COL_FG 0xC8C8C8u
@@ -61,8 +63,55 @@ static bool gQuitArmed = false;
static char gFilename[PATH_MAX2] = "untitled.txt";
static char gMessage[MSG_MAX] = "ready";
typedef struct SCREEN_CELL {
char c;
uint32_t fg;
uint32_t bg;
} SCREEN_CELL;
static SCREEN_CELL gScreenCache[MAX_SCREEN_COLS * MAX_SCREEN_ROWS];
static bool gScreenCacheValid = false;
static void invalidate_screen_cache(void) {
gScreenCacheValid = false;
}
static void update_screen_size(void) {
int pxW = 0, pxH = 0;
int oldCols = gCols;
int oldRows = gRows;
if (SysScreenGetSize(&pxW, &pxH) == 0 && pxW > 0 && pxH > 0) {
gCols = pxW / GLYPH_W;
gRows = pxH / GLYPH_H;
if (gCols < 20) gCols = 20;
if (gRows < 5) gRows = 5;
if (gCols > MAX_SCREEN_COLS) gCols = MAX_SCREEN_COLS;
if (gRows > MAX_SCREEN_ROWS) gRows = MAX_SCREEN_ROWS;
}
if (gCols != oldCols || gRows != oldRows)
invalidate_screen_cache();
}
static void put_cell(int col, int row, char c, uint32_t fg, uint32_t bg) {
SysScreenPutChar(c ? c : ' ', col * GLYPH_W, row * GLYPH_H, fg, bg);
if (col < 0 || row < 0 || col >= gCols || row >= gRows)
return;
if (!c) c = ' ';
if (col < MAX_SCREEN_COLS && row < MAX_SCREEN_ROWS) {
SCREEN_CELL* cell = &gScreenCache[row * MAX_SCREEN_COLS + col];
if (gScreenCacheValid && cell->c == c && cell->fg == fg && cell->bg == bg)
return;
cell->c = c;
cell->fg = fg;
cell->bg = bg;
}
SysScreenPutChar(c, col * GLYPH_W, row * GLYPH_H, fg, bg);
}
static void clear_row(int row, uint32_t bg) {
@@ -151,13 +200,7 @@ static void ensure_visible(void) {
}
static void render(void) {
int pxW = 0, pxH = 0;
if (SysScreenGetSize(&pxW, &pxH) == 0 && pxW > 0 && pxH > 0) {
gCols = pxW / GLYPH_W;
gRows = pxH / GLYPH_H;
if (gCols < 20) gCols = 20;
if (gRows < 5) gRows = 5;
}
update_screen_size();
clamp_cursor();
ensure_visible();
@@ -172,28 +215,40 @@ static void render(void) {
append_str(status, sizeof(status), &p, ", Col ");
append_u32(status, sizeof(status), &p, (uint32_t)(gCx + 1));
clear_row(0, COL_STATUS);
draw_text(0, 0, status, COL_STATUSF, COL_STATUS);
size_t statusLen = p;
for (int sx = 0; sx < gCols; sx++) {
char c = ((size_t)sx < statusLen) ? status[sx] : ' ';
put_cell(sx, 0, c, COL_STATUSF, COL_STATUS);
}
int textRows = gRows - 2;
for (int sy = 0; sy < textRows; sy++) {
int row = sy + 1;
int li = gTop + sy;
clear_row(row, COL_BG);
if (li >= gLineCount) continue;
LINE* ln = &gLines[li];
for (int sx = 0; sx < gCols; sx++) {
int ci = gLeft + sx;
char c = (ci < ln->len) ? ln->text[ci] : ' ';
bool atCursor = (li == gCy && ci == gCx);
char c = ' ';
bool atCursor = false;
if (li < gLineCount) {
LINE* ln = &gLines[li];
c = (ci < ln->len) ? ln->text[ci] : ' ';
atCursor = (li == gCy && ci == gCx);
}
put_cell(sx, row, c, atCursor ? COL_CURSORF : COL_FG,
atCursor ? COL_CURSOR : COL_BG);
}
}
clear_row(gRows - 1, COL_STATUS);
draw_text(0, gRows - 1, gMessage, COL_STATUSF, COL_STATUS);
size_t messageLen = strlen(gMessage);
for (int sx = 0; sx < gCols; sx++) {
char c = ((size_t)sx < messageLen) ? gMessage[sx] : ' ';
put_cell(sx, gRows - 1, c, COL_STATUSF, COL_STATUS);
}
gScreenCacheValid = true;
}
static void insert_char_at_cursor(char c) {
@@ -481,8 +536,10 @@ int main(void) {
parse_filename_from_cmdline();
load_file();
SysScreenClear(COL_BG);
invalidate_screen_cache();
editor_loop();
SysScreenClear(COL_BG);
SysScreenClear(0x012456);
invalidate_screen_cache();
print("edit: goodbye\n");
SysExitProcess(0);
return 0;
+93 -1
View File
@@ -95,6 +95,7 @@ static void cmd_help() {
print("Available commands:\n"
" help - Show this list\n"
" mem - Show memory usage\n"
" stats - Show scheduler/CPU/PMM telemetry\n"
" ps - List running process IDs\n"
" dir [path] - List directory contents\n"
" cd <path> - Change directory\n"
@@ -110,6 +111,96 @@ static void printSizeKiB(uint64_t bytes) {
print(" KiB");
}
static void printPagesKiB(uint64_t pages) {
printUInt64(pages * 4u);
print(" KiB");
}
static void printCpuFlags(uint32_t flags) {
if (flags & SYS_CPU_FLAG_BSP) print("bsp ");
if (flags & SYS_CPU_FLAG_ONLINE) print("online ");
if (flags & SYS_CPU_FLAG_PARKED) print("parked ");
if (flags & SYS_CPU_FLAG_PRIMARY) print("primary ");
if (flags & SYS_CPU_FLAG_STARTED) print("started ");
if (flags & SYS_CPU_FLAG_PRESENT) print("present ");
}
static void cmd_stats(void) {
SYS_SCHEDULER_STATS sched;
SYS_PMM_STATS pmm;
SYS_CPU_STATS cpu;
uint32_t status;
status = SysQueryKernelStats(SYS_KERNEL_STATS_SCHEDULER, &sched, sizeof(sched), NULL);
if (status != 0) {
print("stats: scheduler query failed: ");
printUInt(status);
print("\n");
return;
}
status = SysQueryKernelStats(SYS_KERNEL_STATS_PMM, &pmm, sizeof(pmm), NULL);
if (status != 0) {
print("stats: pmm query failed: ");
printUInt(status);
print("\n");
return;
}
status = SysQueryKernelStats(SYS_KERNEL_STATS_CPU, &cpu, sizeof(cpu), NULL);
if (status != 0) {
print("stats: cpu query failed: ");
printUInt(status);
print("\n");
return;
}
print("Scheduler:\n");
print(" ticks: "); printUInt64(sched.Ticks); print("\n");
print(" context switches: "); printUInt64(sched.ContextSwitches); print("\n");
print(" quantum expires: "); printUInt64(sched.QuantumExpirations); print("\n");
print(" priority preempts: "); printUInt64(sched.PriorityPreemptions); print("\n");
print(" idle selections: "); printUInt64(sched.IdleSelections); print("\n");
print(" keep-current: "); printUInt64(sched.KeepCurrentDecisions); print("\n");
print(" demotions: "); printUInt64(sched.Demotions); print("\n");
print(" aging promotions: "); printUInt64(sched.AgingPromotions); print("\n");
print(" voluntary blocks: "); printUInt64(sched.VoluntaryBlocks); print("\n");
print(" SMT deferrals: "); printUInt64(sched.SmtSiblingDeferrals); print("\n");
print(" SMT primary pokes: "); printUInt64(sched.SmtPrimaryPokes); print("\n");
print("CPUs:\n");
uint32_t n = cpu.CpuCount;
if (n > SYS_KERNEL_STATS_MAX_CPUS)
n = SYS_KERNEL_STATS_MAX_CPUS;
for (uint32_t i = 0; i < n; i++) {
SYS_CPU_STAT* c = &cpu.Cpu[i];
print(" cpu"); printUInt(c->CpuIndex);
print(" lapic="); printUInt(c->LapicId);
print(" tid="); printUInt(c->CurrentTid);
print(" ticks="); printUInt64(c->SchedulerTicks);
print(" switches="); printUInt64(c->ContextSwitches);
print(" flags="); printCpuFlags(c->Flags);
print("\n");
}
print("Physical memory:\n");
print(" total: "); printPagesKiB(pmm.TotalFrames); print(" (frames="); printUInt64(pmm.TotalFrames); print(")\n");
print(" used: "); printPagesKiB(pmm.UsedFrames); print(" (frames="); printUInt64(pmm.UsedFrames); print(")\n");
print(" free: "); printPagesKiB(pmm.FreeFrames); print(" (frames="); printUInt64(pmm.FreeFrames); print(")\n");
print(" largest free run: "); printPagesKiB(pmm.LargestFreeRun); print(" (frames="); printUInt64(pmm.LargestFreeRun); print(")\n");
print(" free runs: "); printUInt64(pmm.FreeRunCount); print("\n");
print(" run histogram:\n");
print(" 1: "); printUInt64(pmm.FreeRunHistogram[0]); print("\n");
print(" 2-3: "); printUInt64(pmm.FreeRunHistogram[1]); print("\n");
print(" 4-7: "); printUInt64(pmm.FreeRunHistogram[2]); print("\n");
print(" 8-15: "); printUInt64(pmm.FreeRunHistogram[3]); print("\n");
print(" 16-63: "); printUInt64(pmm.FreeRunHistogram[4]); print("\n");
print(" 64-255: "); printUInt64(pmm.FreeRunHistogram[5]); print("\n");
print(" 256-1023: "); printUInt64(pmm.FreeRunHistogram[6]); print("\n");
print(" 1024+: "); printUInt64(pmm.FreeRunHistogram[7]); print("\n");
}
static void cmd_mem(void) {
SYS_MEMORY_STATUS st;
if (SysGetMemoryStatus(&st) != 0) {
@@ -240,7 +331,7 @@ static int runCommand(const char* cmd) {
if (!cmd || *cmd == '\0') return 0;
if (strcmp(cmd, "exit") == 0) return 1;
if (strcmp(cmd, "help") == 0) { cmd_help(); return 0; }
if (strcmp(cmd, "clear") == 0) { SysScreenClear(0); return 0; }
if (strcmp(cmd, "clear") == 0) { SysScreenClear(0x012456); return 0; }
if (strncmp(cmd, "crash", 5) == 0) {
// Check the sub-option trailing "crash " (offset 6)
if (strcmp(cmd + 6, "void") == 0) {
@@ -280,6 +371,7 @@ static int runCommand(const char* cmd) {
}
}
if (strcmp(cmd, "mem") == 0) { cmd_mem(); return 0; }
if (strcmp(cmd, "stats") == 0 || strcmp(cmd, "telemetry") == 0) { cmd_stats(); return 0; }
if (strcmp(cmd, "ps") == 0) { cmd_ps(); return 0; }
if (strcmp(cmd, "dir") == 0) { cmd_dir("."); return 0; }
if (strncmp(cmd, "dir ", 4) == 0) { cmd_dir(cmd + 4); return 0; }
+4 -3
View File
@@ -1,6 +1,7 @@
// posix_dir.c - chdir, getcwd, opendir, readdir, closedir
#include <string.h>
#include <ntlite/syscall.h>
#include <stdlib.h>
#include "posix.h"
#include "posix_path.h"
@@ -38,8 +39,8 @@ __declspec(dllexport) DIR* opendir(const char* path) {
uint32_t s = SysOpenDir(&req);
if (s != 0) { errno = ENOENT; return (DIR*)0; }
// Allocate DIR on the kernel heap (SysAlloc) so it outlives the stack.
DIR* d = (DIR*)SysAlloc(sizeof(DIR));
// Allocate DIR on the kernel heap (malloc) so it outlives the stack.
DIR* d = (DIR*)malloc(sizeof(DIR));
if (!d) { SysCloseHandle(kh); errno = ENOMEM; return (DIR*)0; }
d->KHandle = kh;
d->Valid = false;
@@ -64,6 +65,6 @@ __declspec(dllexport) struct dirent* readdir(DIR* d) {
__declspec(dllexport) int closedir(DIR* d) {
if (!d) { errno = EBADF; return -1; }
SysCloseHandle(d->KHandle);
SysFree(d);
free(d);
return 0;
}
+1 -1
View File
@@ -7,7 +7,7 @@
#include "posix_path.h"
__declspec(dllexport) void clearscreen(void) {
SysScreenClear(0x00000000);
SysScreenClear(0x012456);
}
__declspec(dllexport) void clearkeyboard(void) {
+6 -5
View File
@@ -1,5 +1,6 @@
// posix_socket.c - POSIX-ish socket wrappers over native Sys* sockets.
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.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) {
if (!fds || nfds == 0 || nfds > 64) { errno = EINVAL; return -1; }
SYS_POLLFD* kfds = (SYS_POLLFD*)SysAlloc(sizeof(SYS_POLLFD) * nfds);
SYS_POLLFD* kfds = (SYS_POLLFD*)malloc(sizeof(SYS_POLLFD) * nfds);
if (!kfds) { errno = ENOMEM; return -1; }
for (nfds_t i = 0; i < nfds; i++) {
@@ -348,7 +349,7 @@ __declspec(dllexport) int poll(struct pollfd* fds, nfds_t nfds, int timeout) {
uint32_t timeoutMs = timeout < 0 ? SYS_POLL_TIMEOUT_INFINITE : (uint32_t)timeout;
uint32_t s = SysPoll(kfds, nfds, timeoutMs, &ready);
if (s != 0) {
SysFree(kfds);
free(kfds);
errno = PosixStatusToErrno(s);
return -1;
}
@@ -365,7 +366,7 @@ __declspec(dllexport) int poll(struct pollfd* fds, nfds_t nfds, int timeout) {
if (re) out++;
}
SysFree(kfds);
free(kfds);
return out;
}
@@ -446,7 +447,7 @@ __declspec(dllexport) int getaddrinfo(const char* node, const char* service,
a.Port = service ? ParsePort(service) : 0;
size_t total = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
struct addrinfo* ai = (struct addrinfo*)SysAlloc(total);
struct addrinfo* ai = (struct addrinfo*)malloc(total);
if (!ai) return ENOMEM;
memset(ai, 0, total);
@@ -467,5 +468,5 @@ __declspec(dllexport) int getaddrinfo(const char* node, const char* service,
}
__declspec(dllexport) void freeaddrinfo(struct addrinfo* res) {
if (res) SysFree(res);
if (res) free(res);
}
+4 -3
View File
@@ -1,5 +1,6 @@
// posix_thread.c - pthread_create, pthread_join, pthread_exit, pthread_mutex_*
#include <stddef.h>
#include <stdlib.h>
#include <ntlite/syscall.h>
#include "posix.h"
@@ -56,7 +57,7 @@ static void PthreadTrampoline(uintptr_t raw) {
PTHREAD_SLOT* slot = PthreadSlotFind(pid, tid);
if (!slot) slot = PthreadSlotAlloc(pid, tid);
SysFree(tr);
free(tr);
void* retval = fn(arg);
@@ -76,7 +77,7 @@ __declspec(dllexport) int pthread_create(pthread_t* t, const pthread_attr_t* att
uint32_t pid = SysGetCurrentPid();
PTHREAD_TRAMP* tr = (PTHREAD_TRAMP*)SysAlloc(sizeof(PTHREAD_TRAMP));
PTHREAD_TRAMP* tr = (PTHREAD_TRAMP*)malloc(sizeof(PTHREAD_TRAMP));
if (!tr) return ENOMEM;
tr->Fn = fn;
tr->Arg = arg;
@@ -86,7 +87,7 @@ __declspec(dllexport) int pthread_create(pthread_t* t, const pthread_attr_t* att
uint32_t s = SysCreateThread((uint64_t)PthreadTrampoline,
(uint64_t)tr, 1 /*PriorityNormal*/, &tid);
if (s != 0) {
SysFree(tr);
free(tr);
return EAGAIN;
}
// The trampoline allocates the retval slot itself after it knows its real
+5 -4
View File
@@ -1,6 +1,7 @@
// gdi32.c
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <ntlite/syscall.h>
#if defined(__SSE2__) || defined(_M_X64) || defined(_M_IX86)
@@ -92,14 +93,14 @@ __declspec(dllexport) int StretchDIBits(
// Only reallocate if the new size is LARGER than what we already have
int requiredPixels = DestWidth * DestHeight;
if (requiredPixels > currentDestCapacity) {
SysFree(destBuffer);
destBuffer = (uint32_t*)SysAlloc(requiredPixels * sizeof(uint32_t));
free(destBuffer);
destBuffer = (uint32_t*)malloc(requiredPixels * sizeof(uint32_t));
currentDestCapacity = requiredPixels;
}
if (DestWidth > currentXMapCapacity) {
SysFree(srcX_map);
srcX_map = (int*)SysAlloc(DestWidth * sizeof(int));
free(srcX_map);
srcX_map = (int*)malloc(DestWidth * sizeof(int));
currentXMapCapacity = DestWidth;
}
+70 -23
View File
@@ -9,7 +9,7 @@
// HANDLE_TO_KH / KH_TO_HANDLE do that conversion in one place.
// - INVALID_HANDLE_VALUE maps to kernel handle 0 (the always-invalid slot).
// - HeapAlloc / HeapFree / HeapReAlloc ignore the HANDLE heap argument and
// always use the single kernel user-heap. This is fine: we don't expose
// always use the single user-mode heap. This is fine: we don't expose
// multiple heaps, and NULL is a legal (no-op) heap argument under Win32.
// - Win32 per-thread state lives behind SYS_TEB::SubsystemData so the native
// TEB ABI stays subsystem-neutral.
@@ -21,6 +21,7 @@
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <intrin.h>
@@ -66,6 +67,31 @@ typedef struct _MEMORY_BASIC_INFORMATION {
DWORD Type;
} MEMORY_BASIC_INFORMATION;
static uint32_t WinProtectToSysVm(DWORD protect) {
switch (protect) {
case PAGE_NOACCESS: return SYS_VM_NOACCESS;
case PAGE_READONLY: return SYS_VM_READ;
case PAGE_READWRITE:
case PAGE_WRITECOPY: return SYS_VM_READWRITE;
case PAGE_EXECUTE: return SYS_VM_EXECUTE;
case PAGE_EXECUTE_READ: return SYS_VM_EXECUTE_READ;
case PAGE_EXECUTE_READWRITE: return SYS_VM_EXECUTE_READWRITE;
default: return SYS_VM_READWRITE;
}
}
static DWORD SysVmProtectToWin(uint32_t protect) {
switch (protect) {
case SYS_VM_NOACCESS: return PAGE_NOACCESS;
case SYS_VM_READ: return PAGE_READONLY;
case SYS_VM_READWRITE: return PAGE_READWRITE;
case SYS_VM_EXECUTE: return PAGE_EXECUTE;
case SYS_VM_EXECUTE_READ: return PAGE_EXECUTE_READ;
case SYS_VM_EXECUTE_READWRITE: return PAGE_EXECUTE_READWRITE;
default: return PAGE_NOACCESS;
}
}
// File-find structures
typedef struct _FILETIME {
DWORD dwLowDateTime;
@@ -228,7 +254,7 @@ static WIN32_THREAD_ENV* K32ThreadEnv(void) {
WIN32_THREAD_ENV* env = (WIN32_THREAD_ENV*)teb->SubsystemData;
if (!env) {
env = (WIN32_THREAD_ENV*)SysAlloc(sizeof(WIN32_THREAD_ENV));
env = (WIN32_THREAD_ENV*)malloc(sizeof(WIN32_THREAD_ENV));
if (!env) return &gFallbackThreadEnv;
memset(env, 0, sizeof(*env));
teb->SubsystemData = env;
@@ -363,28 +389,27 @@ __declspec(dllexport) uint64_t GetTickCount64(void) {
}
// ---------------------------------------------------------------------------
// Memory (heap argument is ignored - single kernel user-heap)
// Memory (heap argument is ignored - single user-mode heap)
// ---------------------------------------------------------------------------
__declspec(dllexport) void* HeapAlloc(void* heap, DWORD flags, size_t size) {
(void)heap;
(void)heap; (void)flags;
if (!size) return NULL;
void* ptr = SysAlloc(size);
void* ptr = malloc(size);
if (!ptr) gLastError = 8; // ERROR_NOT_ENOUGH_MEMORY
return ptr;
}
__declspec(dllexport) BOOL HeapFree(void* heap, DWORD flags, void* ptr) {
(void)heap; (void)flags;
// Win32's HeapFree doesn't need the size; we pass 0 and the kernel's
// allocator handles it (the block header carries the size).
if (ptr) SysFree(ptr);
// Win32's HeapFree doesn't need the size; we pass 0 and the user-mode heap carries the block size.
if (ptr) free(ptr);
return TRUE;
}
__declspec(dllexport) void* HeapReAlloc(void* heap, DWORD flags,
void* ptr, size_t size) {
(void)heap; (void)flags;
void* newptr = SysRealloc(ptr, size);
void* newptr = realloc(ptr, size);
if (!newptr && size) gLastError = 8;
return newptr;
}
@@ -400,23 +425,37 @@ __declspec(dllexport) void* GetProcessHeap(void) {
// ---------------------------------------------------------------------------
__declspec(dllexport) void* VirtualAlloc(void* lpAddress, size_t dwSize,
DWORD flAllocationType, DWORD flProtect) {
(void)lpAddress; (void)flAllocationType; (void)flProtect;
(void)flAllocationType;
if (!dwSize) return NULL;
void* ptr = SysAlloc(dwSize);
if (!ptr) gLastError = 8; // ERROR_NOT_ENOUGH_MEMORY
return ptr;
size_t pages = (dwSize + 4095u) / 4096u;
void* base = NULL;
uint32_t flags = lpAddress ? SYS_VM_FLAG_FIXED : SYS_VM_FLAG_NONE;
uint32_t s = SysVmAlloc(lpAddress, pages, WinProtectToSysVm(flProtect), flags, &base);
if (s != SYS_STATUS_SUCCESS) {
gLastError = (s == SYS_STATUS_NOT_FOUND || s == SYS_STATUS_INVALID_PARAMETER) ? 87 : 8;
return NULL;
}
return base;
}
__declspec(dllexport) BOOL VirtualFree(void* lpAddress, size_t dwSize, DWORD dwFreeType) {
(void)dwSize; (void)dwFreeType;
if (lpAddress) SysFree(lpAddress);
if (!lpAddress) return TRUE;
uint32_t s = SysVmFree(lpAddress);
if (s != SYS_STATUS_SUCCESS) { gLastError = 87; return FALSE; }
return TRUE;
}
__declspec(dllexport) BOOL VirtualProtect(void* lpAddress, size_t dwSize,
DWORD flNewProtect, DWORD* lpflOldProtect) {
(void)lpAddress; (void)dwSize; (void)flNewProtect;
if (lpflOldProtect) *lpflOldProtect = PAGE_EXECUTE_READWRITE;
if (!lpAddress || !dwSize) { gLastError = 87; return FALSE; }
size_t pages = (dwSize + 4095u) / 4096u;
uint32_t oldSysProtect = 0;
uint32_t s = SysVmProtect(lpAddress, pages, WinProtectToSysVm(flNewProtect),
lpflOldProtect ? &oldSysProtect : NULL);
if (s != SYS_STATUS_SUCCESS) { gLastError = 87; return FALSE; }
if (lpflOldProtect) *lpflOldProtect = SysVmProtectToWin(oldSysProtect);
return TRUE;
}
@@ -427,13 +466,21 @@ __declspec(dllexport) size_t VirtualQuery(const void* lpAddress,
gLastError = 87; // ERROR_INVALID_PARAMETER
return 0;
}
uintptr_t base = (uintptr_t)lpAddress & ~(uintptr_t)0xFFF;
lpBuffer->BaseAddress = (void*)base;
lpBuffer->AllocationBase = (void*)base;
lpBuffer->AllocationProtect = PAGE_EXECUTE_READWRITE;
lpBuffer->RegionSize = 0x1000;
SYS_VM_REGION_INFO info;
uint32_t s = SysVmQuery((void*)lpAddress, &info);
if (s != SYS_STATUS_SUCCESS) {
gLastError = 87;
return 0;
}
DWORD protect = SysVmProtectToWin(info.Protect);
lpBuffer->BaseAddress = info.Base;
lpBuffer->AllocationBase = info.Base;
lpBuffer->AllocationProtect = protect;
lpBuffer->RegionSize = info.PageCount * 4096u;
lpBuffer->State = MEM_COMMIT;
lpBuffer->Protect = PAGE_EXECUTE_READWRITE;
lpBuffer->Protect = protect;
lpBuffer->Type = MEM_PRIVATE;
return sizeof(MEMORY_BASIC_INFORMATION);
}
@@ -512,7 +559,7 @@ __declspec(dllexport) BOOL FlushConsoleInputBuffer(HANDLE hConsoleInput) {
// !Made-up! clear console api.
__declspec(dllexport) BOOL ClearConsoleScreenBuffer(HANDLE hConsole) {
SysScreenClear(0x00000000);
SysScreenClear(0x012456);
return TRUE;
}
+2 -1
View File
@@ -2,6 +2,7 @@
// No COM infrastructure at this stage; all functions fail gracefully.
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <ntlite/syscall.h>
// ---------------------------------------------------------------------------
@@ -65,7 +66,7 @@ __declspec(dllexport) HRESULT CoCreateInstance(const GUID* clsid, IUnknown* oute
// Memory
// ---------------------------------------------------------------------------
__declspec(dllexport) void CoTaskMemFree(void* pv) {
if (pv) SysFree(pv);
if (pv) free(pv);
}
// ---------------------------------------------------------------------------
+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);
}
+93 -91
View File
@@ -1,94 +1,96 @@
; syscall_nr.inc
SYS_EXIT_PROCESS EQU 0
SYS_EXIT_THREAD EQU 1
SYS_CREATE_PROCESS EQU 2
SYS_WAIT_FOR_PROCESS EQU 3
SYS_GET_PROCESS_EXIT_CODE EQU 4
SYS_KILL_PROCESS EQU 5
SYS_GET_PROCESS_LIST EQU 6
SYS_GET_PROCESS_PID EQU 7
SYS_CREATE_THREAD EQU 8
SYS_WAIT_THREAD EQU 9
SYS_GET_CURRENT_TID EQU 10
SYS_GET_CURRENT_PID EQU 11
SYS_SET_THREAD_PRIORITY EQU 12
SYS_YIELD EQU 13
SYS_SLEEP EQU 14
SYS_SET_USER_APC_DISPATCHER EQU 15
SYS_APC_RETURN EQU 16
SYS_ALLOC EQU 17
SYS_FREE EQU 18
SYS_REALLOC EQU 19
SYS_CLOSE_HANDLE EQU 20
SYS_MUTEX_CREATE EQU 21
SYS_MUTEX_ACQUIRE EQU 22
SYS_MUTEX_TRY_ACQUIRE EQU 23
SYS_MUTEX_RELEASE EQU 24
SYS_SEM_CREATE EQU 25
SYS_SEM_WAIT EQU 26
SYS_SEM_TRY_WAIT EQU 27
SYS_SEM_SIGNAL EQU 28
SYS_EVENT_CREATE EQU 29
SYS_EVENT_SIGNAL EQU 30
SYS_EVENT_CLEAR EQU 31
SYS_EVENT_WAIT EQU 32
SYS_QUEUE_CREATE EQU 33
SYS_QUEUE_SEND EQU 34
SYS_QUEUE_RECV EQU 35
SYS_PUBLISH_QUEUE EQU 36
SYS_OPEN_NAMED_QUEUE EQU 37
SYS_QUEUE_DUPLICATE EQU 38
SYS_NAMED_QUEUE_OWNER_PID EQU 39
SYS_OPEN_FILE EQU 40
SYS_CREATE_FILE EQU 41
SYS_READ_FILE EQU 42
SYS_WRITE_FILE EQU 43
SYS_READ_FILE_ASYNC EQU 44
SYS_WRITE_FILE_ASYNC EQU 45
SYS_CANCEL_IO EQU 46
SYS_SEEK_FILE EQU 47
SYS_GET_FILE_POS EQU 48
SYS_GET_FILE_SIZE EQU 49
SYS_TRUNCATE_FILE EQU 50
SYS_DELETE_FILE EQU 51
SYS_RENAME_FILE EQU 52
SYS_OPEN_DIR EQU 53
SYS_READ_DIR EQU 54
SYS_CREATE_DIR EQU 55
SYS_REMOVE_DIR EQU 56
SYS_SET_CWD EQU 57
SYS_GET_CWD EQU 58
SYS_WRITE_CONSOLE EQU 59
SYS_SCREEN_BLIT EQU 60
SYS_SCREEN_CLEAR EQU 61
SYS_SCREEN_GET_SIZE EQU 62
SYS_SCREEN_PUT_CHAR EQU 63
SYS_KB_POLL EQU 64
SYS_KB_IS_KEY_DOWN EQU 65
SYS_KB_READ_CHAR EQU 66
SYS_KB_READ_KEY EQU 67
SYS_KB_GET_MODIFIERS EQU 68
SYS_MOUSE_POLL EQU 69
SYS_MOUSE_READ EQU 70
SYS_MOUSE_GET_POS EQU 71
SYS_GET_TICK EQU 72
SYS_DEBUG_PRINT EQU 73
SYS_QUERY_TRAP_FRAME EQU 74
SYS_SOCKET EQU 75
SYS_BIND EQU 76
SYS_LISTEN EQU 77
SYS_ACCEPT EQU 78
SYS_CONNECT EQU 79
SYS_SEND EQU 80
SYS_RECV EQU 81
SYS_SHUTDOWN EQU 82
SYS_SEND_TO EQU 83
SYS_RECV_FROM EQU 84
SYS_RESOLVE_HOST EQU 85
SYS_SET_SOCKET_OPTION EQU 86
SYS_GET_SOCKET_OPTION EQU 87
SYS_POLL EQU 88
SYS_GET_MEMORY_STATUS EQU 89
SYS_EXIT_PROCESS EQU 0
SYS_EXIT_THREAD EQU 1
SYS_CREATE_PROCESS EQU 2
SYS_WAIT_FOR_PROCESS EQU 3
SYS_GET_PROCESS_EXIT_CODE EQU 4
SYS_KILL_PROCESS EQU 5
SYS_GET_PROCESS_LIST EQU 6
SYS_GET_PROCESS_PID EQU 7
SYS_CREATE_THREAD EQU 8
SYS_WAIT_THREAD EQU 9
SYS_GET_CURRENT_TID EQU 10
SYS_GET_CURRENT_PID EQU 11
SYS_SET_THREAD_PRIORITY EQU 12
SYS_YIELD EQU 13
SYS_SLEEP EQU 14
SYS_SET_USER_APC_DISPATCHER EQU 15
SYS_APC_RETURN EQU 16
SYS_VM_ALLOC EQU 17
SYS_VM_FREE EQU 18
SYS_VM_PROTECT EQU 19
SYS_VM_QUERY EQU 20
SYS_CLOSE_HANDLE EQU 21
SYS_MUTEX_CREATE EQU 22
SYS_MUTEX_ACQUIRE EQU 23
SYS_MUTEX_TRY_ACQUIRE EQU 24
SYS_MUTEX_RELEASE EQU 25
SYS_SEM_CREATE EQU 26
SYS_SEM_WAIT EQU 27
SYS_SEM_TRY_WAIT EQU 28
SYS_SEM_SIGNAL EQU 29
SYS_EVENT_CREATE EQU 30
SYS_EVENT_SIGNAL EQU 31
SYS_EVENT_CLEAR EQU 32
SYS_EVENT_WAIT EQU 33
SYS_QUEUE_CREATE EQU 34
SYS_QUEUE_SEND EQU 35
SYS_QUEUE_RECV EQU 36
SYS_PUBLISH_QUEUE EQU 37
SYS_OPEN_NAMED_QUEUE EQU 38
SYS_QUEUE_DUPLICATE EQU 39
SYS_NAMED_QUEUE_OWNER_PID EQU 40
SYS_OPEN_FILE EQU 41
SYS_CREATE_FILE EQU 42
SYS_READ_FILE EQU 43
SYS_WRITE_FILE EQU 44
SYS_READ_FILE_ASYNC EQU 45
SYS_WRITE_FILE_ASYNC EQU 46
SYS_CANCEL_IO EQU 47
SYS_SEEK_FILE EQU 48
SYS_GET_FILE_POS EQU 49
SYS_GET_FILE_SIZE EQU 50
SYS_TRUNCATE_FILE EQU 51
SYS_DELETE_FILE EQU 52
SYS_RENAME_FILE EQU 53
SYS_OPEN_DIR EQU 54
SYS_READ_DIR EQU 55
SYS_CREATE_DIR EQU 56
SYS_REMOVE_DIR EQU 57
SYS_SET_CWD EQU 58
SYS_GET_CWD EQU 59
SYS_WRITE_CONSOLE EQU 60
SYS_SCREEN_BLIT EQU 61
SYS_SCREEN_CLEAR EQU 62
SYS_SCREEN_GET_SIZE EQU 63
SYS_SCREEN_PUT_CHAR EQU 64
SYS_KB_POLL EQU 65
SYS_KB_IS_KEY_DOWN EQU 66
SYS_KB_READ_CHAR EQU 67
SYS_KB_READ_KEY EQU 68
SYS_KB_GET_MODIFIERS EQU 69
SYS_MOUSE_POLL EQU 70
SYS_MOUSE_READ EQU 71
SYS_MOUSE_GET_POS EQU 72
SYS_GET_TICK EQU 73
SYS_DEBUG_PRINT EQU 74
SYS_QUERY_TRAP_FRAME EQU 75
SYS_SOCKET EQU 76
SYS_BIND EQU 77
SYS_LISTEN EQU 78
SYS_ACCEPT EQU 79
SYS_CONNECT EQU 80
SYS_SEND EQU 81
SYS_RECV EQU 82
SYS_SHUTDOWN EQU 83
SYS_SEND_TO EQU 84
SYS_RECV_FROM EQU 85
SYS_RESOLVE_HOST EQU 86
SYS_SET_SOCKET_OPTION EQU 87
SYS_GET_SOCKET_OPTION EQU 88
SYS_POLL EQU 89
SYS_GET_MEMORY_STATUS EQU 90
SYS_QUERY_KERNEL_STATS EQU 91
SYS_MAX EQU 90
SYS_MAX EQU 92
+6 -4
View File
@@ -108,11 +108,12 @@ SysUserApcDispatcher_Failed:
SysUserApcDispatcher ENDP
; ---------------------------------------------------------------------------
; Memory and handles
; Virtual memory and handles
; ---------------------------------------------------------------------------
SYSCALL_STUB2 Alloc, SYS_ALLOC
SYSCALL_STUB2 Free, SYS_FREE
SYSCALL_STUB2 Realloc, SYS_REALLOC
SYSCALL_STUB6 VmAlloc, SYS_VM_ALLOC
SYSCALL_STUB2 VmFree, SYS_VM_FREE
SYSCALL_STUB2 VmProtect, SYS_VM_PROTECT
SYSCALL_STUB2 VmQuery, SYS_VM_QUERY
SYSCALL_STUB2 CloseHandle, SYS_CLOSE_HANDLE
; ---------------------------------------------------------------------------
@@ -216,5 +217,6 @@ SYSCALL_STUB2 GetSocketOption, SYS_GET_SOCKET_OPTION
SYSCALL_STUB2 Poll, SYS_POLL
SYSCALL_STUB2 GetMemoryStatus, SYS_GET_MEMORY_STATUS
SYSCALL_STUB2 QueryKernelStats, SYS_QUERY_KERNEL_STATS
END
+3 -2
View File
@@ -1,5 +1,6 @@
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <intrin.h>
#include <ntlite/syscall.h>
@@ -82,7 +83,7 @@ int main(void) {
SysExitProcess(1);
}
uint8_t* buffer = (uint8_t*)SysAlloc(512);
uint8_t* buffer = (uint8_t*)malloc(512);
if (!buffer) {
print("async_apc: allocation failed\n");
SysExitProcess(1);
@@ -141,7 +142,7 @@ int main(void) {
SysCloseHandle(event);
SysCloseHandle(file);
SysFree(buffer);
free(buffer);
if (!ok) {
print("async_apc: FAIL\n");
+3 -2
View File
@@ -1,5 +1,6 @@
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <ntlite/syscall.h>
@@ -51,7 +52,7 @@ int main(void) {
SysExitProcess(1);
}
uint8_t* buffer = (uint8_t*)SysAlloc(512);
uint8_t* buffer = (uint8_t*)malloc(512);
if (!buffer) {
print("async_cancel: alloc failed\n");
SysExitProcess(1);
@@ -101,7 +102,7 @@ int main(void) {
SysCloseHandle(request);
SysCloseHandle(event);
SysCloseHandle(file);
SysFree(buffer);
free(buffer);
if (!ok) {
print("async_cancel: FAIL\n");