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:
1 parent
8c7564d5e1
commit
a37f5b1581
14 files changed
+288
-75
No files matched your search
+17
-3
@@ -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
@@ -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
@@ -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
|
||||
|
||||
Reference in new issue
Block a user