remove weird double spaces, remove /EXPORT from build.bat in favor of __declspec(dllexport)

This commit is contained in:
maksw committed 2026-05-03 19:54:51 +02:00
1 parent 9fa2a7e0db
commit 83d48e09bb
41 files changed
+156 -170

No files matched your search

Binary file not shown.
+7 -21
View File
@@ -44,7 +44,7 @@ for %%f in (%SRC%\boot\*.c) do (
:: ---- Link bootloader ----
echo Linking bootx64.efi...
link %LFLAGS% /SUBSYSTEM:EFI_APPLICATION /ENTRY:UefiMain /OUT:"bin\bootx64.efi" ^
/PDB:"bin\bootx64.pdb" %SRC%\boot\efilib.lib obj\ini_parser.obj obj\libc.obj obj\boot\*.obj || exit /b 1
/PDB:"bin\bootx64.pdb" %SRC%\boot\efilib.lib obj\ini_parser.obj obj\libc.obj obj\boot\*.obj || exit /b 1
:: ---- Compile HAL ----
echo Compiling hal...
@@ -54,11 +54,7 @@ for %%f in (%SRC%\hal\*.c) do (
:: ---- Link hal.dll ----
echo Linking hal.dll...
link %LFLAGS% /DLL /OUT:"bin\hal.dll" ^
/ENTRY:HalInitialize /IGNORE:4216 ^
/EXPORT:HalInitialize /EXPORT:HalRegisterScheduler /EXPORT:HalGetApi ^
/EXPORT:IoRegisterDisk /EXPORT:HalDiskDispatch ^
obj\printf.obj obj\libc.obj obj\hal\*.obj || exit /b 1
link %LFLAGS% /DLL /OUT:"bin\hal.dll" /ENTRY:HalInitialize obj\printf.obj obj\libc.obj obj\hal\*.obj || exit /b 1
:: ---- Compile kernel ----
echo Compiling kernel...
@@ -68,13 +64,7 @@ for %%f in (%SRC%\kernel\*.c) do (
:: ---- Link kernel.exe ----
echo Linking kernel.exe...
link %LFLAGS% /SUBSYSTEM:NATIVE /ENTRY:KernelMain /OUT:"bin\kernel.exe" ^
/PDB:"bin\kernel.pdb" /EXPORT:MmAllocatePool /EXPORT:MmFreePool /EXPORT:IoRegisterFilesystem ^
/EXPORT:KeSignalEvent /EXPORT:MmAllocateContiguous /EXPORT:ObDereferenceObject /EXPORT:KeEventCreate ^
/EXPORT:KeWaitForEvent /EXPORT:KeClearEvent /EXPORT:MmGetPhysicalAddress /EXPORT:DbgPrint /EXPORT:KeIrqDispatch ^
/EXPORT:MmMapPage /EXPORT:MmSetPageProtect /EXPORT:KeYield /EXPORT:KeIrqRegister ^
/EXPORT:SemaphoreCreate /EXPORT:KeWaitSemaphore /EXPORT:KeSignalSemaphore /EXPORT:KeCreateKernelThread ^
/EXPORT:IrpQueueInit /EXPORT:IrpQueueEnqueue /EXPORT:IrpQueueDequeue ^
link %LFLAGS% /SUBSYSTEM:NATIVE /ENTRY:KernelMain /OUT:"bin\kernel.exe" /PDB:"bin\kernel.pdb" ^
bin\hal.lib obj\ini_parser.obj obj\printf.obj obj\libc.obj obj\kernel\*.obj || exit /b 1
:: ---- Compile syscall.dll ----
@@ -93,23 +83,19 @@ link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL ^
:: ---- Compile drivers ----
echo Compiling drivers...
cl %CFLAGS% /I"%SRC%\hal" /c /Fo"obj\drivers\ide.obj" "%SRC%\drivers\ide\ide.c" || exit /b 1
link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL ^
/OUT:"bin\ide.sys" /IGNORE:4216 /ENTRY:DriverEntry /EXPORT:DriverEntry ^
link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:"bin\ide.sys" /ENTRY:DriverEntry ^
bin\hal.lib bin\kernel.lib obj\libc.obj obj\drivers\ide.obj || exit /b 1
cl %CFLAGS% /I"%SRC%\hal" /c /Fo"obj\drivers\ahci.obj" "%SRC%\drivers\ahci\ahci.c" || exit /b 1
link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL ^
/OUT:"bin\ahci.sys" /IGNORE:4216 /ENTRY:DriverEntry /EXPORT:DriverEntry ^
link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:"bin\ahci.sys" /ENTRY:DriverEntry ^
bin\hal.lib bin\kernel.lib obj\libc.obj obj\drivers\ahci.obj || exit /b 1
cl %CFLAGS% /I"%SRC%\fat32" /c /Fo"obj\drivers\fat32.obj" "%SRC%\drivers\fat32\fat32.c" || exit /b 1
link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL ^
/OUT:"bin\fat32.sys" /IGNORE:4216 /ENTRY:DriverEntry /EXPORT:DriverEntry ^
link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:"bin\fat32.sys" /ENTRY:DriverEntry ^
bin\hal.lib bin\kernel.lib obj\libc.obj obj\drivers\fat32.obj || exit /b 1
cl %CFLAGS% /I"%SRC%\usb" /c /Fo"obj\drivers\usb.obj" "%SRC%\drivers\usb\usb.c" || exit /b 1
link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL ^
/OUT:"bin\usb.sys" /IGNORE:4216 /ENTRY:DriverEntry /EXPORT:DriverEntry ^
link /nologo /SUBSYSTEM:NATIVE /NODEFAULTLIB /DLL /OUT:"bin\usb.sys" /ENTRY:DriverEntry ^
bin\hal.lib bin\kernel.lib obj\libc.obj obj\drivers\usb.obj || exit /b 1
:: ---- Compile shell ----
+1 -1
View File
@@ -784,7 +784,7 @@ EFI_STATUS EFIAPI UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable
// --- Load minimal GDT / IDT, enable NXE, set CR3 ---
// (These are inline since we have no runtime services after ExitBootServices.)
// GDT is set up by the kernel's KeInitializeGdt; we just need a valid one to
// reach KernelMain. The bootloader installed a flat 64-bit GDT earlier via
// reach KernelMain. The bootloader installed a flat 64-bit GDT earlier via
// EDK2, which is fine for the jump.
// Enable NXE bit in EFER.
+9 -9
View File
@@ -10,14 +10,14 @@
//
// Async I/O model (IRP path):
// Each drive has a dedicated kernel worker thread (AhciWorker) that blocks
// on a per-drive counting semaphore. Callers submit IRPs via AhciSubmitIrp,
// which enqueues the IRP and signals the semaphore. The worker dequeues
// on a per-drive counting semaphore. Callers submit IRPs via AhciSubmitIrp,
// which enqueues the IRP and signals the semaphore. The worker dequeues
// one IRP at a time, runs the synchronous hardware transfer (blocking the
// worker, NOT the submitting thread), then writes irp->Status and fires
// irp->CompletionEvent / irp->CompletionFn.
//
// This gives true async I/O from the caller's perspective: IoSubmitIrp()
// returns STATUS_PENDING immediately. Multiple callers can have outstanding
// returns STATUS_PENDING immediately. Multiple callers can have outstanding
// requests against different drives concurrently without stalling each other.
//
// NCQ extension (future work — see "NCQ TODO" comments):
@@ -30,13 +30,13 @@
// • In AhciIsr: completed slots = prev_sact ^ port->sact; look up
// slot_irp[slot] and fire each completion from within the ISR.
// • The worker becomes a pure dispatcher: grab a free slot, build the
// command, issue it, return immediately. No per-slot KeWaitForEvent.
// command, issue it, return immediately. No per-slot KeWaitForEvent.
//
// Interrupt model (unchanged):
// GHC.IE and per-port PORT_IE are enabled after each port is initialised.
// AhciIsr fires on the PCI IRQ line and signals the per-drive completionEvent.
// port_issue_cmd blocks the worker thread on KeWaitForEvent instead of
// spinning on CI. port_issue_cmd_poll is kept for early init (IDENTIFY)
// spinning on CI. port_issue_cmd_poll is kept for early init (IDENTIFY)
// before the scheduler is live.
#include <stdint.h>
@@ -383,7 +383,7 @@ typedef struct {
// -----------------------------------------------------------------------
// IRP queue — async dispatch
// -----------------------------------------------------------------------
// AhciWorker blocks here waiting for work. AhciSubmitIrp enqueues an IRP
// AhciWorker blocks here waiting for work. AhciSubmitIrp enqueues an IRP
// and signals the semaphore to wake the worker.
IRP_QUEUE irpQueue;
THREAD *workerThread;
@@ -838,7 +838,7 @@ static KSTATUS AhciSubmitIrp(void *ctx, IRP *irp) {
// AhciWorker — kernel thread, one per drive.
// Dequeues IRPs and executes them one at a time using the existing
// single-slot interrupt-driven path. Completion fires the IRP's event
// single-slot interrupt-driven path. Completion fires the IRP's event
// and/or callback so the original caller can observe the result without
// ever having blocked in a driver call.
//
@@ -1106,7 +1106,7 @@ KSTATUS AhciInitialize(const HAL_API *hal) {
// Phase 5b: create the IRP queue semaphore and initialise the queue.
// The semaphore starts at 0; each submitted IRP increments it by one.
SEMAPHORE *irpSem = (SEMAPHORE *)0;
st = SemaphoreCreate(0, 0x7FFFFFFF, &irpSem);
st = KeSemaphoreCreate(0, 0x7FFFFFFF, &irpSem);
if (!KSUCCESS(st)) {
DbgPrint("AHCI: port %u: semaphore create failed (0x%x)\n", portno, st);
continue;
@@ -1167,7 +1167,7 @@ KSTATUS AhciInitialize(const HAL_API *hal) {
}
// -----------------------------------------------------------------------
// Register the ISR. All ports on this HBA share one PCI IRQ line.
// Register the ISR. All ports on this HBA share one PCI IRQ line.
// Do this after all drives are initialised so the ISR sees valid state.
// -----------------------------------------------------------------------
KeIrqRegister(g_irq, AhciIsr);
+5 -5
View File
@@ -65,8 +65,8 @@ typedef struct HAL_INTC {
} HAL_INTC;
typedef struct HAL_POWER {
// ACPI S5 soft-off. Disables interrupts, writes SLP_EN to PM1a/b_CNT,
// and halts if firmware doesn't respond. Does not return.
// ACPI S5 soft-off. Disables interrupts, writes SLP_EN to PM1a/b_CNT,
// and halts if firmware doesn't respond. Does not return.
void (*Shutdown)(void);
} HAL_POWER;
@@ -101,6 +101,6 @@ typedef struct HAL_INIT_PARAMS {
#define HAL_API_VERSION 1
const HAL_API* HalGetApi(void);
void HalRegisterScheduler(void (*pKeSchedulerTick)(void));
KSTATUS HalInitialize(const HAL_INIT_PARAMS* params);
__declspec(dllexport) const HAL_API* HalGetApi(void);
__declspec(dllexport) void HalRegisterScheduler(void (*pKeSchedulerTick)(void));
__declspec(dllexport) KSTATUS HalInitialize(const HAL_INIT_PARAMS* params);
+4 -4
View File
@@ -6,7 +6,7 @@
// in the dependency graph.
//
// HalDiskDispatch is the one bridge: it calls the driver's SubmitIrp (async)
// or runs the sync callbacks inline and writes irp->Status. It does not
// or runs the sync callbacks inline and writes irp->Status. It does not
// touch irp->CompletionEvent — that is ke_irp.c's responsibility.
#include <stdint.h>
@@ -20,7 +20,7 @@
static DISK_DRIVER gDrives[MAX_DRIVES];
static bool gPresent[MAX_DRIVES];
KSTATUS IoRegisterDisk(uint8_t index, const DISK_DRIVER *driver) {
__declspec(dllexport) KSTATUS IoRegisterDisk(uint8_t index, const DISK_DRIVER *driver) {
if (index >= MAX_DRIVES || !driver) return STATUS_INVALID_PARAMETER;
if (gPresent[index]) return STATUS_ALREADY_EXISTS;
gDrives[index] = *driver;
@@ -39,10 +39,10 @@ KSTATUS IoRegisterDisk(uint8_t index, const DISK_DRIVER *driver) {
// ke_irp.c must NOT touch irp->CompletionEvent
// yet; the driver will fire it.
// Returns STATUS_SUCCESS — sync fallback ran; irp->Status is already
// written. ke_irp.c should fire completion hooks.
// written. ke_irp.c should fire completion hooks.
// Returns STATUS_NOT_FOUND — drive not registered.
KSTATUS HalDiskDispatch(uint8_t drive, IRP *irp) {
__declspec(dllexport) KSTATUS HalDiskDispatch(uint8_t drive, IRP *irp) {
if (drive >= MAX_DRIVES || !gPresent[drive]) return STATUS_NOT_FOUND;
DISK_DRIVER *drv = &gDrives[drive];
+6 -6
View File
@@ -1,15 +1,15 @@
// hal_keyboard.c – PS/2 keyboard, interrupt-driven, 256-entry ring buffer
//
// Scan-code set 1 (XT-compatible), as output by the 8042's built-in
// translation layer. Supports make/break for all standard keys, Shift /
// translation layer. Supports make/break for all standard keys, Shift /
// Ctrl / Alt / CapsLock / NumLock modifiers, and the E0-prefixed extended
// key set (arrows, Home/End/PgUp/PgDn/Ins/Del, RCtrl, RAlt, numpad-Enter,
// numpad-divide).
//
// Threading model
// ---------------
// Single-producer (ISR on IRQ 1) / single-consumer ring buffer. All
// ISR-written state is declared volatile. On a uniprocessor, volatile
// Single-producer (ISR on IRQ 1) / single-consumer ring buffer. All
// ISR-written state is declared volatile. On a uniprocessor, volatile
// plus the natural atomicity of aligned int reads/writes is sufficient.
// On SMP, add acquire/release memory barriers around gHead and gTail.
//
@@ -69,7 +69,7 @@ static volatile bool gNextExtended = false; // previous byte was 0xE0
static void (* volatile gCallback)(uint8_t) = NULL;
// -- ASCII translation tables – scan-code set 1, non-extended keys only --------
// Index = 7-bit make code (SC1_BREAK_BIT cleared). 0 = no printable glyph.
// Index = 7-bit make code (SC1_BREAK_BIT cleared). 0 = no printable glyph.
// Numpad digits yield their digit characters; a NumLock-aware wrapper can
// substitute cursor-movement codes (e.g. HAL_KEY_HOME) when NumLock is clear.
//
@@ -234,7 +234,7 @@ static bool KbdPoll(void) {
return gHead != gTail;
}
// Blocking read. Spins with PAUSE until a make code is available.
// Blocking read. Spins with PAUSE until a make code is available.
// On a preemptive kernel, replace the _mm_pause() loop with a
// condition variable or sti/hlt to avoid wasting CPU cycles.
static uint8_t KbdReadScancode(void) {
@@ -247,7 +247,7 @@ static uint8_t KbdReadScancode(void) {
}
// Returns the ASCII character for the next keypress, applying the current
// Shift and CapsLock state. Returns 0 for keys with no ASCII mapping
// Shift and CapsLock state. Returns 0 for keys with no ASCII mapping
// (function keys, arrows, unmodified Ctrl/Alt keys, etc.).
//
// CapsLock inverts shift only for alphabetic keys (a–z); digit and symbol
+5 -5
View File
@@ -295,7 +295,7 @@ static void WalkAcpi(uintptr_t rsdpPhys) {
}
// ---------------------------------------------------------------------------
// HalShutdown - ACPI S5 soft power-off. Does not return.
// HalShutdown - ACPI S5 soft power-off. Does not return.
// ---------------------------------------------------------------------------
#include <intrin.h>
@@ -309,12 +309,12 @@ static void HalShutdown(void) {
if (gPm1aCntBlk) __outword(gPm1aCntBlk, valA);
if (gPm1bCntBlk) __outword(gPm1bCntBlk, valB);
// Firmware should have powered off by now. If it didn't, halt.
// Firmware should have powered off by now. If it didn't, halt.
while (true) __halt();
}
// ---------------------------------------------------------------------------
KSTATUS HalInitialize(const HAL_INIT_PARAMS* initParams) {
__declspec(dllexport) KSTATUS HalInitialize(const HAL_INIT_PARAMS* initParams) {
if (gInitialised) return STATUS_ALREADY_EXISTS;
gPhysBase = initParams->PhysicalWindowBase;
gApi.PhysToVirt = HalPhysToVirt;
@@ -360,8 +360,8 @@ KSTATUS HalInitialize(const HAL_INIT_PARAMS* initParams) {
return STATUS_SUCCESS;
}
void HalRegisterScheduler(void (*pKeSchedulerTick)(void)) {
__declspec(dllexport) void HalRegisterScheduler(void (*pKeSchedulerTick)(void)) {
gTimerCallback = pKeSchedulerTick;
}
const HAL_API* HalGetApi(void) { return &gApi; }
__declspec(dllexport) const HAL_API* HalGetApi(void) { return &gApi; }
+2 -2
View File
@@ -1,7 +1,7 @@
// hal_screen.c - GOP framebuffer screen driver with embedded 8x16 font
//
// The 8x16 bitmap font is a standard VGA/PC font. We embed just the
// printable ASCII range (0x20–0x7E). Each glyph is 16 bytes; bit 7 of
// The 8x16 bitmap font is a standard VGA/PC font. We embed just the
// printable ASCII range (0x20–0x7E). Each glyph is 16 bytes; bit 7 of
// each byte is the leftmost pixel.
#include <stdint.h>
#include <string.h>
+5 -5
View File
@@ -1,7 +1,7 @@
#pragma once
// io_driver.h - driver-side interface for registering disk controllers
//
// DISK_DRIVER.SubmitIrp is the async path. IRP is forward-declared here so
// DISK_DRIVER.SubmitIrp is the async path. IRP is forward-declared here so
// this header (and hal_disk.c) remain free of kernel sync-object dependencies.
// Drivers that implement SubmitIrp include ke_irp.h themselves.
@@ -25,16 +25,16 @@ typedef struct DISK_DRIVER {
// --- Asynchronous path (optional) --------------------------------------
// NULL = driver has not implemented async; IoSubmitIrp() falls back to
// the sync path. Returns STATUS_PENDING when the IRP is accepted.
// the sync path. Returns STATUS_PENDING when the IRP is accepted.
KSTATUS (*SubmitIrp)(void *ctx, struct IRP *irp);
uint64_t SectorCount;
} DISK_DRIVER;
KSTATUS IoRegisterDisk (uint8_t driveIndex, const DISK_DRIVER *driver);
__declspec(dllexport) KSTATUS IoRegisterDisk(uint8_t driveIndex, const DISK_DRIVER *driver);
// Internal dispatch used by ke_irp.c. Calls SubmitIrp if present, otherwise
// Internal dispatch used by ke_irp.c. Calls SubmitIrp if present, otherwise
// runs the sync callbacks inline and writes irp->Status; does NOT touch any
// kernel sync objects so it is safe to call from the HAL layer.
// Returns STATUS_PENDING (async path taken) or STATUS_SUCCESS (ran inline).
KSTATUS HalDiskDispatch (uint8_t drive, struct IRP *irp);
__declspec(dllexport) KSTATUS HalDiskDispatch(uint8_t drive, struct IRP *irp);
+6 -6
View File
@@ -17,7 +17,7 @@ static VOLUME_ENTRY gVolumes[MAX_DRIVES];
// ---------------------------------------------------------------------------
// Registration
// ---------------------------------------------------------------------------
KSTATUS IoRegisterFilesystem(uint8_t volumeIndex,
__declspec(dllexport) KSTATUS IoRegisterFilesystem(uint8_t volumeIndex,
IO_FILESYSTEM *fs,
const IO_VOLUME_PARAMS *vol) {
if (volumeIndex >= MAX_DRIVES || !fs || !vol)
@@ -54,7 +54,7 @@ static void FileDestroy(OBJECT* obj) {
// ---------------------------------------------------------------------------
// IoOpenFile
// ---------------------------------------------------------------------------
KSTATUS IoOpenFile(const char* path, FILE_OBJECT **out) {
__declspec(dllexport) KSTATUS IoOpenFile(const char* path, FILE_OBJECT **out) {
if (!path || !out) return STATUS_INVALID_PARAMETER;
const char* relPath;
@@ -83,7 +83,7 @@ KSTATUS IoOpenFile(const char* path, FILE_OBJECT **out) {
// ---------------------------------------------------------------------------
// IoReadFile - sequential read at current offset
// ---------------------------------------------------------------------------
KSTATUS IoReadFile(FILE_OBJECT* file, void* buf, size_t size, size_t* bytesRead) {
__declspec(dllexport) KSTATUS IoReadFile(FILE_OBJECT* file, void* buf, size_t size, size_t* bytesRead) {
if (!file || !buf) return STATUS_INVALID_PARAMETER;
if (file->Offset >= file->Size) { *bytesRead = 0; return STATUS_SUCCESS; }
@@ -98,16 +98,16 @@ KSTATUS IoReadFile(FILE_OBJECT* file, void* buf, size_t size, size_t* bytesRead)
}
// ---------------------------------------------------------------------------
KSTATUS IoSeekFile(FILE_OBJECT* file, uint64_t offset) {
__declspec(dllexport) KSTATUS IoSeekFile(FILE_OBJECT* file, uint64_t offset) {
if (!file) return STATUS_INVALID_PARAMETER;
file->Offset = offset;
return STATUS_SUCCESS;
}
uint64_t IoGetFileSize(FILE_OBJECT* file) {
__declspec(dllexport) uint64_t IoGetFileSize(FILE_OBJECT* file) {
return file ? file->Size : 0;
}
void IoCloseFile(FILE_OBJECT* file) {
__declspec(dllexport) void IoCloseFile(FILE_OBJECT* file) {
if (file) ObDereferenceObject(&file->Header);
}
+6 -6
View File
@@ -53,14 +53,14 @@ typedef struct IO_VOLUME_PARAMS {
// Registration - called by fat32.sys from DriverEntry
// ---------------------------------------------------------------------------
// driveIndex matches the index passed to IoRegisterDisk.
KSTATUS IoRegisterFilesystem(uint8_t driveIndex, IO_FILESYSTEM* fs, const IO_VOLUME_PARAMS *vol);
__declspec(dllexport) KSTATUS IoRegisterFilesystem(uint8_t driveIndex, IO_FILESYSTEM* fs, const IO_VOLUME_PARAMS *vol);
// ---------------------------------------------------------------------------
// Kernel-side API
// ---------------------------------------------------------------------------
KSTATUS IoOpenFile(const char* path, FILE_OBJECT **out);
KSTATUS IoReadFile(FILE_OBJECT* file, void* buf,
__declspec(dllexport) KSTATUS IoOpenFile(const char* path, FILE_OBJECT **out);
__declspec(dllexport) KSTATUS IoReadFile(FILE_OBJECT* file, void* buf,
size_t size, size_t* bytesRead);
KSTATUS IoSeekFile(FILE_OBJECT* file, uint64_t offset);
uint64_t IoGetFileSize(FILE_OBJECT* file);
void IoCloseFile(FILE_OBJECT* file);
__declspec(dllexport) KSTATUS IoSeekFile(FILE_OBJECT* file, uint64_t offset);
__declspec(dllexport) uint64_t IoGetFileSize(FILE_OBJECT* file);
__declspec(dllexport) void IoCloseFile(FILE_OBJECT* file);
+1 -1
View File
@@ -14,7 +14,7 @@ void kernel_putchar(char c) {
PrintChar(c, 0x00FF00, 0x000000);
}
void DbgPrint(const char* fmt, ...) {
__declspec(dllexport) void DbgPrint(const char* fmt, ...) {
if (!gDebugEnabled) return;
static SPINLOCK sl = {0};
+1 -1
View File
@@ -4,6 +4,6 @@
#include <stdint.h>
void KeInitDebug(void (*PrintPtr)(char, uint32_t, uint32_t), int v);
void DbgPrint(const char* fmt, ...);
__declspec(dllexport) void DbgPrint(const char* fmt, ...);
#endif // KE_DEBUG_H
+4 -4
View File
@@ -7,7 +7,7 @@
static void EventDestroy(OBJECT* obj) { (void)obj; }
KSTATUS KeEventCreate(EVENT_TYPE type, uint32_t initialState, EVENT **out) {
__declspec(dllexport) KSTATUS KeEventCreate(EVENT_TYPE type, uint32_t initialState, EVENT **out) {
if (!out) return STATUS_INVALID_PARAMETER;
EVENT* e = (EVENT *)ObAllocateObject(ObjectTypeEvent, sizeof(EVENT));
if (!e) return STATUS_NO_MEMORY;
@@ -20,7 +20,7 @@ KSTATUS KeEventCreate(EVENT_TYPE type, uint32_t initialState, EVENT **out) {
return STATUS_SUCCESS;
}
void KeSignalEvent(EVENT* event) {
__declspec(dllexport) void KeSignalEvent(EVENT* event) {
if (!event) return;
uintptr_t flags = KeAcquireSpinlock(&event->Lock);
@@ -46,14 +46,14 @@ void KeSignalEvent(EVENT* event) {
KeReleaseSpinlock(&event->Lock, flags);
}
void KeClearEvent(EVENT* event) {
__declspec(dllexport) void KeClearEvent(EVENT* event) {
if (!event) return;
uintptr_t flags = KeAcquireSpinlock(&event->Lock);
event->Signaled = 0;
KeReleaseSpinlock(&event->Lock, flags);
}
KSTATUS KeWaitForEvent(EVENT* event) {
__declspec(dllexport) KSTATUS KeWaitForEvent(EVENT* event) {
if (!event) return STATUS_INVALID_PARAMETER;
THREAD* self = KeCurrentThread();
+4 -4
View File
@@ -16,7 +16,7 @@ typedef struct EVENT {
LIST_ENTRY WaitList;
} EVENT;
KSTATUS KeEventCreate(EVENT_TYPE type, uint32_t initialState, EVENT **out);
void KeSignalEvent(EVENT* event);
void KeClearEvent(EVENT* event);
KSTATUS KeWaitForEvent(EVENT* event);
__declspec(dllexport) KSTATUS KeEventCreate(EVENT_TYPE type, uint32_t initialState, EVENT **out);
__declspec(dllexport) void KeSignalEvent(EVENT* event);
__declspec(dllexport) void KeClearEvent(EVENT* event);
__declspec(dllexport) KSTATUS KeWaitForEvent(EVENT* event);
+7 -7
View File
@@ -1,7 +1,7 @@
// ke_irp.c - I/O Request Packet dispatch and queue helpers
//
// This file lives in the kernel layer and is the ONLY place that bridges the
// IRP abstraction to kernel sync objects. All calls to KeEventCreate,
// IRP abstraction to kernel sync objects. All calls to KeEventCreate,
// KeSignalEvent, KeWaitForEvent, KeSignalSemaphore, and ObDereferenceObject
// are confined here; hal_disk.c and io_driver.h remain free of those symbols.
//
@@ -26,13 +26,13 @@
// ke_irp.h can avoid including ke_semaphore.h, keeping the header safe
// for inclusion from the HAL layer.
void IrpQueueInit(IRP_QUEUE *q, struct SEMAPHORE *sem) {
__declspec(dllexport) void IrpQueueInit(IRP_QUEUE *q, struct SEMAPHORE *sem) {
q->Lock = (SPINLOCK)SPINLOCK_INIT;
q->Semaphore = sem;
LIST_INIT(&q->Head);
}
void IrpQueueEnqueue(IRP_QUEUE *q, IRP *irp) {
__declspec(dllexport) void IrpQueueEnqueue(IRP_QUEUE *q, IRP *irp) {
uintptr_t flags = KeAcquireSpinlock(&q->Lock);
if (irp->Flags & IRP_FLAG_PRIORITY)
ListInsertHead(&q->Head, &irp->Link);
@@ -43,7 +43,7 @@ void IrpQueueEnqueue(IRP_QUEUE *q, IRP *irp) {
KeSignalSemaphore((SEMAPHORE *)q->Semaphore);
}
IRP *IrpQueueDequeue(IRP_QUEUE *q) {
__declspec(dllexport) IRP *IrpQueueDequeue(IRP_QUEUE *q) {
uintptr_t flags = KeAcquireSpinlock(&q->Lock);
LIST_ENTRY *node = ListPopHead(&q->Head);
KeReleaseSpinlock(&q->Lock, flags);
@@ -58,7 +58,7 @@ IRP *IrpQueueDequeue(IRP_QUEUE *q) {
// If the dispatch ran inline (sync fallback), we fire the completion hooks
// here in the kernel layer where we can legally call KeSignalEvent.
KSTATUS IoSubmitIrp(IRP *irp) {
__declspec(dllexport) KSTATUS IoSubmitIrp(IRP *irp) {
if (!irp) return STATUS_INVALID_PARAMETER;
KSTATUS st = HalDiskDispatch(irp->DriveIndex, irp);
@@ -84,10 +84,10 @@ KSTATUS IoSubmitIrp(IRP *irp) {
// IoSubmitIrpSync
// -------------------------------------------------------------------------
// Creates a stack-allocated auto-reset event, attaches it to the IRP,
// submits, and blocks. Callers that already provided a CompletionEvent
// submits, and blocks. Callers that already provided a CompletionEvent
// should use IoSubmitIrp() directly and wait on their own event instead.
KSTATUS IoSubmitIrpSync(IRP *irp) {
__declspec(dllexport) KSTATUS IoSubmitIrpSync(IRP *irp) {
if (!irp) return STATUS_INVALID_PARAMETER;
EVENT *ev = (EVENT *)0;
+8 -8
View File
@@ -3,7 +3,7 @@
//
// This header intentionally includes only ke_list.h, ke_spinlock.h, and
// ke_status.h — all of which are pure-inline / macro headers with no
// external symbol references. ke_event.h and ke_semaphore.h are forward-
// external symbol references. ke_event.h and ke_semaphore.h are forward-
// declared here so the HAL layer (hal_disk.c, io_driver.h) can include this
// header without dragging in kernel sync-object link dependencies.
//
@@ -80,16 +80,16 @@ typedef struct IRP_QUEUE {
} IRP_QUEUE;
// Non-inline: defined in ke_irp.c, which can pull in ke_semaphore.h safely.
void IrpQueueInit (IRP_QUEUE *q, struct SEMAPHORE *sem);
void IrpQueueEnqueue (IRP_QUEUE *q, IRP *irp);
IRP *IrpQueueDequeue (IRP_QUEUE *q);
__declspec(dllexport) void IrpQueueInit (IRP_QUEUE *q, struct SEMAPHORE *sem);
__declspec(dllexport) void IrpQueueEnqueue (IRP_QUEUE *q, IRP *irp);
__declspec(dllexport) IRP *IrpQueueDequeue (IRP_QUEUE *q);
// -------------------------------------------------------------------------
// Public dispatch API — implemented in kernel/ke_irp.c
// -------------------------------------------------------------------------
// Submit asynchronously. Returns STATUS_PENDING on success.
KSTATUS IoSubmitIrp (IRP *irp);
// Submit asynchronously. Returns STATUS_PENDING on success.
__declspec(dllexport) KSTATUS IoSubmitIrp (IRP *irp);
// Submit and block until complete. Returns irp->Status.
KSTATUS IoSubmitIrpSync(IRP *irp);
// Submit and block until complete. Returns irp->Status.
__declspec(dllexport) KSTATUS IoSubmitIrpSync(IRP *irp);
+1 -1
View File
@@ -11,7 +11,7 @@ void KeIrqInitialize(const HAL_API *hal) {
gHal = hal;
}
void KeIrqRegister(uint8_t irq, void (*handler)(void)) {
__declspec(dllexport) void KeIrqRegister(uint8_t irq, void (*handler)(void)) {
if (irq >= MAX_IRQS || !handler) return;
gIrqHandlers[irq] = handler;
gHal->Intc.RouteIrq(irq);
+1 -1
View File
@@ -3,5 +3,5 @@
#include <hal_api.h>
void KeIrqInitialize(const HAL_API *hal);
void KeIrqRegister(uint8_t irq, void (*handler)(void));
__declspec(dllexport) void KeIrqRegister(uint8_t irq, void (*handler)(void));
void KeIrqDispatch(uint8_t irq); // called from ke_syscall.asm
+1 -1
View File
@@ -152,7 +152,7 @@ void KeSchedulerTick(void) {
KeSchedulerPostSwitch();
}
void KeYield(void) {
__declspec(dllexport) void KeYield(void) {
THREAD* cur = gCurrentThread;
if (!cur) return;
+5 -5
View File
@@ -1,9 +1,9 @@
#pragma once
// ke_sched.h - Multi-Level Feedback Queue scheduler
// Three run queues (Low / Normal / High). IRQ 0 drives KeSchedulerTick.
// Three run queues (Low / Normal / High). IRQ 0 drives KeSchedulerTick.
#include <ke_thread.h>
#define QUANTUM_MS 10 /* base time slice in milliseconds */
#define QUANTUM_MS 10 // base time slice in milliseconds
// Called once by KernelMain before any threads are created.
void KeInitializeScheduler(void);
@@ -15,11 +15,11 @@ void KeUnreadyThread(THREAD* thread);
// Called from the timer ISR every QUANTUM_MS.
void KeSchedulerTick(void);
// Voluntarily yield the CPU. Picks the next runnable thread immediately.
void KeYield(void);
// Voluntarily yield the CPU. Picks the next runnable thread immediately.
__declspec(dllexport) void KeYield(void);
// Returns the thread currently running on this CPU (reads GS:[0]).
THREAD* KeCurrentThread(void);
// Set the current-thread GS slot. Called once per CPU at boot.
// Set the current-thread GS slot. Called once per CPU at boot.
void KeSetCurrentThread(THREAD* thread);
+4 -4
View File
@@ -7,7 +7,7 @@
static void SemDestroy(OBJECT* obj) { (void)obj; }
KSTATUS SemaphoreCreate(int32_t initial, int32_t max, SEMAPHORE **out) {
__declspec(dllexport) KSTATUS KeSemaphoreCreate(int32_t initial, int32_t max, SEMAPHORE **out) {
if (!out || initial < 0 || max < 1 || initial > max)
return STATUS_INVALID_PARAMETER;
SEMAPHORE* s = (SEMAPHORE *)ObAllocateObject(ObjectTypeSemaphore, sizeof(SEMAPHORE));
@@ -21,7 +21,7 @@ KSTATUS SemaphoreCreate(int32_t initial, int32_t max, SEMAPHORE **out) {
return STATUS_SUCCESS;
}
KSTATUS KeWaitSemaphore(SEMAPHORE* sem) {
__declspec(dllexport) KSTATUS KeWaitSemaphore(SEMAPHORE* sem) {
if (!sem) return STATUS_INVALID_PARAMETER;
THREAD* self = KeCurrentThread();
@@ -38,7 +38,7 @@ KSTATUS KeWaitSemaphore(SEMAPHORE* sem) {
}
}
KSTATUS KeTrySemaphore(SEMAPHORE* sem) {
__declspec(dllexport) KSTATUS KeTrySemaphore(SEMAPHORE* sem) {
if (!sem) return STATUS_INVALID_PARAMETER;
uintptr_t flags = KeAcquireSpinlock(&sem->Lock);
if (sem->Count > 0) {
@@ -50,7 +50,7 @@ KSTATUS KeTrySemaphore(SEMAPHORE* sem) {
return STATUS_FAILURE;
}
void KeSignalSemaphore(SEMAPHORE* sem) {
__declspec(dllexport) void KeSignalSemaphore(SEMAPHORE* sem) {
if (!sem) return;
uintptr_t flags = KeAcquireSpinlock(&sem->Lock);
if (!LIST_IS_EMPTY(&sem->WaitList)) {
+4 -4
View File
@@ -14,7 +14,7 @@ typedef struct SEMAPHORE {
LIST_ENTRY WaitList;
} SEMAPHORE;
KSTATUS SemaphoreCreate(int32_t initial, int32_t max, SEMAPHORE **out);
KSTATUS KeWaitSemaphore(SEMAPHORE* semaphore);
KSTATUS KeTrySemaphore(SEMAPHORE* semaphore);
void KeSignalSemaphore(SEMAPHORE* semaphore);
__declspec(dllexport) KSTATUS KeSemaphoreCreate(int32_t initial, int32_t max, SEMAPHORE **out);
__declspec(dllexport) KSTATUS KeWaitSemaphore(SEMAPHORE* semaphore);
__declspec(dllexport) KSTATUS KeTrySemaphore(SEMAPHORE* semaphore);
__declspec(dllexport) void KeSignalSemaphore(SEMAPHORE* semaphore);
+2 -2
View File
@@ -89,7 +89,7 @@ KeThreadEntry ENDP
; -------------------------------------------------------------------------
; KeKernelThreadEntry - landing pad for kernel-mode threads created by
; KeCreateKernelThread. Never touches ring 3; no IRETQ.
; KeCreateKernelThread. Never touches ring 3; no IRETQ.
;
; Stack layout when we arrive here (above the KCONTEXT already popped by
; KeSwitchContext's ret):
@@ -97,7 +97,7 @@ KeThreadEntry ENDP
; [rsp+08] arg ptr
;
; We pop both into non-volatile registers so KeSchedulerPostSwitch can
; clobber volatile ones freely, then call fn(arg). On return we call
; clobber volatile ones freely, then call fn(arg). On return we call
; KeExitThread so the thread is cleanly destroyed.
; -------------------------------------------------------------------------
KeKernelThreadEntry PROC
+1 -1
View File
@@ -37,7 +37,7 @@ KeSyscallEntry PROC
KeSyscallEntry ENDP
; ---------------------------------------------------------------------------
; Fault stubs - print a message and halt. A real kernel would do a bugcheck.
; Fault stubs - print a message and halt. A real kernel would do a bugcheck.
; ---------------------------------------------------------------------------
EXTERN DbgPrint:PROC
+4 -4
View File
@@ -26,7 +26,7 @@
// -> obj->Destroy(obj) [type-specific cleanup, e.g. FileDestroy]
// -> MmFreePool(obj)
//
// There is no separate SyscallCloseFile. Removing that stub was the right
// There is no separate SyscallCloseFile. Removing that stub was the right
// call: the object model already handled it; the dedicated syscall was only
// adding a footgun where callers could bypass the unified refcount path.
@@ -288,7 +288,7 @@ static uint64_t SyscallSemCreate(uint64_t a0, uint64_t a1, uint64_t a2,
(void)a3; (void)a4; (void)a5;
if (!a2) return STATUS_INVALID_PARAMETER;
SEMAPHORE* sem = NULL;
KSTATUS s = SemaphoreCreate((int32_t)a0, (int32_t)a1, &sem);
KSTATUS s = KeSemaphoreCreate((int32_t)a0, (int32_t)a1, &sem);
if (!KSUCCESS(s)) return s;
uint32_t h = 0;
s = AllocHandleForCurrent(&sem->Header, &h);
@@ -440,8 +440,8 @@ static uint64_t SyscallQueueRecv(uint64_t a0, uint64_t a1, uint64_t a2,
// ---------------------------------------------------------------------------
// SYS_CLOSE_HANDLE (26) a0 = handle
//
// The one and only close path. KeCloseHandle drops the handle-table reference
// on 'obj'. If that was the last reference, ObDereferenceObject runs the
// The one and only close path. KeCloseHandle drops the handle-table reference
// on 'obj'. If that was the last reference, ObDereferenceObject runs the
// type-specific Destroy callback (FileDestroy, etc.) and frees the pool memory.
// No per-type close syscall needed or wanted.
// ---------------------------------------------------------------------------
+4 -4
View File
@@ -33,7 +33,7 @@ static void ThreadDestroy(OBJECT* obj) {
}
}
KSTATUS KeCreateThread(PROCESS* owner, uintptr_t entry, uintptr_t arg,
__declspec(dllexport) KSTATUS KeCreateThread(PROCESS* owner, uintptr_t entry, uintptr_t arg,
THREAD_PRIORITY priority, THREAD **out) {
if (!owner || !out) return STATUS_INVALID_PARAMETER;
if (priority >= PriorityCount) return STATUS_INVALID_PARAMETER;
@@ -110,7 +110,7 @@ KSTATUS KeCreateThread(PROCESS* owner, uintptr_t entry, uintptr_t arg,
return STATUS_SUCCESS;
}
void KeExitThread(THREAD* thread, int code) {
__declspec(dllexport) void KeExitThread(THREAD* thread, int code) {
(void)code;
if (!thread) return;
@@ -133,9 +133,9 @@ void KeExitThread(THREAD* thread, int code) {
// ---------------------------------------------------------------------------
extern void KeKernelThreadEntry(void);
KSTATUS KeCreateKernelThread(uintptr_t fn, uintptr_t arg,
__declspec(dllexport) KSTATUS KeCreateKernelThread(uintptr_t fn, uintptr_t arg,
THREAD_PRIORITY priority, THREAD **out) {
// Kernel threads are owned by the idle process. We need a PROCESS* for
// Kernel threads are owned by the idle process. We need a PROCESS* for
// the owner field; grab it from the idle/init thread that already exists.
THREAD* idleThread = KeCurrentThread(); // safe to call before scheduler starts
PROCESS* owner = idleThread ? idleThread->Owner : (PROCESS*)0;
+6 -6
View File
@@ -69,18 +69,18 @@ typedef struct THREAD {
void* UserStackBase; // Tracks user stack allocation to prevent memory leaks
} THREAD;
KSTATUS KeCreateThread(PROCESS* owner, uintptr_t entry, uintptr_t arg,
__declspec(dllexport) KSTATUS KeCreateThread(PROCESS* owner, uintptr_t entry, uintptr_t arg,
THREAD_PRIORITY priority, THREAD **out);
// Create a kernel-mode-only thread. fn is called directly in ring 0 with
// arg; when fn returns the thread exits automatically. No user stack or TEB
// is allocated. The thread is owned by the idle process and runs at the
// Create a kernel-mode-only thread. fn is called directly in ring 0 with
// arg; when fn returns the thread exits automatically. No user stack or TEB
// is allocated. The thread is owned by the idle process and runs at the
// given priority.
KSTATUS KeCreateKernelThread(uintptr_t fn, uintptr_t arg,
__declspec(dllexport) KSTATUS KeCreateKernelThread(uintptr_t fn, uintptr_t arg,
THREAD_PRIORITY priority, THREAD **out);
// Mark a thread dead and deschedule it permanently.
void KeExitThread(THREAD* thread, int code);
__declspec(dllexport) void KeExitThread(THREAD* thread, int code);
// Block / unblock primitives used by sync objects.
void KeBlockThread(THREAD* thread, OBJECT* waitObject);
+2 -2
View File
@@ -1,7 +1,7 @@
// mm_phys.c - physical memory manager
//
// The free-frame stack is a flat array of PHYSICAL_ADDRESS values carved out of
// the first suitable usable region before any allocation is served. All access
// the first suitable usable region before any allocation is served. All access
// to physical memory goes through the direct physical window established by the
// bootloader at PhysicalWindowBase (always 0xFFFF880000000000).
//
@@ -124,7 +124,7 @@ void MmFreeFrame(PHYSICAL_ADDRESS frame) {
KeReleaseSpinlock(&gFrameStack.Lock, flags);
}
PHYSICAL_ADDRESS MmAllocateContiguous(size_t count) {
__declspec(dllexport) PHYSICAL_ADDRESS MmAllocateContiguous(size_t count) {
if (!count) return (PHYSICAL_ADDRESS)0;
uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock);
+2 -2
View File
@@ -20,8 +20,8 @@ PHYSICAL_ADDRESS MmAllocateFrame(void);
void MmFreeFrame(PHYSICAL_ADDRESS frame);
// Allocate 'count' physically contiguous 4 KB frames.
// Returns 0 on failure. Use sparingly (DMA, page tables).
PHYSICAL_ADDRESS MmAllocateContiguous(size_t count);
// Returns 0 on failure. Use sparingly (DMA, page tables).
__declspec(dllexport) PHYSICAL_ADDRESS MmAllocateContiguous(size_t count);
size_t MmFreeFrameCount(void);
size_t MmTotalFrameCount(void);
+12 -12
View File
@@ -11,7 +11,7 @@
//
// User heap:
// A single best-fit free list in the lower half.
// Backed on demand from the PMM. No per-process heaps.
// Backed on demand from the PMM. No per-process heaps.
#include <stddef.h>
#include <string.h>
#include <mm_virt.h>
@@ -60,7 +60,7 @@ static PHYSICAL_ADDRESS EnsureTable(PHYSICAL_ADDRESS parentPhys,
// ---------------------------------------------------------------------------
// Public mapping
// ---------------------------------------------------------------------------
KSTATUS MmMapPage(uintptr_t virt, PHYSICAL_ADDRESS phys, uint64_t flags) {
__declspec(dllexport) KSTATUS MmMapPage(uintptr_t virt, PHYSICAL_ADDRESS phys, uint64_t flags) {
unsigned userFlag = (flags & PAGE_USER) ? PAGE_USER : 0;
PHYSICAL_ADDRESS pdpt = EnsureTable(gPml4Phys, PML4_IDX(virt), userFlag);
@@ -76,7 +76,7 @@ KSTATUS MmMapPage(uintptr_t virt, PHYSICAL_ADDRESS phys, uint64_t flags) {
return STATUS_SUCCESS;
}
KSTATUS MmUnmapPage(uintptr_t virt) {
__declspec(dllexport) KSTATUS MmUnmapPage(uintptr_t virt) {
uint64_t* e4 = PtePtr(gPml4Phys, PML4_IDX(virt));
if (!(*e4 & PAGE_PRESENT)) return STATUS_NOT_FOUND;
uint64_t* e3 = PtePtr(*e4 & ~0xFFFULL, PDPT_IDX(virt));
@@ -89,7 +89,7 @@ KSTATUS MmUnmapPage(uintptr_t virt) {
return STATUS_SUCCESS;
}
KSTATUS MmSetPageProtect(uintptr_t virt, size_t size, uint64_t flags) {
__declspec(dllexport) KSTATUS MmSetPageProtect(uintptr_t virt, size_t size, uint64_t flags) {
if (!size) return STATUS_SUCCESS;
// Round down to page boundary, round size up.
@@ -115,7 +115,7 @@ KSTATUS MmSetPageProtect(uintptr_t virt, size_t size, uint64_t flags) {
return STATUS_SUCCESS;
}
PHYSICAL_ADDRESS MmGetPhysicalAddress(uintptr_t virt) {
__declspec(dllexport) PHYSICAL_ADDRESS MmGetPhysicalAddress(uintptr_t virt) {
if (!gPml4Phys) return 0; // Not initialized
uint64_t pml4_idx = (virt >> 39) & 0x1FF;
@@ -153,7 +153,7 @@ PHYSICAL_ADDRESS MmGetPhysicalAddress(uintptr_t virt) {
// Boundary-tag allocator (used for both pool and user heap)
// ---------------------------------------------------------------------------
// Each allocation has a BLOCK_HDR immediately before the user data, and a
// BLOCK_FTR immediately after. Both carry the block size and a 'free' flag.
// BLOCK_FTR immediately after. Both carry the block size and a 'free' flag.
// This allows O(1) coalescing of adjacent free blocks.
#define BLOCK_MAGIC 0xB10CB10CUL
@@ -433,16 +433,16 @@ void MmActivate(void) {
// ---------------------------------------------------------------------------
// Public pool API
// ---------------------------------------------------------------------------
void* MmAllocatePool(size_t size) { return HeapAlloc(&gPoolHeap, size); }
void MmFreePool(void* ptr) { HeapFree(&gPoolHeap, ptr); }
void* MmReallocatePool(void* ptr, size_t newSize) { return HeapRealloc(&gPoolHeap, ptr, newSize); }
__declspec(dllexport) void* MmAllocatePool(size_t size) { return HeapAlloc(&gPoolHeap, size); }
__declspec(dllexport) void MmFreePool(void* ptr) { HeapFree(&gPoolHeap, ptr); }
__declspec(dllexport) void* MmReallocatePool(void* ptr, size_t newSize) { return HeapRealloc(&gPoolHeap, ptr, newSize); }
// ---------------------------------------------------------------------------
// Public user heap API
// ---------------------------------------------------------------------------
void* MmAllocateUserMemory(size_t size) { return HeapAlloc(&gUserHeap, size); }
void MmFreeUserMemory(void* ptr, size_t size) { (void)size; HeapFree(&gUserHeap, ptr); }
void* MmReallocateUserMemory(void* ptr, size_t newSize) { return HeapRealloc(&gUserHeap, ptr, newSize); }
__declspec(dllexport) void* MmAllocateUserMemory(size_t size) { return HeapAlloc(&gUserHeap, size); }
__declspec(dllexport) void MmFreeUserMemory(void* ptr, size_t size) { (void)size; HeapFree(&gUserHeap, ptr); }
__declspec(dllexport) void* MmReallocateUserMemory(void* ptr, size_t newSize) { return HeapRealloc(&gUserHeap, ptr, newSize); }
size_t MmGetKernelPoolUsage(void) {
// Returns bytes committed to the kernel pool
+10 -10
View File
@@ -40,34 +40,34 @@ void MmActivate(void);
// ---------------------------------------------------------------------------
// Page mapping
// ---------------------------------------------------------------------------
KSTATUS MmMapPage(uintptr_t virt, PHYSICAL_ADDRESS phys, uint64_t flags);
KSTATUS MmUnmapPage(uintptr_t virt);
__declspec(dllexport) KSTATUS MmMapPage(uintptr_t virt, PHYSICAL_ADDRESS phys, uint64_t flags);
__declspec(dllexport) KSTATUS MmUnmapPage(uintptr_t virt);
// Modify protection flags on an already-mapped virtual range.
// 'flags' is the complete new set of PAGE_* bits - it replaces the old flags
// entirely (except the physical address, which is preserved).
// Returns STATUS_NOT_FOUND if any page in the range is not mapped.
KSTATUS MmSetPageProtect(uintptr_t virt, size_t size, uint64_t flags);
__declspec(dllexport) KSTATUS MmSetPageProtect(uintptr_t virt, size_t size, uint64_t flags);
// Walk the page tables to translate a virtual address to physical.
// Returns 0 if the address is not mapped.
PHYSICAL_ADDRESS MmGetPhysicalAddress(uintptr_t virt);
__declspec(dllexport) PHYSICAL_ADDRESS MmGetPhysicalAddress(uintptr_t virt);
// ---------------------------------------------------------------------------
// Kernel pool - ring 0 only, never PAGE_USER.
// Best-fit free-list allocator, thread-safe via spinlock.
// ---------------------------------------------------------------------------
void* MmAllocatePool(size_t size);
void MmFreePool(void* ptr);
void* MmReallocatePool(void* ptr, size_t newSize);
__declspec(dllexport) void* MmAllocatePool(size_t size);
__declspec(dllexport) void MmFreePool(void* ptr);
__declspec(dllexport) void* MmReallocatePool(void* ptr, size_t newSize);
// ---------------------------------------------------------------------------
// User heap - shared flat space, ring 3 accessible.
// All allocations are PAGE_PRESENT | PAGE_WRITE | PAGE_USER.
// ---------------------------------------------------------------------------
void* MmAllocateUserMemory(size_t size);
void MmFreeUserMemory(void* ptr, size_t size);
void* MmReallocateUserMemory(void* ptr, size_t newSize);
__declspec(dllexport) void* MmAllocateUserMemory(size_t size);
__declspec(dllexport) void MmFreeUserMemory(void* ptr, size_t size);
__declspec(dllexport) void* MmReallocateUserMemory(void* ptr, size_t newSize);
size_t MmGetKernelPoolUsage(void);
size_t MmGetUserHeapUsage(void);
+3 -3
View File
@@ -11,10 +11,10 @@
//
// Handle semantics:
// Every kernel object (file, mutex, semaphore, event, queue) is reference-
// counted. SYS_CLOSE_HANDLE is the ONE way to close any handle regardless
// of the object type behind it. KeCloseHandle calls ObDereferenceObject,
// counted. SYS_CLOSE_HANDLE is the ONE way to close any handle regardless
// of the object type behind it. KeCloseHandle calls ObDereferenceObject,
// which fires the type-specific Destroy callback (e.g. FileDestroy)
// automatically when the refcount reaches zero. There is no separate
// automatically when the refcount reaches zero. There is no separate
// SYS_CLOSE_FILE - that was redundant.
// ---------------------------------------------------------------------------
+1 -1
View File
@@ -118,7 +118,7 @@ static char* trim(char* s) {
}
// ---------------------------------------------------------------------------
// Run one command. Returns 1 if the shell should exit.
// Run one command. Returns 1 if the shell should exit.
// ---------------------------------------------------------------------------
static int runCommand(const char* cmd) {
if (!cmd || *cmd == '\0')
+1 -1
View File
@@ -173,7 +173,7 @@ typedef struct BINKSND {
// will do it's own threading)
// 2 = No background thread processing at all, but setup
// thread mutexes, so that BinkServiceSound() can be
// call from an external background thread.
// call from an external background thread.
U32 SoundDroppedOut;
U32 sndconvert8; // convert back to 8-bit sound at runtime
+2 -2
View File
@@ -1,5 +1,5 @@
/// ========================================================================
// (C) Copyright 1994- 2014 RAD Game Tools, Inc. Global types header file
// (C) Copyright 1994- 2014 RAD Game Tools, Inc. Global types header file
// ========================================================================
#ifndef __RADRR_COREH__
@@ -648,7 +648,7 @@
!defined(__RADPSP__) && !defined(__RADPSP2__) && !defined(__RADPS3__) && !defined(__RADSPU__) && \
!defined(__RADWII__) && !defined(__RADIPHONE__) && !defined(__RADX32__) && !defined(__RADARM__) && \
!defined(__RADWIIU__) && !defined(__RADANDROID__) && !defined(__RADNACL__) && !defined (__RADQNX__) )
#error "RAD.H did not detect your platform. Define DOS, WINDOWS, WIN32, macintosh, powerpc, or appropriate console."
#error "RAD.H did not detect your platform. Define DOS, WINDOWS, WIN32, macintosh, powerpc, or appropriate console."
#endif
+3 -3
View File
@@ -9,9 +9,9 @@
// 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 kernel user-heap. This is fine: we don't expose
// multiple heaps, and NULL is a legal (no-op) heap argument under Win32.
// - GetLastError / SetLastError are per-thread on Windows. We keep a single
// - GetLastError / SetLastError are per-thread on Windows. We keep a single
// global for now; enough for Bink and similar single-threaded guests.
// - File I/O uses SYS_OPEN_FILE / SYS_READ_FILE / SYS_SEEK_FILE /
// SYS_GET_FILE_SIZE / SYS_CLOSE_HANDLE (unified close path - no separate
@@ -342,7 +342,7 @@ __declspec(dllexport) DWORD GetCurrentThreadId(void) { return (DWORD)SysGetCurr
__declspec(dllexport) DWORD GetCurrentProcessId(void) { return (DWORD)SysGetCurrentPid(); }
// GetModuleHandleA/W – no PE map; return NULL so callers that check can fail
// gracefully. GetModuleHandleA(NULL) on Windows returns the exe base; we
// gracefully. GetModuleHandleA(NULL) on Windows returns the exe base; we
// return a recognisable non-NULL sentinel so code that just passes it to
// GetProcAddress doesn't immediately crash.
__declspec(dllexport) HANDLE GetModuleHandleA(const char* lpModuleName) {
+1 -1
View File
@@ -23,7 +23,7 @@ typedef void* HWND;
// ---------------------------------------------------------------------------
// GetAsyncKeyState: returns non-zero if a key is available in the input
// buffer. We have no per-key state, so the vKey argument is ignored and
// buffer. We have no per-key state, so the vKey argument is ignored and
// the high bit (key-down) is set whenever SysKbPoll reports data waiting.
__declspec(dllexport) short GetAsyncKeyState(int vKey) {
(void)vKey;
+1 -1
View File
@@ -52,7 +52,7 @@ typedef struct {
// ---------------------------------------------------------------------------
// timeGetTime is the lightweight alternative to GetTickCount; both return
// milliseconds since system start. We forward to the kernel tick counter.
// milliseconds since system start. We forward to the kernel tick counter.
extern uint64_t SysGetTick(void);
__declspec(dllexport) unsigned long timeGetTime(void) {
+4 -4
View File
@@ -4,9 +4,9 @@ Boots. Runs processes. Mimics Windows to some extent.
## what is it?
A 64-bit operating system kernel written from scratch.
UEFI bootloader, physical and virtual memory managers, preemptive scheduler, HAL, VFS, PE loader, partial Win32 layer.
It boots into a shell.
A 64-bit operating system kernel written from scratch.
UEFI bootloader, physical and virtual memory managers, preemptive scheduler, HAL, VFS, PE loader, partial Win32 layer.
It boots into a shell.
~20k lines of C and assembly.
## features
@@ -39,7 +39,7 @@ drivers are PE32+ `.sys` files with an entry point preferably named DriverEntry
drivers to be loaded have their path stored in `drivers.ini`, split into essential for boot (loaded by bootloader) and not required for boot (loaded by kernel).
a disk driver fills in a `DISK_DRIVER` vtable and calls `IoRegisterDisk(index, &driver)`.
a disk driver fills in a `DISK_DRIVER` vtable and calls `IoRegisterDisk(index, &driver)`.
a filesystem driver fills in an `IO_FILESYSTEM` vtable and calls `IoRegisterFilesystem(index, &fs, &vol)`.
## how it boots