fix ps/2 mouse init, make Stall more precise, rename CurrentProcess to KeGetCurrentProcess, correct type about maneuvers, add file writing to win32

This commit is contained in:
maksw committed 2026-05-05 10:30:13 +02:00
1 parent 8c7564d5e1
commit a37f5b1581
14 files changed
+288 -75

No files matched your search

+17 -3
View File
@@ -4,6 +4,7 @@
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#include <intrin.h>
#include <printf.h>
// Declared in other hal_*.c files:
@@ -298,9 +299,8 @@ static void WalkAcpi(uintptr_t rsdpPhys) {
// ---------------------------------------------------------------------------
// HalShutdown - ACPI S5 soft power-off. Does not return.
// ---------------------------------------------------------------------------
#include <intrin.h>
static void HalShutdown(void) {
// Silence! Stop the world!
_disable();
// SLP_EN (bit 13) | SLP_TYPx (bits 12:10)
@@ -310,7 +310,7 @@ static void HalShutdown(void) {
if (gPm1aCntBlk) __outword(gPm1aCntBlk, valA);
if (gPm1bCntBlk) __outword(gPm1bCntBlk, valB);
// Firmware should have powered off by now. If it didn't, halt.
// Die!
while (true) __halt();
}
@@ -360,6 +360,20 @@ __declspec(dllexport) KSTATUS HalInitialize(const HAL_INIT_PARAMS* initParams) {
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 use a decaying poll to grab whatever the controller left for us ("Drain and Pray").
for (int i = 0; i < 1000; i++) {
if (__inbyte(0x64) & 0x01) {
__inbyte(0x60); // Consume
i = 0; // Reset timeout if we are still getting data
}
gApi.Timer.Stall(1); // Micro-stalls
}
HalDbgPrint("HAL: initialisation complete.\n");
return STATUS_SUCCESS;
}
+43 -6
View File
@@ -27,6 +27,7 @@
#include <stdbool.h>
#include <intrin.h>
#include <hal_api.h>
#include <hal_debug.h>
// -- PS/2 port addresses -------------------------------------------------------
#define PS2_DATA 0x60u
@@ -74,10 +75,18 @@ static void Ps2WaitInput(void) {
// Wait until the 8042's output buffer has data (bit 0 of status = 1).
static void Ps2WaitOutput(void) {
int timeout = 100000;
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();
@@ -192,27 +201,55 @@ void HalMouseInitialize(HAL_MOUSE* out, int screenW, int screenH) {
gMouseY = screenH / 2;
// -----------------------------------------------------------------
// Step 1: Enable aux interrupts in the 8042 command byte.
// - Bit 1 (0x02): enable auxiliary interrupt (drives IRQ 12).
// - Bit 5 (0x20): disables the aux clock when set; clear it.
// 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).
// Mouse replies: ACK (0xFA), self-test pass (0xAA), ID (0x00).
// -----------------------------------------------------------------
MouseSendByte(0xFFu); // reset
MouseRecvByte(); // 0xFA - ACK
// 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
+44 -9
View File
@@ -20,6 +20,9 @@
extern HAL_API gApi;
static volatile uint32_t* gLapic = NULL;
static uint32_t gApicTicksPerUs = 0;
static uint64_t gHpetTicksPerUs = 0;
static volatile uint64_t* gHpet = NULL;
#define LAPIC_REG(off) (*(volatile uint32_t *)((uint8_t *)gLapic + (off)))
static volatile uint64_t gTicks = 0;
@@ -37,17 +40,41 @@ static void TimerIsr(void) {
static uint64_t QueryTicks(void) { return gTicks; }
static void Stall(uint32_t us) {
uint64_t start = gTicks;
uint64_t ms = (us + 999) / 1000;
// 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;
}
// Spin up to 100ms worth of IO delays waiting for ticks to advance.
// If gTicks doesn't move (interrupts off), fall back to pure IO delay.
uint32_t io_iters = (uint32_t)(ms * 1000);
for (uint32_t i = 0; i < io_iters; i++) {
if ((gTicks - start) >= ms) return; // interrupt-driven path
// 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 QUANTUM_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);
}
// If we exhausted the IO delay loop we've waited long enough anyway.
}
// Returns HPET ticks/second, or 0 if HPET is unavailable.
@@ -62,7 +89,7 @@ static uint64_t HpetInit(uintptr_t hpetPhys) {
if (!periodFs) return 0;
// Enable the HPET main counter (General Configuration, offset 0x10, bit 0)
hpet[2] |= 1; // offset 0x10 / 8 = index 2
hpet[2] |= 1; // offset 0x10 / 8 = index 2
return (uint64_t)1e15 / periodFs; // ticks per second
}
@@ -129,6 +156,14 @@ KSTATUS HalTimerInitialize(uintptr_t lapicPhys, uintptr_t hpetPhys, HAL_TIMER *o
return STATUS_DEVICE_ERROR;
}
gApicTicksPerUs = ticksPerMs / 1000;
if (hpetPhys) {
gHpet = (volatile uint64_t*)gApi.PhysToVirt(hpetPhys);
uint64_t hpetHz = HpetInit(hpetPhys);
gHpetTicksPerUs = hpetHz / 1000000;
}
HalDbgPrint("HAL: APIC timer: %u ticks/ms\n", ticksPerMs);
// Configure LAPIC timer in periodic mode