colonel.exe 🤑, refactor all include directives, AHCI is now interrupt driven, upgrades to IDE, implemented I/O Request Packets, fix numerous keyboard issues, change all for (;;) and while (1) to while (true), DbgPrint guarded by spinlock, fix KeSignalEvent, major KernelMain refactor, added SystemInitThread because of new blocking I/O, replace memcpy manouvers with strncpy and strncat, add: run for ide, runa for ahci, rund for debug and ide, runad for debug and ahci.
This commit is contained in:
1 parent
7f4052f41c
commit
9fa2a7e0db
61 files changed
+1311
-456
No files matched your search
+7
-3
@@ -3,7 +3,7 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "ke_status.h"
|
||||
#include <ke_status.h>
|
||||
|
||||
typedef struct BOOT_INFO BOOT_INFO;
|
||||
|
||||
@@ -21,6 +21,7 @@ typedef struct HAL_KEYBOARD {
|
||||
bool (*Poll)(void);
|
||||
uint8_t (*ReadScancode)(void);
|
||||
char (*ReadChar)(void);
|
||||
uint32_t (*GetModifiers)(void);
|
||||
void (*SetCallback)(void (*cb)(uint8_t scancode));
|
||||
void (*Isr)(void);
|
||||
uint8_t IrqNumber;
|
||||
@@ -43,14 +44,17 @@ typedef struct HAL_TIMER {
|
||||
} HAL_TIMER;
|
||||
|
||||
typedef struct HAL_PCI {
|
||||
uint32_t (*ConfigRead32)(uint8_t bus, uint8_t dev,
|
||||
uint32_t (*Read32)(uint8_t bus, uint8_t dev,
|
||||
uint8_t fn, uint8_t reg);
|
||||
void (*ConfigWrite32)(uint8_t bus, uint8_t dev,
|
||||
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 {
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
// hal_apic.c - Local APIC + I/O APIC
|
||||
#include "hal_apic.h"
|
||||
#include "hal_api.h"
|
||||
#include <hal_apic.h>
|
||||
#include <hal_api.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern HAL_API gApi;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
// hal_debug.h - HAL debug output function
|
||||
// Do not include outside HAL.
|
||||
|
||||
void HalDbgPrint(const char* fmt, ...);
|
||||
+62
-12
@@ -1,15 +1,26 @@
|
||||
// hal_disk.c - drive registry; drivers register themselves via IoRegisterDisk
|
||||
#include "hal_api.h"
|
||||
#include "io_driver.h"
|
||||
// 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];
|
||||
|
||||
KSTATUS IoRegisterDisk(uint8_t index, const DISK_DRIVER* driver) {
|
||||
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;
|
||||
@@ -17,27 +28,66 @@ KSTATUS IoRegisterDisk(uint8_t index, const DISK_DRIVER* driver) {
|
||||
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.
|
||||
|
||||
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) {
|
||||
uint32_t count, void *buf) {
|
||||
if (drive >= MAX_DRIVES || !gPresent[drive]) return STATUS_NOT_FOUND;
|
||||
return gDrives[drive].ReadSectors(lba, count, buf);
|
||||
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) {
|
||||
uint32_t count, const void *buf) {
|
||||
if (drive >= MAX_DRIVES || !gPresent[drive]) return STATUS_NOT_FOUND;
|
||||
return gDrives[drive].WriteSectors(lba, count, buf);
|
||||
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;
|
||||
void HalDiskInitialize(HAL_DISK *out) {
|
||||
out->ReadSectors = DiskRead;
|
||||
out->WriteSectors = DiskWrite;
|
||||
out->DrivePresent = DiskPresent;
|
||||
out->DriveSectorCount = DiskSectorCount;
|
||||
}
|
||||
+260
-33
@@ -1,71 +1,298 @@
|
||||
// hal_keyboard.c - PS/2 keyboard, interrupt-driven, 256-entry ring buffer
|
||||
#include "hal_api.h"
|
||||
#include "hal_apic.h"
|
||||
#include "hal_debug.h"
|
||||
// hal_keyboard.c – PS/2 keyboard, interrupt-driven, 256-entry ring buffer
|
||||
//
|
||||
// Scan-code set 1 (XT-compatible), as output by the 8042's built-in
|
||||
// translation layer. Supports make/break for all standard keys, Shift /
|
||||
// Ctrl / Alt / CapsLock / NumLock modifiers, and the E0-prefixed extended
|
||||
// key set (arrows, Home/End/PgUp/PgDn/Ins/Del, RCtrl, RAlt, numpad-Enter,
|
||||
// numpad-divide).
|
||||
//
|
||||
// Threading model
|
||||
// ---------------
|
||||
// Single-producer (ISR on IRQ 1) / single-consumer ring buffer. All
|
||||
// ISR-written state is declared volatile. On a uniprocessor, volatile
|
||||
// plus the natural atomicity of aligned int reads/writes is sufficient.
|
||||
// On SMP, add acquire/release memory barriers around gHead and gTail.
|
||||
//
|
||||
// Caller responsibilities
|
||||
// -----------------------
|
||||
// 1. Register KbdIsr with your interrupt dispatcher for IRQ 1.
|
||||
// 2. Send the APIC/PIC EOI *after* KbdIsr returns, in the surrounding
|
||||
// wrapper – not inside KbdIsr itself.
|
||||
// 3. Unmask IRQ 1 in the APIC or 8259 before expecting any interrupts.
|
||||
//
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <intrin.h>
|
||||
#include <hal_api.h>
|
||||
#include <hal_apic.h>
|
||||
#include <hal_debug.h>
|
||||
|
||||
#define PS2_DATA 0x60
|
||||
#define PS2_STAT 0x64
|
||||
#define PS2_CMD 0x64
|
||||
// -- Port addresses ------------------------------------------------------------
|
||||
#define PS2_DATA 0x60u
|
||||
#define PS2_STAT 0x64u
|
||||
#define PS2_CMD 0x64u
|
||||
|
||||
#define KBD_BUF_SIZE 256
|
||||
// -- Ring buffer ---------------------------------------------------------------
|
||||
// KBD_BUF_SIZE must be a power of two; KBD_BUF_MASK replaces % with &.
|
||||
#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, gTail = 0;
|
||||
static void (*gCallback)(uint8_t) = (void *)0;
|
||||
static uint8_t gBuf[KBD_BUF_SIZE];
|
||||
static volatile int gHead = 0; // consumer read pointer (updated by reader)
|
||||
static volatile int gTail = 0; // producer write pointer (updated by ISR)
|
||||
|
||||
// Minimal Set-2 to ASCII translation (unshifted only).
|
||||
static const char gScanToAscii[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','.',0,0,0,
|
||||
// -- Scan-code set 1 constants -------------------------------------------------
|
||||
#define SC1_BREAK_BIT 0x80u // OR'd into every break (key-up) scan code
|
||||
#define SC1_MAKE_MASK 0x7Fu // complement of SC1_BREAK_BIT; avoids ~uint cast
|
||||
#define SC1_EXT_PREFIX 0xE0u // one-byte prefix for extended keys
|
||||
|
||||
// -- 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) // toggle, not a held key
|
||||
#define MOD_NUMLOCK (1u << 7) // toggle, not a held key
|
||||
|
||||
#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; // previous byte was 0xE0
|
||||
|
||||
// -- Raw-scancode callback (invoked from ISR context) --------------------------
|
||||
// The pointer must be volatile so the compiler re-reads it on every ISR entry
|
||||
// rather than caching the value seen at startup.
|
||||
static void (* volatile gCallback)(uint8_t) = NULL;
|
||||
|
||||
// -- ASCII translation tables – scan-code set 1, non-extended keys only --------
|
||||
// Index = 7-bit make code (SC1_BREAK_BIT cleared). 0 = no printable glyph.
|
||||
// Numpad digits yield their digit characters; a NumLock-aware wrapper can
|
||||
// substitute cursor-movement codes (e.g. HAL_KEY_HOME) when NumLock is clear.
|
||||
//
|
||||
// Layout verified against the IBM PC/AT scan-code set 1 reference.
|
||||
|
||||
static const char gUnshifted[128] = {
|
||||
/*00*/ 0,
|
||||
/*01*/ 0, // ESC
|
||||
/*02*/ '1','2','3','4','5','6','7','8','9','0','-','=', // 02–0D
|
||||
/*0E*/ '\b',
|
||||
/*0F*/ '\t',
|
||||
/*10*/ 'q','w','e','r','t','y','u','i','o','p','[',']', // 10–1B
|
||||
/*1C*/ '\n',
|
||||
/*1D*/ 0, // Left Ctrl
|
||||
/*1E*/ 'a','s','d','f','g','h','j','k','l',';','\'','`', // 1E–29
|
||||
/*2A*/ 0, // Left Shift
|
||||
/*2B*/ '\\',
|
||||
/*2C*/ 'z','x','c','v','b','n','m',',','.','/', // 2C–35
|
||||
/*36*/ 0, // Right Shift
|
||||
/*37*/ '*', // Numpad * (also PrtSc on some keyboards)
|
||||
/*38*/ 0, // Left Alt
|
||||
/*39*/ ' ',
|
||||
/*3A*/ 0, // Caps Lock
|
||||
/*3B*/ 0,0,0,0,0,0,0,0,0,0, // F1–F10 (3B–44)
|
||||
/*45*/ 0, // Num Lock
|
||||
/*46*/ 0, // Scroll Lock
|
||||
/*47*/ '7','8','9', // Numpad 7–9
|
||||
/*4A*/ '-', // Numpad –
|
||||
/*4B*/ '4','5','6', // Numpad 4–6
|
||||
/*4E*/ '+', // Numpad +
|
||||
/*4F*/ '1','2','3', // Numpad 1–3
|
||||
/*52*/ '0', // Numpad 0
|
||||
/*53*/ '.', // Numpad .
|
||||
/*54*/ 0,0,0,
|
||||
/*57*/ 0, // F11
|
||||
/*58*/ 0, // F12
|
||||
/*59*/ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 59–68
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 69–78
|
||||
0,0,0,0,0,0,0, // 79–7F
|
||||
};
|
||||
|
||||
static const char gShifted[128] = {
|
||||
/*00*/ 0,
|
||||
/*01*/ 0, // ESC
|
||||
/*02*/ '!','@','#','$','%','^','&','*','(',')','_','+', // 02–0D
|
||||
/*0E*/ '\b',
|
||||
/*0F*/ '\t',
|
||||
/*10*/ 'Q','W','E','R','T','Y','U','I','O','P','{','}', // 10–1B
|
||||
/*1C*/ '\n',
|
||||
/*1D*/ 0, // Left Ctrl
|
||||
/*1E*/ 'A','S','D','F','G','H','J','K','L',':','"','~', // 1E–29
|
||||
/*2A*/ 0, // Left Shift
|
||||
/*2B*/ '|',
|
||||
/*2C*/ 'Z','X','C','V','B','N','M','<','>','?', // 2C–35
|
||||
/*36*/ 0, // Right Shift
|
||||
/*37*/ '*',
|
||||
/*38*/ 0, // Left Alt
|
||||
/*39*/ ' ',
|
||||
/*3A*/ 0, // Caps Lock
|
||||
/*3B*/ 0,0,0,0,0,0,0,0,0,0, // F1–F10
|
||||
/*45*/ 0,
|
||||
/*46*/ 0,
|
||||
/*47*/ '7','8','9',
|
||||
/*4A*/ '-',
|
||||
/*4B*/ '4','5','6',
|
||||
/*4E*/ '+',
|
||||
/*4F*/ '1','2','3',
|
||||
/*52*/ '0',
|
||||
/*53*/ '.',
|
||||
/*54*/ 0,0,0,
|
||||
/*57*/ 0, // F11
|
||||
/*58*/ 0, // F12
|
||||
/*59*/ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,
|
||||
};
|
||||
|
||||
// -- Interrupt service routine --------------------------------------------------
|
||||
// Called with interrupts disabled (inside the hardware IRQ handler).
|
||||
// The caller's wrapper must send the APIC/PIC EOI after this returns.
|
||||
static void KbdIsr(void) {
|
||||
uint8_t sc = __inbyte(PS2_DATA);
|
||||
if (sc & 0x80) return; // key-up, ignore
|
||||
int next = (gTail + 1) % KBD_BUF_SIZE;
|
||||
if (next != gHead) {
|
||||
gBuf[gTail] = sc;
|
||||
gTail = next;
|
||||
|
||||
// E0 prefix: the following byte is an extended make/break code.
|
||||
if (sc == SC1_EXT_PREFIX) {
|
||||
gNextExtended = true;
|
||||
return;
|
||||
}
|
||||
if (gCallback) gCallback(sc);
|
||||
|
||||
bool extended = gNextExtended;
|
||||
bool is_break = (sc & SC1_BREAK_BIT) != 0;
|
||||
uint8_t make = sc & SC1_MAKE_MASK;
|
||||
|
||||
gNextExtended = false;
|
||||
|
||||
// -- Update modifier state -------------------------------------------------
|
||||
if (!extended) {
|
||||
switch (make) {
|
||||
case 0x2A: // Left Shift
|
||||
gModifiers = is_break ? (gModifiers & ~MOD_LSHIFT)
|
||||
: (gModifiers | MOD_LSHIFT);
|
||||
return;
|
||||
case 0x36: // Right Shift
|
||||
gModifiers = is_break ? (gModifiers & ~MOD_RSHIFT)
|
||||
: (gModifiers | MOD_RSHIFT);
|
||||
return;
|
||||
case 0x1D: // Left Ctrl
|
||||
gModifiers = is_break ? (gModifiers & ~MOD_LCTRL)
|
||||
: (gModifiers | MOD_LCTRL);
|
||||
return;
|
||||
case 0x38: // Left Alt
|
||||
gModifiers = is_break ? (gModifiers & ~MOD_LALT)
|
||||
: (gModifiers | MOD_LALT);
|
||||
return;
|
||||
case 0x3A: // Caps Lock – toggle on make only
|
||||
if (!is_break) gModifiers ^= MOD_CAPS;
|
||||
return;
|
||||
case 0x45: // Num Lock – toggle on make only
|
||||
if (!is_break) gModifiers ^= MOD_NUMLOCK;
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Extended make codes that map to modifier keys.
|
||||
switch (make) {
|
||||
case 0x1D: // Right Ctrl (E0 1D)
|
||||
gModifiers = is_break ? (gModifiers & ~MOD_RCTRL)
|
||||
: (gModifiers | MOD_RCTRL);
|
||||
return;
|
||||
case 0x38: // Right Alt / AltGr (E0 38)
|
||||
gModifiers = is_break ? (gModifiers & ~MOD_RALT)
|
||||
: (gModifiers | MOD_RALT);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// All other extended keys (arrows, Home/End, etc.) fall through
|
||||
// and are enqueued as make codes for consumer-side interpretation.
|
||||
}
|
||||
|
||||
// -- Discard break codes for non-modifier keys -----------------------------
|
||||
if (is_break) return;
|
||||
|
||||
// -- Enqueue make code; silently drop if buffer is full --------------------
|
||||
int next = (gTail + 1) & (int)KBD_BUF_MASK;
|
||||
if (next != gHead) {
|
||||
gBuf[gTail] = make;
|
||||
gTail = next;
|
||||
}
|
||||
|
||||
// -- Notify optional callback with the raw make code -----------------------
|
||||
// Take a local snapshot so the compiler cannot reorder the NULL check and
|
||||
// the call across a volatile barrier, and to avoid double-fetching.
|
||||
void (*cb)(uint8_t) = (void (*)(uint8_t))gCallback;
|
||||
if (cb) cb(make);
|
||||
}
|
||||
|
||||
// -- Consumer API --------------------------------------------------------------
|
||||
|
||||
static bool KbdPoll(void) {
|
||||
return gHead != gTail;
|
||||
}
|
||||
|
||||
// Blocking read. Spins with PAUSE until a make code is available.
|
||||
// On a preemptive kernel, replace the _mm_pause() loop with a
|
||||
// condition variable or sti/hlt to avoid wasting CPU cycles.
|
||||
static uint8_t KbdReadScancode(void) {
|
||||
while (gHead == gTail) { _mm_pause(); }
|
||||
while (gHead == gTail) {
|
||||
_mm_pause();
|
||||
}
|
||||
uint8_t sc = gBuf[gHead];
|
||||
gHead = (gHead + 1) % KBD_BUF_SIZE;
|
||||
gHead = (gHead + 1) & (int)KBD_BUF_MASK;
|
||||
return sc;
|
||||
}
|
||||
|
||||
// Returns the ASCII character for the next keypress, applying the current
|
||||
// Shift and CapsLock state. Returns 0 for keys with no ASCII mapping
|
||||
// (function keys, arrows, unmodified Ctrl/Alt keys, etc.).
|
||||
//
|
||||
// CapsLock inverts shift only for alphabetic keys (a–z); digit and symbol
|
||||
// keys are always governed solely by the physical Shift state.
|
||||
static char KbdReadChar(void) {
|
||||
uint8_t sc = KbdReadScancode();
|
||||
if (sc < 128) return gScanToAscii[sc];
|
||||
return 0;
|
||||
uint8_t make = KbdReadScancode();
|
||||
if (make >= 128) return 0;
|
||||
|
||||
uint32_t mods = gModifiers; // snapshot; safe outside ISR
|
||||
bool shifted = (mods & MOD_SHIFT) != 0;
|
||||
|
||||
// CapsLock toggles the effective shift for alphabetic keys only.
|
||||
if (mods & MOD_CAPS) {
|
||||
char base = gUnshifted[make];
|
||||
if (base >= 'a' && base <= 'z') {
|
||||
shifted = !shifted;
|
||||
}
|
||||
}
|
||||
|
||||
return shifted ? gShifted[make] : gUnshifted[make];
|
||||
}
|
||||
|
||||
static void KbdSetCallback(void (*cb)(uint8_t sc)) {
|
||||
static void KbdSetCallback(void (*cb)(uint8_t)) {
|
||||
gCallback = cb;
|
||||
}
|
||||
|
||||
// Returns the current modifier bitmask (OR of MOD_* flags above).
|
||||
// Snapshot is taken outside ISR and may lag by at most one interrupt.
|
||||
static uint32_t KbdGetModifiers(void) {
|
||||
return gModifiers;
|
||||
}
|
||||
|
||||
// -- Initializer ---------------------------------------------------------------
|
||||
void HalKeyboardInitialize(HAL_KEYBOARD *out) {
|
||||
// Flush PS/2 output buffer
|
||||
while (__inbyte(PS2_STAT) & 1) __inbyte(PS2_DATA);
|
||||
// Drain any stale bytes sitting in the PS/2 output buffer before
|
||||
// enabling interrupts, so the first ISR call sees a clean state.
|
||||
while (__inbyte(PS2_STAT) & 1) {
|
||||
__inbyte(PS2_DATA);
|
||||
}
|
||||
|
||||
out->Poll = KbdPoll;
|
||||
out->ReadScancode = KbdReadScancode;
|
||||
out->ReadChar = KbdReadChar;
|
||||
out->SetCallback = KbdSetCallback;
|
||||
out->GetModifiers = KbdGetModifiers;
|
||||
out->Isr = KbdIsr;
|
||||
out->IrqNumber = 1;
|
||||
}
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
// hal_main.c - HAL initialisation and HalGetApi
|
||||
#include "hal_api.h"
|
||||
#include "hal_apic.h"
|
||||
#include <hal_api.h>
|
||||
#include <hal_apic.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include "printf.h"
|
||||
#include <printf.h>
|
||||
|
||||
// Declared in other hal_*.c files:
|
||||
void HalScreenInitialize(uintptr_t fb, int w, int h, int stride, HAL_SCREEN* out);
|
||||
@@ -310,7 +310,7 @@ static void HalShutdown(void) {
|
||||
if (gPm1bCntBlk) __outword(gPm1bCntBlk, valB);
|
||||
|
||||
// Firmware should have powered off by now. If it didn't, halt.
|
||||
for (;;) __halt();
|
||||
while (true) __halt();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
+10
-3
@@ -1,6 +1,6 @@
|
||||
// hal_pci.c - PCI configuration space via Mechanism 1 port I/O
|
||||
#include "hal_api.h"
|
||||
#include <stdint.h>
|
||||
#include <hal_api.h>
|
||||
|
||||
#define PCI_CONFIG_ADDR 0xCF8
|
||||
#define PCI_CONFIG_DATA 0xCFC
|
||||
@@ -55,9 +55,16 @@ static bool PciFindClass(uint8_t classCode, uint8_t subclass,
|
||||
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->ConfigRead32 = PciRead32;
|
||||
out->ConfigWrite32 = PciWrite32;
|
||||
out->Read32 = PciRead32;
|
||||
out->Write32 = PciWrite32;
|
||||
out->FindDevice = PciFindDevice;
|
||||
out->FindClass = PciFindClass;
|
||||
out->GetIrqLine = PciGetIrqLine;
|
||||
}
|
||||
@@ -3,10 +3,10 @@
|
||||
// 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 "hal_api.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
#include <hal_api.h>
|
||||
|
||||
static uint32_t* gFb = (uint32_t *)0;
|
||||
static int gWidth = 0;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// hal_timer.c - Local APIC timer, calibrated against PIT channel 2
|
||||
#include "hal_api.h"
|
||||
#include "hal_apic.h"
|
||||
#include "hal_debug.h"
|
||||
// hal_timer.c - Local APIC timer
|
||||
#include <stdint.h>
|
||||
#include <intrin.h>
|
||||
#include <hal_api.h>
|
||||
#include <hal_apic.h>
|
||||
#include <hal_debug.h>
|
||||
|
||||
#define LAPIC_TIMER_LVT 0x320
|
||||
#define LAPIC_TIMER_INIT 0x380
|
||||
|
||||
+30
-7
@@ -1,17 +1,40 @@
|
||||
#pragma once
|
||||
// io_driver.h - driver-side interface for registering disk controllers
|
||||
#include "hal_api.h"
|
||||
#include "ke_status.h"
|
||||
#include "../kernel/io_file.h"
|
||||
// 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 {
|
||||
KSTATUS (*ReadSectors)(uint64_t lba, uint32_t count, void* buf);
|
||||
KSTATUS (*WriteSectors)(uint64_t lba, uint32_t count, const void* buf);
|
||||
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;
|
||||
|
||||
KSTATUS IoRegisterDisk(uint8_t driveIndex, const DISK_DRIVER* driver);
|
||||
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).
|
||||
KSTATUS HalDiskDispatch (uint8_t drive, struct IRP *irp);
|
||||
Reference in new issue
Block a user