implement proper IRQL, DPCs, kernel and user APCs, alertable waits, async file I/O with cancellation, trap frames, selftests, a real driver/device model, native async FAT32, VFAT dotfile fixes, syscall ABI cleanup, async_apc and async_cancel tests, POSIX multi-volume paths, and pimp the readme.
This commit is contained in:
1 parent
f5fd7bdd75
commit
529f816166
75 files changed
+9969
-5675
No files matched your search
+126
-132
@@ -1,132 +1,126 @@
|
||||
#pragma once
|
||||
// hal_api.h - HAL interface table exported as HalGetApi()
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <ke_status.h>
|
||||
|
||||
typedef struct BOOT_INFO BOOT_INFO;
|
||||
|
||||
typedef struct HAL_SCREEN {
|
||||
void (*Clear)(uint32_t color);
|
||||
void (*PutPixel)(int x, int y, uint32_t color);
|
||||
void (*Blit)(int x, int y, int w, int h, const uint32_t* pixels);
|
||||
void (*GetSize)(int* width, int* height);
|
||||
void (*Scroll)(int lines);
|
||||
void (*PutChar)(char c, int x, int y, uint32_t fg, uint32_t bg);
|
||||
void (*PrintChar)(char c, uint32_t fg, uint32_t bg);
|
||||
// Hardware mouse cursor: save/restore background and blit sprite
|
||||
void (*DrawCursor)(int x, int y);
|
||||
void (*EraseCursor)(void);
|
||||
} HAL_SCREEN;
|
||||
|
||||
typedef struct HAL_KEYBOARD {
|
||||
uint8_t (*Poll)(void);
|
||||
uint8_t (*ReadScancode)(void);
|
||||
char (*ReadChar)(void);
|
||||
uint32_t (*GetModifiers)(void);
|
||||
void (*SetCallback)(void (*cb)(uint8_t scancode));
|
||||
bool (*IsKeyDown)(uint8_t scancode, bool extended);
|
||||
void (*Isr)(void);
|
||||
uint8_t IrqNumber;
|
||||
} HAL_KEYBOARD;
|
||||
|
||||
// HAL_MOUSE – PS/2 auxiliary mouse on IRQ 12.
|
||||
// Packet format: standard 3-byte PS/2 (buttons, deltaX, deltaY).
|
||||
// Y is already screen-oriented (positive = down) after ISR inversion.
|
||||
typedef struct HAL_MOUSE {
|
||||
// Non-blocking: returns true if a packet is waiting in the ring buffer.
|
||||
bool (*Poll)(void);
|
||||
// Non-blocking dequeue. Returns false when buffer is empty.
|
||||
// buttons: bit0=left, bit1=right, bit2=middle
|
||||
bool (*Read)(int* dx, int* dy, uint8_t* buttons);
|
||||
// Callback invoked from ISR context after every completed packet.
|
||||
void (*SetCallback)(void (*cb)(int dx, int dy, uint8_t buttons));
|
||||
// Absolute cursor position, clamped to screen bounds.
|
||||
void (*GetPosition)(int* x, int* y);
|
||||
void (*SetPosition)(int x, int y);
|
||||
// Update the clamping rectangle (call after mode change / resize).
|
||||
void (*SetBounds)(int w, int h);
|
||||
// Raw ISR – called by KeIrqDispatch for IRQ 12.
|
||||
void (*Isr)(void);
|
||||
uint8_t IrqNumber; // always 12
|
||||
} HAL_MOUSE;
|
||||
|
||||
typedef struct HAL_DISK {
|
||||
KSTATUS (*ReadSectors)(uint8_t drive, uint64_t lba,
|
||||
uint32_t count, void* buf);
|
||||
KSTATUS (*WriteSectors)(uint8_t drive, uint64_t lba,
|
||||
uint32_t count, const void* buf);
|
||||
bool (*DrivePresent)(uint8_t drive);
|
||||
uint64_t (*DriveSectorCount)(uint8_t drive);
|
||||
} HAL_DISK;
|
||||
|
||||
typedef struct HAL_TIMER {
|
||||
uint64_t (*QueryTicks)(void);
|
||||
void (*Stall)(uint32_t us);
|
||||
void (*Isr)(void);
|
||||
uint8_t IrqNumber;
|
||||
} HAL_TIMER;
|
||||
|
||||
typedef struct HAL_PCI {
|
||||
uint32_t (*Read32)(uint8_t bus, uint8_t dev,
|
||||
uint8_t fn, uint8_t reg);
|
||||
void (*Write32)(uint8_t bus, uint8_t dev,
|
||||
uint8_t fn, uint8_t reg, uint32_t val);
|
||||
bool (*FindDevice)(uint16_t vendor, uint16_t device,
|
||||
uint8_t* bus, uint8_t* dev, uint8_t* fn);
|
||||
bool (*FindClass)(uint8_t classCode, uint8_t subclass,
|
||||
uint8_t* bus, uint8_t* dev, uint8_t* fn);
|
||||
// Returns the IRQ line from PCI config space (register 0x3C, byte 0).
|
||||
// Returns 0xFF if no interrupt is wired.
|
||||
uint8_t (*GetIrqLine)(uint8_t bus, uint8_t dev, uint8_t fn);
|
||||
} HAL_PCI;
|
||||
|
||||
typedef struct HAL_INTC {
|
||||
void (*RouteIrq)(uint8_t irq);
|
||||
void (*MaskIrq)(uint8_t irq);
|
||||
void (*UnmaskIrq)(uint8_t irq);
|
||||
void (*SendEoi)(void);
|
||||
} HAL_INTC;
|
||||
|
||||
typedef struct HAL_POWER {
|
||||
// ACPI S5 soft-off. Disables interrupts, writes SLP_EN to PM1a/b_CNT,
|
||||
// and halts if firmware doesn't respond. Does not return.
|
||||
void (*Shutdown)(void);
|
||||
} HAL_POWER;
|
||||
|
||||
typedef struct HAL_API {
|
||||
uint32_t Version;
|
||||
void *(*PhysToVirt)(uint64_t physAddr);
|
||||
HAL_SCREEN Screen;
|
||||
HAL_KEYBOARD Keyboard;
|
||||
HAL_MOUSE Mouse;
|
||||
HAL_DISK Disk;
|
||||
HAL_TIMER Timer;
|
||||
HAL_PCI Pci;
|
||||
HAL_INTC Intc;
|
||||
HAL_POWER Power;
|
||||
} HAL_API;
|
||||
|
||||
typedef struct HAL_INIT_PARAMS {
|
||||
// Framebuffer
|
||||
uintptr_t FramebufferBase;
|
||||
uint32_t FramebufferWidth;
|
||||
uint32_t FramebufferHeight;
|
||||
uint32_t FramebufferStride;
|
||||
|
||||
// ACPI
|
||||
uintptr_t RsdpPhysical;
|
||||
|
||||
// Memory
|
||||
uint64_t PhysicalWindowBase;
|
||||
|
||||
// Debug
|
||||
int DebugEnabled;
|
||||
} HAL_INIT_PARAMS;
|
||||
|
||||
#define HAL_API_VERSION 1
|
||||
|
||||
__declspec(dllexport) const HAL_API* HalGetApi(void);
|
||||
__declspec(dllexport) void HalRegisterScheduler(void (*pKeSchedulerTick)(void));
|
||||
__declspec(dllexport) KSTATUS HalInitialize(const HAL_INIT_PARAMS* params);
|
||||
#pragma once
|
||||
// hal_api.h - HAL interface table exported as HalGetApi()
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <ke_status.h>
|
||||
|
||||
typedef struct BOOT_INFO BOOT_INFO;
|
||||
|
||||
typedef struct HAL_SCREEN {
|
||||
void (*Clear)(uint32_t color);
|
||||
void (*PutPixel)(int x, int y, uint32_t color);
|
||||
void (*Blit)(int x, int y, int w, int h, const uint32_t* pixels);
|
||||
void (*GetSize)(int* width, int* height);
|
||||
void (*Scroll)(int lines);
|
||||
void (*PutChar)(char c, int x, int y, uint32_t fg, uint32_t bg);
|
||||
void (*PrintChar)(char c, uint32_t fg, uint32_t bg);
|
||||
// Hardware mouse cursor: save/restore background and blit sprite
|
||||
void (*DrawCursor)(int x, int y);
|
||||
void (*EraseCursor)(void);
|
||||
} HAL_SCREEN;
|
||||
|
||||
typedef struct HAL_KEYBOARD {
|
||||
uint8_t (*Poll)(void);
|
||||
uint8_t (*ReadScancode)(void);
|
||||
char (*ReadChar)(void);
|
||||
uint32_t (*GetModifiers)(void);
|
||||
void (*SetCallback)(void (*cb)(uint8_t scancode));
|
||||
bool (*IsKeyDown)(uint8_t scancode, bool extended);
|
||||
void (*Isr)(void);
|
||||
// Optional bottom half, queued by the kernel after IRQ dispatch.
|
||||
void (*Dpc)(void);
|
||||
uint8_t IrqNumber;
|
||||
} HAL_KEYBOARD;
|
||||
|
||||
// HAL_MOUSE – PS/2 auxiliary mouse on IRQ 12.
|
||||
// Packet format: standard 3-byte PS/2 (buttons, deltaX, deltaY).
|
||||
// Y is already screen-oriented (positive = down) after ISR inversion.
|
||||
typedef struct HAL_MOUSE {
|
||||
// Non-blocking: returns true if a packet is waiting in the ring buffer.
|
||||
bool (*Poll)(void);
|
||||
// Non-blocking dequeue. Returns false when buffer is empty.
|
||||
// buttons: bit0=left, bit1=right, bit2=middle
|
||||
bool (*Read)(int* dx, int* dy, uint8_t* buttons);
|
||||
// Callback invoked from DPC context after every completed packet.
|
||||
void (*SetCallback)(void (*cb)(int dx, int dy, uint8_t buttons));
|
||||
// Absolute cursor position, clamped to screen bounds.
|
||||
void (*GetPosition)(int* x, int* y);
|
||||
void (*SetPosition)(int x, int y);
|
||||
// Update the clamping rectangle (call after mode change / resize).
|
||||
void (*SetBounds)(int w, int h);
|
||||
// Raw ISR – called by KeIrqDispatch for IRQ 12.
|
||||
void (*Isr)(void);
|
||||
// Optional bottom half, queued by the kernel after IRQ dispatch.
|
||||
void (*Dpc)(void);
|
||||
uint8_t IrqNumber; // always 12
|
||||
} HAL_MOUSE;
|
||||
|
||||
typedef struct HAL_TIMER {
|
||||
uint64_t (*QueryTicks)(void);
|
||||
void (*Stall)(uint32_t us);
|
||||
void (*Isr)(void);
|
||||
uint8_t IrqNumber;
|
||||
} HAL_TIMER;
|
||||
|
||||
typedef struct HAL_PCI {
|
||||
uint32_t (*Read32)(uint8_t bus, uint8_t dev,
|
||||
uint8_t fn, uint8_t reg);
|
||||
void (*Write32)(uint8_t bus, uint8_t dev,
|
||||
uint8_t fn, uint8_t reg, uint32_t val);
|
||||
bool (*FindDevice)(uint16_t vendor, uint16_t device,
|
||||
uint8_t* bus, uint8_t* dev, uint8_t* fn);
|
||||
bool (*FindClass)(uint8_t classCode, uint8_t subclass,
|
||||
uint8_t* bus, uint8_t* dev, uint8_t* fn);
|
||||
// Returns the IRQ line from PCI config space (register 0x3C, byte 0).
|
||||
// Returns 0xFF if no interrupt is wired.
|
||||
uint8_t (*GetIrqLine)(uint8_t bus, uint8_t dev, uint8_t fn);
|
||||
} HAL_PCI;
|
||||
|
||||
typedef struct HAL_INTC {
|
||||
void (*RouteIrq)(uint8_t irq);
|
||||
void (*MaskIrq)(uint8_t irq);
|
||||
void (*UnmaskIrq)(uint8_t irq);
|
||||
void (*SendEoi)(void);
|
||||
} HAL_INTC;
|
||||
|
||||
typedef struct HAL_POWER {
|
||||
// ACPI S5 soft-off. Disables interrupts, writes SLP_EN to PM1a/b_CNT,
|
||||
// and halts if firmware doesn't respond. Does not return.
|
||||
void (*Shutdown)(void);
|
||||
} HAL_POWER;
|
||||
|
||||
typedef struct HAL_API {
|
||||
uint32_t Version;
|
||||
void *(*PhysToVirt)(uint64_t physAddr);
|
||||
HAL_SCREEN Screen;
|
||||
HAL_KEYBOARD Keyboard;
|
||||
HAL_MOUSE Mouse;
|
||||
HAL_TIMER Timer;
|
||||
HAL_PCI Pci;
|
||||
HAL_INTC Intc;
|
||||
HAL_POWER Power;
|
||||
} HAL_API;
|
||||
|
||||
typedef struct HAL_INIT_PARAMS {
|
||||
// Framebuffer
|
||||
uintptr_t FramebufferBase;
|
||||
uint32_t FramebufferWidth;
|
||||
uint32_t FramebufferHeight;
|
||||
uint32_t FramebufferStride;
|
||||
|
||||
// ACPI
|
||||
uintptr_t RsdpPhysical;
|
||||
|
||||
// Memory
|
||||
uint64_t PhysicalWindowBase;
|
||||
|
||||
// Debug
|
||||
int Debug;
|
||||
} HAL_INIT_PARAMS;
|
||||
|
||||
#define HAL_API_VERSION 2
|
||||
|
||||
__declspec(dllexport) const HAL_API* HalGetApi(void);
|
||||
__declspec(dllexport) void HalRegisterScheduler(void (*pKeSchedulerTick)(void));
|
||||
__declspec(dllexport) KSTATUS HalInitialize(const HAL_INIT_PARAMS* params);
|
||||
+2
-93
@@ -1,93 +1,2 @@
|
||||
// hal_disk.c - drive registry; drivers register themselves via IoRegisterDisk.
|
||||
//
|
||||
// This file lives in the HAL layer and must NOT reference any kernel sync
|
||||
// objects (KeEventCreate, KeSignalEvent, KeWaitForEvent, ObDereferenceObject).
|
||||
// All IRP event signalling is done in kernel/ke_irp.c, which sits above us
|
||||
// in the dependency graph.
|
||||
//
|
||||
// HalDiskDispatch is the one bridge: it calls the driver's SubmitIrp (async)
|
||||
// or runs the sync callbacks inline and writes irp->Status. It does not
|
||||
// touch irp->CompletionEvent - that is ke_irp.c's responsibility.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <hal_api.h>
|
||||
#include <io_driver.h>
|
||||
#include <ke_irp.h>
|
||||
|
||||
#define MAX_DRIVES 8
|
||||
|
||||
static DISK_DRIVER gDrives[MAX_DRIVES];
|
||||
static bool gPresent[MAX_DRIVES];
|
||||
|
||||
__declspec(dllexport) KSTATUS IoRegisterDisk(uint8_t index, const DISK_DRIVER *driver) {
|
||||
if (index >= MAX_DRIVES || !driver) return STATUS_INVALID_PARAMETER;
|
||||
if (gPresent[index]) return STATUS_ALREADY_EXISTS;
|
||||
gDrives[index] = *driver;
|
||||
gPresent[index] = true;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// HalDiskDispatch - called exclusively by ke_irp.c::IoSubmitIrp()
|
||||
// -------------------------------------------------------------------------
|
||||
// Separating dispatch here keeps hal_disk.c free of event primitives while
|
||||
// still allowing ke_irp.c (kernel layer) to fire completion hooks after we
|
||||
// return.
|
||||
//
|
||||
// Returns STATUS_PENDING - driver accepted the IRP asynchronously.
|
||||
// ke_irp.c must NOT touch irp->CompletionEvent
|
||||
// yet; the driver will fire it.
|
||||
// Returns STATUS_SUCCESS - sync fallback ran; irp->Status is already
|
||||
// written. ke_irp.c should fire completion hooks.
|
||||
// Returns STATUS_NOT_FOUND - drive not registered.
|
||||
|
||||
__declspec(dllexport) KSTATUS HalDiskDispatch(uint8_t drive, IRP *irp) {
|
||||
if (drive >= MAX_DRIVES || !gPresent[drive]) return STATUS_NOT_FOUND;
|
||||
DISK_DRIVER *drv = &gDrives[drive];
|
||||
|
||||
if (drv->SubmitIrp)
|
||||
return drv->SubmitIrp(drv->Ctx, irp); // STATUS_PENDING
|
||||
|
||||
// Sync fallback: execute inline, write result, let caller fire hooks.
|
||||
bool write = !!(irp->Flags & IRP_FLAG_WRITE);
|
||||
if (write)
|
||||
irp->Status = drv->WriteSectors(drv->Ctx, irp->Lba, irp->SectorCount, irp->Buffer);
|
||||
else
|
||||
irp->Status = drv->ReadSectors (drv->Ctx, irp->Lba, irp->SectorCount, irp->Buffer);
|
||||
|
||||
return STATUS_SUCCESS; // ran synchronously
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Legacy HAL_DISK vtable - direct sync calls, no IRP involvement.
|
||||
// Existing callers (FAT32, shell) use this path unchanged.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static KSTATUS DiskRead(uint8_t drive, uint64_t lba,
|
||||
uint32_t count, void *buf) {
|
||||
if (drive >= MAX_DRIVES || !gPresent[drive]) return STATUS_NOT_FOUND;
|
||||
return gDrives[drive].ReadSectors(gDrives[drive].Ctx, lba, count, buf);
|
||||
}
|
||||
|
||||
static KSTATUS DiskWrite(uint8_t drive, uint64_t lba,
|
||||
uint32_t count, const void *buf) {
|
||||
if (drive >= MAX_DRIVES || !gPresent[drive]) return STATUS_NOT_FOUND;
|
||||
return gDrives[drive].WriteSectors(gDrives[drive].Ctx, lba, count, buf);
|
||||
}
|
||||
|
||||
static bool DiskPresent(uint8_t drive) {
|
||||
return drive < MAX_DRIVES && gPresent[drive];
|
||||
}
|
||||
|
||||
static uint64_t DiskSectorCount(uint8_t drive) {
|
||||
if (drive >= MAX_DRIVES || !gPresent[drive]) return 0;
|
||||
return gDrives[drive].SectorCount;
|
||||
}
|
||||
|
||||
void HalDiskInitialize(HAL_DISK *out) {
|
||||
out->ReadSectors = DiskRead;
|
||||
out->WriteSectors = DiskWrite;
|
||||
out->DrivePresent = DiskPresent;
|
||||
out->DriveSectorCount = DiskSectorCount;
|
||||
}
|
||||
// hal_disk.c intentionally left empty.
|
||||
// Disk registration and dispatch live in kernel/io_device.c.
|
||||
+46
-2
@@ -17,6 +17,17 @@ 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
|
||||
@@ -62,6 +73,21 @@ static const char gShifted[128] = {
|
||||
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);
|
||||
@@ -108,8 +134,15 @@ void KbdIsr(void) {
|
||||
gTail = next;
|
||||
}
|
||||
|
||||
void (*cb)(uint8_t) = (void (*)(uint8_t))gCallback;
|
||||
if (cb) cb(make);
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +179,14 @@ static char KbdReadChar(void) {
|
||||
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);
|
||||
@@ -154,7 +195,10 @@ void HalKeyboardInitialize(HAL_KEYBOARD *out) {
|
||||
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
-384
@@ -1,384 +1,381 @@
|
||||
// hal_main.c - HAL initialisation and HalGetApi
|
||||
#include <hal_api.h>
|
||||
#include <hal_apic.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <intrin.h>
|
||||
#include <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);
|
||||
void HalDiskInitialize(HAL_DISK* 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->DebugEnabled;
|
||||
|
||||
// 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);
|
||||
HalDiskInitialize(&gApi.Disk);
|
||||
|
||||
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; }
|
||||
// hal_main.c - HAL initialisation and HalGetApi
|
||||
#include <hal_api.h>
|
||||
#include <hal_apic.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <intrin.h>
|
||||
#include <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; }
|
||||
+59
-35
@@ -13,15 +13,15 @@
|
||||
// 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), clamps the absolute position to [0, bounds), enqueues a
|
||||
// MOUSE_EVENT, and then calls EraseOldCursor / DrawNewCursor via the two
|
||||
// screen helpers that hal_screen.c exports.
|
||||
// (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
|
||||
// ---------------
|
||||
// Single-producer (ISR on IRQ 12) / single-consumer ring buffer.
|
||||
// All ISR-written fields are volatile; on a uniprocessor this is sufficient.
|
||||
// On SMP, add acquire/release barriers around gHead / gTail.
|
||||
// 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>
|
||||
@@ -44,8 +44,13 @@ typedef struct {
|
||||
} MOUSE_EVENT;
|
||||
|
||||
static MOUSE_EVENT gBuf[MOUSE_BUF_SIZE];
|
||||
static volatile int gHead = 0; // consumer read pointer
|
||||
static volatile int gTail = 0; // producer write pointer (updated by ISR)
|
||||
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;
|
||||
@@ -57,7 +62,7 @@ static volatile int gBoundsH = 1080;
|
||||
static volatile uint8_t gPacket[3];
|
||||
static volatile int gPacketIdx = 0; // 0, 1, or 2
|
||||
|
||||
// -- Optional callback (called from ISR) ---------------------------------------
|
||||
// -- 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 -----------------------------------
|
||||
@@ -101,9 +106,45 @@ static uint8_t MouseRecvByte(void) {
|
||||
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 before this function is invoked.
|
||||
// The dispatcher sends the APIC EOI after this function returns.
|
||||
static void MouseIsr(void) {
|
||||
uint8_t data = __inbyte(PS2_DATA);
|
||||
|
||||
@@ -130,32 +171,14 @@ static void MouseIsr(void) {
|
||||
int dy = (int)gPacket[2] - ((flags & 0x20u) ? 256 : 0);
|
||||
dy = -dy; // PS/2 Y+ = up; screen Y+ = down, so invert.
|
||||
|
||||
// -- Update absolute position (clamped to screen bounds) ------------------
|
||||
HalScreenEraseCursor();
|
||||
|
||||
int nx = gMouseX + dx;
|
||||
int ny = gMouseY + 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);
|
||||
|
||||
// -- Enqueue event; silently drop if buffer is full -----------------------
|
||||
int next = (gTail + 1) & (int)MOUSE_BUF_MASK;
|
||||
if (next != gHead) {
|
||||
gBuf[gTail].dx = dx;
|
||||
gBuf[gTail].dy = dy;
|
||||
gBuf[gTail].buttons = buttons;
|
||||
gTail = next;
|
||||
// -- 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;
|
||||
}
|
||||
|
||||
// -- Optional callback (raw ISR context) -----------------------------------
|
||||
void (*cb)(int, int, uint8_t) = (void (*)(int, int, uint8_t))gCallback;
|
||||
if (cb) cb(dx, dy, buttons);
|
||||
}
|
||||
|
||||
// -- Consumer API --------------------------------------------------------------
|
||||
@@ -278,5 +301,6 @@ void HalMouseInitialize(HAL_MOUSE* out, int screenW, int screenH) {
|
||||
out->SetPosition = MouseSetPosition;
|
||||
out->SetBounds = MouseSetBounds;
|
||||
out->Isr = MouseIsr;
|
||||
out->Dpc = MouseDpc;
|
||||
out->IrqNumber = 12;
|
||||
}
|
||||
+69
-40
@@ -1,40 +1,69 @@
|
||||
#pragma once
|
||||
// io_driver.h - driver-side interface for registering disk controllers
|
||||
//
|
||||
// DISK_DRIVER.SubmitIrp is the async path. IRP is forward-declared here so
|
||||
// this header (and hal_disk.c) remain free of kernel sync-object dependencies.
|
||||
// Drivers that implement SubmitIrp include ke_irp.h themselves.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <hal_api.h>
|
||||
#include <ke_status.h>
|
||||
#include <io_file.h>
|
||||
|
||||
typedef KSTATUS (*DRIVER_ENTRY_FN)(const HAL_API* hal);
|
||||
typedef void (*DRIVER_UNLOAD_FN)(void);
|
||||
|
||||
// Forward declaration only - avoids dragging ke_event.h into the HAL layer.
|
||||
struct IRP;
|
||||
|
||||
typedef struct DISK_DRIVER {
|
||||
void *Ctx;
|
||||
|
||||
// --- Synchronous path (always present) ---------------------------------
|
||||
KSTATUS (*ReadSectors) (void *ctx, uint64_t lba, uint32_t count, void *buf);
|
||||
KSTATUS (*WriteSectors)(void *ctx, uint64_t lba, uint32_t count, const void *buf);
|
||||
|
||||
// --- Asynchronous path (optional) --------------------------------------
|
||||
// NULL = driver has not implemented async; IoSubmitIrp() falls back to
|
||||
// the sync path. Returns STATUS_PENDING when the IRP is accepted.
|
||||
KSTATUS (*SubmitIrp)(void *ctx, struct IRP *irp);
|
||||
|
||||
uint64_t SectorCount;
|
||||
} DISK_DRIVER;
|
||||
|
||||
__declspec(dllexport) KSTATUS IoRegisterDisk(uint8_t driveIndex, const DISK_DRIVER *driver);
|
||||
|
||||
// Internal dispatch used by ke_irp.c. Calls SubmitIrp if present, otherwise
|
||||
// runs the sync callbacks inline and writes irp->Status; does NOT touch any
|
||||
// kernel sync objects so it is safe to call from the HAL layer.
|
||||
// Returns STATUS_PENDING (async path taken) or STATUS_SUCCESS (ran inline).
|
||||
__declspec(dllexport) KSTATUS HalDiskDispatch(uint8_t drive, struct IRP *irp);
|
||||
#pragma once
|
||||
// io_driver.h - definitive kernel driver/device I/O model
|
||||
//
|
||||
// Disk controllers register DEVICE_OBJECTs. IRPs are submitted only through
|
||||
// IoCallDriver()/IoSubmitIrp(); drivers complete accepted IRPs by calling
|
||||
// IoCompleteRequest(). There is no legacy DISK_DRIVER submit table.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <ke_status.h>
|
||||
|
||||
typedef struct HAL_API HAL_API;
|
||||
typedef KSTATUS (*DRIVER_ENTRY_FN)(const HAL_API* hal);
|
||||
typedef void (*DRIVER_UNLOAD_FN)(void);
|
||||
|
||||
struct IRP;
|
||||
typedef struct DRIVER_OBJECT DRIVER_OBJECT;
|
||||
typedef struct DEVICE_OBJECT DEVICE_OBJECT;
|
||||
|
||||
typedef enum IO_MAJOR_FUNCTION {
|
||||
IRP_MJ_READ = 0,
|
||||
IRP_MJ_WRITE = 1,
|
||||
IRP_MJ_DEVICE_CONTROL = 2,
|
||||
IRP_MJ_MAXIMUM_FUNCTION = 3,
|
||||
} IO_MAJOR_FUNCTION;
|
||||
|
||||
typedef KSTATUS (*PDRIVER_DISPATCH)(DEVICE_OBJECT* device, struct IRP* irp);
|
||||
|
||||
struct DRIVER_OBJECT {
|
||||
const char* Name;
|
||||
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION];
|
||||
DRIVER_UNLOAD_FN DriverUnload;
|
||||
};
|
||||
|
||||
struct DEVICE_OBJECT {
|
||||
DRIVER_OBJECT* DriverObject;
|
||||
void* DeviceExtension;
|
||||
uint32_t Flags;
|
||||
uint32_t AlignmentRequirement;
|
||||
uint64_t SectorCount;
|
||||
uint8_t DiskIndex;
|
||||
};
|
||||
|
||||
#define DEVICE_OBJECT_DISK 0x00000001u
|
||||
#define DEVICE_OBJECT_REMOVABLE 0x00000002u
|
||||
|
||||
__declspec(dllexport) KSTATUS IoCreateDevice(DRIVER_OBJECT* driver,
|
||||
size_t extensionSize,
|
||||
DEVICE_OBJECT** outDevice);
|
||||
__declspec(dllexport) void IoDeleteDevice(DEVICE_OBJECT* device);
|
||||
|
||||
__declspec(dllexport) KSTATUS IoRegisterDiskDevice(uint8_t driveIndex,
|
||||
DEVICE_OBJECT* device);
|
||||
__declspec(dllexport) DEVICE_OBJECT* IoGetDiskDevice(uint8_t driveIndex);
|
||||
__declspec(dllexport) bool IoDiskDevicePresent(uint8_t driveIndex);
|
||||
__declspec(dllexport) uint64_t IoDiskSectorCount(uint8_t driveIndex);
|
||||
|
||||
__declspec(dllexport) KSTATUS IoCallDriver(DEVICE_OBJECT* device,
|
||||
struct IRP* irp);
|
||||
|
||||
__declspec(dllexport) KSTATUS IoReadDiskSectors(uint8_t driveIndex,
|
||||
uint64_t lba,
|
||||
uint32_t count,
|
||||
void* buffer);
|
||||
__declspec(dllexport) KSTATUS IoWriteDiskSectors(uint8_t driveIndex,
|
||||
uint64_t lba,
|
||||
uint32_t count,
|
||||
const void* buffer);
|
||||
Reference in new issue
Block a user