major restructuring, prepare for smp

This commit is contained in:
maksw committed 2026-05-28 18:53:37 +02:00
1 parent b3569a2b90
commit 6bff37746d
229 files changed
+1617 -1489

No files matched your search

-44
View File
@@ -1,44 +0,0 @@
#pragma once
// 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>
#define BOOT_INFO_MAGIC 0x424F4F54494E464FULL /* 'BOOTINFO' */
#define MAX_BOOT_MODULES 32
typedef struct BOOT_MODULE {
char Name[32]; /* e.g. "hal.dll", "ide.sys" */
uintptr_t VirtBase; /* Virtual address (mapped) */
uintptr_t PhysBase; /* Raw physical address (file) */
size_t ImageSize; /* File size / Image size */
} BOOT_MODULE;
typedef struct BOOT_INFO {
uint64_t Magic;
/* Physical memory. */
MEMORY_MAP MemoryMap;
/* GOP framebuffer. */
uintptr_t FramebufferBase;
uint32_t FramebufferWidth;
uint32_t FramebufferHeight;
uint32_t FramebufferStride; /* pixels per row */
/* Loaded modules. */
BOOT_MODULE Modules[MAX_BOOT_MODULES];
uint32_t ModuleCount;
uint32_t _pad1;
char CommandLine[64];
/* ACPI RSDP physical address (for APIC, HPET). */
uintptr_t RsdpPhysical;
/* Direct physical window base - always 0xFFFF880000000000. */
uintptr_t PhysicalMapBase;
/* From boot.ini */
uint32_t Debug;
} BOOT_INFO;
+74
View File
@@ -0,0 +1,74 @@
// hal_apic.c - Local APIC + I/O APIC
#include <kernel/hal/hal_apic.h>
#include <ntlite/ddi/hal_api.h>
#include <stdint.h>
extern HAL_API gApi;
// ---- Local APIC ----
static volatile uint32_t* gLapic = (volatile uint32_t *)0;
#define LAPIC_REG(off) (*(volatile uint32_t *)((uint8_t *)gLapic + (off)))
#define LAPIC_EOI 0x0B0
#define LAPIC_SPURIOUS 0x0F0
#define LAPIC_ENABLE 0x100 // bit in spurious vector register
// ---- I/O APIC ----
static volatile uint32_t* gIoapic = (volatile uint32_t *)0;
#define IOAPIC_IDX 0x00
#define IOAPIC_DATA 0x10
static uint32_t IoapicRead(uint8_t reg) {
*(volatile uint32_t *)((uint8_t *)gIoapic + IOAPIC_IDX) = reg;
return *(volatile uint32_t *)((uint8_t *)gIoapic + IOAPIC_DATA);
}
static void IoapicWrite(uint8_t reg, uint32_t val) {
*(volatile uint32_t *)((uint8_t *)gIoapic + IOAPIC_IDX) = reg;
*(volatile uint32_t *)((uint8_t *)gIoapic + IOAPIC_DATA) = val;
}
// IRQ n -> redirection table at register 0x10 + 2*n (low), 0x11 + 2*n (high).
#define IOREDTBL_LO(n) (0x10 + 2*(n))
#define IOREDTBL_HI(n) (0x11 + 2*(n))
// Interrupt vector base: IRQ 0 -> vector 0x20, IRQ 1 -> 0x21, ...
#define IRQ_VECTOR_BASE 0x20
void HalApicRouteIrq(uint8_t irq) {
// Full initial setup of the redirection entry.
// Sets the vector and clears the mask bit in one write.
uint32_t vector = IRQ_VECTOR_BASE + irq; // e.g. IRQ 1 -> vector 0x21
IoapicWrite(IOREDTBL_LO(irq), vector); // unmasked (bit 16 = 0), edge, fixed
IoapicWrite(IOREDTBL_HI(irq), 0); // deliver to LAPIC id 0
}
void HalApicMaskIrq(uint8_t irq) {
uint32_t lo = IoapicRead(IOREDTBL_LO(irq));
lo |= (1 << 16);
IoapicWrite(IOREDTBL_LO(irq), lo);
}
void HalApicUnmaskIrq(uint8_t irq) {
uint32_t lo = IoapicRead(IOREDTBL_LO(irq));
lo &= ~(1 << 16); // clear mask bit
lo = (lo & ~0xFF) | (IRQ_VECTOR_BASE + irq);
IoapicWrite(IOREDTBL_LO(irq), lo);
IoapicWrite(IOREDTBL_HI(irq), 0); // LAPIC id 0
}
void HalApicSendEoi(void) {
LAPIC_REG(LAPIC_EOI) = 0;
}
void HalApicInitialize(uintptr_t lapicPhys, uintptr_t ioapicPhys) {
gLapic = (volatile uint32_t *)(gApi.PhysToVirt(lapicPhys));
gIoapic = (volatile uint32_t *)(gApi.PhysToVirt(ioapicPhys));
// Enable Local APIC, set spurious vector to 0xFF.
LAPIC_REG(LAPIC_SPURIOUS) = LAPIC_ENABLE | 0xFF;
// Mask all IOAPIC lines initially.
uint32_t maxRedir = (IoapicRead(1) >> 16) & 0xFF;
for (uint8_t i = 0; i <= maxRedir; i++) {
IoapicWrite(IOREDTBL_LO(i), (1 << 16) | (IRQ_VECTOR_BASE + i));
IoapicWrite(IOREDTBL_HI(i), 0);
}
}
+2
View File
@@ -0,0 +1,2 @@
// hal_disk.c intentionally left empty.
// Disk registration and dispatch live in kernel/io_device.c.
+204
View File
@@ -0,0 +1,204 @@
// hal_keyboard.c - PS/2 keyboard, interrupt-driven, with live state tracking
#include <stdint.h>
#include <stdbool.h>
#include <intrin.h>
#include <ntlite/ddi/hal_api.h>
// -- Port addresses ------------------------------------------------------------
#define PS2_DATA 0x60u
#define PS2_STAT 0x64u
#define PS2_CMD 0x64u
// -- Ring buffer (for ASCII/typing) -------------------------------------------
#define KBD_BUF_SIZE 256u
#define KBD_BUF_MASK (KBD_BUF_SIZE - 1u)
static uint8_t gBuf[KBD_BUF_SIZE];
static volatile int gHead = 0;
static volatile int gTail = 0;
// -- Deferred callback queue ---------------------------------------------------
// The hard IRQ path updates the key state and stores completed make codes.
// Optional client callbacks are delivered later from the kernel-queued DPC,
// never directly from DIRQL/ISR context.
#define KBD_DPC_BUF_SIZE 128u
#define KBD_DPC_BUF_MASK (KBD_DPC_BUF_SIZE - 1u)
static uint8_t gDpcBuf[KBD_DPC_BUF_SIZE];
static volatile int gDpcHead = 0;
static volatile int gDpcTail = 0;
// -- Live Key State (for GetAsyncKeyState) ------------------------------------
// These arrays track whether a key is currently held down.
static volatile uint8_t gKeyState[128]; // Standard scan codes
static volatile uint8_t gKeyStateExt[128]; // Extended (E0) scan codes
// -- Scan-code set 1 constants -------------------------------------------------
#define SC1_BREAK_BIT 0x80u
#define SC1_MAKE_MASK 0x7Fu
#define SC1_EXT_PREFIX 0xE0u
// -- Modifier flags ------------------------------------------------------------
#define MOD_LSHIFT (1u << 0)
#define MOD_RSHIFT (1u << 1)
#define MOD_LCTRL (1u << 2)
#define MOD_RCTRL (1u << 3)
#define MOD_LALT (1u << 4)
#define MOD_RALT (1u << 5)
#define MOD_CAPS (1u << 6)
#define MOD_NUMLOCK (1u << 7)
#define MOD_SHIFT (MOD_LSHIFT | MOD_RSHIFT)
#define MOD_CTRL (MOD_LCTRL | MOD_RCTRL)
#define MOD_ALT (MOD_LALT | MOD_RALT)
static volatile uint32_t gModifiers = 0;
static volatile bool gNextExtended = false;
static void (* volatile gCallback)(uint8_t) = NULL;
// -- ASCII Translation Tables --------------------------------------------------
static const char gUnshifted[128] = {
0, 0, '1','2','3','4','5','6','7','8','9','0','-','=','\b','\t',
'q','w','e','r','t','y','u','i','o','p','[',']','\n', 0, 'a','s',
'd','f','g','h','j','k','l',';','\'','`', 0, '\\','z','x','c','v',
'b','n','m',',','.','/', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, '7','8','9','-', '4','5','6','+', '1','2','3','0','.'
};
static const char gShifted[128] = {
0, 0, '!','@','#','$','%','^','&','*','(',')','_','+','\b','\t',
'Q','W','E','R','T','Y','U','I','O','P','{','}','\n', 0, 'A','S',
'D','F','G','H','J','K','L',':','"','~', 0, '|','Z','X','C','V',
'B','N','M','<','>','?', 0, '*', 0, ' ', 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, '7','8','9','-', '4','5','6','+', '1','2','3','0','.'
};
// -- Deferred callback delivery ------------------------------------------------
static void KbdDpc(void) {
for (;;) {
if (gDpcHead == gDpcTail)
break;
uint8_t make = gDpcBuf[gDpcHead];
gDpcHead = (gDpcHead + 1) & (int)KBD_DPC_BUF_MASK;
void (*cb)(uint8_t) = (void (*)(uint8_t))gCallback;
if (cb)
cb(make);
}
}
// -- ISR: The Engine -----------------------------------------------------------
void KbdIsr(void) {
uint8_t sc = __inbyte(PS2_DATA);
if (sc == SC1_EXT_PREFIX) {
gNextExtended = true;
return;
}
bool extended = gNextExtended;
bool is_break = (sc & SC1_BREAK_BIT) != 0;
uint8_t make = sc & SC1_MAKE_MASK;
gNextExtended = false;
// Update the live state arrays
if (extended) {
gKeyStateExt[make] = is_break ? 0 : 1;
} else {
gKeyState[make] = is_break ? 0 : 1;
}
// Update modifiers
if (!extended) {
switch (make) {
case 0x2A: gModifiers = is_break ? (gModifiers & ~MOD_LSHIFT) : (gModifiers | MOD_LSHIFT); break;
case 0x36: gModifiers = is_break ? (gModifiers & ~MOD_RSHIFT) : (gModifiers | MOD_RSHIFT); break;
case 0x1D: gModifiers = is_break ? (gModifiers & ~MOD_LCTRL) : (gModifiers | MOD_LCTRL); break;
case 0x38: gModifiers = is_break ? (gModifiers & ~MOD_LALT) : (gModifiers | MOD_LALT); break;
case 0x3A: if (!is_break) gModifiers ^= MOD_CAPS; break;
case 0x45: if (!is_break) gModifiers ^= MOD_NUMLOCK; break;
}
} else {
switch (make) {
case 0x1D: gModifiers = is_break ? (gModifiers & ~MOD_RCTRL) : (gModifiers | MOD_RCTRL); break;
case 0x38: gModifiers = is_break ? (gModifiers & ~MOD_RALT) : (gModifiers | MOD_RALT); break;
}
}
// Buffer management (only for 'make' codes)
if (!is_break) {
int next = (gTail + 1) & (int)KBD_BUF_MASK;
if (next != gHead) {
gBuf[gTail] = make;
gTail = next;
}
// Queue optional callback delivery to the DPC path. Keep a separate
// callback queue so the public ReadScancode ring remains independent.
if (gCallback) {
int dpcNext = (gDpcTail + 1) & (int)KBD_DPC_BUF_MASK;
if (dpcNext != gDpcHead) {
gDpcBuf[gDpcTail] = make;
gDpcTail = dpcNext;
}
}
}
}
// -- Public API ----------------------------------------------------------------
// Use this inside your GetAsyncKeyState implementation!
bool KbdIsKeyDown(uint8_t scancode, bool extended) {
if (extended) return gKeyStateExt[scancode & 0x7F] != 0;
return gKeyState[scancode & 0x7F] != 0;
}
static uint8_t KbdPoll(void) {
return (gHead == gTail) ? 0 : gBuf[gHead];
}
static uint8_t KbdReadScancode(void) {
while (gHead == gTail) { _mm_pause(); }
uint8_t sc = gBuf[gHead];
gHead = (gHead + 1) & (int)KBD_BUF_MASK;
return sc;
}
static char KbdReadChar(void) {
uint8_t make = KbdReadScancode();
if (make >= 128) return 0;
uint32_t mods = gModifiers;
bool shifted = (mods & MOD_SHIFT) != 0;
if (mods & MOD_CAPS) {
char base = gUnshifted[make];
if (base >= 'a' && base <= 'z') shifted = !shifted;
}
return shifted ? gShifted[make] : gUnshifted[make];
}
static uint32_t KbdGetModifiers(void) {
return gModifiers;
}
static void KbdSetCallback(void (*cb)(uint8_t scancode)) {
gCallback = cb;
}
void HalKeyboardInitialize(HAL_KEYBOARD *out) {
while (__inbyte(PS2_STAT) & 2);
__outbyte(PS2_CMD, 0xA8);
while (__inbyte(PS2_STAT) & 1) { __inbyte(PS2_DATA); }
out->Poll = KbdPoll;
out->ReadScancode = KbdReadScancode;
out->ReadChar = KbdReadChar;
out->GetModifiers = KbdGetModifiers;
out->SetCallback = KbdSetCallback;
out->IsKeyDown = KbdIsKeyDown;
out->Isr = KbdIsr;
out->Dpc = KbdDpc;
out->IrqNumber = 1;
}
+381
View File
@@ -0,0 +1,381 @@
// hal_main.c - HAL initialisation and HalGetApi
#include <ntlite/ddi/hal_api.h>
#include <kernel/hal/hal_apic.h>
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#include <intrin.h>
#include <common/printf.h>
// Declared in other hal_*.c files:
void HalScreenInitialize(uintptr_t fb, int w, int h, int stride, HAL_SCREEN* out);
void HalKeyboardInitialize(HAL_KEYBOARD* out);
void HalMouseInitialize(HAL_MOUSE* out, int screenW, int screenH);
KSTATUS HalTimerInitialize(uintptr_t lapicPhys, uintptr_t hpetPhys, HAL_TIMER *out);
void HalPciInitialize(HAL_PCI* out);
extern void HalSetDebugEnabled(int v);
// Defined in mm_virt.c - HAL needs it for MMIO window access.
static uint64_t gPhysBase = 0xFFFF880000000000ULL;
HAL_API gApi;
static int gInitialised = 0;
extern void (*gTimerCallback)(void);
// ---------------------------------------------------------------------------
// ACPI table walker - minimal, just enough to find APIC and HPET addresses.
// ---------------------------------------------------------------------------
#define ACPI_SIG(a,b,c,d) ((uint32_t)(a)|((uint32_t)(b)<<8)|((uint32_t)(c)<<16)|((uint32_t)(d)<<24))
#pragma pack(push, 1)
#pragma warning(disable : 4200)
// ACPI RSDP (Root System Description Pointer)
typedef struct {
char Signature[8];
uint8_t Checksum;
char OEMID[6];
uint8_t Revision;
uint32_t RsdtAddress;
uint32_t Length;
uint64_t XsdtAddress;
uint8_t ExtendedChecksum;
uint8_t Reserved[3];
} RSDP;
// ACPI SDT Header
typedef struct {
char Signature[4];
uint32_t Length;
uint8_t Revision;
uint8_t Checksum;
char OEMID[6];
char OEMTableID[8];
uint32_t OEMRevision;
uint32_t CreatorID;
uint32_t CreatorRevision;
} ACPISDTHeader;
// RSDT (Root System Description Table)
typedef struct {
ACPISDTHeader Header;
uint32_t PointerToOtherSDT[];
} RSDT;
// XSDT (Extended System Description Table)
typedef struct {
ACPISDTHeader Header;
uint64_t PointerToOtherSDT[];
} XSDT;
// MADT (Multiple APIC Description Table)
typedef struct {
ACPISDTHeader Header;
uint32_t LocalAPICAddress;
uint32_t Flags;
uint8_t Entries[];
} MADT;
#pragma pack(pop)
static uintptr_t gLapicPhys = 0xFEE00000;
static uintptr_t gIoapicPhys = 0xFEC00000;
static uintptr_t gHpetPhys = 0xFED00000;
// ACPI power-off state (filled in by ParseFadt / ScanDsdtForS5)
static uint16_t gPm1aCntBlk = 0;
static uint16_t gPm1bCntBlk = 0;
static uint8_t gSlpTypA = 5; // S5 SLP_TYP for PM1a; 5 is correct for QEMU/most VMs
static uint8_t gSlpTypB = 5; // S5 SLP_TYP for PM1b
int debugEnabled = 0;
int _fltused; // fuckass
static void hal_putchar(char c) {
gApi.Screen.PrintChar(c, 0x00FF00, 0x000000);
}
void HalDbgPrint(const char* fmt, ...) {
if (!debugEnabled) return;
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
static void *HalPhysToVirt(uint64_t phys) {
return (void *)(phys + gPhysBase);
}
// FADT (Fixed ACPI Description Table) - partial layout up to PM1b_CNT_BLK.
// We only need offsets 40 (DSDT ptr), 64 (PM1a_CNT_BLK), 68 (PM1b_CNT_BLK).
// The full table is ~276 bytes (ACPI 2.0+); we never access beyond offset 68.
#pragma pack(push, 1)
typedef struct {
ACPISDTHeader Header; // 0 (36 bytes)
uint32_t FirmwareCtrl; // 36
uint32_t Dsdt; // 40 - physical addr of DSDT
uint8_t Reserved1; // 44
uint8_t PreferredPmProfile; // 45
uint16_t SciInt; // 46
uint32_t SmiCmd; // 48
uint8_t AcpiEnable; // 52
uint8_t AcpiDisable; // 53
uint8_t S4BiosReq; // 54
uint8_t PstateCnt; // 55
uint32_t Pm1aEvtBlk; // 56
uint32_t Pm1bEvtBlk; // 60
uint32_t Pm1aCntBlk; // 64 - I/O port for PM1a control register
uint32_t Pm1bCntBlk; // 68 - I/O port for PM1b control register
} FADT;
#pragma pack(pop)
// Scan DSDT AML for the _S5_ Name object and extract SLP_TYP values.
// The encoding looks like:
// 0x08 '_' 'S' '5' '_' ; NameOp + "_S5_"
// 0x12 <PkgLen> ; PackageOp + encoded length
// <NumElements> ; usually 0x04
// 0x0A <slp_typ_a> ; BytePrefix + value (or 0x00 for zero)
// 0x0A <slp_typ_b>
static void ScanDsdtForS5(const uint8_t* aml, uint32_t len) {
for (uint32_t i = 0; i + 9 < len; i++) {
// Match NameOp + "_S5_" + PackageOp
if (aml[i] != 0x08) continue;
if (aml[i+1] != 0x5F || aml[i+2] != 0x53 ||
aml[i+3] != 0x35 || aml[i+4] != 0x5F) continue;
if (aml[i+5] != 0x12) continue;
// PkgLength encoding: low 6 bits = byte count (0 → only this byte);
// bits [7:6] = number of following bytes in the length field.
uint8_t pkgByte = aml[i+6];
uint32_t pkgExtra = pkgByte >> 6; // 0..3 extra bytes
uint32_t j = i + 7 + pkgExtra; // skip PkgLen field
if (j + 2 >= len) break;
j++; // skip NumElements byte
// SLP_TYP_A
if (aml[j] == 0x0A && j + 1 < len) {
gSlpTypA = aml[j + 1]; j += 2;
} else if (aml[j] == 0x00) {
gSlpTypA = 0; j++;
} else {
break; // unexpected encoding - keep defaults
}
// SLP_TYP_B
if (j < len && aml[j] == 0x0A && j + 1 < len)
gSlpTypB = aml[j + 1];
else if (j < len && aml[j] == 0x00)
gSlpTypB = 0;
HalDbgPrint("HAL: _S5_ SLP_TYP_A=0x%02x SLP_TYP_B=0x%02x\n",
gSlpTypA, gSlpTypB);
return;
}
HalDbgPrint("HAL: _S5_ not found in DSDT, using defaults (A=0x%02x B=0x%02x)\n",
gSlpTypA, gSlpTypB);
}
static int validate_checksum(void* table, uint32_t length) {
uint8_t sum = 0;
uint8_t* bytes = (uint8_t*)table;
for (uint32_t i = 0; i < length; i++) {
sum += bytes[i];
}
return sum == 0;
}
static void ParseFadt(const FADT* fadt) {
gPm1aCntBlk = (uint16_t)fadt->Pm1aCntBlk;
gPm1bCntBlk = (uint16_t)fadt->Pm1bCntBlk;
HalDbgPrint("HAL: FADT PM1a_CNT=0x%04x PM1b_CNT=0x%04x DSDT=0x%08x\n",
gPm1aCntBlk, gPm1bCntBlk, fadt->Dsdt);
if (fadt->Dsdt) {
const ACPISDTHeader* dsdt =
(const ACPISDTHeader*)((uintptr_t)fadt->Dsdt + gPhysBase);
if (memcmp(dsdt->Signature, "DSDT", 4) == 0 &&
validate_checksum((void*)dsdt, dsdt->Length)) {
const uint8_t* aml = (const uint8_t*)(dsdt + 1);
ScanDsdtForS5(aml, dsdt->Length - (uint32_t)sizeof(ACPISDTHeader));
}
}
}
static void ParseMadt(MADT* madt) {
gLapicPhys = madt->LocalAPICAddress;
uint8_t* p = (uint8_t *)(madt + 1);
uint8_t* end = (uint8_t *)madt + madt->Header.Length;
while (p < end) {
uint8_t type = p[0], len = p[1];
if (type == 1) { // I/O APIC entry
gIoapicPhys = *(uint32_t *)(p + 4);
}
p += len ? len : 1;
}
}
static void WalkAcpi(uintptr_t rsdpPhys) {
if (!rsdpPhys) return;
// Map RSDP into virtual memory
RSDP* rsdp = (RSDP*)(rsdpPhys + gPhysBase);
if (memcmp(rsdp->Signature, "RSD PTR ", 8) != 0) {
HalDbgPrint("HAL: Invalid RSDP signature!\n");
return;
}
ACPISDTHeader* sdtHeader = NULL;
uint32_t count = 0;
int isXsdt = 0;
// Safely find and validate the XSDT (ACPI 2.0+)
if (rsdp->Revision >= 2 && rsdp->XsdtAddress != 0) {
XSDT* xsdt = (XSDT*)(rsdp->XsdtAddress + gPhysBase);
if (validate_checksum(xsdt, xsdt->Header.Length) &&
memcmp(xsdt->Header.Signature, "XSDT", 4) == 0) {
sdtHeader = &xsdt->Header;
count = (xsdt->Header.Length - sizeof(ACPISDTHeader)) / 8;
isXsdt = 1;
}
}
// Fallback to safely finding and validating the RSDT (ACPI 1.0)
if (sdtHeader == NULL && rsdp->RsdtAddress != 0) {
RSDT* rsdt = (RSDT*)((uintptr_t)rsdp->RsdtAddress + gPhysBase);
if (validate_checksum(rsdt, rsdt->Header.Length) &&
memcmp(rsdt->Header.Signature, "RSDT", 4) == 0) {
sdtHeader = &rsdt->Header;
count = (rsdt->Header.Length - sizeof(ACPISDTHeader)) / 4;
isXsdt = 0;
}
}
if (sdtHeader == NULL) {
HalDbgPrint("HAL: No valid XSDT or RSDT found!\n");
return;
}
// Walk the tables
for (uint32_t i = 0; i < count; i++) {
uintptr_t tablePhys = 0;
if (isXsdt) {
tablePhys = ((XSDT*)sdtHeader)->PointerToOtherSDT[i];
} else {
tablePhys = ((RSDT*)sdtHeader)->PointerToOtherSDT[i];
}
// Paranoid alignment check to reject firmware garbage pointers
if (!tablePhys || (tablePhys & 3) != 0) continue;
ACPISDTHeader* header = (ACPISDTHeader*)(tablePhys + gPhysBase);
// Ensure the table isn't corrupt before parsing
if (!validate_checksum(header, header->Length)) continue;
// Parse MADT
if (memcmp(header->Signature, "APIC", 4) == 0) {
ParseMadt((MADT*)header);
}
// Parse FADT (signature "FACP") for PM1 control ports and DSDT pointer
else if (memcmp(header->Signature, "FACP", 4) == 0) {
ParseFadt((const FADT*)header);
}
// Parse HPET
else if (memcmp(header->Signature, "HPET", 4) == 0) {
// HPET base address block is located at offset 44
// (which is 8 bytes past the 36-byte ACPISDTHeader)
gHpetPhys = *(uint64_t*)((uint8_t*)header + 44) & ~0xFFFULL;
}
}
}
// ---------------------------------------------------------------------------
// HalShutdown - ACPI S5 soft power-off. Does not return.
// ---------------------------------------------------------------------------
static void HalShutdown(void) {
// Silence! Stop the world!
_disable();
// SLP_EN (bit 13) | SLP_TYPx (bits 12:10)
uint16_t valA = (uint16_t)((gSlpTypA << 10) | (1 << 13));
uint16_t valB = (uint16_t)((gSlpTypB << 10) | (1 << 13));
if (gPm1aCntBlk) __outword(gPm1aCntBlk, valA);
if (gPm1bCntBlk) __outword(gPm1bCntBlk, valB);
// Die!
while (true) __halt();
}
// ---------------------------------------------------------------------------
__declspec(dllexport) KSTATUS HalInitialize(const HAL_INIT_PARAMS* initParams) {
if (gInitialised) return STATUS_ALREADY_EXISTS;
gPhysBase = initParams->PhysicalWindowBase;
gApi.PhysToVirt = HalPhysToVirt;
debugEnabled = initParams->Debug;
// Screen first so DbgPrint works immediately.
HalScreenInitialize(initParams->FramebufferBase + initParams->PhysicalWindowBase,
(int)initParams->FramebufferWidth,
(int)initParams->FramebufferHeight,
(int)initParams->FramebufferStride,
&gApi.Screen);
printf_set_putchar(hal_putchar);
HalDbgPrint("HAL: screen %dx%d\n",
initParams->FramebufferWidth, initParams->FramebufferHeight);
// Parse ACPI to find LAPIC / IOAPIC / HPET addresses.
if (initParams->RsdpPhysical) WalkAcpi(initParams->RsdpPhysical);
HalDbgPrint("HAL: LAPIC=%016llx IOAPIC=%016llx HPET=%016llx\n",
gLapicPhys, gIoapicPhys, gHpetPhys);
HalApicInitialize(gLapicPhys, gIoapicPhys);
HalKeyboardInitialize(&gApi.Keyboard);
HalMouseInitialize(&gApi.Mouse,
(int)initParams->FramebufferWidth,
(int)initParams->FramebufferHeight);
KSTATUS ts = HalTimerInitialize(gLapicPhys, gHpetPhys, &gApi.Timer);
if (!KSUCCESS(ts)) HalDbgPrint("HAL: HPET unavailable, using fallback\n");
HalPciInitialize(&gApi.Pci);
gApi.Intc.RouteIrq = HalApicRouteIrq;
gApi.Intc.MaskIrq = HalApicMaskIrq;
gApi.Intc.UnmaskIrq = HalApicUnmaskIrq;
gApi.Intc.SendEoi = HalApicSendEoi;
gApi.Power.Shutdown = HalShutdown;
gApi.Version = HAL_API_VERSION;
gInitialised = 1;
// This shouldn't be here but i have no other way.
// After i send 0xF4 and move the mouse the controller sends an interrupts that doesn't fire
// and because the CPU missed the IRQ 12 edge transition (cli) later when we expect it to fire, it doesn't
// leaving us with no mouse and no keyboard. The dreaded 8042 will hold the CLOCK line low forever.
// To combat this we just go about our day executing the rest of the init and just before the end
// of init we just iterate 256 times to grab whatever the controller left for us ("Drain and Pray").
for (int i = 0; i < 256; i++) {
if (__inbyte(0x64) & 0x01) {
__inbyte(0x60); // Consume
}
gApi.Timer.Stall(1); // Micro-stalls
}
HalDbgPrint("HAL: initialisation complete.\n");
return STATUS_SUCCESS;
}
__declspec(dllexport) void HalRegisterScheduler(void (*pKeSchedulerTick)(void)) {
gTimerCallback = pKeSchedulerTick;
}
__declspec(dllexport) const HAL_API* HalGetApi(void) { return &gApi; }
+306
View File
@@ -0,0 +1,306 @@
// hal_mouse.c - PS/2 auxiliary mouse driver
//
// Sits on IRQ 12, sharing the 8042 controller with the keyboard (IRQ 1).
// hal_keyboard.c has already issued command 0xA8 (enable aux port) by the
// time HalMouseInitialize is called, so we only need to:
// 1. Enable aux interrupts in the 8042 command byte (bit 1, clears bit 5).
// 2. Send the standard mouse init sequence (reset → defaults → enable).
// 3. Wire up the ISR and expose the HAL_MOUSE vtable.
//
// Packet format - standard 3-byte PS/2 mouse (no scroll wheel):
// Byte 0: [YOV][XOV][YS][XS][1][M][R][L]
// Byte 1: delta-X unsigned magnitude (sign in byte-0 bit 4)
// Byte 2: delta-Y unsigned magnitude (sign in byte-0 bit 5); PS/2 Y+ = up
//
// The ISR accumulates the 3-byte packet, converts it to a screen-space delta
// (Y-axis flipped), and queues the completed packet to the HAL's kernel-queued
// bottom half. Cursor drawing, public event enqueue, and optional callbacks
// run from that bottom half instead of hard IRQ context.
//
// Threading model
// ---------------
// Public events are produced by the mouse DPC and consumed by callers.
// Raw completed packets are produced by the ISR and consumed by the same DPC.
// On SMP, add acquire/release barriers around the ring head/tail pairs.
#include <stdint.h>
#include <stdbool.h>
#include <intrin.h>
#include <ntlite/ddi/hal_api.h>
#include <kernel/hal/hal_debug.h>
// -- PS/2 port addresses -------------------------------------------------------
#define PS2_DATA 0x60u
#define PS2_STAT 0x64u
#define PS2_CMD 0x64u
// -- Ring buffer ---------------------------------------------------------------
#define MOUSE_BUF_SIZE 64u
#define MOUSE_BUF_MASK (MOUSE_BUF_SIZE - 1u)
typedef struct {
int dx, dy;
uint8_t buttons; // bit0=left, bit1=right, bit2=middle
} MOUSE_EVENT;
static MOUSE_EVENT gBuf[MOUSE_BUF_SIZE];
static volatile int gHead = 0; // public consumer read pointer
static volatile int gTail = 0; // public producer write pointer (updated by DPC)
// Completed hardware packets waiting for the DPC bottom half.
static MOUSE_EVENT gDpcBuf[MOUSE_BUF_SIZE];
static volatile int gDpcHead = 0;
static volatile int gDpcTail = 0;
// -- Absolute cursor position & screen bounds ----------------------------------
static volatile int gMouseX = 0;
static volatile int gMouseY = 0;
static volatile int gBoundsW = 1920;
static volatile int gBoundsH = 1080;
// -- 3-byte packet assembly ----------------------------------------------------
static volatile uint8_t gPacket[3];
static volatile int gPacketIdx = 0; // 0, 1, or 2
// -- Optional callback (called from mouse DPC) ---------------------------------
static void (* volatile gCallback)(int dx, int dy, uint8_t buttons) = NULL;
// -- Cursor helpers provided by hal_screen.c -----------------------------------
// Declared here; defined in hal_screen.c.
extern void HalScreenDrawCursor(int x, int y);
extern void HalScreenEraseCursor(void);
// -- 8042 low-level helpers ----------------------------------------------------
// Wait until the 8042's input buffer is empty (bit 1 of status = 0) so we
// can safely write to PS2_DATA or PS2_CMD.
static void Ps2WaitInput(void) {
int timeout = 100000;
while ((__inbyte(PS2_STAT) & 0x02u) && --timeout) { /* spin */ }
}
// Wait until the 8042's output buffer has data (bit 0 of status = 1).
static void Ps2WaitOutput(void) {
int timeout = 5000000;
while (!(__inbyte(PS2_STAT) & 0x01u) && --timeout) { /* spin */ }
}
// Reads from PS2_DATA until the output buffer is empty
static void Ps2FlushOutput(void) {
int timeout = 100000;
while ((__inbyte(PS2_STAT) & 0x01u) && --timeout) {
__inbyte(PS2_DATA);
}
}
// Route the next write to the auxiliary (mouse) device rather than the keyboard.
static void MouseSendByte(uint8_t byte) {
Ps2WaitInput();
__outbyte(PS2_CMD, 0xD4u); // "write to mouse" prefix
Ps2WaitInput();
__outbyte(PS2_DATA, byte);
}
// Read one byte from the PS/2 output buffer (shared by keyboard and mouse).
static uint8_t MouseRecvByte(void) {
Ps2WaitOutput();
return __inbyte(PS2_DATA);
}
// -- Deferred mouse bottom half -------------------------------------------------
static void MouseDpc(void) {
for (;;) {
if (gDpcHead == gDpcTail)
break;
MOUSE_EVENT ev = gDpcBuf[gDpcHead];
gDpcHead = (gDpcHead + 1) & (int)MOUSE_BUF_MASK;
// Update absolute position and redraw the cursor outside DIRQL.
HalScreenEraseCursor();
int nx = gMouseX + ev.dx;
int ny = gMouseY + ev.dy;
if (nx < 0) nx = 0;
if (nx >= gBoundsW) nx = gBoundsW - 1;
if (ny < 0) ny = 0;
if (ny >= gBoundsH) ny = gBoundsH - 1;
gMouseX = nx;
gMouseY = ny;
HalScreenDrawCursor(nx, ny);
// Publish event to the normal consumer ring.
int next = (gTail + 1) & (int)MOUSE_BUF_MASK;
if (next != gHead) {
gBuf[gTail] = ev;
gTail = next;
}
void (*cb)(int, int, uint8_t) = (void (*)(int, int, uint8_t))gCallback;
if (cb)
cb(ev.dx, ev.dy, ev.buttons);
}
}
// -- Interrupt service routine --------------------------------------------------
// Called with interrupts disabled by KeIrqDispatch (IRQ 12).
// The dispatcher sends the APIC EOI after this function returns.
static void MouseIsr(void) {
uint8_t data = __inbyte(PS2_DATA);
// Synchronisation guard: the first byte of every packet has bit 3 set.
// If we lose sync, wait for the next valid first byte before assembling.
if (gPacketIdx == 0) {
if (!(data & 0x08u)) return; // not a valid first byte - discard
}
gPacket[gPacketIdx++] = data;
if (gPacketIdx < 3) return; // packet not yet complete
gPacketIdx = 0;
// -- Decode flags ----------------------------------------------------------
uint8_t flags = gPacket[0];
// Overflow bits: if either is set the movement data is meaningless.
if (flags & 0xC0u) return;
uint8_t buttons = flags & 0x07u;
// Convert unsigned magnitudes + sign bits to signed 9-bit values.
int dx = (int)gPacket[1] - ((flags & 0x10u) ? 256 : 0);
int dy = (int)gPacket[2] - ((flags & 0x20u) ? 256 : 0);
dy = -dy; // PS/2 Y+ = up; screen Y+ = down, so invert.
// -- Queue completed packet to the DPC bottom half -------------------------
int next = (gDpcTail + 1) & (int)MOUSE_BUF_MASK;
if (next != gDpcHead) {
gDpcBuf[gDpcTail].dx = dx;
gDpcBuf[gDpcTail].dy = dy;
gDpcBuf[gDpcTail].buttons = buttons;
gDpcTail = next;
}
}
// -- Consumer API --------------------------------------------------------------
static bool MousePoll(void) {
return gHead != gTail;
}
static bool MouseRead(int* dx, int* dy, uint8_t* buttons) {
if (gHead == gTail) return false;
*dx = gBuf[gHead].dx;
*dy = gBuf[gHead].dy;
*buttons = gBuf[gHead].buttons;
gHead = (gHead + 1) & (int)MOUSE_BUF_MASK;
return true;
}
static void MouseGetPosition(int* x, int* y) {
*x = gMouseX;
*y = gMouseY;
}
static void MouseSetPosition(int x, int y) {
gMouseX = x;
gMouseY = y;
}
static void MouseSetBounds(int w, int h) {
gBoundsW = w;
gBoundsH = h;
}
static void MouseSetCallback(void (*cb)(int dx, int dy, uint8_t buttons)) {
gCallback = cb;
}
// -- Initializer ---------------------------------------------------------------
// Called from HalInitialize in hal_main.c after the screen is ready.
// hal_keyboard.c has already sent 0xA8 (enable aux port) to port 0x64.
void HalMouseInitialize(HAL_MOUSE* out, int screenW, int screenH) {
gBoundsW = screenW;
gBoundsH = screenH;
gMouseX = screenW / 2;
gMouseY = screenH / 2;
// -----------------------------------------------------------------
// Step 0: Deafen the controller and flush
// -----------------------------------------------------------------
Ps2WaitInput();
__outbyte(PS2_CMD, 0xA7u); // Disable Aux port (ignores mouse)
Ps2WaitInput();
__outbyte(PS2_CMD, 0xADu); // Disable Main port (ignores keyboard)
// Now flush the buffer. Because the ports are disabled, we guarantee
// no new data can sneak in behind our backs.
Ps2FlushOutput();
// -----------------------------------------------------------------
// Step 1: Safely configure the 8042 Command Byte
// -----------------------------------------------------------------
Ps2WaitInput();
__outbyte(PS2_CMD, 0x20u); // read current command byte
Ps2WaitOutput();
uint8_t cmd = __inbyte(PS2_DATA);
cmd |= 0x02u; // enable aux interrupt
cmd &= ~0x20u; // clear "disable aux clock"
Ps2WaitInput();
__outbyte(PS2_CMD, 0x60u); // write command byte
Ps2WaitInput();
__outbyte(PS2_DATA, cmd);
// Re-enable both ports now that config is safely written
Ps2WaitInput();
__outbyte(PS2_CMD, 0xA8u); // Enable Aux port
Ps2WaitInput();
__outbyte(PS2_CMD, 0xAEu); // Enable Main port
// -----------------------------------------------------------------
// Step 2: Reset mouse (0xFF).
// -----------------------------------------------------------------
MouseSendByte(0xFFu); // reset
// The BIOS or an earlier phase might have left a movement packet
// partially in flight right as we re-enabled the port.
// We loop and discard anything that isn't the 0xFA ACK.
uint8_t ack;
int retries = 10;
do {
ack = MouseRecvByte();
} while (ack != 0xFAu && --retries > 0);
// Thanks to the increased Ps2WaitOutput timeout, we will actually
// wait long enough for the physical hardware self-test to finish here.
MouseRecvByte(); // 0xAA - BAT passed
MouseRecvByte(); // 0x00 - device ID
// -----------------------------------------------------------------
// Step 3: Set default parameters (sampling rate 100, 4 counts/mm).
// Mouse replies: ACK.
// -----------------------------------------------------------------
MouseSendByte(0xF6u); // set defaults
MouseRecvByte(); // ACK
// -----------------------------------------------------------------
// Step 4: Enable data reporting.
// Mouse will now send 3-byte packets on every movement/button event.
// -----------------------------------------------------------------
MouseSendByte(0xF4u); // enable data reporting
MouseRecvByte(); // ACK
// Draw the initial cursor at the centre of the screen.
HalScreenDrawCursor(gMouseX, gMouseY);
// Populate vtable.
out->Poll = MousePoll;
out->Read = MouseRead;
out->SetCallback = MouseSetCallback;
out->GetPosition = MouseGetPosition;
out->SetPosition = MouseSetPosition;
out->SetBounds = MouseSetBounds;
out->Isr = MouseIsr;
out->Dpc = MouseDpc;
out->IrqNumber = 12;
}
+70
View File
@@ -0,0 +1,70 @@
// hal_pci.c - PCI configuration space via Mechanism 1 port I/O
#include <stdint.h>
#include <ntlite/ddi/hal_api.h>
#define PCI_CONFIG_ADDR 0xCF8
#define PCI_CONFIG_DATA 0xCFC
static uint32_t MakeAddr(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t reg) {
return 0x80000000UL
| ((uint32_t)bus << 16)
| ((uint32_t)(dev & 0x1F) << 11)
| ((uint32_t)(fn & 0x07) << 8)
| (reg & 0xFC);
}
static uint32_t PciRead32(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t reg) {
__outdword(PCI_CONFIG_ADDR, MakeAddr(bus, dev, fn, reg));
return __indword(PCI_CONFIG_DATA);
}
static void PciWrite32(uint8_t bus, uint8_t dev, uint8_t fn,
uint8_t reg, uint32_t val) {
__outdword(PCI_CONFIG_ADDR, MakeAddr(bus, dev, fn, reg));
__outdword(PCI_CONFIG_DATA, val);
}
static bool PciFindDevice(uint16_t vendor, uint16_t device,
uint8_t* outBus, uint8_t* outDev, uint8_t* outFn) {
for (int bus = 0; bus < 256; bus++)
for (int dev = 0; dev < 32; dev++)
for (int fn = 0; fn < 8; fn++) {
uint32_t id = PciRead32((uint8_t)bus, (uint8_t)dev, (uint8_t)fn, 0);
if ((id & 0xFFFF) == vendor && (id >> 16) == device) {
*outBus = (uint8_t)bus; *outDev = (uint8_t)dev; *outFn = (uint8_t)fn;
return true;
}
}
return false;
}
static bool PciFindClass(uint8_t classCode, uint8_t subclass,
uint8_t* outBus, uint8_t* outDev, uint8_t* outFn) {
for (int bus = 0; bus < 256; bus++)
for (int dev = 0; dev < 32; dev++)
for (int fn = 0; fn < 8; fn++) {
uint32_t id = PciRead32((uint8_t)bus,(uint8_t)dev,(uint8_t)fn,0);
if ((id & 0xFFFF) == 0xFFFF) continue; // no device
uint32_t cc = PciRead32((uint8_t)bus,(uint8_t)dev,(uint8_t)fn,8);
if (((cc >> 24) & 0xFF) == classCode &&
((cc >> 16) & 0xFF) == subclass) {
*outBus = (uint8_t)bus; *outDev = (uint8_t)dev; *outFn = (uint8_t)fn;
return true;
}
}
return false;
}
static uint8_t PciGetIrqLine(uint8_t bus, uint8_t dev, uint8_t fn) {
// PCI config register 0x3C: byte 0 = IRQ line, byte 1 = IRQ pin
uint32_t val = PciRead32(bus, dev, fn, 0x3C);
return (uint8_t)(val & 0xFF); // 0xFF = not connected
}
void HalPciInitialize(HAL_PCI* out) {
out->Read32 = PciRead32;
out->Write32 = PciWrite32;
out->FindDevice = PciFindDevice;
out->FindClass = PciFindClass;
out->GetIrqLine = PciGetIrqLine;
}
+285
View File
@@ -0,0 +1,285 @@
// 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
// each byte is the leftmost pixel.
#include <stdint.h>
#include <string.h>
#include <intrin.h>
#include <ntlite/ddi/hal_api.h>
static uint32_t* gFb = (uint32_t *)0;
static int gWidth = 0;
static int gHeight = 0;
static int gStride = 0; // pixels per row
static int gCursorX = 0, gCursorY = 0;
#define FONT_W 8
#define FONT_H 16
// ---------------------------------------------------------------------------
// 8x16 VGA font - printable ASCII only (glyph 0 = space = 0x20)
// ---------------------------------------------------------------------------
#include <kernel/hal/font8x16.h> // see font8x16.h below
// ---------------------------------------------------------------------------
// Internals
// ---------------------------------------------------------------------------
static inline void PutPixelRaw(int x, int y, uint32_t color) {
if ((unsigned)x < (unsigned)gWidth && (unsigned)y < (unsigned)gHeight)
gFb[y * gStride + x] = color;
}
// ---------------------------------------------------------------------------
// HAL_SCREEN implementations
// ---------------------------------------------------------------------------
static void ScreenClear(uint32_t color) {
for (int y = 0; y < gHeight; y++)
for (int x = 0; x < gWidth; x++)
gFb[y * gStride + x] = color;
gCursorX = 0; gCursorY = 0;
}
static void ScreenPutPixel(int x, int y, uint32_t color) {
PutPixelRaw(x, y, color);
}
static void ScreenBlit(int x, int y, int w, int h, const uint32_t* pixels) {
// Calculate clipping bounds
int startX = (x < 0) ? 0 : x;
int startY = (y < 0) ? 0 : y;
int endX = (x + w > gWidth) ? gWidth : (x + w);
int endY = (y + h > gHeight) ? gHeight : (y + h);
int drawW = endX - startX;
int drawH = endY - startY;
// If the image is entirely off-screen, do nothing
if (drawW <= 0 || drawH <= 0) {
return;
}
// Adjust the source pointer if the image was clipped on the top or left
int srcOffsetX = startX - x;
int srcOffsetY = startY - y;
// Calculate bytes to copy per row
size_t bytesPerRow = (size_t)drawW * sizeof(uint32_t);
// If the width we are drawing exactly matches the physical screen stride,
// AND it matches the original source image width, memory is perfectly contiguous.
if (drawW == gStride && drawW == w) {
uint32_t* dst = gFb + (startY * gStride) + startX;
const uint32_t* src = pixels + (srcOffsetY * w) + srcOffsetX;
memcpy(dst, src, bytesPerRow * drawH);
return;
}
// Copy row-by-row
for (int row = 0; row < drawH; row++) {
// Destination in the actual framebuffer (accounting for stride)
uint32_t* dst = gFb + ((startY + row) * gStride) + startX;
// Source from the provided pixel buffer
const uint32_t* src = pixels + ((srcOffsetY + row) * w) + srcOffsetX;
memcpy(dst, src, bytesPerRow);
}
}
static void ScreenGetSize(int* w, int* h) { *w = gWidth; *h = gHeight; }
static void ScreenScroll(int lines) {
if (lines <= 0 || lines >= gHeight) { ScreenClear(0); return; }
int rowBytes = gStride * sizeof(uint32_t);
memmove(gFb, gFb + lines * gStride,
(size_t)(gHeight - lines) * rowBytes);
// Clear the revealed rows at the bottom.
memset(gFb + (gHeight - lines) * gStride, 0,
(size_t)lines * rowBytes);
}
static void ScreenPutChar(char c, int x, int y, uint32_t fg, uint32_t bg) {
if ((unsigned char)c < 0x20 || (unsigned char)c > 0x7E) c = '?';
const uint8_t* glyph = Font8x16 + ((unsigned char)c - 0x20) * 16;
for (int row = 0; row < 16; row++) {
uint8_t bits = glyph[row];
for (int col = 0; col < 8; col++) {
uint32_t color = (bits & (1 << col)) ? fg : bg; // i don't know why, i don't want to know why
// i shouldn't have to wonder why but the font is backwards unless we do this terriblness
PutPixelRaw(x + col, y + row, color);
}
}
}
static void ScreenPrintChar(char c, uint32_t fg, uint32_t bg) {
int cols = gWidth / FONT_W;
int rows = gHeight / FONT_H;
// Mirror to serial
while ((__inbyte(0x3FD) & 0x20) == 0);
if (c == '\n') __outbyte(0x3F8, '\r');
__outbyte(0x3F8, c);
if (c == '\n') {
gCursorX = 0;
gCursorY++;
} else if (c == '\r') {
gCursorX = 0;
} else if (c == '\b') {
if (gCursorX > 0) {
gCursorX--;
} else if (gCursorY > 0) {
gCursorY--;
gCursorX = cols - 1;
}
} else {
ScreenPutChar(c, gCursorX * FONT_W, gCursorY * FONT_H, fg, bg);
if (++gCursorX >= cols) { gCursorX = 0; gCursorY++; }
}
if (gCursorY >= rows) {
ScreenScroll(FONT_H);
gCursorY = rows - 1;
}
}
// ---------------------------------------------------------------------------
// Mouse cursor – 12×19 monochrome arrow sprite
// 0 = transparent 1 = black outline 2 = white fill
// The hotspot is at (0,0) (top-left pixel = tip of the arrow).
// ---------------------------------------------------------------------------
#define CURSOR_W 16
#define CURSOR_H 25
// Each entry is 0xAARRGGBB stored as a uint32_t.
// Pixels with brightness < 24 are fully transparent.
static const unsigned int gCursorPixels[CURSOR_H][CURSOR_W] = {
{ 0x7F575757, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFAFAFA, 0x855D5D5D, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFEFEFE, 0xFFFFFFFF, 0x865E5E5E, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFDFDFD, 0xFFFDFDFD, 0xFFFFFFFF, 0x8A626262, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFFFFFF, 0xFFFEFEFE, 0xFFFDFDFD, 0xFFFFFFFF, 0x8D656565, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFEFEFE, 0xFFFDFDFD, 0xFFFFFFFF, 0x8E666666, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFEFEFE, 0xFFFCFCFC, 0xFFFFFFFF, 0x91696969, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFEFEFE, 0xFFFDFDFD, 0xFFFFFFFF, 0x946C6C6C, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFEFEFE, 0xFFFCFCFC, 0xFFFFFFFF, 0x956D6D6D, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFEFEFE, 0xFFFCFCFC, 0xFFFFFFFF, 0x99717171, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFEFEFE, 0xFFFCFCFC, 0xFFFFFFFF, 0x9B737373, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFEFEFE, 0xFFFCFCFC, 0xFFFFFFFF, 0x9D757575, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFEFEFE, 0xFFFCFCFC, 0xFFFFFFFF, 0xA0787878, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFDFDFD, 0xFFFDFDFD, 0xFFFCFCFC, 0xFFF9F9F9, 0xFFFFFFFF, 0xA1797979, 0x00000000, 0x00000000 },
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFEFEFE, 0xFFFEFEFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xAE868686, 0x00000000 },
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFEFEFE, 0xFFFFFFFF, 0xFDD5D5D5, 0xF4CCCCCC, 0xF4CCCCCC, 0xF4CCCCCC, 0xF3CBCBCB, 0xF1C9C9C9, 0xFAD2D2D2, 0x7E565656 },
{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFEFEFE, 0xFFFEFEFE, 0xFFFCFCFC, 0xFFEFEFEF, 0xFFFCFCFC, 0xFFFFFFFF, 0x9A727272, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFFFFFF, 0xFFFEFEFE, 0xFFFDFDFD, 0xFFFFFFFF, 0x7F575757, 0x8F676767, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFE0E0E0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFEFEFE, 0xFFFDFDFD, 0xFFFFFFFF, 0x90686868, 0x00000000, 0x00000000, 0xFFEBEBEB, 0xFFFFFFFF, 0xFFFFFFFF, 0x81595959, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFDFDFD, 0xFFFFFFFF, 0x8C646464, 0x00000000, 0x00000000, 0x00000000, 0xB78F8F8F, 0xFFFFFFFF, 0xFFFEFEFE, 0xECC4C4C4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0xFFFFFFFF, 0x90686868, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x50282828, 0xFFF9F9F9, 0xFFFFFFFF, 0xFFFFFFFF, 0x623A3A3A, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x865E5E5E, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xD8B0B0B0, 0xFFFFFFFF, 0xFFFFFFFF, 0xCDA5A5A5, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6C444444, 0xFFFFFFFF, 0xFFFCFCFC, 0xFFF4F4F4, 0x4D252525, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xF2CACACA, 0xFFFFFFFF, 0xFFFFFFFF, 0x99717171, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
{ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8E666666, 0xEFC7C7C7, 0x7D555555, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
};
// Saved framebuffer pixels beneath the current cursor position.
static uint32_t gCursorSavedBg[CURSOR_W * CURSOR_H];
static int gCursorDrawX = -1; // -1 = cursor not yet drawn
static int gCursorDrawY = -1;
// Save the background rectangle [x,y,CURSOR_W,CURSOR_H] from the framebuffer.
static void CursorSaveBg(int x, int y) {
for (int row = 0; row < CURSOR_H; row++) {
int fy = y + row;
for (int col = 0; col < CURSOR_W; col++) {
int fx = x + col;
uint32_t px = 0;
if ((unsigned)fx < (unsigned)gWidth && (unsigned)fy < (unsigned)gHeight)
px = gFb[fy * gStride + fx];
gCursorSavedBg[row * CURSOR_W + col] = px;
}
}
}
// Restore the background previously saved by CursorSaveBg.
static void CursorRestoreBg(int x, int y) {
for (int row = 0; row < CURSOR_H; row++) {
int fy = y + row;
for (int col = 0; col < CURSOR_W; col++) {
int fx = x + col;
if ((unsigned)fx < (unsigned)gWidth && (unsigned)fy < (unsigned)gHeight)
gFb[fy * gStride + fx] = gCursorSavedBg[row * CURSOR_W + col];
}
}
}
// Alpha-blend a cursor pixel over a framebuffer pixel.
// Framebuffer format: 0x00RRGGBB (high byte ignored / always 0).
// Cursor pixel format: 0xAARRGGBB.
static inline uint32_t BlendPixel(uint32_t dst, uint32_t src) {
uint8_t a = (uint8_t)(src >> 24);
if (a == 0) return dst;
if (a == 255) return src & 0x00FFFFFFu;
uint8_t sr = (uint8_t)(src >> 16);
uint8_t sg = (uint8_t)(src >> 8);
uint8_t sb = (uint8_t)(src );
uint8_t dr = (uint8_t)(dst >> 16);
uint8_t dg = (uint8_t)(dst >> 8);
uint8_t db = (uint8_t)(dst );
uint8_t na = 255 - a;
uint8_t or_ = (uint8_t)((a * sr + na * dr) >> 8);
uint8_t og = (uint8_t)((a * sg + na * dg) >> 8);
uint8_t ob = (uint8_t)((a * sb + na * db) >> 8);
return ((uint32_t)or_ << 16) | ((uint32_t)og << 8) | ob;
}
// Draw the arrow sprite at (x,y), saving the background first.
// Called from hal_mouse.c via extern declaration.
void HalScreenDrawCursor(int x, int y) {
CursorSaveBg(x, y);
gCursorDrawX = x;
gCursorDrawY = y;
for (int row = 0; row < CURSOR_H; row++) {
int fy = y + row;
for (int col = 0; col < CURSOR_W; col++) {
uint32_t src = gCursorPixels[row][col];
if ((src >> 24) == 0) continue; // fully transparent, skip
int fx = x + col;
if ((unsigned)fx < (unsigned)gWidth && (unsigned)fy < (unsigned)gHeight) {
uint32_t* dst = &gFb[fy * gStride + fx];
*dst = BlendPixel(*dst, src);
}
}
}
}
// Erase the cursor by restoring the saved background.
void HalScreenEraseCursor(void) {
if (gCursorDrawX < 0) return; // never drawn
CursorRestoreBg(gCursorDrawX, gCursorDrawY);
gCursorDrawX = -1;
gCursorDrawY = -1;
}
// ---------------------------------------------------------------------------
// Populate the HAL_SCREEN vtable
// ---------------------------------------------------------------------------
void HalScreenInitialize(uintptr_t fb, int w, int h, int stride,
HAL_SCREEN* out) {
gFb = (uint32_t *)fb;
gWidth = w;
gHeight = h;
gStride = stride;
out->Clear = ScreenClear;
out->PutPixel = ScreenPutPixel;
out->Blit = ScreenBlit;
out->GetSize = ScreenGetSize;
out->Scroll = ScreenScroll;
out->PutChar = ScreenPutChar;
out->PrintChar = ScreenPrintChar;
out->DrawCursor = HalScreenDrawCursor;
out->EraseCursor = HalScreenEraseCursor;
ScreenClear(0x000000);
}
+218
View File
@@ -0,0 +1,218 @@
// hal_timer.c - Local APIC timer
#include <stdint.h>
#include <intrin.h>
#include <ntlite/ddi/hal_api.h>
#include <kernel/hal/hal_apic.h>
#include <kernel/hal/hal_debug.h>
#define LAPIC_TIMER_LVT 0x320
#define LAPIC_TIMER_INIT 0x380
#define LAPIC_TIMER_CUR 0x390
#define LAPIC_TIMER_DIV 0x3E0
#define TIMER_VECTOR 0x20 // vector 0x20 = IRQ 0 slot in IDT
#define TIMER_PERIODIC (1 << 17)
#define TIMER_MASKED (1 << 16)
#define TIMER_DIV16 0x3
#define TIMER_PERIOD_MS 10
#define PIT_HZ 1193182UL
extern HAL_API gApi;
static volatile uint32_t* gLapic = NULL;
static uint32_t gApicTicksPerUs = 0;
static uint32_t gApicTicksPerQuantum = 0;
static uint64_t gHpetTicksPerUs = 0;
static uint64_t gHpetHz = 0;
static volatile uint64_t* gHpet = NULL;
#define LAPIC_REG(off) (*(volatile uint32_t *)((uint8_t *)gLapic + (off)))
static volatile uint64_t gTicks = 0;
void (* volatile gTimerCallback)(void) = NULL;
static inline void outb(uint16_t port, uint8_t val) { __outbyte(port, val); }
static inline uint8_t inb(uint16_t port) { return __inbyte(port); }
static void TimerIsr(void) {
gTicks++;
if (gTimerCallback) gTimerCallback();
// EOI is sent by KeIrqDispatch after this returns
}
static uint64_t QueryTicks(void) {
// Prefer HPET when present: it is already a monotonically increasing main
// counter and avoids races between the LAPIC periodic tick and the current
// countdown register.
if (gHpet && gHpetHz) {
uint64_t counter = gHpet[30]; // offset 0xF0: main counter
uint64_t seconds = counter / gHpetHz;
uint64_t rem = counter % gHpetHz;
return seconds * 1000000ull + (rem * 1000000ull) / gHpetHz;
}
// Fallback: combine the coarse periodic tick with the current LAPIC
// countdown. Read the coarse tick twice so an interrupt between gTicks and
// LAPIC_TIMER_CUR cannot make time jump backwards by almost one quantum.
uint64_t baseTicks1;
uint64_t baseTicks2;
uint32_t current;
do {
baseTicks1 = gTicks;
current = LAPIC_REG(LAPIC_TIMER_CUR);
baseTicks2 = gTicks;
} while (baseTicks1 != baseTicks2);
uint32_t initial = gApicTicksPerQuantum;
uint32_t elapsedApicTicks = 0;
if (current < initial) {
elapsedApicTicks = initial - current;
}
uint64_t subQuantumUs = 0;
if (gApicTicksPerUs)
subQuantumUs = elapsedApicTicks / gApicTicksPerUs;
return (baseTicks1 * TIMER_PERIOD_MS * 1000ull) + subQuantumUs;
}
static void Stall(uint32_t us) {
// Priority 1: Use HPET (Highest Precision)
if (gHpet && gHpetTicksPerUs > 0) {
uint64_t start = gHpet[30]; // Offset 0xF0 is the Main Counter
uint64_t delta = (uint64_t)us * gHpetTicksPerUs;
while ((gHpet[30] - start) < delta) {
_mm_pause(); // Hint to CPU we are in a spin-loop
}
return;
}
// Priority 2: Use APIC Timer (High Precision, but handles wrap-around)
if (gApicTicksPerUs > 0) {
uint32_t total_ticks = us * gApicTicksPerUs;
uint32_t last_val = LAPIC_REG(LAPIC_TIMER_CUR);
uint32_t elapsed = 0;
while (elapsed < total_ticks) {
uint32_t current = LAPIC_REG(LAPIC_TIMER_CUR);
if (current < last_val) {
elapsed += (last_val - current);
} else if (current > last_val) {
// Handled the reset/wrap at the end of TIMER_PERIOD_MS
uint32_t init_val = LAPIC_REG(LAPIC_TIMER_INIT);
elapsed += (last_val + (init_val - current));
}
last_val = current;
_mm_pause();
}
return;
}
// Priority 3: Fallback to Port 0x80
for (uint32_t i = 0; i < us; i++) {
__outbyte(0x80, 0);
}
}
// Returns HPET ticks/second, or 0 if HPET is unavailable.
static uint64_t HpetInit(uintptr_t hpetPhys) {
// HPET register block, accessed through physical window
volatile uint64_t *hpet = (volatile uint64_t *)gApi.PhysToVirt(hpetPhys);
// General Capabilities register (offset 0):
// Bits 63:32 = counter clock period in femtoseconds
uint64_t caps = hpet[0];
uint32_t periodFs = (uint32_t)(caps >> 32);
if (!periodFs) return 0;
// Enable the HPET main counter (General Configuration, offset 0x10, bit 0)
hpet[2] |= 1; // offset 0x10 / 8 = index 2
return (uint64_t)1e15 / periodFs; // ticks per second
}
// Use PIT channel 2 one-shot to measure how many APIC ticks elapse in 10 ms, then return ticks/ms.
static uint32_t CalibrateApicTimerViaPit(void) {
// Divide by 16
LAPIC_REG(LAPIC_TIMER_DIV) = TIMER_DIV16;
// Mask, set vector - leave masked during calibration
LAPIC_REG(LAPIC_TIMER_LVT) = TIMER_MASKED | TIMER_VECTOR;
// Load max count
LAPIC_REG(LAPIC_TIMER_INIT) = 0xFFFFFFFF;
// PIT channel 2: one-shot, ~10 ms
uint16_t pit_count = (uint16_t)(PIT_HZ / 100); // 11931 ≈ 10 ms
outb(0x61, (inb(0x61) & ~0x02) | 0x01); // gate on, speaker off
outb(0x43, 0xB0); // ch2, lo/hi, mode 0, binary
outb(0x42, (uint8_t)(pit_count & 0xFF));
outb(0x42, (uint8_t)(pit_count >> 8));
// Wait for OUT2 (bit 5 of port 0x61) to go high
while (!(inb(0x61) & 0x20)) _mm_pause();
uint32_t elapsed = 0xFFFFFFFF - LAPIC_REG(LAPIC_TIMER_CUR);
return elapsed / 10; // ticks per ms
}
// Use HPET main counter to measure how many APIC ticks elapse in 10 ms, then return ticks/ms.
static uint32_t CalibrateApicTimerViaHpet(uintptr_t hpetPhys) {
volatile uint64_t *hpet = (volatile uint64_t *)gApi.PhysToVirt(hpetPhys);
uint64_t hpetHz = HpetInit(hpetPhys);
if (!hpetHz) return 0;
// Ticks in 10 ms = hpetHz / 100
uint64_t ticksFor10ms = hpetHz / 100;
LAPIC_REG(LAPIC_TIMER_DIV) = TIMER_DIV16;
LAPIC_REG(LAPIC_TIMER_LVT) = TIMER_MASKED | TIMER_VECTOR;
LAPIC_REG(LAPIC_TIMER_INIT) = 0xFFFFFFFF;
// HPET main counter is at offset 0xF0, index 0xF0/8 = 30
uint64_t hpetStart = hpet[30];
while ((hpet[30] - hpetStart) < ticksFor10ms) _mm_pause();
uint32_t elapsed = 0xFFFFFFFF - LAPIC_REG(LAPIC_TIMER_CUR);
return elapsed / 10; // APIC ticks per ms
}
KSTATUS HalTimerInitialize(uintptr_t lapicPhys, uintptr_t hpetPhys, HAL_TIMER *out) {
gLapic = (volatile uint32_t *)gApi.PhysToVirt(lapicPhys);
HalDbgPrint("HAL: lapicPhys=0x%llX, lapicVirt=0x%llX, hpetPhys=0x%llX\n", lapicPhys, (uintptr_t)gLapic, hpetPhys);
uint32_t ticksPerMs = 0;
if (hpetPhys) {
HalDbgPrint("HAL: Attempting to calibrate APIC timer via HPET...\n");
ticksPerMs = CalibrateApicTimerViaHpet(hpetPhys);
}
if (!ticksPerMs) {
HalDbgPrint("HAL: HPET unavailable or calibration failed. Falling back to PIT...\n");
ticksPerMs = CalibrateApicTimerViaPit();
}
if (!ticksPerMs) {
HalDbgPrint("HAL: APIC calibration failed. How?\n");
return STATUS_DEVICE_ERROR;
}
gApicTicksPerUs = ticksPerMs / 1000;
gApicTicksPerQuantum = ticksPerMs * TIMER_PERIOD_MS;
if (hpetPhys) {
gHpet = (volatile uint64_t*)gApi.PhysToVirt(hpetPhys);
uint64_t hpetHz = HpetInit(hpetPhys);
gHpetHz = hpetHz;
gHpetTicksPerUs = hpetHz / 1000000;
}
HalDbgPrint("HAL: APIC timer: %u ticks/ms\n", ticksPerMs);
// Configure LAPIC timer in periodic mode
LAPIC_REG(LAPIC_TIMER_DIV) = TIMER_DIV16;
LAPIC_REG(LAPIC_TIMER_LVT) = TIMER_PERIODIC | TIMER_VECTOR;
LAPIC_REG(LAPIC_TIMER_INIT) = gApicTicksPerQuantum;
out->QueryTicks = QueryTicks;
out->Stall = Stall;
out->Isr = TimerIsr;
out->IrqNumber = 0;
return STATUS_SUCCESS;
}
+199
View File
@@ -0,0 +1,199 @@
#pragma once
// font8x16.h - embedded 8x16 VGA bitmap font, printable ASCII (0x20-0x7E)
// 95 glyphs × 16 bytes = 1520 bytes total.
// Each byte is one scanline; bit 7 = leftmost pixel.
#include <stdint.h>
static const uint8_t Font8x16[95 * 16] = {
// 0x20 ' '
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x21 '!'
0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
// 0x22 '"'
0x00,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x23 '#'
0x00,0x36,0x36,0x7F,0x36,0x36,0x36,0x7F,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x24 '$'
0x18,0x18,0x3E,0x63,0x03,0x03,0x1E,0x30,0x30,0x63,0x3E,0x18,0x18,0x00,0x00,0x00,
// 0x25 '%'
0x00,0x00,0x63,0x33,0x18,0x0C,0x06,0x31,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x26 '&'
0x00,0x1C,0x36,0x1C,0x0E,0x3B,0x33,0x33,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x27 '\''
0x00,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x28 '('
0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x29 ')'
0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x2A '*'
0x00,0x00,0x00,0x33,0x1E,0xFF,0x1E,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x2B '+'
0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x2C ','
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x2D '-'
0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x2E '.'
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x2F '/'
0x00,0x60,0x30,0x18,0x0C,0x06,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x30 '0'
0x00,0x3C,0x66,0x66,0x76,0x6E,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x31 '1'
0x00,0x18,0x1C,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x32 '2'
0x00,0x3C,0x66,0x60,0x30,0x18,0x0C,0x66,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x33 '3'
0x00,0x3C,0x66,0x60,0x38,0x60,0x60,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x34 '4'
0x00,0x30,0x38,0x3C,0x36,0x33,0x7F,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x35 '5'
0x00,0x7E,0x06,0x06,0x3E,0x60,0x60,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x36 '6'
0x00,0x38,0x0C,0x06,0x3E,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x37 '7'
0x00,0x7E,0x60,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x38 '8'
0x00,0x3C,0x66,0x66,0x3C,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x39 '9'
0x00,0x3C,0x66,0x66,0x7C,0x60,0x30,0x18,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x3A ':'
0x00,0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x3B ';'
0x00,0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x3C '<'
0x00,0x60,0x30,0x18,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x3D '='
0x00,0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x3E '>'
0x00,0x06,0x0C,0x18,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x3F '?'
0x00,0x3C,0x66,0x60,0x30,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x40 '@'
0x00,0x3E,0x63,0x7B,0x7B,0x7B,0x3B,0x03,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x41 'A'
0x00,0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x42 'B'
0x00,0x3E,0x66,0x66,0x3E,0x66,0x66,0x66,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x43 'C'
0x00,0x3C,0x66,0x06,0x06,0x06,0x06,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x44 'D'
0x00,0x1E,0x36,0x66,0x66,0x66,0x66,0x36,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x45 'E'
0x00,0x7E,0x06,0x06,0x3E,0x06,0x06,0x06,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x46 'F'
0x00,0x7E,0x06,0x06,0x3E,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x47 'G'
0x00,0x3C,0x66,0x06,0x06,0x76,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x48 'H'
0x00,0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x49 'I'
0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x4A 'J'
0x00,0x78,0x30,0x30,0x30,0x30,0x36,0x36,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x4B 'K'
0x00,0x66,0x36,0x1E,0x0E,0x1E,0x36,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x4C 'L'
0x00,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x4D 'M'
0x00,0x63,0x77,0x7F,0x6B,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x4E 'N'
0x00,0x63,0x67,0x6F,0x7B,0x73,0x63,0x63,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x4F 'O'
0x00,0x3C,0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x50 'P'
0x00,0x3E,0x66,0x66,0x3E,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x51 'Q'
0x00,0x3C,0x66,0x66,0x66,0x66,0x6E,0x3C,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x52 'R'
0x00,0x3E,0x66,0x66,0x3E,0x36,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x53 'S'
0x00,0x3C,0x66,0x06,0x1C,0x30,0x60,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x54 'T'
0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x55 'U'
0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x56 'V'
0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x57 'W'
0x00,0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x58 'X'
0x00,0x66,0x66,0x3C,0x18,0x3C,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x59 'Y'
0x00,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x5A 'Z'
0x00,0x7E,0x60,0x30,0x18,0x0C,0x06,0x06,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x5B '['
0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x5C '\'
0x00,0x03,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x5D ']'
0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x5E '^'
0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x5F '_'
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x60 '`'
0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x61-0x7A lowercase - condensed to save space, using same shapes as upper offset by 32
// 0x61 'a'
0x00,0x00,0x00,0x1C,0x30,0x3C,0x33,0x33,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x62 'b'
0x00,0x06,0x06,0x1E,0x36,0x66,0x66,0x66,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x63 'c'
0x00,0x00,0x00,0x3C,0x06,0x06,0x06,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x64 'd'
0x00,0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x65 'e'
0x00,0x00,0x00,0x3C,0x66,0x7E,0x06,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x66 'f'
0x00,0x38,0x0C,0x0C,0x3E,0x0C,0x0C,0x0C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x67 'g'
0x00,0x00,0x7C,0x66,0x66,0x66,0x7C,0x60,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x68 'h'
0x00,0x06,0x06,0x3E,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x69 'i'
0x00,0x18,0x00,0x1C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x6A 'j'
0x00,0x30,0x00,0x38,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x6B 'k'
0x00,0x06,0x06,0x66,0x36,0x1E,0x36,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x6C 'l'
0x00,0x1C,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x6D 'm'
0x00,0x00,0x00,0x37,0x7F,0x6B,0x6B,0x6B,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x6E 'n'
0x00,0x00,0x00,0x1E,0x36,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x6F 'o'
0x00,0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x70 'p'
0x00,0x00,0x3E,0x66,0x66,0x3E,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x71 'q'
0x00,0x00,0x7C,0x66,0x66,0x7C,0x60,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x72 'r'
0x00,0x00,0x00,0x3E,0x06,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x73 's'
0x00,0x00,0x00,0x3C,0x06,0x1C,0x30,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x74 't'
0x00,0x0C,0x0C,0x3E,0x0C,0x0C,0x0C,0x0C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x75 'u'
0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x76 'v'
0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x77 'w'
0x00,0x00,0x00,0x63,0x6B,0x6B,0x7F,0x77,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x78 'x'
0x00,0x00,0x00,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x79 'y'
0x00,0x00,0x66,0x66,0x66,0x7C,0x60,0x30,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x7A 'z'
0x00,0x00,0x00,0x7E,0x30,0x18,0x0C,0x06,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x7B '{'
0x00,0x30,0x18,0x18,0x0C,0x18,0x18,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x7C '|'
0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x7D '}'
0x00,0x0C,0x18,0x18,0x30,0x18,0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x7E '~'
0x00,0x6E,0x3B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
@@ -0,0 +1,9 @@
// hal_apic.h
#pragma once
#include <stdint.h>
void HalApicRouteIrq(uint8_t irq);
void HalApicMaskIrq(uint8_t irq);
void HalApicUnmaskIrq(uint8_t irq);
void HalApicSendEoi(void);
void HalApicInitialize(uintptr_t lapicPhys, uintptr_t ioapicPhys);
@@ -0,0 +1,4 @@
#pragma once
// hal_debug.h - HAL debug output function
void HalDbgPrint(const char* fmt, ...);
@@ -4,22 +4,15 @@
// Kernel and user code open files through IoOpenFile.
#include <stdint.h>
#include <stddef.h>
#include <ke_status.h>
#include <ob_object.h>
#include <ke_spinlock.h>
#include <sys_string.h>
#include <ntlite/status.h>
#include <kernel/ob_object.h>
#include <kernel/ke_spinlock.h>
#include <ntlite/string_view.h>
#include <ntlite/dirent.h>
// ---------------------------------------------------------------------------
// KDIR_ENTRY - one directory entry returned by ReadDir / SYS_READ_DIR
// Attribute flags match FAT32/Win32: ATTR_DIRECTORY=0x10, ATTR_ARCHIVE=0x20
// ---------------------------------------------------------------------------
#define KDIR_NAME_MAX 260
typedef struct KDIR_ENTRY {
char Name[KDIR_NAME_MAX]; // null-terminated filename
uint8_t Attr; // FAT attribute byte (0x10=dir, 0x20=file)
uint32_t FileSize; // 0 for directories
} KDIR_ENTRY;
// Kernel/filesystem code uses the public directory-entry ABI directly.
typedef SYS_DIR_ENTRY KDIR_ENTRY;
#define KDIR_NAME_MAX SYS_DIR_NAME_MAX
// Native asynchronous filesystem completion. Filesystems that provide
// ReadAsync/WriteAsync accept the operation, return STATUS_PENDING, and later
@@ -99,7 +92,7 @@ typedef struct IO_FILESYSTEM {
// Fills 'out' with name, attributes, and size.
// Returns STATUS_NO_MORE_FILES when the directory is exhausted.
KSTATUS (*ReadDir)(struct IO_FILESYSTEM* fs, void* dirCtx,
struct KDIR_ENTRY* out);
KDIR_ENTRY* out);
// Release resources allocated by OpenDir.
void (*CloseDir)(struct IO_FILESYSTEM* fs, void* dirCtx);
@@ -8,8 +8,8 @@
#include <stdint.h>
#include <stdbool.h>
#include <ke_list.h>
#include <ke_status.h>
#include <kernel/ke_list.h>
#include <ntlite/status.h>
struct THREAD;
typedef struct THREAD THREAD;
+49
View File
@@ -0,0 +1,49 @@
#pragma once
// ke_cpu.h - per-CPU execution state
//
// SMP phase 1 still runs only the bootstrap processor, but the kernel now
// represents CPU-local state explicitly. AP startup can fill additional KCPU
// entries later without first untangling scheduler/IRQL/TSS globals.
#include <stdint.h>
#include <kernel/ke_irql.h>
#include <kernel/ke_idt.h>
#define KE_MAX_CPUS 32u
#define KE_INVALID_CPU 0xFFFFFFFFu
struct THREAD;
typedef struct KCPU {
uint32_t CpuIndex;
uint32_t LapicId;
uint8_t Present;
uint8_t Online;
uint8_t IsBsp;
uint8_t Reserved0;
struct THREAD* CurrentThread;
struct THREAD* IdleThread;
struct THREAD* OutgoingThread;
KIRQL CurrentIrql;
uint32_t InterruptDepth;
volatile long ReschedulePending;
TSS64 Tss;
void* KernelStack;
uintptr_t KernelStackTop;
uint64_t SchedulerTicks;
uint64_t ContextSwitches;
} KCPU;
extern KCPU gCpus[KE_MAX_CPUS];
extern uint32_t gCpuCount;
void KeInitializeBootstrapCpu(void);
KCPU* KeGetCurrentCpu(void);
KCPU* KeGetCpuByIndex(uint32_t index);
uint32_t KeGetCurrentCpuIndex(void);
TSS64* KeGetCurrentTss(void);
File renamed without changes.
@@ -8,8 +8,8 @@
#include <stdint.h>
#include <stdbool.h>
#include <ke_list.h>
#include <ke_spinlock.h>
#include <kernel/ke_list.h>
#include <kernel/ke_spinlock.h>
typedef struct KDPC KDPC;
@@ -1,10 +1,10 @@
#pragma once
// ke_event.h - auto-reset and manual-reset events
#include <stdint.h>
#include <ob_object.h>
#include <ke_spinlock.h>
#include <ke_list.h>
#include <ke_status.h>
#include <kernel/ob_object.h>
#include <kernel/ke_spinlock.h>
#include <kernel/ke_list.h>
#include <ntlite/status.h>
typedef enum EVENT_TYPE { EventAutoReset, EventManualReset } EVENT_TYPE;
@@ -17,6 +17,9 @@ typedef struct TSS64 {
} TSS64;
#pragma pack(pop)
// Compatibility pointer used by ke_switch.asm.
// It points at CPU0's TSS until the context-switch path grows a true
// per-CPU base lookup.
extern TSS64* gTss;
void KeInitializeGdt(void);
@@ -13,9 +13,9 @@
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <ke_list.h>
#include <ke_spinlock.h>
#include <ke_status.h>
#include <kernel/ke_list.h>
#include <kernel/ke_spinlock.h>
#include <ntlite/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.
@@ -1,14 +1,14 @@
#pragma once
#include <stdint.h>
#include <hal_api.h>
void KeIrqInitialize(const HAL_API *hal);
__declspec(dllexport) void KeIrqRegister(uint8_t irq, void (*handler)(void));
void KeIrqDispatch(uint8_t irq); // called from ke_syscall.asm
// Low-level interrupt entry/exit hooks. These are called by the common IRQ
// assembly stub around KeIrqDispatch. The exit hook is where deferred
// interrupt-time scheduling now happens, so IRQ handlers never switch away
// before KeIrqDispatch has returned and sent EOI.
void KiEnterInterrupt(void);
void KiExitInterrupt(void);
#pragma once
#include <stdint.h>
#include <ntlite/ddi/hal_api.h>
void KeIrqInitialize(const HAL_API *hal);
__declspec(dllexport) void KeIrqRegister(uint8_t irq, void (*handler)(void));
void KeIrqDispatch(uint8_t irq); // called from ke_syscall.asm
// Low-level interrupt entry/exit hooks. These are called by the common IRQ
// assembly stub around KeIrqDispatch. The exit hook is where deferred
// interrupt-time scheduling now happens, so IRQ handlers never switch away
// before KeIrqDispatch has returned and sent EOI.
void KiEnterInterrupt(void);
void KiExitInterrupt(void);
File renamed without changes.
File renamed without changes.
@@ -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 <kernel/ob_object.h>
#include <kernel/ke_spinlock.h>
#include <kernel/ke_list.h>
#include <ntlite/status.h>
typedef struct MUTEX {
OBJECT Header;
@@ -2,13 +2,13 @@
// 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 <kernel/ob_object.h>
#include <kernel/ke_list.h>
#include <kernel/ke_spinlock.h>
#include <kernel/ke_event.h>
#include <stddef.h>
#include <stdint.h>
#include <sys_string.h>
#include <ntlite/string_view.h>
#define PROCESS_NAME_MAX 64
#define HANDLE_TABLE_SIZE 256
@@ -4,10 +4,10 @@
// on both sides. The queue is only a synchronisation and ordering tool.
#include <stdint.h>
#include <stdbool.h>
#include <ob_object.h>
#include <ke_spinlock.h>
#include <ke_list.h>
#include <ke_status.h>
#include <kernel/ob_object.h>
#include <kernel/ke_spinlock.h>
#include <kernel/ke_list.h>
#include <ntlite/status.h>
#define QUEUE_MESSAGE_SIZE 64 /* bytes, fixed */
#define QUEUE_DEPTH 256
@@ -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 <kernel/ke_thread.h>
#define SCHED_TICK_MS 10u
#define SCHED_HIGH_QUANTUM_TICKS 2u
@@ -50,8 +50,8 @@ __declspec(dllexport) void KeYield(void);
void KeGetSchedulerStats(KE_SCHED_STATS* out);
// Returns the thread currently running on this CPU (reads GS:[0]).
// Returns the thread currently running on this CPU.
THREAD* KeGetCurrentThread(void);
// Set the current-thread GS slot. Called once per CPU at boot.
// Set the current thread for the current CPU. Used during CPU/scheduler bring-up.
void KeSetCurrentThread(THREAD* thread);
@@ -4,6 +4,6 @@
// These tests intentionally live behind one call site so they can be walled
// off or compiled out later without touching kmain.c again.
#include <hal_api.h>
#include <ntlite/ddi/hal_api.h>
void KiRunKernelSelfTests(const HAL_API* hal);
@@ -1,20 +1,20 @@
#pragma once
// ke_semaphore.h - counting semaphore
#include <stdint.h>
#include <ob_object.h>
#include <ke_spinlock.h>
#include <ke_list.h>
#include <ke_status.h>
typedef struct SEMAPHORE {
OBJECT Header;
SPINLOCK Lock;
int32_t Count;
int32_t MaxCount;
LIST_ENTRY WaitList;
} 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);
#pragma once
// ke_semaphore.h - counting semaphore
#include <stdint.h>
#include <kernel/ob_object.h>
#include <kernel/ke_spinlock.h>
#include <kernel/ke_list.h>
#include <ntlite/status.h>
typedef struct SEMAPHORE {
OBJECT Header;
SPINLOCK Lock;
int32_t Count;
int32_t MaxCount;
LIST_ENTRY WaitList;
} 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);
@@ -1,7 +1,7 @@
#pragma once
#include <stddef.h>
#include <ke_status.h>
#include <ntlite/status.h>
#define KE_SETTINGS_PATH "system\\settings.ini"
@@ -11,7 +11,7 @@
// Never hold a spinlock across a wait/blocking operation.
#include <stdint.h>
#include <intrin.h>
#include <ke_irql.h>
#include <kernel/ke_irql.h>
typedef struct SPINLOCK {
volatile long Locked;
@@ -1,7 +1,7 @@
#pragma once
#include <stdint.h>
#include <hal_api.h>
#include <ntlite/ddi/hal_api.h>
// Set the HAL API pointer for syscalls
void KeSyscallInit(const HAL_API* hal);
@@ -2,12 +2,12 @@
// ke_thread.h - thread model
// A THREAD is the unit of scheduling. Every thread belongs to exactly one process.
#include <stdint.h>
#include <ob_object.h>
#include <ke_list.h>
#include <ke_process.h>
#include <ke_event.h>
#include <ke_spinlock.h>
#include <ke_trap.h>
#include <kernel/ob_object.h>
#include <kernel/ke_list.h>
#include <kernel/ke_process.h>
#include <kernel/ke_event.h>
#include <kernel/ke_spinlock.h>
#include <kernel/ke_trap.h>
#define KSTACK_SIZE (64 * 1024) /* 64 KB kernel stack */
#define USTACK_SIZE (512 * 1024) /* 512 KB user stack */
@@ -88,6 +88,7 @@ typedef struct THREAD {
uint32_t QuantumRemaining;
uint32_t CpuBurstTicks;
uint32_t LastRunTicks;
uint32_t RunningCpu;
// Set by wait primitives before blocking and completed by the object
// that wakes the thread. Keep this field after the assembly-visible
@@ -7,7 +7,7 @@
// slots before returning to user mode.
#include <stdint.h>
#include <ke_status.h>
#include <ntlite/status.h>
#define KTRAP_FRAME_MAGIC 0x4650545241544B31ULL
@@ -4,7 +4,7 @@
#include <stdint.h>
#include <stddef.h>
#include <sys_string.h>
#include <ntlite/string_view.h>
#define SYS_PEB_MAGIC 0x30424550u /* "PEB0" */
#define SYS_TEB_MAGIC 0x30424554u /* "TEB0" */
@@ -2,7 +2,7 @@
#pragma once
#include <string.h>
#include <mm_virt.h>
#include <kernel/mm_virt.h>
// ---------------------------------------------------------------------------
// Dynamic array (stretchy-buffer style)
@@ -4,7 +4,7 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <ke_status.h>
#include <ntlite/status.h>
// Map a PE32+ image from 'buffer' into the kernel virtual address space.
// On success, *baseOut receives the virtual base address.
@@ -1,28 +1,28 @@
#pragma once
// mm_phys.h - physical memory manager (PMM)
// Stack allocator over 4 KB frames, seeded from MEMORY_MAP.
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <memory_map.h>
#define PAGE_SIZE 4096ULL
#define PAGE_MASK (~(PAGE_SIZE - 1))
typedef uint64_t PHYSICAL_ADDRESS;
// Called once by KernelMain with the MEMORY_MAP from BOOT_INFO.
bool MmInitializePhysical(const MEMORY_MAP* map,
uint64_t physicalWindowBase);
// Allocate / free a single 4 KB frame.
// MmAllocateFrame returns 0 on failure.
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).
__declspec(dllexport) PHYSICAL_ADDRESS MmAllocateContiguous(size_t count);
size_t MmFreeFrameCount(void);
size_t MmTotalFrameCount(void);
#pragma once
// mm_phys.h - physical memory manager (PMM)
// Stack allocator over 4 KB frames, seeded from MEMORY_MAP.
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <ntlite/memory_map.h>
#define PAGE_SIZE 4096ULL
#define PAGE_MASK (~(PAGE_SIZE - 1))
typedef uint64_t PHYSICAL_ADDRESS;
// Called once by KernelMain with the MEMORY_MAP from BOOT_INFO.
bool MmInitializePhysical(const MEMORY_MAP* map,
uint64_t physicalWindowBase);
// Allocate / free a single 4 KB frame.
// MmAllocateFrame returns 0 on failure.
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).
__declspec(dllexport) PHYSICAL_ADDRESS MmAllocateContiguous(size_t count);
size_t MmFreeFrameCount(void);
size_t MmTotalFrameCount(void);
@@ -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 <kernel/mm_phys.h>
#include <ntlite/status.h>
// ---------------------------------------------------------------------------
// Page flags (x86-64 PTE bits)
@@ -6,9 +6,9 @@
#include <stdint.h>
#include <stddef.h>
#include <ke_status.h>
#include <ob_object.h>
#include <net_abi.h>
#include <ntlite/status.h>
#include <kernel/ob_object.h>
#include <ntlite/ddi/net_abi.h>
struct NET_STACK_PROVIDER;
@@ -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 <ntlite/status.h>
typedef enum OBJECT_TYPE {
ObjectTypeProcess = 1,
File renamed without changes.
-4
View File
@@ -1,4 +0,0 @@
#pragma once
typedef void (*IniCallback)(const char* section, const char* key,
const char* value, void* userdata);
void IniParse(char* buf, IniCallback cb, void* userdata);
+3 -3
View File
@@ -1,8 +1,8 @@
// io_device.c - kernel driver/device dispatch and disk registry
#include <string.h>
#include <io_driver.h>
#include <ke_irp.h>
#include <mm_virt.h>
#include <ntlite/ddi/io_driver.h>
#include <kernel/ke_irp.h>
#include <kernel/mm_virt.h>
#define MAX_DISK_DEVICES 8
+12 -12
View File
@@ -1,17 +1,17 @@
// io_file.c - VFS dispatch layer
#include <string.h>
#include <ke_list.h>
#include <ke_process.h>
#include <io_file.h>
#include <mm_virt.h>
#include <ob_object.h>
#include <ke_userenv.h>
#include <ke_irql.h>
#include <ke_event.h>
#include <ke_apc.h>
#include <ke_semaphore.h>
#include <ke_thread.h>
#include <ke_sched.h>
#include <kernel/ke_list.h>
#include <kernel/ke_process.h>
#include <kernel/io_file.h>
#include <kernel/mm_virt.h>
#include <kernel/ob_object.h>
#include <kernel/ke_userenv.h>
#include <kernel/ke_irql.h>
#include <kernel/ke_event.h>
#include <kernel/ke_apc.h>
#include <kernel/ke_semaphore.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_sched.h>
#define MAX_DRIVES 8
+7 -7
View File
@@ -1,11 +1,11 @@
// ke_apc.c - kernel APC infrastructure
#include <ke_apc.h>
#include <ke_thread.h>
#include <ke_sched.h>
#include <ke_spinlock.h>
#include <ke_irql.h>
#include <ke_trap.h>
#include <mm_virt.h>
#include <kernel/ke_apc.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_spinlock.h>
#include <kernel/ke_irql.h>
#include <kernel/ke_trap.h>
#include <kernel/mm_virt.h>
#include <string.h>
#include <intrin.h>
+51
View File
@@ -0,0 +1,51 @@
// ke_cpu.c - bootstrap/per-CPU state plumbing
#include <string.h>
#include <kernel/ke_cpu.h>
#define BOOTSTRAP_CPU_STACK_SIZE 0x4000u
KCPU gCpus[KE_MAX_CPUS];
uint32_t gCpuCount = 0;
static uint8_t gBootstrapCpuStack[BOOTSTRAP_CPU_STACK_SIZE];
void KeInitializeBootstrapCpu(void) {
memset(gCpus, 0, sizeof(gCpus));
KCPU* cpu = &gCpus[0];
cpu->CpuIndex = 0;
cpu->LapicId = 0;
cpu->Present = 1;
cpu->Online = 1;
cpu->IsBsp = 1;
cpu->CurrentIrql = PASSIVE_LEVEL;
cpu->InterruptDepth = 0;
cpu->ReschedulePending = 0;
cpu->KernelStack = gBootstrapCpuStack;
cpu->KernelStackTop = (uintptr_t)(gBootstrapCpuStack + sizeof(gBootstrapCpuStack));
memset(&cpu->Tss, 0, sizeof(cpu->Tss));
cpu->Tss.IoMapBase = sizeof(TSS64);
cpu->Tss.RSP0 = cpu->KernelStackTop;
gCpuCount = 1;
}
KCPU* KeGetCurrentCpu(void) {
// SMP phase 1: only CPU0 is online. Later this becomes LAPIC-ID or
// per-CPU-base based lookup once the bootloader parks APs for us.
return &gCpus[0];
}
KCPU* KeGetCpuByIndex(uint32_t index) {
if (index >= KE_MAX_CPUS)
return (KCPU*)0;
return &gCpus[index];
}
uint32_t KeGetCurrentCpuIndex(void) {
return KeGetCurrentCpu()->CpuIndex;
}
TSS64* KeGetCurrentTss(void) {
return &KeGetCurrentCpu()->Tss;
}
+8 -8
View File
@@ -2,14 +2,14 @@
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <hal_api.h>
#include <ke_debug.h>
#include <ke_spinlock.h>
#include <ke_process.h>
#include <ke_thread.h>
#include <ke_sched.h>
#include <mm_virt.h>
#include <printf.h>
#include <ntlite/ddi/hal_api.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_spinlock.h>
#include <kernel/ke_process.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_sched.h>
#include <kernel/mm_virt.h>
#include <common/printf.h>
int _fltused; // fuckass
int gDebugEnabled = 0;
+3 -3
View File
@@ -1,7 +1,7 @@
// ke_dpc.c - deferred procedure calls
#include <ke_dpc.h>
#include <ke_irql.h>
#include <ke_debug.h>
#include <kernel/ke_dpc.h>
#include <kernel/ke_irql.h>
#include <kernel/ke_debug.h>
#include <intrin.h>
static LIST_ENTRY gDpcQueue;
+6 -6
View File
@@ -1,11 +1,11 @@
// ke_event.c - synchronisation events
#include <stdbool.h>
#include <ke_event.h>
#include <ke_thread.h>
#include <ke_sched.h>
#include <ke_irql.h>
#include <ke_apc.h>
#include <ob_object.h>
#include <kernel/ke_event.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_irql.h>
#include <kernel/ke_apc.h>
#include <kernel/ob_object.h>
static void KiEventDestroy(OBJECT* obj) { (void)obj; }
+13 -11
View File
@@ -10,7 +10,8 @@
// 0x30 TSS high
#include <stdint.h>
#include <string.h>
#include <ke_idt.h>
#include <kernel/ke_idt.h>
#include <kernel/ke_cpu.h>
// External assembly procedures
extern void KeFlushGdt(void* pGdtr, uint16_t codeSel, uint16_t dataSel, uint16_t tssSel);
@@ -77,10 +78,7 @@ extern void KeFaultRSV31(void);
// GDT
// ---------------------------------------------------------------------------
#define GDT_ENTRIES 8
#define KERNEL_IST_STACK_SIZE 0x4000
static uint64_t gGdt[GDT_ENTRIES];
static uint8_t gKernelStack[KERNEL_IST_STACK_SIZE];
#pragma pack(push, 1)
typedef struct { uint16_t Limit; uint64_t Base; } GDTR;
@@ -112,12 +110,14 @@ static void KiGdtSetTss(int idx, uintptr_t base, uint32_t limit) {
gGdt[idx+1] = (base >> 32);
}
TSS64 gTssStruct;
TSS64* gTss = &gTssStruct;
TSS64* gTss = (TSS64*)0;
void KeInitializeGdt(void) {
KCPU* cpu = KeGetCurrentCpu();
TSS64* tss = &cpu->Tss;
gTss = tss;
memset(gGdt, 0, sizeof(gGdt));
memset(&gTssStruct, 0, sizeof(gTssStruct));
// 0x00: Null
KiGdtSetEntry(0, 0, 0, 0, 0);
@@ -130,11 +130,13 @@ void KeInitializeGdt(void) {
// 0x20: Ring-3 Data
KiGdtSetEntry(4, 0, 0xFFFFF, 0xF2, 0xC);
// 0x28: TSS (Occupies two slots: 0x28 and 0x30)
gTssStruct.IoMapBase = sizeof(TSS64);
gTssStruct.RSP0 = (uint64_t)(gKernelStack + KERNEL_IST_STACK_SIZE); // top of stack
// 0x28: TSS (Occupies two slots: 0x28 and 0x30).
// The TSS storage is per-CPU; phase 1 initializes CPU0 only.
tss->IoMapBase = sizeof(TSS64);
if (!tss->RSP0)
tss->RSP0 = cpu->KernelStackTop;
KiGdtSetTss(5, (uintptr_t)&gTssStruct, sizeof(TSS64) - 1);
KiGdtSetTss(5, (uintptr_t)tss, sizeof(TSS64) - 1);
GDTR gdtr = { sizeof(gGdt) - 1, (uint64_t)gGdt };
+6 -6
View File
@@ -12,12 +12,12 @@
// → ob_object.h (ObDereferenceObject)
// → io_driver.h (DEVICE_OBJECT / IoCallDriver)
#include <ke_irp.h>
#include <ke_event.h>
#include <ke_semaphore.h>
#include <ke_apc.h>
#include <ob_object.h>
#include <io_driver.h>
#include <kernel/ke_irp.h>
#include <kernel/ke_event.h>
#include <kernel/ke_semaphore.h>
#include <kernel/ke_apc.h>
#include <kernel/ob_object.h>
#include <ntlite/ddi/io_driver.h>
// -------------------------------------------------------------------------
// IRP_QUEUE operations
+12 -11
View File
@@ -1,10 +1,11 @@
// ke_irq.c - IRQ dispatch, kernel-side
#include <ke_irq.h>
#include <ke_sched.h>
#include <ke_irql.h>
#include <ke_dpc.h>
#include <hal_api.h>
#include <ke_debug.h>
#include <kernel/ke_irq.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_cpu.h>
#include <kernel/ke_irql.h>
#include <kernel/ke_dpc.h>
#include <ntlite/ddi/hal_api.h>
#include <kernel/ke_debug.h>
#define MAX_IRQS 24
#define MAX_IRQ_HANDLERS 8
@@ -16,7 +17,6 @@ typedef struct IRQ_HANDLER_LIST {
static IRQ_HANDLER_LIST gIrqHandlers[MAX_IRQS];
static const HAL_API *gHal;
static volatile uint32_t gInterruptDepth = 0;
static KIRQL KiIrqToIrql(uint8_t irq) {
KIRQL irql = (KIRQL)(DIRQL_BASE + irq);
@@ -77,18 +77,19 @@ void KeIrqDispatch(uint8_t irq) {
}
void KiEnterInterrupt(void) {
gInterruptDepth++;
KeGetCurrentCpu()->InterruptDepth++;
}
void KiExitInterrupt(void) {
if (gInterruptDepth)
gInterruptDepth--;
KCPU* cpu = KeGetCurrentCpu();
if (cpu->InterruptDepth)
cpu->InterruptDepth--;
// A reschedule is only legal after the interrupt unwound back to the
// interrupted thread's original PASSIVE context. If a future path ever
// permits nested interrupting of DISPATCH/DIRQL code, leave the request
// pending instead of switching while a spinlock/high-IRQL region is active.
if (gInterruptDepth == 0 && KeGetCurrentIrql() == PASSIVE_LEVEL) {
if (cpu->InterruptDepth == 0 && KeGetCurrentIrql() == PASSIVE_LEVEL) {
KiDrainDpcQueue();
if (KeGetCurrentIrql() == PASSIVE_LEVEL)
KiScheduleFromInterrupt();
+11 -11
View File
@@ -1,10 +1,8 @@
// ke_irql.c - software IRQL skeleton
#include <ke_irql.h>
#include <ke_debug.h>
#include <ke_apc.h>
// Single-CPU bring-up state. When SMP arrives this becomes per-CPU state.
static volatile KIRQL gCurrentIrql = PASSIVE_LEVEL;
#include <kernel/ke_irql.h>
#include <kernel/ke_cpu.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_apc.h>
__declspec(dllexport) const char* KeIrqlName(KIRQL irql) {
switch (irql) {
@@ -20,11 +18,12 @@ __declspec(dllexport) const char* KeIrqlName(KIRQL irql) {
}
__declspec(dllexport) KIRQL KeGetCurrentIrql(void) {
return gCurrentIrql;
return KeGetCurrentCpu()->CurrentIrql;
}
__declspec(dllexport) KIRQL KeRaiseIrql(KIRQL newIrql) {
KIRQL oldIrql = gCurrentIrql;
KCPU* cpu = KeGetCurrentCpu();
KIRQL oldIrql = cpu->CurrentIrql;
if (newIrql > HIGH_LEVEL) {
KePanic("KeRaiseIrql: invalid target IRQL %u\n", (unsigned)newIrql);
@@ -36,12 +35,13 @@ __declspec(dllexport) KIRQL KeRaiseIrql(KIRQL newIrql) {
KeIrqlName(newIrql), (unsigned)newIrql);
}
gCurrentIrql = newIrql;
cpu->CurrentIrql = newIrql;
return oldIrql;
}
__declspec(dllexport) void KeLowerIrql(KIRQL oldIrql) {
KIRQL currentIrql = gCurrentIrql;
KCPU* cpu = KeGetCurrentCpu();
KIRQL currentIrql = cpu->CurrentIrql;
if (oldIrql > HIGH_LEVEL) {
KePanic("KeLowerIrql: invalid target IRQL %u\n", (unsigned)oldIrql);
@@ -53,7 +53,7 @@ __declspec(dllexport) void KeLowerIrql(KIRQL oldIrql) {
KeIrqlName(oldIrql), (unsigned)oldIrql);
}
gCurrentIrql = oldIrql;
cpu->CurrentIrql = oldIrql;
if (oldIrql == PASSIVE_LEVEL && currentIrql != PASSIVE_LEVEL)
KiDeliverKernelApcs();
+6 -6
View File
@@ -1,11 +1,11 @@
// ke_mutex.c - binary ownership mutex
#include <stdbool.h>
#include <ke_mutex.h>
#include <ke_thread.h>
#include <ke_sched.h>
#include <ke_irql.h>
#include <mm_virt.h>
#include <ob_object.h>
#include <kernel/ke_mutex.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_irql.h>
#include <kernel/mm_virt.h>
#include <kernel/ob_object.h>
static void KiMutexDestroy(OBJECT* obj) { (void)obj; }
+7 -7
View File
@@ -1,13 +1,13 @@
// ke_process.c - process model
#include <string.h>
#include <intrin.h>
#include <ke_process.h>
#include <ke_thread.h>
#include <ke_sched.h>
#include <ke_event.h>
#include <ke_userenv.h>
#include <mm_virt.h>
#include <ob_object.h>
#include <kernel/ke_process.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_event.h>
#include <kernel/ke_userenv.h>
#include <kernel/mm_virt.h>
#include <kernel/ob_object.h>
// ---------------------------------------------------------------------------
// Global process list
+5 -5
View File
@@ -1,10 +1,10 @@
// ke_queue.c - ring-buffer message queue
#include <string.h>
#include <ke_queue.h>
#include <ke_thread.h>
#include <ke_sched.h>
#include <ke_irql.h>
#include <ob_object.h>
#include <kernel/ke_queue.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_irql.h>
#include <kernel/ob_object.h>
static void KiQueueDestroy(OBJECT* obj) { (void)obj; }
+47 -36
View File
@@ -1,23 +1,20 @@
// ke_sched.c - MLFQ scheduler
#include <stddef.h>
#include <stdbool.h>
#include <ke_sched.h>
#include <ke_process.h>
#include <ke_thread.h>
#include <ke_spinlock.h>
#include <ke_irql.h>
#include <ke_apc.h>
#include <ke_list.h>
#include <mm_virt.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_cpu.h>
#include <kernel/ke_process.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_spinlock.h>
#include <kernel/ke_irql.h>
#include <kernel/ke_apc.h>
#include <kernel/ke_list.h>
#include <kernel/mm_virt.h>
static LIST_ENTRY gRunQueue[PriorityCount];
static SPINLOCK gSchedLock;
static THREAD* gCurrentThread;
static THREAD* gIdleThread;
static THREAD* gOutgoingThread;
static uint32_t gAgingCounter = 0;
static volatile long gReschedulePending = 0;
static KE_SCHED_STATS gSchedStats;
static uint32_t KiBaseQuantumForPriority(THREAD_PRIORITY priority) {
@@ -30,7 +27,7 @@ static uint32_t KiBaseQuantumForPriority(THREAD_PRIORITY priority) {
}
static uint32_t KiComputeQuantumLocked(THREAD* thread) {
if (!thread || thread == gIdleThread)
if (!thread || thread == KeGetCurrentCpu()->IdleThread)
return 1;
uint32_t quantum = KiBaseQuantumForPriority(thread->Priority);
@@ -53,8 +50,8 @@ static void KiRefillQuantumLocked(THREAD* thread) {
thread->QuantumRemaining = thread->QuantumTicks;
}
THREAD* KeGetCurrentThread(void) { return gCurrentThread; }
void KeSetCurrentThread(THREAD* t) { gCurrentThread = t; }
THREAD* KeGetCurrentThread(void) { return KeGetCurrentCpu()->CurrentThread; }
void KeSetCurrentThread(THREAD* t) { KeGetCurrentCpu()->CurrentThread = t; }
void KeGetSchedulerStats(KE_SCHED_STATS* out) {
if (!out) return;
@@ -68,6 +65,8 @@ static void KiIdleLoop(void) {
}
void KeInitializeScheduler(void) {
KCPU* cpu = KeGetCurrentCpu();
for (int i = 0; i < PriorityCount; i++) LIST_INIT(&gRunQueue[i]);
gSchedLock = (SPINLOCK)SPINLOCK_INIT;
@@ -90,6 +89,7 @@ void KeInitializeScheduler(void) {
idle->QuantumRemaining = 1;
idle->CpuBurstTicks = 0;
idle->LastRunTicks = 0;
idle->RunningCpu = cpu->CpuIndex;
idle->Owner = idleProc;
idle->WaitObject = (OBJECT *)0;
idle->WaitStatus = STATUS_SUCCESS;
@@ -127,20 +127,23 @@ void KeInitializeScheduler(void) {
idleProc->ThreadCount++;
KeReleaseSpinlock(&idleProc->HandleLock, idleFlags);
gIdleThread = idle;
gCurrentThread = idle;
cpu->IdleThread = idle;
cpu->CurrentThread = idle;
cpu->OutgoingThread = (THREAD*)0;
}
// Safely release the lock and clean up any dead threads natively post-switch
void KeSchedulerPostSwitch(void) {
THREAD* cur = KeGetCurrentThread();
KCPU* cpu = KeGetCurrentCpu();
THREAD* cur = cpu->CurrentThread;
KeReleaseSpinlock(&gSchedLock, cur->SchedLockFlags);
KiDeliverKernelApcs();
if (gOutgoingThread && gOutgoingThread->State == ThreadDead) {
THREAD* dead = gOutgoingThread;
gOutgoingThread = (THREAD*)0;
if (cpu->OutgoingThread && cpu->OutgoingThread->State == ThreadDead) {
THREAD* dead = cpu->OutgoingThread;
cpu->OutgoingThread = (THREAD*)0;
dead->RunningCpu = KE_INVALID_CPU;
ObDereferenceObject(&dead->Header);
}
}
@@ -155,8 +158,9 @@ void KeReadyThread(THREAD* thread) {
uintptr_t flags = KeAcquireSpinlock(&gSchedLock);
ListInsertTail(&gRunQueue[p], &thread->SchedulerLink);
THREAD* cur = gCurrentThread;
if (!cur || cur == gIdleThread) {
KCPU* cpu = KeGetCurrentCpu();
THREAD* cur = cpu->CurrentThread;
if (!cur || cur == cpu->IdleThread) {
KiRequestReschedule();
} else if (cur->State == ThreadRunning && thread->Priority > cur->Priority) {
gSchedStats.PriorityPreemptions++;
@@ -189,22 +193,24 @@ static THREAD* KiPickNext(void) {
return CONTAINING_RECORD(node, THREAD, SchedulerLink);
}
}
return gIdleThread;
return KeGetCurrentCpu()->IdleThread;
}
void KiRequestReschedule(void) {
gReschedulePending = 1;
KeGetCurrentCpu()->ReschedulePending = 1;
}
int KiIsReschedulePending(void) {
return gReschedulePending != 0;
return KeGetCurrentCpu()->ReschedulePending != 0;
}
static void KiSchedule(void) {
THREAD* cur = gCurrentThread;
KCPU* cpu = KeGetCurrentCpu();
THREAD* cur = cpu->CurrentThread;
THREAD* idle = cpu->IdleThread;
if (!cur) return;
gReschedulePending = 0;
cpu->ReschedulePending = 0;
uintptr_t flags = KeAcquireSpinlock(&gSchedLock);
cur->SchedLockFlags = flags;
@@ -213,7 +219,7 @@ static void KiSchedule(void) {
// still runnable and nobody else is ready, keep executing it. Otherwise a
// lone CPU-bound thread gets alternated with the idle thread on every timer
// tick, effectively turning a periodic preemption check into a 50% throttle.
if (cur != gIdleThread && cur->State == ThreadRunning && !KiAnyRunnableLocked()) {
if (cur != idle && cur->State == ThreadRunning && !KiAnyRunnableLocked()) {
if (cur->QuantumRemaining == 0)
KiRefillQuantumLocked(cur);
gSchedStats.KeepCurrentDecisions++;
@@ -222,12 +228,12 @@ static void KiSchedule(void) {
}
THREAD* next = KiPickNext();
if (next == gIdleThread) gSchedStats.IdleSelections++;
if (next == idle) gSchedStats.IdleSelections++;
if (next == cur) {
// Only re-queue if still running normally; a ThreadWaiting/ThreadDead
// caller has already placed SchedulerLink elsewhere (or is discarding
// the thread).
if (cur != gIdleThread && cur->State == ThreadRunning)
if (cur != idle && cur->State == ThreadRunning)
ListInsertTail(&gRunQueue[cur->Priority], &cur->SchedulerLink);
KeReleaseSpinlock(&gSchedLock, flags);
return;
@@ -235,19 +241,22 @@ static void KiSchedule(void) {
next->State = ThreadRunning;
KiRefillQuantumLocked(next);
gCurrentThread = next;
cpu->CurrentThread = next;
next->RunningCpu = cpu->CpuIndex;
// Only re-queue the outgoing thread if it is still in the running state.
// If KeBlockThread set State = ThreadWaiting, SchedulerLink was already
// inserted into the sync object's wait list - inserting it here too would
// corrupt both lists simultaneously (same intrusive node in two lists).
// If KeExitThread set State = ThreadDead, the thread must not be re-queued.
if (cur != gIdleThread && cur->State == ThreadRunning) {
if (cur != idle && cur->State == ThreadRunning) {
cur->State = ThreadReady;
ListInsertTail(&gRunQueue[cur->Priority], &cur->SchedulerLink);
}
gOutgoingThread = cur;
if (cur) cur->RunningCpu = KE_INVALID_CPU;
cpu->OutgoingThread = cur;
cpu->ContextSwitches++;
gSchedStats.ContextSwitches++;
KeSwitchContext(cur, next);
KeSchedulerPostSwitch();
@@ -267,7 +276,9 @@ void KiSchedulerNoteVoluntaryBlock(THREAD* thread) {
}
void KeSchedulerTick(void) {
THREAD* cur = gCurrentThread;
KCPU* cpu = KeGetCurrentCpu();
THREAD* cur = cpu->CurrentThread;
THREAD* idle = cpu->IdleThread;
if (!cur) return;
uintptr_t flags = KeAcquireSpinlock(&gSchedLock);
@@ -277,7 +288,7 @@ void KeSchedulerTick(void) {
int requestReschedule = 0;
if (cur == gIdleThread) {
if (cur == idle) {
if (KiAnyRunnableLocked())
requestReschedule = 1;
} else {
+14 -14
View File
@@ -3,20 +3,20 @@
#include <stddef.h>
#include <string.h>
#include <hal_api.h>
#include <ke_apc.h>
#include <ke_debug.h>
#include <ke_event.h>
#include <ke_irp.h>
#include <ke_irql.h>
#include <ke_sched.h>
#include <ke_status.h>
#include <ke_thread.h>
#include <io_file.h>
#include <io_driver.h>
#include <ke_trap.h>
#include <mm_virt.h>
#include <ob_object.h>
#include <ntlite/ddi/hal_api.h>
#include <kernel/ke_apc.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_event.h>
#include <kernel/ke_irp.h>
#include <kernel/ke_irql.h>
#include <kernel/ke_sched.h>
#include <ntlite/status.h>
#include <kernel/ke_thread.h>
#include <kernel/io_file.h>
#include <ntlite/ddi/io_driver.h>
#include <kernel/ke_trap.h>
#include <kernel/mm_virt.h>
#include <kernel/ob_object.h>
// -------------------------------------------------------------------------
// Kernel APC self-test
+5 -5
View File
@@ -1,10 +1,10 @@
// ke_semaphore.c - counting semaphore
#include <stdbool.h>
#include <ke_semaphore.h>
#include <ke_thread.h>
#include <ke_sched.h>
#include <ke_irql.h>
#include <ob_object.h>
#include <kernel/ke_semaphore.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_irql.h>
#include <kernel/ob_object.h>
static void KiSemaphoreDestroy(OBJECT* obj) { (void)obj; }
+4 -4
View File
@@ -7,10 +7,10 @@
#include <stdint.h>
#include <string.h>
#include <ke_settings.h>
#include <io_file.h>
#include <mm_virt.h>
#include <ini_parser.h>
#include <kernel/ke_settings.h>
#include <kernel/io_file.h>
#include <kernel/mm_virt.h>
#include <common/ini_parser.h>
#define KE_SETTINGS_MAX_FILE_BYTES (64u * 1024u)
-46
View File
@@ -1,46 +0,0 @@
#pragma once
// ke_status.h - kernel status codes
// All fallible kernel functions return KSTATUS.
// Success is always zero; failures are positive named constants.
#include <stdint.h>
typedef uint32_t KSTATUS;
// --- General & Control (0x0000) ---
#define STATUS_SUCCESS ((KSTATUS)0x0000)
#define STATUS_FAILURE ((KSTATUS)0x0001)
#define STATUS_NOT_SUPPORTED ((KSTATUS)0x0002)
#define STATUS_TIMEOUT ((KSTATUS)0x0003)
#define STATUS_PENDING ((KSTATUS)0x0004)
#define STATUS_ALERTED ((KSTATUS)0x0005)
#define STATUS_KERNEL_APC ((KSTATUS)0x0006)
#define STATUS_USER_APC ((KSTATUS)0x0007)
// --- Validation & Parameters (0x0010) ---
#define STATUS_INVALID_PARAMETER ((KSTATUS)0x0010)
#define STATUS_INVALID_HANDLE ((KSTATUS)0x0011)
#define STATUS_BUFFER_TOO_SMALL ((KSTATUS)0x0012)
#define STATUS_CHECKSUM_MISMATCH ((KSTATUS)0x0013)
// --- Resource & Access (0x0020) ---
#define STATUS_NO_MEMORY ((KSTATUS)0x0020)
#define STATUS_ACCESS_DENIED ((KSTATUS)0x0021)
#define STATUS_NOT_FOUND ((KSTATUS)0x0022)
#define STATUS_ALREADY_EXISTS ((KSTATUS)0x0023)
#define STATUS_OBJECT_NAME_COLLISION ((KSTATUS)0x0024)
// --- State & Lifecycle (0x0030) ---
#define STATUS_OBJECT_DEAD ((KSTATUS)0x0030)
#define STATUS_QUEUE_FULL ((KSTATUS)0x0031)
#define STATUS_QUEUE_EMPTY ((KSTATUS)0x0032)
#define STATUS_CANCELLED ((KSTATUS)0x0033)
// --- Hardware & External (0x0040) ---
#define STATUS_DEVICE_ERROR ((KSTATUS)0x0040)
#define STATUS_NO_MORE_FILES ((KSTATUS)0x0050)
// --- Execution level (0x0060) ---
#define STATUS_INVALID_IRQL ((KSTATUS)0x0060)
#define KSUCCESS(s) ((s) == STATUS_SUCCESS)
+1 -1
View File
@@ -14,7 +14,7 @@ THREAD_Teb EQU 112
THREAD_FpuContext EQU 168
TSS_RSP0_OFFSET EQU 4
EXTERN gTss:QWORD ; address of the single TSS, exported from ke_idt.c
EXTERN gTss:QWORD ; phase-1 pointer to current CPU TSS, exported from ke_idt.c
.CODE
+17 -17
View File
@@ -33,23 +33,23 @@
#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_apc.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 <net_socket.h>
#include <ke_trap.h>
#include <syscall.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_process.h>
#include <kernel/ke_mutex.h>
#include <kernel/ke_semaphore.h>
#include <kernel/ke_event.h>
#include <kernel/ke_apc.h>
#include <kernel/ke_queue.h>
#include <kernel/ke_debug.h>
#include <kernel/mm_virt.h>
#include <kernel/ldr_image.h>
#include <kernel/syscall_nr.h>
#include <ntlite/ddi/hal_api.h>
#include <kernel/io_file.h>
#include <kernel/net_socket.h>
#include <kernel/ke_trap.h>
#include <ntlite/syscall.h>
// ---------------------------------------------------------------------------
// HAL pointer - set once at boot by KeSyscallSetHal()
+11 -8
View File
@@ -2,14 +2,15 @@
#include <string.h>
#include <stddef.h>
#include <intrin.h>
#include <ke_thread.h>
#include <ke_sched.h>
#include <ke_irql.h>
#include <ke_event.h>
#include <ke_apc.h>
#include <ke_userenv.h>
#include <mm_virt.h>
#include <ob_object.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_cpu.h>
#include <kernel/ke_irql.h>
#include <kernel/ke_event.h>
#include <kernel/ke_apc.h>
#include <kernel/ke_userenv.h>
#include <kernel/mm_virt.h>
#include <kernel/ob_object.h>
#define FPU_FCW_DEFAULT 0x037Fu
#define FPU_MXCSR_DEFAULT 0x1F80u
@@ -91,6 +92,7 @@ __declspec(dllexport) KSTATUS KeCreateThread(PROCESS* owner, uintptr_t entry, ui
thread->QuantumRemaining = 0;
thread->CpuBurstTicks = 0;
thread->LastRunTicks = 0;
thread->RunningCpu = KE_INVALID_CPU;
thread->WaitObject = (OBJECT *)0;
thread->WaitStatus = STATUS_SUCCESS;
thread->WaitListHead = (LIST_ENTRY*)0;
@@ -249,6 +251,7 @@ __declspec(dllexport) KSTATUS KeCreateKernelThread(uintptr_t fn, uintptr_t arg,
thread->QuantumRemaining = 0;
thread->CpuBurstTicks = 0;
thread->LastRunTicks = 0;
thread->RunningCpu = KE_INVALID_CPU;
thread->WaitObject = (OBJECT*)0;
thread->WaitStatus = STATUS_SUCCESS;
thread->WaitListHead = (LIST_ENTRY*)0;
+5 -5
View File
@@ -1,11 +1,11 @@
// ke_trap.c - current-thread trap-frame tracking and validation
#include <stddef.h>
#include <string.h>
#include <ke_trap.h>
#include <ke_thread.h>
#include <ke_sched.h>
#include <ke_debug.h>
#include <ke_apc.h>
#include <kernel/ke_trap.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_apc.h>
#define STATIC_ASSERT_OFFSET(type, field, expected) \
_Static_assert(offsetof(type, field) == (expected), \
+22 -20
View File
@@ -2,25 +2,26 @@
#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_dpc.h>
#include <ke_syscall.h>
#include <net_device.h>
#include <ke_debug.h>
#include <ke_util.h>
#include <ldr_image.h>
#include <hal_api.h>
#include <io_file.h>
#include <ke_selftest.h>
#include <ini_parser.h>
#include <ntlite/boot_info.h>
#include <kernel/mm_phys.h>
#include <kernel/mm_virt.h>
#include <kernel/ob_object.h>
#include <kernel/ke_process.h>
#include <kernel/ke_thread.h>
#include <kernel/ke_sched.h>
#include <kernel/ke_cpu.h>
#include <kernel/ke_idt.h>
#include <kernel/ke_irq.h>
#include <kernel/ke_dpc.h>
#include <kernel/ke_syscall.h>
#include <ntlite/ddi/net_device.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_util.h>
#include <kernel/ldr_image.h>
#include <ntlite/ddi/hal_api.h>
#include <kernel/io_file.h>
#include <kernel/ke_selftest.h>
#include <common/ini_parser.h>
typedef struct {
BOOT_INFO* bootInfo;
@@ -438,8 +439,9 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
MmInitializeVirtual(pml4, 4 * 1024 * 1024 /* 4 MB initial pool */);
//
// CPU Architecture setup (GDT/IDT/Faults)
// Bootstrap CPU and architecture setup (GDT/IDT/Faults)
//
KeInitializeBootstrapCpu();
KeInitializeGdt();
KeInitializeIdt();
+6 -6
View File
@@ -1,12 +1,12 @@
// ldr_image.c - PE32+ loader and export resolver
#include <stdint.h>
#include <string.h>
#include <ldr_image.h>
#include <boot_info.h>
#include <ke_process.h>
#include <io_file.h>
#include <mm_virt.h>
#include <ke_debug.h>
#include <kernel/ldr_image.h>
#include <ntlite/boot_info.h>
#include <kernel/ke_process.h>
#include <kernel/io_file.h>
#include <kernel/mm_virt.h>
#include <kernel/ke_debug.h>
int _stricmp(const char* a, const char* b);
-30
View File
@@ -1,30 +0,0 @@
#pragma once
// memory_map.h - shared between bootx64.efi and kernel.exe
// Describes physical memory layout passed from bootloader to kernel.
#include <stdint.h>
#define MEMORY_MAP_MAGIC 0x4D454D4D41500000ULL /* 'MEMMAP\0\0' */
#define MEMORY_MAX_REGIONS 256
typedef enum MEMORY_TYPE {
MemoryUsable = 0, /* free RAM, available to the PMM */
MemoryReserved = 1, /* firmware-reserved, do not touch */
MemoryMappedIO = 2, /* device MMIO regions */
MemoryFramebuffer = 3, /* GOP framebuffer */
MemoryBootloader = 4, /* bootloader code/data (reclaimable) */
MemoryKernel = 5, /* kernel + HAL + drivers image pages */
} MEMORY_TYPE;
typedef struct MEMORY_REGION {
uint64_t Base;
uint64_t Length; /* in bytes, always page-aligned */
MEMORY_TYPE Type;
uint32_t _pad;
} MEMORY_REGION;
typedef struct MEMORY_MAP {
uint64_t Magic;
uint32_t RegionCount;
uint32_t _pad;
MEMORY_REGION Regions[MEMORY_MAX_REGIONS];
} MEMORY_MAP;
+2 -2
View File
@@ -6,8 +6,8 @@
// 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 <kernel/mm_phys.h>
#include <kernel/ke_spinlock.h>
// ---------------------------------------------------------------------------
// Physical-to-virtual translation via the direct map window.
+3 -3
View File
@@ -14,9 +14,9 @@
// Backed on demand from the PMM. No per-process heaps.
#include <stddef.h>
#include <string.h>
#include <mm_virt.h>
#include <ke_spinlock.h>
#include <ke_irql.h>
#include <kernel/mm_virt.h>
#include <kernel/ke_spinlock.h>
#include <kernel/ke_irql.h>
// ---------------------------------------------------------------------------
// Helpers - physical window access
-45
View File
@@ -1,45 +0,0 @@
#pragma once
// net_abi.h - native networking ABI shared by the kernel socket facade
// and network stack provider drivers.
#include <stdint.h>
#include <stddef.h>
#define SYS_AF_INET 2u
#define SYS_SOCK_STREAM 1u
#define SYS_SOCK_DGRAM 2u
#define SYS_SOCK_RAW 3u
#define SYS_IPPROTO_ICMP 1u
#define SYS_IPPROTO_TCP 6u
#define SYS_IPPROTO_UDP 17u
#define SYS_SHUTDOWN_READ 0u
#define SYS_SHUTDOWN_WRITE 1u
#define SYS_SHUTDOWN_BOTH 2u
#define SYS_SOCKET_ADDRESS_IPV4_SIZE 16u
#define SYS_RESOLVE_HOST_NAME_MAX 255u
#define SYS_SOCKET_OPT_RECV_TIMEOUT_MS 1u
#define SYS_SOCKET_OPT_SEND_TIMEOUT_MS 2u
#define SYS_SOCKET_OPT_NONBLOCKING 3u
#define SYS_POLL_READ 0x0001u
#define SYS_POLL_WRITE 0x0002u
#define SYS_POLL_ERROR 0x0004u
#define SYS_POLL_HANGUP 0x0008u
#define SYS_POLL_INVALID 0x0010u
#define SYS_POLL_TIMEOUT_INFINITE 0xFFFFFFFFu
typedef struct SYS_SOCKET_ADDRESS_IPV4_K {
uint16_t Family; // SYS_AF_INET
uint16_t Port; // host byte order
uint8_t Address[4]; // dotted-quad bytes, e.g. {10,0,2,2}
uint8_t Reserved[8];
} SYS_SOCKET_ADDRESS_IPV4_K;
typedef struct SYS_POLLFD_K {
uint32_t Handle;
uint32_t Events;
uint32_t ReturnedEvents;
} SYS_POLLFD_K;
+4 -4
View File
@@ -3,10 +3,10 @@
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <net_device.h>
#include <net_stack.h>
#include <ke_debug.h>
#include <ke_spinlock.h>
#include <ntlite/ddi/net_device.h>
#include <ntlite/ddi/net_stack.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_spinlock.h>
#define NET_MAX_DEVICES 8u
-57
View File
@@ -1,57 +0,0 @@
#pragma once
// net_device.h - kernel network-device registry.
//
// NIC drivers register NET_DEVICE objects here and feed complete Ethernet
// frames into NetReceiveFrame(). Protocol ownership belongs to whichever
// network stack driver registered through net_stack.h.
#include <stdint.h>
#include <stddef.h>
#include <ke_status.h>
#define NET_DEVICE_NAME_MAX 16u
#define NET_HWADDR_MAX 16u
#define NET_MTU_ETHERNET 1500u
#define NET_ETHERNET_ADDRESS_LENGTH 6u
#define NET_ETHERNET_HEADER_LENGTH 14u
#define NET_ETHERNET_MIN_FRAME 60u
#define NET_ETHERNET_MAX_FRAME (NET_ETHERNET_HEADER_LENGTH + NET_MTU_ETHERNET)
struct NET_DEVICE;
typedef struct NET_DEVICE NET_DEVICE;
typedef KSTATUS (*NET_SEND_FRAME)(NET_DEVICE* device,
const void* frame,
size_t length);
typedef struct NET_DEVICE_STATS {
uint64_t TxPackets;
uint64_t TxBytes;
uint64_t TxErrors;
uint64_t RxPackets;
uint64_t RxBytes;
uint64_t RxDrops;
} NET_DEVICE_STATS;
struct NET_DEVICE {
char Name[NET_DEVICE_NAME_MAX];
uint32_t Index;
uint32_t Mtu;
uint8_t HardwareAddressLength;
uint8_t HardwareAddress[NET_HWADDR_MAX];
void* DriverContext;
NET_SEND_FRAME SendFrame;
NET_DEVICE_STATS Stats;
};
__declspec(dllexport) KSTATUS NetRegisterDevice(NET_DEVICE* device);
__declspec(dllexport) uint32_t NetGetDeviceCount(void);
__declspec(dllexport) NET_DEVICE* NetGetDevice(uint32_t index);
__declspec(dllexport) KSTATUS NetGetDeviceStats(uint32_t index,
NET_DEVICE_STATS* stats);
__declspec(dllexport) KSTATUS NetSendFrame(uint32_t index,
const void* frame,
size_t length);
__declspec(dllexport) void NetReceiveFrame(NET_DEVICE* device,
const void* frame,
size_t length);
+3 -3
View File
@@ -4,9 +4,9 @@
#include <stddef.h>
#include <string.h>
#include <net_socket.h>
#include <net_stack.h>
#include <ob_object.h>
#include <kernel/net_socket.h>
#include <ntlite/ddi/net_stack.h>
#include <kernel/ob_object.h>
#define NET_SOCKET_IO_MAX_BYTES (1024u * 1024u)
#define NET_SOCKET_UDP_MAX_BYTES 65507u
+4 -4
View File
@@ -2,10 +2,10 @@
#include <stdint.h>
#include <stddef.h>
#include <net_stack.h>
#include <net_device.h>
#include <ke_debug.h>
#include <ke_spinlock.h>
#include <ntlite/ddi/net_stack.h>
#include <ntlite/ddi/net_device.h>
#include <kernel/ke_debug.h>
#include <kernel/ke_spinlock.h>
static const NET_STACK_PROVIDER* gNetStackProvider = 0;
static SPINLOCK gNetStackLock = SPINLOCK_INIT;
-48
View File
@@ -1,48 +0,0 @@
#pragma once
// net_stack.h - provider interface between kernel socket facade and network stack drivers.
//
// The kernel owns process handles, user-memory copying, NET_DEVICE registration,
// and SOCKET_OBJECT lifetime. A stack driver owns protocol implementation.
#include <stdint.h>
#include <stddef.h>
#include <ke_status.h>
#include <net_device.h>
#include <net_abi.h>
#define NET_STACK_PROVIDER_VERSION 1u
typedef struct NET_STACK_PROVIDER NET_STACK_PROVIDER;
struct NET_STACK_PROVIDER {
uint32_t Version;
const char* Name;
KSTATUS (*AttachDevice)(NET_DEVICE* device);
KSTATUS (*ReceiveFrame)(NET_DEVICE* device, const void* frame, size_t length);
KSTATUS (*SocketCreate)(uint32_t domain, uint32_t type, uint32_t protocol, void** outSocket);
void (*SocketClose)(void* socket);
KSTATUS (*Bind)(void* socket, const SYS_SOCKET_ADDRESS_IPV4_K* address, size_t addressSize);
KSTATUS (*Listen)(void* socket, uint32_t backlog);
KSTATUS (*Accept)(void* socket, void** acceptedOut, SYS_SOCKET_ADDRESS_IPV4_K* remoteOut);
KSTATUS (*Connect)(void* socket, const SYS_SOCKET_ADDRESS_IPV4_K* address, size_t addressSize);
KSTATUS (*Send)(void* socket, const void* buffer, size_t length, uint32_t flags, size_t* sentOut);
KSTATUS (*Receive)(void* socket, void* buffer, size_t length, uint32_t flags, size_t* receivedOut);
KSTATUS (*SendTo)(void* socket, const void* buffer, size_t length, uint32_t flags,
const SYS_SOCKET_ADDRESS_IPV4_K* remote, size_t remoteSize, size_t* sentOut);
KSTATUS (*ReceiveFrom)(void* socket, void* buffer, size_t length, uint32_t flags,
SYS_SOCKET_ADDRESS_IPV4_K* remoteOut, size_t* receivedOut);
KSTATUS (*Shutdown)(void* socket, uint32_t how);
KSTATUS (*SetOption)(void* socket, uint32_t option, const void* value, size_t valueSize);
KSTATUS (*GetOption)(void* socket, uint32_t option, void* value, size_t valueSize, size_t* actualSizeOut);
KSTATUS (*Poll)(void* socket, uint32_t events, uint32_t* returnedEventsOut);
KSTATUS (*ResolveHostIpv4)(const char* name, SYS_SOCKET_ADDRESS_IPV4_K* addressOut);
};
__declspec(dllexport) KSTATUS NetRegisterStackProvider(const NET_STACK_PROVIDER* provider);
__declspec(dllexport) const NET_STACK_PROVIDER* NetGetStackProvider(void);
+2 -2
View File
@@ -1,8 +1,8 @@
// ob_object.c - executive object manager
#include <string.h>
#include <intrin.h>
#include <ob_object.h>
#include <mm_virt.h>
#include <kernel/ob_object.h>
#include <kernel/mm_virt.h>
__declspec(dllexport) OBJECT* ObAllocateObject(OBJECT_TYPE type, size_t size) {
if (size < sizeof(OBJECT)) size = sizeof(OBJECT);
-119
View File
@@ -1,119 +0,0 @@
///////////////////////////////////////////////////////////////////////////////
// \author (c) Marco Paland (info@paland.com)
// 2014-2019, PALANDesign Hannover, Germany
//
// \license The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
// embedded systems with a very limited resources.
// Use this instead of bloated standard/newlib printf.
// These routines are thread safe and reentrant.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef _PRINTF_H_
#define _PRINTF_H_
#include <stdarg.h>
#include <stddef.h>
// maksw: yeah that hack i mentioned earlier
void printf_set_putchar(void (*fn)(char));
#ifdef __cplusplus
extern "C" {
#endif
/**
* Output a character to a custom device like UART, used by the printf() function
* This function is declared here only. You have to write your custom implementation somewhere
* \param character Character to output
*/
//void _putchar(char character);
/**
* Tiny printf implementation
* You have to implement _putchar if you use printf()
* To avoid conflicts with the regular printf() API it is overridden by macro defines
* and internal underscore-appended functions like printf_() are used
* \param format A string that specifies the format of the output
* \return The number of characters that are written into the array, not counting the terminating null character
*/
#define printf printf_
int printf_(const char* format, ...);
/**
* Tiny sprintf implementation
* Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD!
* \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output!
* \param format A string that specifies the format of the output
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
*/
#define sprintf sprintf_
int sprintf_(char* buffer, const char* format, ...);
/**
* Tiny snprintf/vsnprintf implementation
* \param buffer A pointer to the buffer where to store the formatted string
* \param count The maximum number of characters to store in the buffer, including a terminating null character
* \param format A string that specifies the format of the output
* \param va A value identifying a variable arguments list
* \return The number of characters that COULD have been written into the buffer, not counting the terminating
* null character. A value equal or larger than count indicates truncation. Only when the returned value
* is non-negative and less than count, the string has been completely written.
*/
#define snprintf snprintf_
#define vsnprintf vsnprintf_
int snprintf_(char* buffer, size_t count, const char* format, ...);
int vsnprintf_(char* buffer, size_t count, const char* format, va_list va);
/**
* Tiny vprintf implementation
* \param format A string that specifies the format of the output
* \param va A value identifying a variable arguments list
* \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
*/
#define vprintf vprintf_
int vprintf_(const char* format, va_list va);
/**
* printf with output function
* You may use this as dynamic alternative to printf() with its fixed _putchar() output
* \param out An output function which takes one character and an argument pointer
* \param arg An argument pointer for user data passed to output function
* \param format A string that specifies the format of the output
* \return The number of characters that are sent to the output function, not counting the terminating null character
*/
int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
#ifdef __cplusplus
}
#endif
#endif // _PRINTF_H_