colonel.exe 🤑, refactor all include directives, AHCI is now interrupt driven, upgrades to IDE, implemented I/O Request Packets, fix numerous keyboard issues, change all for (;;) and while (1) to while (true), DbgPrint guarded by spinlock, fix KeSignalEvent, major KernelMain refactor, added SystemInitThread because of new blocking I/O, replace memcpy manouvers with strncpy and strncat, add: run for ide, runa for ahci, rund for debug and ide, runad for debug and ahci.
This commit is contained in:
1 parent
7f4052f41c
commit
9fa2a7e0db
61 files changed
+1311
-456
No files matched your search
@@ -2,7 +2,7 @@
|
||||
// boot_info.h - shared between bootx64.efi and kernel.exe
|
||||
// The bootloader fills this structure and passes a pointer to KernelMain.
|
||||
#include <stdint.h>
|
||||
#include "memory_map.h"
|
||||
#include <memory_map.h>
|
||||
|
||||
#define BOOT_INFO_MAGIC 0x424F4F54494E464FULL /* 'BOOTINFO' */
|
||||
#define MAX_BOOT_MODULES 32
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// io_file.c - VFS dispatch layer
|
||||
#include "ke_list.h"
|
||||
#include "io_file.h"
|
||||
#include "mm_virt.h"
|
||||
#include "ob_object.h"
|
||||
#include <string.h>
|
||||
#include <ke_list.h>
|
||||
#include <io_file.h>
|
||||
#include <mm_virt.h>
|
||||
#include <ob_object.h>
|
||||
|
||||
#define MAX_DRIVES 8
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
// io_file.h - VFS layer
|
||||
// Filesystem drivers register an IO_FILESYSTEM vtable via IoRegisterFilesystem.
|
||||
// Kernel and user code open files through IoOpenFile.
|
||||
#include "ke_status.h"
|
||||
#include "ob_object.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <ke_status.h>
|
||||
#include <ob_object.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Filesystem driver vtable - filled in by fat32.sys (or any future fs driver)
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// ke_debug.c - debugging utilities
|
||||
#include "hal_api.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "printf.h"
|
||||
#include <hal_api.h>
|
||||
#include <ke_spinlock.h>
|
||||
#include <printf.h>
|
||||
int _fltused; // fuckass
|
||||
|
||||
int gDebugEnabled = 0;
|
||||
@@ -16,10 +17,13 @@ void kernel_putchar(char c) {
|
||||
void DbgPrint(const char* fmt, ...) {
|
||||
if (!gDebugEnabled) return;
|
||||
|
||||
static SPINLOCK sl = {0};
|
||||
uintptr_t flags = KeAcquireSpinlock(&sl);
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
vprintf(fmt, va);
|
||||
va_end(va);
|
||||
KeReleaseSpinlock(&sl, flags);
|
||||
}
|
||||
|
||||
void KeInitDebug(void (*PrintPtr)(char, uint32_t, uint32_t), int v) {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// ke_event.c - synchronisation events
|
||||
#include "ke_event.h"
|
||||
#include "ke_thread.h"
|
||||
#include "ke_sched.h"
|
||||
#include "ob_object.h"
|
||||
#include <stdbool.h>
|
||||
#include <ke_event.h>
|
||||
#include <ke_thread.h>
|
||||
#include <ke_sched.h>
|
||||
#include <ob_object.h>
|
||||
|
||||
static void EventDestroy(OBJECT* obj) { (void)obj; }
|
||||
|
||||
@@ -33,6 +34,7 @@ void KeSignalEvent(EVENT* event) {
|
||||
flags = KeAcquireSpinlock(&event->Lock);
|
||||
}
|
||||
} else {
|
||||
event->Signaled = 1;
|
||||
if (!LIST_IS_EMPTY(&event->WaitList)) {
|
||||
LIST_ENTRY* node = ListPopHead(&event->WaitList);
|
||||
THREAD* t = CONTAINING_RECORD(node, THREAD, SchedulerLink);
|
||||
@@ -40,7 +42,6 @@ void KeSignalEvent(EVENT* event) {
|
||||
KeUnblockThread(t);
|
||||
return;
|
||||
}
|
||||
event->Signaled = 1;
|
||||
}
|
||||
KeReleaseSpinlock(&event->Lock, flags);
|
||||
}
|
||||
@@ -56,7 +57,7 @@ KSTATUS KeWaitForEvent(EVENT* event) {
|
||||
if (!event) return STATUS_INVALID_PARAMETER;
|
||||
THREAD* self = KeCurrentThread();
|
||||
|
||||
for (;;) {
|
||||
while (true) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&event->Lock);
|
||||
if (event->Signaled) {
|
||||
if (event->Type == EventAutoReset) event->Signaled = 0;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
// ke_event.h - auto-reset and manual-reset events
|
||||
#include "ob_object.h"
|
||||
#include "ke_spinlock.h"
|
||||
#include "ke_list.h"
|
||||
#include "ke_status.h"
|
||||
#include <stdint.h>
|
||||
#include <ob_object.h>
|
||||
#include <ke_spinlock.h>
|
||||
#include <ke_list.h>
|
||||
#include <ke_status.h>
|
||||
|
||||
typedef enum EVENT_TYPE { EventAutoReset, EventManualReset } EVENT_TYPE;
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
// 0x20 ring-3 data (DPL=3) - note: 0x1B/0x23 = 0x18|3 / 0x20|3
|
||||
// 0x28 TSS low
|
||||
// 0x30 TSS high
|
||||
#include "ke_idt.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ke_idt.h>
|
||||
|
||||
// External assembly procedures
|
||||
extern void KeFlushGdt(void* pGdtr, uint16_t codeSel, uint16_t dataSel, uint16_t tssSel);
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
// 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,
|
||||
// KeSignalEvent, KeWaitForEvent, KeSignalSemaphore, and ObDereferenceObject
|
||||
// are confined here; hal_disk.c and io_driver.h remain free of those symbols.
|
||||
//
|
||||
// Dependency graph (→ = includes / calls):
|
||||
// ke_irp.c → ke_irp.h (IRP type, IRP_QUEUE, forward decls)
|
||||
// → ke_event.h (KeEventCreate, KeSignalEvent, KeWaitForEvent)
|
||||
// → ke_semaphore.h (KeSignalSemaphore)
|
||||
// → ob_object.h (ObDereferenceObject)
|
||||
// → io_driver.h (HalDiskDispatch)
|
||||
// hal_disk.c → io_driver.h only (no ke_event.h, no ke_semaphore.h)
|
||||
|
||||
#include <ke_irp.h>
|
||||
#include <ke_event.h>
|
||||
#include <ke_semaphore.h>
|
||||
#include <ob_object.h>
|
||||
#include <io_driver.h>
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// IRP_QUEUE operations
|
||||
// -------------------------------------------------------------------------
|
||||
// These are defined here (not as static inlines in ke_irp.h) so that
|
||||
// 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) {
|
||||
q->Lock = (SPINLOCK)SPINLOCK_INIT;
|
||||
q->Semaphore = sem;
|
||||
LIST_INIT(&q->Head);
|
||||
}
|
||||
|
||||
void IrpQueueEnqueue(IRP_QUEUE *q, IRP *irp) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&q->Lock);
|
||||
if (irp->Flags & IRP_FLAG_PRIORITY)
|
||||
ListInsertHead(&q->Head, &irp->Link);
|
||||
else
|
||||
ListInsertTail(&q->Head, &irp->Link);
|
||||
KeReleaseSpinlock(&q->Lock, flags);
|
||||
// Signal outside the spinlock — safe, and avoids priority-inversion risk.
|
||||
KeSignalSemaphore((SEMAPHORE *)q->Semaphore);
|
||||
}
|
||||
|
||||
IRP *IrpQueueDequeue(IRP_QUEUE *q) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&q->Lock);
|
||||
LIST_ENTRY *node = ListPopHead(&q->Head);
|
||||
KeReleaseSpinlock(&q->Lock, flags);
|
||||
if (!node) return (IRP *)0;
|
||||
return CONTAINING_RECORD(node, IRP, Link);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// IoSubmitIrp
|
||||
// -------------------------------------------------------------------------
|
||||
// Calls HalDiskDispatch() which is HAL-layer safe (no event references).
|
||||
// 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) {
|
||||
if (!irp) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS st = HalDiskDispatch(irp->DriveIndex, irp);
|
||||
|
||||
if (st == STATUS_NOT_FOUND)
|
||||
return STATUS_NOT_FOUND;
|
||||
|
||||
if (st == STATUS_SUCCESS) {
|
||||
// Sync fallback ran; irp->Status is already written.
|
||||
// Fire completion hooks now — we are in kernel context so this is safe.
|
||||
if (irp->CompletionEvent)
|
||||
KeSignalEvent((EVENT *)irp->CompletionEvent);
|
||||
if (irp->CompletionFn)
|
||||
irp->CompletionFn(irp, irp->CompletionCtx);
|
||||
}
|
||||
|
||||
// Return STATUS_PENDING in both cases so callers have a uniform contract:
|
||||
// "completion is signalled via the event/callback, not this return value."
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// IoSubmitIrpSync
|
||||
// -------------------------------------------------------------------------
|
||||
// Creates a stack-allocated auto-reset event, attaches it to the IRP,
|
||||
// submits, and blocks. Callers that already provided a CompletionEvent
|
||||
// should use IoSubmitIrp() directly and wait on their own event instead.
|
||||
|
||||
KSTATUS IoSubmitIrpSync(IRP *irp) {
|
||||
if (!irp) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
EVENT *ev = (EVENT *)0;
|
||||
KSTATUS st = KeEventCreate(EventAutoReset, 0, &ev);
|
||||
if (!KSUCCESS(st)) return st;
|
||||
|
||||
// Attach our event; preserve any callback the caller may have set.
|
||||
irp->CompletionEvent = ev;
|
||||
|
||||
st = IoSubmitIrp(irp);
|
||||
// IoSubmitIrp always returns STATUS_PENDING on the non-error paths.
|
||||
// The event is signalled either by the driver worker (async) or by
|
||||
// IoSubmitIrp itself (sync fallback), so KeWaitForEvent will always
|
||||
// return promptly in the sync-fallback case.
|
||||
if (st == STATUS_PENDING)
|
||||
KeWaitForEvent(ev);
|
||||
|
||||
// Release our reference to the temporary event object.
|
||||
ObDereferenceObject(&ev->Header);
|
||||
|
||||
return irp->Status;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
// ke_irp.h - I/O Request Packet
|
||||
//
|
||||
// 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-
|
||||
// declared here so the HAL layer (hal_disk.c, io_driver.h) can include this
|
||||
// header without dragging in kernel sync-object link dependencies.
|
||||
//
|
||||
// Files that actually call KeEventCreate / KeSignalEvent / KeWaitForEvent
|
||||
// (ke_irp.c, ahci.c) include ke_event.h and ke_semaphore.h themselves.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <ke_list.h>
|
||||
#include <ke_spinlock.h>
|
||||
#include <ke_status.h>
|
||||
|
||||
// Forward declarations — full types live in ke_event.h / ke_semaphore.h.
|
||||
// We only ever hold pointers in IRP and IRP_QUEUE, so a forward decl suffices.
|
||||
struct EVENT;
|
||||
struct SEMAPHORE;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// IRP flags
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
#define IRP_FLAG_WRITE (1u << 0) // direction: write to device
|
||||
#define IRP_FLAG_PRIORITY (1u << 1) // insert at head of queue (elevated)
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Forward declaration (IRP is self-referential via CompletionFn)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
typedef struct IRP IRP;
|
||||
|
||||
// Completion callback: invoked in driver worker context; must not block.
|
||||
typedef void (*IRP_COMPLETION_FN)(IRP *irp, void *ctx);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// I/O Request Packet
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
typedef struct IRP {
|
||||
// Embedded list node — driver-internal; do not touch after submit.
|
||||
LIST_ENTRY Link;
|
||||
|
||||
// ---- Request parameters (caller fills before IoSubmitIrp) ------------
|
||||
|
||||
uint8_t DriveIndex;
|
||||
uint32_t Flags; // IRP_FLAG_*
|
||||
uint64_t Lba;
|
||||
uint32_t SectorCount;
|
||||
void *Buffer; // kernel VA; valid until completion
|
||||
|
||||
// ---- Completion (caller fills before submit; driver writes Status) ----
|
||||
|
||||
volatile KSTATUS Status;
|
||||
|
||||
// Forward-declared pointer: callers that create events include ke_event.h.
|
||||
struct EVENT *CompletionEvent;
|
||||
|
||||
IRP_COMPLETION_FN CompletionFn;
|
||||
void *CompletionCtx;
|
||||
|
||||
// ---- Driver-internal --------------------------------------------------
|
||||
|
||||
uint8_t HwSlot;
|
||||
void *DriverCtx;
|
||||
} IRP;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// IRP_QUEUE (per-device, driver-internal)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
typedef struct IRP_QUEUE {
|
||||
SPINLOCK Lock;
|
||||
LIST_ENTRY Head;
|
||||
struct SEMAPHORE *Semaphore; // forward-declared pointer
|
||||
} 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);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Public dispatch API — implemented in kernel/ke_irp.c
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
// Submit asynchronously. Returns STATUS_PENDING on success.
|
||||
KSTATUS IoSubmitIrp (IRP *irp);
|
||||
|
||||
// Submit and block until complete. Returns irp->Status.
|
||||
KSTATUS IoSubmitIrpSync(IRP *irp);
|
||||
@@ -1,6 +1,6 @@
|
||||
// ke_irq.c — IRQ dispatch, kernel-side
|
||||
#include "ke_irq.h"
|
||||
#include "hal_api.h"
|
||||
#include <ke_irq.h>
|
||||
#include <hal_api.h>
|
||||
|
||||
#define MAX_IRQS 24
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include "hal_api.h"
|
||||
#include <stdint.h>
|
||||
#include <hal_api.h>
|
||||
|
||||
void KeIrqInitialize(const HAL_API *hal);
|
||||
void KeIrqRegister(uint8_t irq, void (*handler)(void));
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// ke_mutex.c - binary ownership mutex
|
||||
#include "ke_mutex.h"
|
||||
#include "ke_thread.h"
|
||||
#include "ke_sched.h"
|
||||
#include "mm_virt.h"
|
||||
#include "ob_object.h"
|
||||
#include <stdbool.h>
|
||||
#include <ke_mutex.h>
|
||||
#include <ke_thread.h>
|
||||
#include <ke_sched.h>
|
||||
#include <mm_virt.h>
|
||||
#include <ob_object.h>
|
||||
|
||||
static void MutexDestroy(OBJECT* obj) { (void)obj; }
|
||||
|
||||
@@ -23,7 +24,7 @@ KSTATUS KeAcquireMutex(MUTEX* mutex) {
|
||||
if (!mutex) return STATUS_INVALID_PARAMETER;
|
||||
THREAD* self = KeCurrentThread();
|
||||
|
||||
for (;;) {
|
||||
while (true) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&mutex->Lock);
|
||||
if (!mutex->Owner) {
|
||||
mutex->Owner = self;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
// ke_mutex.h - binary ownership mutex
|
||||
#include "ob_object.h"
|
||||
#include "ke_spinlock.h"
|
||||
#include "ke_list.h"
|
||||
#include "ke_status.h"
|
||||
#include <ob_object.h>
|
||||
#include <ke_spinlock.h>
|
||||
#include <ke_list.h>
|
||||
#include <ke_status.h>
|
||||
|
||||
typedef struct MUTEX {
|
||||
OBJECT Header;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// ke_process.c - process model
|
||||
#include "ke_process.h"
|
||||
#include "ke_thread.h"
|
||||
#include "ke_event.h"
|
||||
#include "mm_virt.h"
|
||||
#include "ob_object.h"
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
#include <ke_process.h>
|
||||
#include <ke_thread.h>
|
||||
#include <ke_event.h>
|
||||
#include <mm_virt.h>
|
||||
#include <ob_object.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Global process list
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
// ke_process.h - process model
|
||||
// A process owns a handle table and a list of threads.
|
||||
// There is one shared address space - processes do not own one.
|
||||
#include "ob_object.h"
|
||||
#include "ke_list.h"
|
||||
#include "ke_spinlock.h"
|
||||
#include "ke_event.h"
|
||||
#include <ob_object.h>
|
||||
#include <ke_list.h>
|
||||
#include <ke_spinlock.h>
|
||||
#include <ke_event.h>
|
||||
|
||||
#define PROCESS_NAME_MAX 64
|
||||
#define HANDLE_TABLE_SIZE 256
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// ke_queue.c - ring-buffer message queue
|
||||
#include "ke_queue.h"
|
||||
#include "ke_thread.h"
|
||||
#include "ke_sched.h"
|
||||
#include "ob_object.h"
|
||||
#include <string.h>
|
||||
#include <ke_queue.h>
|
||||
#include <ke_thread.h>
|
||||
#include <ke_sched.h>
|
||||
#include <ob_object.h>
|
||||
|
||||
static void QueueDestroy(OBJECT* obj) { (void)obj; }
|
||||
|
||||
@@ -24,7 +24,7 @@ KSTATUS KeSendMessage(QUEUE* queue, const QUEUE_MESSAGE* msg, bool blocking) {
|
||||
if (!queue || !msg) return STATUS_INVALID_PARAMETER;
|
||||
THREAD* self = KeCurrentThread();
|
||||
|
||||
for (;;) {
|
||||
while (true) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&queue->Lock);
|
||||
if (queue->Count < QUEUE_DEPTH) {
|
||||
queue->Ring[queue->Tail] = *msg;
|
||||
@@ -56,7 +56,7 @@ KSTATUS KeReceiveMessage(QUEUE* queue, QUEUE_MESSAGE* msg, bool blocking) {
|
||||
if (!queue || !msg) return STATUS_INVALID_PARAMETER;
|
||||
THREAD* self = KeCurrentThread();
|
||||
|
||||
for (;;) {
|
||||
while (true) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&queue->Lock);
|
||||
if (queue->Count > 0) {
|
||||
*msg = queue->Ring[queue->Head];
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
// ke_queue.h - fixed-depth message queue
|
||||
// Processes share an address space, so a pointer in Param[] is valid
|
||||
// on both sides. The queue is only a synchronisation and ordering tool.
|
||||
#include "ob_object.h"
|
||||
#include "ke_spinlock.h"
|
||||
#include "ke_list.h"
|
||||
#include "ke_status.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <ob_object.h>
|
||||
#include <ke_spinlock.h>
|
||||
#include <ke_list.h>
|
||||
#include <ke_status.h>
|
||||
|
||||
#define QUEUE_MESSAGE_SIZE 64 /* bytes, fixed */
|
||||
#define QUEUE_DEPTH 256
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// ke_sched.c - MLFQ scheduler
|
||||
#include "ke_sched.h"
|
||||
#include "ke_thread.h"
|
||||
#include "ke_spinlock.h"
|
||||
#include "ke_list.h"
|
||||
#include "mm_virt.h"
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <ke_sched.h>
|
||||
#include <ke_thread.h>
|
||||
#include <ke_spinlock.h>
|
||||
#include <ke_list.h>
|
||||
#include <mm_virt.h>
|
||||
|
||||
#define DEMOTION_QUANTA 4 /* ticks at a level before demotion */
|
||||
|
||||
@@ -20,7 +21,7 @@ THREAD* KeCurrentThread(void) { return gCurrentThread; }
|
||||
void KeSetCurrentThread(THREAD* t){ gCurrentThread = t; }
|
||||
|
||||
static void IdleLoop(void) {
|
||||
for (;;) { __halt(); }
|
||||
while (true) { __halt(); }
|
||||
}
|
||||
|
||||
void KeInitializeScheduler(void) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
// ke_sched.h - Multi-Level Feedback Queue scheduler
|
||||
// Three run queues (Low / Normal / High). IRQ 0 drives KeSchedulerTick.
|
||||
#include "ke_thread.h"
|
||||
#include <ke_thread.h>
|
||||
|
||||
#define QUANTUM_MS 10 /* base time slice in milliseconds */
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// ke_semaphore.c - counting semaphore
|
||||
#include "ke_semaphore.h"
|
||||
#include "ke_thread.h"
|
||||
#include "ke_sched.h"
|
||||
#include "ob_object.h"
|
||||
#include <stdbool.h>
|
||||
#include <ke_semaphore.h>
|
||||
#include <ke_thread.h>
|
||||
#include <ke_sched.h>
|
||||
#include <ob_object.h>
|
||||
|
||||
static void SemDestroy(OBJECT* obj) { (void)obj; }
|
||||
|
||||
@@ -24,7 +25,7 @@ KSTATUS KeWaitSemaphore(SEMAPHORE* sem) {
|
||||
if (!sem) return STATUS_INVALID_PARAMETER;
|
||||
THREAD* self = KeCurrentThread();
|
||||
|
||||
for (;;) {
|
||||
while (true) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&sem->Lock);
|
||||
if (sem->Count > 0) {
|
||||
sem->Count--;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
// ke_semaphore.h - counting semaphore
|
||||
#include "ob_object.h"
|
||||
#include "ke_spinlock.h"
|
||||
#include "ke_list.h"
|
||||
#include "ke_status.h"
|
||||
#include <stdint.h>
|
||||
#include <ob_object.h>
|
||||
#include <ke_spinlock.h>
|
||||
#include <ke_list.h>
|
||||
#include <ke_status.h>
|
||||
|
||||
typedef struct SEMAPHORE {
|
||||
OBJECT Header;
|
||||
|
||||
@@ -11,6 +11,7 @@ typedef uint32_t KSTATUS;
|
||||
#define STATUS_FAILURE ((KSTATUS)0x0001)
|
||||
#define STATUS_NOT_SUPPORTED ((KSTATUS)0x0002)
|
||||
#define STATUS_TIMEOUT ((KSTATUS)0x0003)
|
||||
#define STATUS_PENDING ((KSTATUS)0x0004)
|
||||
|
||||
// --- Validation & Parameters (0x0010) ---
|
||||
#define STATUS_INVALID_PARAMETER ((KSTATUS)0x0010)
|
||||
|
||||
+16
-16
@@ -30,22 +30,22 @@
|
||||
// call: the object model already handled it; the dedicated syscall was only
|
||||
// adding a footgun where callers could bypass the unified refcount path.
|
||||
|
||||
#include "ke_thread.h"
|
||||
#include "ke_sched.h"
|
||||
#include "ke_process.h"
|
||||
#include "ke_mutex.h"
|
||||
#include "ke_semaphore.h"
|
||||
#include "ke_event.h"
|
||||
#include "ke_queue.h"
|
||||
#include "ke_debug.h"
|
||||
#include "mm_virt.h"
|
||||
#include "ldr_image.h"
|
||||
#include "syscall_nr.h"
|
||||
#include "hal_api.h"
|
||||
#include "io_file.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <ke_thread.h>
|
||||
#include <ke_sched.h>
|
||||
#include <ke_process.h>
|
||||
#include <ke_mutex.h>
|
||||
#include <ke_semaphore.h>
|
||||
#include <ke_event.h>
|
||||
#include <ke_queue.h>
|
||||
#include <ke_debug.h>
|
||||
#include <mm_virt.h>
|
||||
#include <ldr_image.h>
|
||||
#include <syscall_nr.h>
|
||||
#include <hal_api.h>
|
||||
#include <io_file.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HAL pointer - set once at boot by KeSyscallSetHal()
|
||||
@@ -106,18 +106,18 @@ static uint64_t SyscallExitProcess(uint64_t a0, uint64_t a1, uint64_t a2,
|
||||
PROCESS* proc = t ? t->Owner : NULL;
|
||||
if (proc) KeExitProcess(proc, (int)a0);
|
||||
if (t) KeExitThread(t, (int)a0);
|
||||
for (;;) ; // unreachable - KeExitThread does not return
|
||||
while (true) ; // unreachable - KeExitThread does not return
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SYS_EXIT_THREAD (1) a0 = exitCode
|
||||
// SYS_EXIT_THREAD (true) a0 = exitCode
|
||||
// ---------------------------------------------------------------------------
|
||||
static uint64_t SyscallExitThread(uint64_t a0, uint64_t a1, uint64_t a2,
|
||||
uint64_t a3, uint64_t a4, uint64_t a5) {
|
||||
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
||||
THREAD* t = KeCurrentThread();
|
||||
if (t) KeExitThread(t, (int)a0);
|
||||
for (;;) ;
|
||||
while (true) ;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "hal_api.h"
|
||||
#include <hal_api.h>
|
||||
|
||||
// Set the HAL API pointer for syscalls
|
||||
void KeSyscallSetHal(const HAL_API* hal);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// ke_thread.c - thread model
|
||||
#include "ke_thread.h"
|
||||
#include "ke_sched.h"
|
||||
#include "mm_virt.h"
|
||||
#include "ob_object.h"
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
#include <ke_thread.h>
|
||||
#include <ke_sched.h>
|
||||
#include <mm_virt.h>
|
||||
#include <ob_object.h>
|
||||
|
||||
static uint32_t gNextThreadId = 1;
|
||||
extern void KeThreadEntry(void);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
// ke_thread.h - thread model
|
||||
// A THREAD is the unit of scheduling. Every thread belongs to exactly one process.
|
||||
#include "ob_object.h"
|
||||
#include "ke_list.h"
|
||||
#include "ke_process.h"
|
||||
#include <stdint.h>
|
||||
#include <ob_object.h>
|
||||
#include <ke_list.h>
|
||||
#include <ke_process.h>
|
||||
|
||||
#define KSTACK_SIZE (64 * 1024) /* 64 KB kernel stack */
|
||||
#define USTACK_SIZE (512 * 1024) /* 512 KB user stack */
|
||||
|
||||
+114
-83
@@ -1,22 +1,22 @@
|
||||
// main.c - kernel entry point
|
||||
#include "boot_info.h"
|
||||
#include "mm_phys.h"
|
||||
#include "mm_virt.h"
|
||||
#include "ob_object.h"
|
||||
#include "ke_process.h"
|
||||
#include "ke_thread.h"
|
||||
#include "ke_sched.h"
|
||||
#include "ke_idt.h"
|
||||
#include "ke_irq.h"
|
||||
#include "ke_syscall.h"
|
||||
#include "ke_debug.h"
|
||||
#include "ldr_image.h"
|
||||
#include "hal_api.h"
|
||||
#include "io_file.h"
|
||||
#include "ini_parser.h"
|
||||
// kmain.c - kernel entry point
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
#include <boot_info.h>
|
||||
#include <mm_phys.h>
|
||||
#include <mm_virt.h>
|
||||
#include <ob_object.h>
|
||||
#include <ke_process.h>
|
||||
#include <ke_thread.h>
|
||||
#include <ke_sched.h>
|
||||
#include <ke_idt.h>
|
||||
#include <ke_irq.h>
|
||||
#include <ke_syscall.h>
|
||||
#include <ke_debug.h>
|
||||
#include <ldr_image.h>
|
||||
#include <hal_api.h>
|
||||
#include <io_file.h>
|
||||
#include <ini_parser.h>
|
||||
|
||||
// dynamic arrays bitch
|
||||
typedef struct {
|
||||
@@ -72,6 +72,11 @@ typedef struct {
|
||||
|
||||
#define arr_free(arr) MmFreePool((Header*)(arr) - 1)
|
||||
|
||||
typedef struct {
|
||||
BOOT_INFO* bootInfo;
|
||||
const HAL_API* hal;
|
||||
} SYSTEM_INIT_ARGS;
|
||||
|
||||
typedef KSTATUS (*DRIVER_ENTRY_FN)(const HAL_API *);
|
||||
|
||||
// HAL pointer cached at boot so kernel threads can reach it without
|
||||
@@ -107,7 +112,7 @@ static void DriversIniCb(const char* section, const char* key,
|
||||
}
|
||||
|
||||
static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
|
||||
DbgPrint("KernelMain: Initializing drivers...\n");
|
||||
DbgPrint("InitializeDrivers: Initializing drivers...\n");
|
||||
|
||||
// boot drivers (provided by the bootloader)
|
||||
for (uint32_t i = 0; i < bootInfo->ModuleCount; i++) {
|
||||
@@ -117,13 +122,13 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
|
||||
size_t len = strlen(name);
|
||||
if (len < 4 || strcmp(name + len - 4, ".sys")) continue;
|
||||
|
||||
DbgPrint("KernelMain: Executing DriverEntry for %s\n", name);
|
||||
DbgPrint("InitializeDrivers: Executing DriverEntry for %s\n", name);
|
||||
|
||||
DRIVER_ENTRY_FN entry = (DRIVER_ENTRY_FN)(LdrGetEntryPoint(bootInfo->Modules[i].VirtBase));
|
||||
|
||||
KSTATUS ds = entry(hal);
|
||||
if (!KSUCCESS(ds)) {
|
||||
DbgPrint("KernelMain: Driver %s failed to init!\n", name);
|
||||
DbgPrint("InitializeDrivers: Driver %s failed to init!\n", name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,17 +138,17 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
|
||||
|
||||
s = IoOpenFile("drivers\\drivers.ini", &f);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
DbgPrint("KernelMain: Failed to open drivers.ini\n");
|
||||
_disable(); while(1) __halt();
|
||||
DbgPrint("InitializeDrivers: Failed to open drivers.ini\n");
|
||||
_disable(); while(true) __halt();
|
||||
}
|
||||
|
||||
uint64_t size = IoGetFileSize(f) + 1;
|
||||
char* mem = MmAllocatePool(size);
|
||||
size_t got;
|
||||
if (!KSUCCESS(IoReadFile(f, mem, size, &got))) {
|
||||
DbgPrint("KernelMain: Failed to read drivers.ini\n");
|
||||
DbgPrint("InitializeDrivers: Failed to read drivers.ini\n");
|
||||
IoCloseFile(f);
|
||||
_disable(); while(1) __halt();
|
||||
_disable(); while(true) __halt();
|
||||
}
|
||||
mem[got] = '\0';
|
||||
|
||||
@@ -159,17 +164,18 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
|
||||
size_t len = strlen(runtimeKeys[i]);
|
||||
char* path = MmAllocatePool(len + 10);
|
||||
if (!path) {
|
||||
DbgPrint("KernelMain: Failed to allocate memory for driver path. How?\n");
|
||||
DbgPrint("InitializeDrivers: Failed to allocate memory for driver path. How?\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// memcpy manouvers
|
||||
memcpy(path, "drivers\\", 8);
|
||||
memcpy(path + 8, runtimeKeys[i], len + 1);
|
||||
// Assemble the path
|
||||
strncpy(path, "drivers\\", sizeof(path) - 1);
|
||||
path[sizeof(path) - 1] = '\0';
|
||||
strncat(path, runtimeKeys[i], sizeof(path) - strlen(path) - 1);
|
||||
|
||||
s = IoOpenFile(path, &f);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
DbgPrint("KernelMain: Failed to open runtime driver: %s\n", runtimeKeys[i]);
|
||||
DbgPrint("InitializeDrivers: Failed to open runtime driver: %s\n", runtimeKeys[i]);
|
||||
continue; // Skip this driver but keep going with others
|
||||
}
|
||||
|
||||
@@ -178,7 +184,7 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
|
||||
uint64_t drvSize = IoGetFileSize(f);
|
||||
void* drvMem = MmAllocatePool(drvSize);
|
||||
if (!KSUCCESS(IoReadFile(f, drvMem, drvSize, &got))) {
|
||||
DbgPrint("KernelMain: Failed to read runtime driver: %s\n", runtimeKeys[i]);
|
||||
DbgPrint("InitializeDrivers: Failed to read runtime driver: %s\n", runtimeKeys[i]);
|
||||
IoCloseFile(f);
|
||||
continue;
|
||||
}
|
||||
@@ -186,7 +192,7 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
|
||||
|
||||
uintptr_t mappedBase = 0;
|
||||
if (!KSUCCESS(LdrLoadImage(drvMem, drvSize, &mappedBase, false))) { // Load into kernel space
|
||||
DbgPrint("KernelMain: Failed to load runtime driver: %s\n", runtimeKeys[i]);
|
||||
DbgPrint("InitializeDrivers: Failed to load runtime driver: %s\n", runtimeKeys[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -194,7 +200,7 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
|
||||
|
||||
KSTATUS ds = entry(hal);
|
||||
if (!KSUCCESS(ds)) {
|
||||
DbgPrint("KernelMain: Driver %s failed to init!\n", runtimeKeys[i]);
|
||||
DbgPrint("InitializeDrivers: Driver %s failed to init!\n", runtimeKeys[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,7 +229,7 @@ static void LoadAndRegisterDll(const char* filename) {
|
||||
// Read the DLL from disk
|
||||
s = IoOpenFile(filename, &f);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
DbgPrint("KernelMain: Failed to open DLL: %s\n", filename);
|
||||
DbgPrint("LoadAndRegisterDll: Failed to open DLL: %s\n", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -231,7 +237,7 @@ static void LoadAndRegisterDll(const char* filename) {
|
||||
void* mem = MmAllocatePool(size); // Temporary pool for the raw file
|
||||
size_t got;
|
||||
if (!KSUCCESS(IoReadFile(f, mem, size, &got))) {
|
||||
DbgPrint("KernelMain: Failed to read %s\n", filename);
|
||||
DbgPrint("LoadAndRegisterDll: Failed to read %s\n", filename);
|
||||
IoCloseFile(f);
|
||||
return;
|
||||
}
|
||||
@@ -242,7 +248,7 @@ static void LoadAndRegisterDll(const char* filename) {
|
||||
uintptr_t mappedBase = 0;
|
||||
s = LdrLoadImage(mem, size, &mappedBase, true);
|
||||
if (!KSUCCESS(s)) {
|
||||
DbgPrint("KernelMain: Failed to map %s\n", filename);
|
||||
DbgPrint("LoadAndRegisterDll: Failed to map %s\n", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -262,23 +268,23 @@ static PROCESS* LaunchUserProcess(const char* filePath) {
|
||||
|
||||
// Read the executable file into a raw buffer
|
||||
s = IoOpenFile(filePath, &f);
|
||||
DbgPrint("KernelMain: IoOpenFile: %d\n", s);
|
||||
DbgPrint("LaunchUserProcess: IoOpenFile: %d\n", s);
|
||||
if (s != STATUS_SUCCESS) {
|
||||
DbgPrint("Failed to load file: \"%s\"!\n", filePath);
|
||||
return (PROCESS*)0;
|
||||
}
|
||||
|
||||
uint64_t size = IoGetFileSize(f);
|
||||
DbgPrint("KernelMain: IoGetFileSize: %llu\n", size);
|
||||
DbgPrint("LaunchUserProcess: IoGetFileSize: %llu\n", size);
|
||||
|
||||
void* mem = MmAllocateUserMemory(size);
|
||||
DbgPrint("KernelMain: MmAllocateUserMemory: 0x%llX\n", mem);
|
||||
DbgPrint("LaunchUserProcess: MmAllocateUserMemory: 0x%llX\n", mem);
|
||||
|
||||
size_t got;
|
||||
s = IoReadFile(f, mem, size, &got);
|
||||
DbgPrint("KernelMain: IoReadFile: %d\n", s);
|
||||
DbgPrint("LaunchUserProcess: IoReadFile: %d\n", s);
|
||||
IoCloseFile(f);
|
||||
DbgPrint("KernelMain: IoCloseFile\n");
|
||||
DbgPrint("LaunchUserProcess: IoCloseFile\n");
|
||||
|
||||
// Create the process object
|
||||
PROCESS* proc;
|
||||
@@ -295,17 +301,17 @@ static PROCESS* LaunchUserProcess(const char* filePath) {
|
||||
uintptr_t imageBase = 0;
|
||||
s = LdrLoadImage(mem, size, &imageBase, true);
|
||||
if (!KSUCCESS(s)) {
|
||||
DbgPrint("KernelMain: LdrLoadImage failed with status: %d\n", s);
|
||||
DbgPrint("LaunchUserProcess: LdrLoadImage failed with status: %d\n", s);
|
||||
}
|
||||
uintptr_t entryPoint = LdrGetEntryPoint(imageBase);
|
||||
DbgPrint("KernelMain: PE Image mapped! Base 0x%llx, Entry 0x%llX\n", imageBase, entryPoint);
|
||||
DbgPrint("LaunchUserProcess: PE Image mapped! Base 0x%llx, Entry 0x%llX\n", imageBase, entryPoint);
|
||||
|
||||
// Create the main thread, pointing it to the PE Entry Point
|
||||
s = KeCreateThread(proc, (uintptr_t)entryPoint, 0, PriorityNormal, &thread);
|
||||
if (!KSUCCESS(s)) {
|
||||
DbgPrint("KernelMain: Failed to create thread. Status: %d\n", s);
|
||||
DbgPrint("LaunchUserProcess: Failed to create thread. Status: %d\n", s);
|
||||
}
|
||||
DbgPrint("KernelMain: Thread created and queued!\n");
|
||||
DbgPrint("LaunchUserProcess: Thread created and queued!\n");
|
||||
|
||||
// Caller owns the reference returned by KeCreateProcess.
|
||||
return proc;
|
||||
@@ -318,11 +324,11 @@ static PROCESS* LaunchUserProcess(const char* filePath) {
|
||||
static void ProcessWatcherThread(void* arg) {
|
||||
PROCESS* proc = (PROCESS*)arg;
|
||||
KeWaitForEvent(proc->ExitEvent);
|
||||
DbgPrint("KernelMain: Process \"%s\" (PID %u) exited with code %d.\n",
|
||||
DbgPrint("ProcessWatcherThread: Process \"%s\" (PID %u) exited with code %d.\n",
|
||||
proc->Name, proc->ProcessId, proc->ExitCode);
|
||||
ObDereferenceObject(&proc->Header);
|
||||
|
||||
DbgPrint("KernelMain: Shutting down.\n");
|
||||
DbgPrint("ProcessWatcherThread: Shutting down.\n");
|
||||
gKmainHal->Power.Shutdown(); // does not return
|
||||
}
|
||||
|
||||
@@ -345,6 +351,47 @@ static void PrintProcessList() {
|
||||
}
|
||||
}
|
||||
|
||||
void SystemInitThread(void* arg) {
|
||||
SYSTEM_INIT_ARGS* args = (SYSTEM_INIT_ARGS*)arg;
|
||||
|
||||
DbgPrint("SystemInitThread: Thread started. Igniting the system...\n");
|
||||
|
||||
InitializeDrivers(args->bootInfo, args->hal);
|
||||
|
||||
ResolveSystemImports(args->bootInfo);
|
||||
|
||||
DbgPrint("SystemInitThread: Loading system DLLs...\n");
|
||||
LoadAndRegisterDll("syscall.dll");
|
||||
LoadAndRegisterDll("win32.dll");
|
||||
LoadAndRegisterDll("bink2w64.dll");
|
||||
|
||||
// Now that they are in memory and registered, we link them together
|
||||
// (e.g., win32.dll resolving its imports against syscall.dll)
|
||||
ResolveSystemImports(args->bootInfo);
|
||||
|
||||
// Print memory status now that the system is fully alive
|
||||
DbgPrint("Memory Status:\n");
|
||||
DbgPrint(" -> Free (PMM): %.2f MB\n", (float)MmFreeFrameCount() * PAGE_SIZE / (1024.0f * 1024.0f));
|
||||
DbgPrint(" -> Kernel Pool: %.2f MB\n", (float)MmGetKernelPoolUsage() / (1024.0f * 1024.0f));
|
||||
DbgPrint(" -> User Heap: %.2f MB\n", (float)MmGetUserHeapUsage() / (1024.0f * 1024.0f));
|
||||
|
||||
args->hal->Screen.Clear(0x000000);
|
||||
|
||||
// Launch User-Mode Shell (this will trigger AHCI & FAT32 which CAN safely block now)
|
||||
PROCESS* shellProc = LaunchUserProcess(args->bootInfo->CommandLine);
|
||||
|
||||
if (shellProc) {
|
||||
KSTATUS ws = KeCreateKernelThread((uintptr_t)ProcessWatcherThread,
|
||||
(uintptr_t)shellProc,
|
||||
PriorityNormal, (THREAD**)0);
|
||||
if (!KSUCCESS(ws)) {
|
||||
DbgPrint("SystemInitThread: Failed to create watcher thread (%d) -- leaking proc ref.\n", ws);
|
||||
}
|
||||
}
|
||||
|
||||
MmFreePool(args);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Main Kernel Entry
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -381,7 +428,7 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
|
||||
.DebugEnabled = bootInfo->DebugEnabled
|
||||
};
|
||||
KSTATUS s = HalInitialize(&halParams);
|
||||
if (!KSUCCESS(s)) for (;;) __halt(); // there's nothing we can do.
|
||||
if (!KSUCCESS(s)) while (true) __halt(); // there's nothing we can do.
|
||||
const HAL_API* hal = HalGetApi();
|
||||
gKmainHal = hal;
|
||||
|
||||
@@ -400,53 +447,37 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
|
||||
// Dynamic Linking & Driver Execution
|
||||
//
|
||||
ResolveSystemImports(bootInfo);
|
||||
InitializeDrivers(bootInfo, hal);
|
||||
//InitializeDrivers(bootInfo, hal);
|
||||
|
||||
//
|
||||
// Scheduler Prep & Status Update
|
||||
//
|
||||
KeInitializeScheduler();
|
||||
hal->Screen.Clear(0x000000);
|
||||
|
||||
DbgPrint("KernelMain: Loading system DLLs...\n");
|
||||
LoadAndRegisterDll("syscall.dll");
|
||||
LoadAndRegisterDll("win32.dll");
|
||||
LoadAndRegisterDll("bink2w64.dll");
|
||||
// Pack the arguments for the init thread
|
||||
SYSTEM_INIT_ARGS* initArgs = MmAllocatePool(sizeof(SYSTEM_INIT_ARGS));
|
||||
initArgs->bootInfo = bootInfo;
|
||||
initArgs->hal = hal;
|
||||
|
||||
// Now that they are in memory and registered, we link them together
|
||||
// (e.g., win32.dll resolving its imports against syscall.dll)
|
||||
ResolveSystemImports(bootInfo);
|
||||
|
||||
//
|
||||
// User-Mode Launch
|
||||
//
|
||||
PROCESS* shellProc = LaunchUserProcess(bootInfo->CommandLine);
|
||||
|
||||
// Spawn a kernel thread that blocks on the process exit event and prints
|
||||
// when it fires. The watcher takes ownership of the LaunchUserProcess
|
||||
// reference so we do not hold a dangling pointer in KernelMain.
|
||||
if (shellProc) {
|
||||
KSTATUS ws = KeCreateKernelThread((uintptr_t)ProcessWatcherThread,
|
||||
(uintptr_t)shellProc,
|
||||
PriorityNormal, (THREAD**)0);
|
||||
if (!KSUCCESS(ws)) {
|
||||
DbgPrint("KernelMain: Failed to create watcher thread (%d) -- leaking proc ref.\n", ws);
|
||||
}
|
||||
// Ownership of shellProc transferred to watcher; do not use it below.
|
||||
// Spawn the Initialization Thread
|
||||
THREAD* initThread = (THREAD*)0;
|
||||
KSTATUS st = KeCreateKernelThread((uintptr_t)SystemInitThread,
|
||||
(uintptr_t)initArgs,
|
||||
PriorityNormal, &initThread);
|
||||
|
||||
if (!KSUCCESS(st)) {
|
||||
DbgPrint("KernelMain: PANIC - Failed to create SystemInitThread! (0x%x)\n", st);
|
||||
_disable();
|
||||
for(;;) __halt();
|
||||
}
|
||||
|
||||
//
|
||||
// Ignite the System
|
||||
//
|
||||
DbgPrint("KernelMain: Starting scheduler... Handing over control.\n");
|
||||
DbgPrint("KernelMain: Handing over to scheduler...\n");
|
||||
|
||||
// Ignite the system
|
||||
_enable();
|
||||
|
||||
DbgPrint("Memory Status:\n");
|
||||
DbgPrint(" -> Free (PMM): %.2f MB\n", (float)MmFreeFrameCount() * PAGE_SIZE / (1024.0f * 1024.0f));
|
||||
DbgPrint(" -> Kernel Pool: %.2f MB\n", (float)MmGetKernelPoolUsage() / (1024.0f * 1024.0f));
|
||||
DbgPrint(" -> User Heap: %.2f MB\n", (float)MmGetUserHeapUsage() / (1024.0f * 1024.0f));
|
||||
|
||||
while (1) {
|
||||
KeYield(); // nothing to do
|
||||
// The Idle Loop: The CPU rests here whenever all other threads are waiting on events.
|
||||
while (true) {
|
||||
__halt();
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,10 @@
|
||||
// ldr_image.c - PE32+ loader and export resolver
|
||||
//
|
||||
// At boot all images are already mapped by the bootloader; LdrLoadImage is
|
||||
// used for any image loaded later (currently unused - all modules come in via
|
||||
// BOOT_INFO). LdrGetExport scans the PE export directory of a registered module.
|
||||
#include "ldr_image.h"
|
||||
#include "boot_info.h"
|
||||
#include "mm_virt.h"
|
||||
#include "ke_debug.h"
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <ldr_image.h>
|
||||
#include <boot_info.h>
|
||||
#include <mm_virt.h>
|
||||
#include <ke_debug.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// PE32+ structures (just what we need)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
// ldr_image.h - minimal PE32+ loader
|
||||
// Loads an already-mapped PE image and resolves its imports.
|
||||
#include "ke_status.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <ke_status.h>
|
||||
|
||||
// Map a PE32+ image from 'buffer' into the kernel virtual address space.
|
||||
// On success, *baseOut receives the virtual base address.
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
// bootloader at PhysicalWindowBase (always 0xFFFF880000000000).
|
||||
//
|
||||
// Lock: a single spinlock guards Push/Pop. O(1) for both operations.
|
||||
#include "mm_phys.h"
|
||||
#include "ke_spinlock.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <mm_phys.h>
|
||||
#include <ke_spinlock.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Physical-to-virtual translation via the direct map window.
|
||||
@@ -70,7 +71,7 @@ void MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) {
|
||||
}
|
||||
|
||||
if (!stackPhys) {
|
||||
for (;;) { __halt(); }
|
||||
while (true) { __halt(); }
|
||||
}
|
||||
|
||||
gFrameStack.Stack = (PHYSICAL_ADDRESS *)PhysToVirt(stackPhys);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// Stack allocator over 4 KB frames, seeded from MEMORY_MAP.
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "memory_map.h"
|
||||
#include <memory_map.h>
|
||||
|
||||
#define PAGE_SIZE 4096ULL
|
||||
#define PAGE_MASK (~(PAGE_SIZE - 1))
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
// User heap:
|
||||
// A single best-fit free list in the lower half.
|
||||
// Backed on demand from the PMM. No per-process heaps.
|
||||
#include "mm_virt.h"
|
||||
#include "ke_spinlock.h"
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <mm_virt.h>
|
||||
#include <ke_spinlock.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers - physical window access
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
// Manages the single shared PML4, kernel pool, and user heap.
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "mm_phys.h"
|
||||
#include "ke_status.h"
|
||||
#include <mm_phys.h>
|
||||
#include <ke_status.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Page flags (x86-64 PTE bits)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// ob_object.c - executive object manager
|
||||
#include "ob_object.h"
|
||||
#include "mm_virt.h" // MmAllocatePool / MmFreePool
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
#include <ob_object.h>
|
||||
#include <mm_virt.h>
|
||||
|
||||
OBJECT* ObAllocateObject(OBJECT_TYPE type, size_t size) {
|
||||
if (size < sizeof(OBJECT)) size = sizeof(OBJECT);
|
||||
@@ -13,7 +13,7 @@ OBJECT* ObAllocateObject(OBJECT_TYPE type, size_t size) {
|
||||
memset(obj, 0, size);
|
||||
obj->Type = type;
|
||||
obj->RefCount = 1;
|
||||
obj->Destroy = (void *)0; /* caller fills this in */
|
||||
obj->Destroy = (void *)0; // caller fills this in
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ void ObDereferenceObject(OBJECT* object) {
|
||||
if (!object) return;
|
||||
long prev = _InterlockedDecrement(&object->RefCount);
|
||||
if (prev == 0) {
|
||||
/* Reference count hit zero - run the destructor then free. */
|
||||
// Reference count hit zero - run the destructor then free.
|
||||
if (object->Destroy) {
|
||||
object->Destroy(object);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// The OBJECT header must be the first member of any derived struct.
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "ke_status.h"
|
||||
#include <ke_status.h>
|
||||
|
||||
typedef enum OBJECT_TYPE {
|
||||
ObjectTypeProcess = 1,
|
||||
@@ -18,7 +18,7 @@ typedef enum OBJECT_TYPE {
|
||||
|
||||
typedef struct OBJECT {
|
||||
OBJECT_TYPE Type;
|
||||
volatile long RefCount; /* interlocked; long = 4 bytes on MSVC x64 */
|
||||
volatile long RefCount; // interlocked; long = 4 bytes on MSVC x64
|
||||
void (*Destroy)(struct OBJECT* self);
|
||||
} OBJECT;
|
||||
|
||||
|
||||
Reference in new issue
Block a user