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
Binary file not shown.
Binary file not shown.
+2
-3
@@ -609,7 +609,7 @@ EFI_STATUS EFIAPI UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (EFI_ERROR(ResolveImports(core[0].physBase, core[1].physBase, core[1].virtBase))) {
|
if (EFI_ERROR(ResolveImports(core[0].physBase, core[1].physBase, core[1].virtBase))) {
|
||||||
Print(L"Failed to resolve imports. System halted.\n");
|
Print(L"Failed to resolve imports.\n");
|
||||||
while(true);
|
while(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -804,6 +804,5 @@ EFI_STATUS EFIAPI UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable
|
|||||||
KernelMain(bi);
|
KernelMain(bi);
|
||||||
|
|
||||||
// Never returns.
|
// Never returns.
|
||||||
_disable(); __halt();
|
_disable(); while (true) __halt();
|
||||||
return EFI_SUCCESS;
|
|
||||||
}
|
}
|
||||||
+17
-3
@@ -4,6 +4,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <intrin.h>
|
||||||
#include <printf.h>
|
#include <printf.h>
|
||||||
|
|
||||||
// Declared in other hal_*.c files:
|
// 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.
|
// HalShutdown - ACPI S5 soft power-off. Does not return.
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
#include <intrin.h>
|
|
||||||
|
|
||||||
static void HalShutdown(void) {
|
static void HalShutdown(void) {
|
||||||
|
// Silence! Stop the world!
|
||||||
_disable();
|
_disable();
|
||||||
|
|
||||||
// SLP_EN (bit 13) | SLP_TYPx (bits 12:10)
|
// SLP_EN (bit 13) | SLP_TYPx (bits 12:10)
|
||||||
@@ -310,7 +310,7 @@ static void HalShutdown(void) {
|
|||||||
if (gPm1aCntBlk) __outword(gPm1aCntBlk, valA);
|
if (gPm1aCntBlk) __outword(gPm1aCntBlk, valA);
|
||||||
if (gPm1bCntBlk) __outword(gPm1bCntBlk, valB);
|
if (gPm1bCntBlk) __outword(gPm1bCntBlk, valB);
|
||||||
|
|
||||||
// Firmware should have powered off by now. If it didn't, halt.
|
// Die!
|
||||||
while (true) __halt();
|
while (true) __halt();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,6 +360,20 @@ __declspec(dllexport) KSTATUS HalInitialize(const HAL_INIT_PARAMS* initParams) {
|
|||||||
gApi.Version = HAL_API_VERSION;
|
gApi.Version = HAL_API_VERSION;
|
||||||
gInitialised = 1;
|
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");
|
HalDbgPrint("HAL: initialisation complete.\n");
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
+43
-6
@@ -27,6 +27,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <intrin.h>
|
#include <intrin.h>
|
||||||
#include <hal_api.h>
|
#include <hal_api.h>
|
||||||
|
#include <hal_debug.h>
|
||||||
|
|
||||||
// -- PS/2 port addresses -------------------------------------------------------
|
// -- PS/2 port addresses -------------------------------------------------------
|
||||||
#define PS2_DATA 0x60u
|
#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).
|
// Wait until the 8042's output buffer has data (bit 0 of status = 1).
|
||||||
static void Ps2WaitOutput(void) {
|
static void Ps2WaitOutput(void) {
|
||||||
int timeout = 100000;
|
int timeout = 5000000;
|
||||||
while (!(__inbyte(PS2_STAT) & 0x01u) && --timeout) { /* spin */ }
|
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.
|
// Route the next write to the auxiliary (mouse) device rather than the keyboard.
|
||||||
static void MouseSendByte(uint8_t byte) {
|
static void MouseSendByte(uint8_t byte) {
|
||||||
Ps2WaitInput();
|
Ps2WaitInput();
|
||||||
@@ -192,27 +201,55 @@ void HalMouseInitialize(HAL_MOUSE* out, int screenW, int screenH) {
|
|||||||
gMouseY = screenH / 2;
|
gMouseY = screenH / 2;
|
||||||
|
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
// Step 1: Enable aux interrupts in the 8042 command byte.
|
// Step 0: Deafen the controller and flush
|
||||||
// - Bit 1 (0x02): enable auxiliary interrupt (drives IRQ 12).
|
// -----------------------------------------------------------------
|
||||||
// - Bit 5 (0x20): disables the aux clock when set; clear it.
|
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();
|
Ps2WaitInput();
|
||||||
__outbyte(PS2_CMD, 0x20u); // read current command byte
|
__outbyte(PS2_CMD, 0x20u); // read current command byte
|
||||||
Ps2WaitOutput();
|
Ps2WaitOutput();
|
||||||
uint8_t cmd = __inbyte(PS2_DATA);
|
uint8_t cmd = __inbyte(PS2_DATA);
|
||||||
|
|
||||||
cmd |= 0x02u; // enable aux interrupt
|
cmd |= 0x02u; // enable aux interrupt
|
||||||
cmd &= ~0x20u; // clear "disable aux clock"
|
cmd &= ~0x20u; // clear "disable aux clock"
|
||||||
|
|
||||||
Ps2WaitInput();
|
Ps2WaitInput();
|
||||||
__outbyte(PS2_CMD, 0x60u); // write command byte
|
__outbyte(PS2_CMD, 0x60u); // write command byte
|
||||||
Ps2WaitInput();
|
Ps2WaitInput();
|
||||||
__outbyte(PS2_DATA, cmd);
|
__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).
|
// Step 2: Reset mouse (0xFF).
|
||||||
// Mouse replies: ACK (0xFA), self-test pass (0xAA), ID (0x00).
|
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
MouseSendByte(0xFFu); // reset
|
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(); // 0xAA - BAT passed
|
||||||
MouseRecvByte(); // 0x00 - device ID
|
MouseRecvByte(); // 0x00 - device ID
|
||||||
|
|
||||||
|
|||||||
+44
-9
@@ -20,6 +20,9 @@
|
|||||||
|
|
||||||
extern HAL_API gApi;
|
extern HAL_API gApi;
|
||||||
static volatile uint32_t* gLapic = NULL;
|
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)))
|
#define LAPIC_REG(off) (*(volatile uint32_t *)((uint8_t *)gLapic + (off)))
|
||||||
|
|
||||||
static volatile uint64_t gTicks = 0;
|
static volatile uint64_t gTicks = 0;
|
||||||
@@ -37,17 +40,41 @@ static void TimerIsr(void) {
|
|||||||
static uint64_t QueryTicks(void) { return gTicks; }
|
static uint64_t QueryTicks(void) { return gTicks; }
|
||||||
|
|
||||||
static void Stall(uint32_t us) {
|
static void Stall(uint32_t us) {
|
||||||
uint64_t start = gTicks;
|
// Priority 1: Use HPET (Highest Precision)
|
||||||
uint64_t ms = (us + 999) / 1000;
|
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.
|
// Priority 2: Use APIC Timer (High Precision, but handles wrap-around)
|
||||||
// If gTicks doesn't move (interrupts off), fall back to pure IO delay.
|
if (gApicTicksPerUs > 0) {
|
||||||
uint32_t io_iters = (uint32_t)(ms * 1000);
|
uint32_t total_ticks = us * gApicTicksPerUs;
|
||||||
for (uint32_t i = 0; i < io_iters; i++) {
|
uint32_t last_val = LAPIC_REG(LAPIC_TIMER_CUR);
|
||||||
if ((gTicks - start) >= ms) return; // interrupt-driven path
|
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);
|
__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.
|
// 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;
|
if (!periodFs) return 0;
|
||||||
|
|
||||||
// Enable the HPET main counter (General Configuration, offset 0x10, bit 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
|
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;
|
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);
|
HalDbgPrint("HAL: APIC timer: %u ticks/ms\n", ticksPerMs);
|
||||||
|
|
||||||
// Configure LAPIC timer in periodic mode
|
// Configure LAPIC timer in periodic mode
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ __declspec(dllexport) void DbgPrint(const char* fmt, ...) {
|
|||||||
KeReleaseSpinlock(&sl, flags);
|
KeReleaseSpinlock(&sl, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
// KePanic - Forces output even if debug was compiled out, then the macro halts.
|
// KePanic
|
||||||
__declspec(dllexport) _Noreturn void KePanic(const char *fmt, ...) {
|
__declspec(dllexport) _Noreturn void KePanic(const char *fmt, ...) {
|
||||||
// We are done, go away
|
// Silence! Stop the world!
|
||||||
_disable();
|
_disable();
|
||||||
|
|
||||||
// Print a bright-red banner so the framebuffer is unmistakable.
|
// Print a bright-red banner so the framebuffer is unmistakable.
|
||||||
@@ -50,7 +50,7 @@ __declspec(dllexport) _Noreturn void KePanic(const char *fmt, ...) {
|
|||||||
vprintf(fmt, va);
|
vprintf(fmt, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
|
|
||||||
// Halt it!
|
// Die!
|
||||||
while (true) __halt();
|
while (true) __halt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,21 +54,13 @@ static const HAL_API* gHal;
|
|||||||
|
|
||||||
void KeSyscallSetHal(const HAL_API* hal) { gHal = hal; }
|
void KeSyscallSetHal(const HAL_API* hal) { gHal = hal; }
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
// Helper: get the current process, or NULL if unavailable.
|
|
||||||
// ---------------------------------------------------------------------------
|
|
||||||
static inline PROCESS* CurrentProcess(void) {
|
|
||||||
THREAD* t = KeGetCurrentThread();
|
|
||||||
return t ? t->Owner : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Helper: look up a handle and type-check it in one call.
|
// Helper: look up a handle and type-check it in one call.
|
||||||
// Bumps the refcount on success; caller must ObDereferenceObject when done.
|
// Bumps the refcount on success; caller must ObDereferenceObject when done.
|
||||||
// Returns NULL if the handle is invalid or the type does not match.
|
// Returns NULL if the handle is invalid or the type does not match.
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
static OBJECT* HandleToObject(uint32_t handle, OBJECT_TYPE expected) {
|
static OBJECT* HandleToObject(uint32_t handle, OBJECT_TYPE expected) {
|
||||||
PROCESS* proc = CurrentProcess();
|
PROCESS* proc = KeGetCurrentProcess();
|
||||||
if (!proc) return NULL;
|
if (!proc) return NULL;
|
||||||
OBJECT* obj = KeLookupHandle(proc, handle); // bumps refcount
|
OBJECT* obj = KeLookupHandle(proc, handle); // bumps refcount
|
||||||
if (!obj) return NULL;
|
if (!obj) return NULL;
|
||||||
@@ -85,7 +77,7 @@ static OBJECT* HandleToObject(uint32_t handle, OBJECT_TYPE expected) {
|
|||||||
// On failure, drops the reference it would have stored.
|
// On failure, drops the reference it would have stored.
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
static KSTATUS AllocHandleForCurrent(OBJECT* obj, uint32_t* handleOut) {
|
static KSTATUS AllocHandleForCurrent(OBJECT* obj, uint32_t* handleOut) {
|
||||||
PROCESS* proc = CurrentProcess();
|
PROCESS* proc = KeGetCurrentProcess();
|
||||||
if (!proc) return STATUS_FAILURE;
|
if (!proc) return STATUS_FAILURE;
|
||||||
KSTATUS s = KeAllocateHandle(proc, obj, handleOut);
|
KSTATUS s = KeAllocateHandle(proc, obj, handleOut);
|
||||||
if (!KSUCCESS(s)) ObDereferenceObject(obj);
|
if (!KSUCCESS(s)) ObDereferenceObject(obj);
|
||||||
@@ -126,7 +118,7 @@ static uint64_t SyscallExitThread(uint64_t a0, uint64_t a1, uint64_t a2,
|
|||||||
static uint64_t SyscallCreateThread(uint64_t a0, uint64_t a1, uint64_t a2,
|
static uint64_t SyscallCreateThread(uint64_t a0, uint64_t a1, uint64_t a2,
|
||||||
uint64_t a3, uint64_t a4, uint64_t a5) {
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
||||||
(void)a4; (void)a5;
|
(void)a4; (void)a5;
|
||||||
PROCESS* proc = CurrentProcess();
|
PROCESS* proc = KeGetCurrentProcess();
|
||||||
if (!proc) return STATUS_FAILURE;
|
if (!proc) return STATUS_FAILURE;
|
||||||
if (a2 >= PriorityCount) return STATUS_INVALID_PARAMETER;
|
if (a2 >= PriorityCount) return STATUS_INVALID_PARAMETER;
|
||||||
|
|
||||||
@@ -154,7 +146,7 @@ static uint64_t SyscallGetCurrentTid(uint64_t a0, uint64_t a1, uint64_t a2,
|
|||||||
static uint64_t SyscallGetCurrentPid(uint64_t a0, uint64_t a1, uint64_t a2,
|
static uint64_t SyscallGetCurrentPid(uint64_t a0, uint64_t a1, uint64_t a2,
|
||||||
uint64_t a3, uint64_t a4, uint64_t a5) {
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
||||||
(void)a0; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
(void)a0; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
||||||
PROCESS* p = CurrentProcess();
|
PROCESS* p = KeGetCurrentProcess();
|
||||||
return p ? p->ProcessId : 0;
|
return p ? p->ProcessId : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,7 +440,7 @@ static uint64_t SyscallQueueRecv(uint64_t a0, uint64_t a1, uint64_t a2,
|
|||||||
static uint64_t SyscallCloseHandle(uint64_t a0, uint64_t a1, uint64_t a2,
|
static uint64_t SyscallCloseHandle(uint64_t a0, uint64_t a1, uint64_t a2,
|
||||||
uint64_t a3, uint64_t a4, uint64_t a5) {
|
uint64_t a3, uint64_t a4, uint64_t a5) {
|
||||||
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
||||||
PROCESS* proc = CurrentProcess();
|
PROCESS* proc = KeGetCurrentProcess();
|
||||||
if (!proc) return STATUS_FAILURE;
|
if (!proc) return STATUS_FAILURE;
|
||||||
KeCloseHandle(proc, (uint32_t)a0);
|
KeCloseHandle(proc, (uint32_t)a0);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
@@ -733,7 +725,7 @@ static uint64_t SyscallCreateProcess(uint64_t a0, uint64_t a1, uint64_t a2,
|
|||||||
if (!KSUCCESS(s)) { ObDereferenceObject(&proc->Header); return s; }
|
if (!KSUCCESS(s)) { ObDereferenceObject(&proc->Header); return s; }
|
||||||
|
|
||||||
// Give the caller a handle to the new process so they can wait on it.
|
// Give the caller a handle to the new process so they can wait on it.
|
||||||
PROCESS* caller = CurrentProcess();
|
PROCESS* caller = KeGetCurrentProcess();
|
||||||
if (!caller) { ObDereferenceObject(&proc->Header); return STATUS_FAILURE; }
|
if (!caller) { ObDereferenceObject(&proc->Header); return STATUS_FAILURE; }
|
||||||
|
|
||||||
uint32_t handle;
|
uint32_t handle;
|
||||||
|
|||||||
+10
-6
@@ -113,7 +113,7 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// memcpy manouvers
|
// memcpy maneuvers
|
||||||
memcpy(path, "drivers\\", 8);
|
memcpy(path, "drivers\\", 8);
|
||||||
memcpy(path + 8, runtimeKeys[i], len + 1);
|
memcpy(path + 8, runtimeKeys[i], len + 1);
|
||||||
|
|
||||||
@@ -329,7 +329,7 @@ void SystemInitThread(void* arg) {
|
|||||||
DbgPrint("SystemInitThread: Failed to create watcher thread (%d) -- leaking proc ref.\n", ws);
|
DbgPrint("SystemInitThread: Failed to create watcher thread (%d) -- leaking proc ref.\n", ws);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MmFreePool(args);
|
MmFreePool(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +340,10 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
|
|||||||
//
|
//
|
||||||
// Physical & Virtual Memory initialization
|
// Physical & Virtual Memory initialization
|
||||||
//
|
//
|
||||||
MmInitializePhysical(&bootInfo->MemoryMap, bootInfo->PhysicalMapBase);
|
if (!MmInitializePhysical(&bootInfo->MemoryMap, bootInfo->PhysicalMapBase)) {
|
||||||
|
_disable(); while (true) __halt(); // there's nothing we can do
|
||||||
|
}
|
||||||
|
|
||||||
PHYSICAL_ADDRESS pml4 = (PHYSICAL_ADDRESS)__readcr3();
|
PHYSICAL_ADDRESS pml4 = (PHYSICAL_ADDRESS)__readcr3();
|
||||||
MmInitializeVirtual(pml4, 4 * 1024 * 1024 /* 4 MB initial pool */);
|
MmInitializeVirtual(pml4, 4 * 1024 * 1024 /* 4 MB initial pool */);
|
||||||
|
|
||||||
@@ -368,11 +371,12 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
|
|||||||
.RsdpPhysical = bootInfo->RsdpPhysical,
|
.RsdpPhysical = bootInfo->RsdpPhysical,
|
||||||
.DebugEnabled = bootInfo->DebugEnabled
|
.DebugEnabled = bootInfo->DebugEnabled
|
||||||
};
|
};
|
||||||
|
|
||||||
KSTATUS s = HalInitialize(&halParams);
|
KSTATUS s = HalInitialize(&halParams);
|
||||||
if (!KSUCCESS(s)) {
|
if (!KSUCCESS(s)) {
|
||||||
_disable();
|
_disable(); while (true) __halt(); // there's nothing we can do.
|
||||||
while (true) __halt(); // there's nothing we can do.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const HAL_API* hal = HalGetApi();
|
const HAL_API* hal = HalGetApi();
|
||||||
gKmainHal = hal;
|
gKmainHal = hal;
|
||||||
|
|
||||||
@@ -416,7 +420,7 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
|
|||||||
|
|
||||||
DbgPrint("KernelMain: Handing over to scheduler...\n");
|
DbgPrint("KernelMain: Handing over to scheduler...\n");
|
||||||
|
|
||||||
// Ignite the system
|
// Ignite the system!
|
||||||
_enable();
|
_enable();
|
||||||
|
|
||||||
// The Idle Loop: The CPU rests here whenever all other threads are waiting on events.
|
// The Idle Loop: The CPU rests here whenever all other threads are waiting on events.
|
||||||
|
|||||||
@@ -6,9 +6,6 @@
|
|||||||
// bootloader at PhysicalWindowBase (always 0xFFFF880000000000).
|
// bootloader at PhysicalWindowBase (always 0xFFFF880000000000).
|
||||||
//
|
//
|
||||||
// Lock: a single spinlock guards Push/Pop. O(1) for both operations.
|
// Lock: a single spinlock guards Push/Pop. O(1) for both operations.
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <mm_phys.h>
|
#include <mm_phys.h>
|
||||||
#include <ke_spinlock.h>
|
#include <ke_spinlock.h>
|
||||||
|
|
||||||
@@ -47,7 +44,7 @@ static void PushFrame(PHYSICAL_ADDRESS frame) {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Initialisation
|
// Initialisation
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
void MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) {
|
bool MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) {
|
||||||
gPhysBase = physicalWindowBase;
|
gPhysBase = physicalWindowBase;
|
||||||
|
|
||||||
// --- Phase 0: Count total usable frames so we can size the stack
|
// --- Phase 0: Count total usable frames so we can size the stack
|
||||||
@@ -71,7 +68,7 @@ void MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!stackPhys) {
|
if (!stackPhys) {
|
||||||
while (true) { __halt(); }
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
gFrameStack.Stack = (PHYSICAL_ADDRESS *)PhysToVirt(stackPhys);
|
gFrameStack.Stack = (PHYSICAL_ADDRESS *)PhysToVirt(stackPhys);
|
||||||
@@ -99,6 +96,8 @@ void MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
// Stack allocator over 4 KB frames, seeded from MEMORY_MAP.
|
// Stack allocator over 4 KB frames, seeded from MEMORY_MAP.
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <memory_map.h>
|
#include <memory_map.h>
|
||||||
|
|
||||||
#define PAGE_SIZE 4096ULL
|
#define PAGE_SIZE 4096ULL
|
||||||
@@ -11,7 +12,7 @@
|
|||||||
typedef uint64_t PHYSICAL_ADDRESS;
|
typedef uint64_t PHYSICAL_ADDRESS;
|
||||||
|
|
||||||
// Called once by KernelMain with the MEMORY_MAP from BOOT_INFO.
|
// Called once by KernelMain with the MEMORY_MAP from BOOT_INFO.
|
||||||
void MmInitializePhysical(const MEMORY_MAP* map,
|
bool MmInitializePhysical(const MEMORY_MAP* map,
|
||||||
uint64_t physicalWindowBase);
|
uint64_t physicalWindowBase);
|
||||||
|
|
||||||
// Allocate / free a single 4 KB frame.
|
// Allocate / free a single 4 KB frame.
|
||||||
|
|||||||
+64
-5
@@ -21,7 +21,9 @@ typedef int BOOL;
|
|||||||
|
|
||||||
// File I/O constants
|
// File I/O constants
|
||||||
#define GENERIC_READ 0x80000000L
|
#define GENERIC_READ 0x80000000L
|
||||||
|
#define GENERIC_WRITE 0x40000000L
|
||||||
#define OPEN_EXISTING 3
|
#define OPEN_EXISTING 3
|
||||||
|
#define CREATE_ALWAYS 2
|
||||||
#define FILE_SHARE_READ 0x00000001
|
#define FILE_SHARE_READ 0x00000001
|
||||||
#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
|
#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
|
||||||
|
|
||||||
@@ -75,9 +77,9 @@ typedef struct _WIN32_FIND_DATAA {
|
|||||||
} WIN32_FIND_DATAA;
|
} WIN32_FIND_DATAA;
|
||||||
|
|
||||||
BOOL CreateProcessA(const char* lpApp, char* lpCmdLine,
|
BOOL CreateProcessA(const char* lpApp, char* lpCmdLine,
|
||||||
void* lpPA, void* lpTA, BOOL bInherit,
|
void* lpPA, void* lpTA, BOOL bInherit,
|
||||||
DWORD dwFlags, void* lpEnv, const char* lpDir,
|
DWORD dwFlags, void* lpEnv, const char* lpDir,
|
||||||
STARTUPINFOA* lpSI, PROCESS_INFORMATION* lpPI);
|
STARTUPINFOA* lpSI, PROCESS_INFORMATION* lpPI);
|
||||||
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMs);
|
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMs);
|
||||||
BOOL GetExitCodeProcess(HANDLE hProcess, DWORD* lpExitCode);
|
BOOL GetExitCodeProcess(HANDLE hProcess, DWORD* lpExitCode);
|
||||||
BOOL CloseHandle(HANDLE hObject);
|
BOOL CloseHandle(HANDLE hObject);
|
||||||
@@ -89,10 +91,12 @@ BOOL FindClose(HANDLE hFindFile);
|
|||||||
BOOL SetCurrentDirectoryA(const char* lpPathName);
|
BOOL SetCurrentDirectoryA(const char* lpPathName);
|
||||||
BOOL DeleteFileA(const char* lpFileName);
|
BOOL DeleteFileA(const char* lpFileName);
|
||||||
HANDLE CreateFileA(const char* lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
HANDLE CreateFileA(const char* lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||||
void* lpSecurityAttributes, DWORD dwCreationDisposition,
|
void* lpSecurityAttributes, DWORD dwCreationDisposition,
|
||||||
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
|
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
|
||||||
BOOL ReadFile(HANDLE hFile, void* lpBuffer, DWORD nNumberOfBytesToRead,
|
BOOL ReadFile(HANDLE hFile, void* lpBuffer, DWORD nNumberOfBytesToRead,
|
||||||
DWORD* lpNumberOfBytesRead, void* lpOverlapped);
|
DWORD* lpNumberOfBytesRead, void* lpOverlapped);
|
||||||
|
BOOL WriteFile(HANDLE hFile, const void* lpBuffer, DWORD nNumberOfBytesToWrite,
|
||||||
|
DWORD* lpNumberOfBytesWritten, void* lpOverlapped);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Global handles
|
// Global handles
|
||||||
@@ -172,6 +176,51 @@ static char* trim(char* s) {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Built-in commands
|
// Built-in commands
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
static void cmd_help() {
|
||||||
|
print("Available commands:\n"
|
||||||
|
" help - Show this list\n"
|
||||||
|
" dir - List files in current directory\n"
|
||||||
|
" cd <path> - Change directory\n"
|
||||||
|
" type <file> - Display file contents\n"
|
||||||
|
" del <file> - Delete a file\n"
|
||||||
|
" write <file> <tx> - Create a file with text\n"
|
||||||
|
" exit - Close the shell\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void cmd_write(const char* args) {
|
||||||
|
char filename[MAX_PATH];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
// Parse filename (up to first space)
|
||||||
|
while (args[i] != ' ' && args[i] != '\0' && i < MAX_PATH - 1) {
|
||||||
|
filename[i] = args[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
filename[i] = '\0';
|
||||||
|
|
||||||
|
if (args[i] == '\0' || args[i+1] == '\0') {
|
||||||
|
print("write: usage: write <filename> <text>\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* text = args + i + 1; // Content starts after the space
|
||||||
|
|
||||||
|
HANDLE hFile = CreateFileA(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
|
||||||
|
if (hFile == INVALID_HANDLE_VALUE) {
|
||||||
|
print("write: could not create file\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD written;
|
||||||
|
if (!WriteFile(hFile, text, (DWORD)strlen(text), &written, 0)) {
|
||||||
|
print("write: error writing to file\n");
|
||||||
|
} else {
|
||||||
|
print("File written successfully.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(hFile);
|
||||||
|
}
|
||||||
|
|
||||||
static void cmd_dir() {
|
static void cmd_dir() {
|
||||||
WIN32_FIND_DATAA fd;
|
WIN32_FIND_DATAA fd;
|
||||||
HANDLE hFind = FindFirstFileA("*", &fd);
|
HANDLE hFind = FindFirstFileA("*", &fd);
|
||||||
@@ -226,6 +275,11 @@ static int runCommand(const char* cmd) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strcmp(cmd, "help") == 0) {
|
||||||
|
cmd_help();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (strcmp(cmd, "dir") == 0) {
|
if (strcmp(cmd, "dir") == 0) {
|
||||||
cmd_dir();
|
cmd_dir();
|
||||||
return 0;
|
return 0;
|
||||||
@@ -256,6 +310,11 @@ static int runCommand(const char* cmd) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strncmp(cmd, "write ", 6) == 0) {
|
||||||
|
cmd_write(cmd + 6);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// --- External Process Execution ---
|
// --- External Process Execution ---
|
||||||
STARTUPINFOA si;
|
STARTUPINFOA si;
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
|
|||||||
+16
-12
@@ -102,17 +102,17 @@ int main() {
|
|||||||
|
|
||||||
CloseHandle(h);
|
CloseHandle(h);
|
||||||
|
|
||||||
HBINK bink = BinkOpen(buf, BINKFROMMEMORY);
|
HBINK b = BinkOpen(buf, BINKFROMMEMORY);
|
||||||
if (!bink) {
|
if (!b) {
|
||||||
WriteConsoleA(h, "video: BinkOpen failed: ", 24, 0, 0);
|
WriteConsoleA(h, "video: BinkOpen failed: ", 24, 0, 0);
|
||||||
const char* err = BinkGetError();
|
const char* err = BinkGetError();
|
||||||
WriteConsoleA(h, err, strlen(err), 0, 0);
|
WriteConsoleA(h, err, (unsigned int)strlen(err), 0, 0);
|
||||||
WriteConsoleA(h, "\n", 1, 0, 0);
|
WriteConsoleA(h, "\n", 1, 0, 0);
|
||||||
ExitProcess(1);
|
ExitProcess(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t width = bink->Width;
|
uint32_t width = b->Width;
|
||||||
uint32_t height = bink->Height;
|
uint32_t height = b->Height;
|
||||||
|
|
||||||
uint32_t* fb = HeapAlloc(0, 0, width * height * sizeof(uint32_t));
|
uint32_t* fb = HeapAlloc(0, 0, width * height * sizeof(uint32_t));
|
||||||
if (!fb) {
|
if (!fb) {
|
||||||
@@ -131,19 +131,20 @@ int main() {
|
|||||||
bmi.bmiHeader.biCompression = BI_RGB;
|
bmi.bmiHeader.biCompression = BI_RGB;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (BinkWait(bink)) {
|
if (BinkWait(b)) {
|
||||||
_mm_pause();
|
_mm_pause();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
BinkDoFrame(bink);
|
BinkDoFrame(b);
|
||||||
|
|
||||||
if (BinkShouldSkip(bink)) {
|
if (BinkShouldSkip(b)) {
|
||||||
BinkNextFrame(bink);
|
BinkNextFrame(b);
|
||||||
|
BinkDoFrame(b);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
BinkCopyToBuffer(bink, fb, width * 4, height, 0, 0,
|
BinkCopyToBuffer(b, fb, width * 4, height, 0, 0,
|
||||||
BINKSURFACE32);
|
BINKSURFACE32);
|
||||||
|
|
||||||
// Welcome to the GDI pipeline!
|
// Welcome to the GDI pipeline!
|
||||||
@@ -163,10 +164,13 @@ int main() {
|
|||||||
|
|
||||||
EndPaint((HWND)0, &ps);
|
EndPaint((HWND)0, &ps);
|
||||||
|
|
||||||
BinkNextFrame(bink);
|
if (b->FrameNum == b->Frames)
|
||||||
|
break;
|
||||||
|
|
||||||
|
BinkNextFrame(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteConsoleA(h, "shell: goodbye\n", 15, 0, 0);
|
WriteConsoleA(h, "shell: goodbye\n", 15, 0, 0);
|
||||||
|
|
||||||
return 0;
|
ExitProcess(0);
|
||||||
}
|
}
|
||||||
+77
-8
@@ -23,6 +23,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <intrin.h>
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Syscall stubs (from syscall.dll, assembled from syscall_stubs.asm)
|
// Syscall stubs (from syscall.dll, assembled from syscall_stubs.asm)
|
||||||
@@ -155,7 +156,7 @@ __declspec(dllexport) void OutputDebugStringA(const char* str) {
|
|||||||
// Timer
|
// Timer
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
__declspec(dllexport) DWORD GetTickCount(void) {
|
__declspec(dllexport) DWORD GetTickCount(void) {
|
||||||
return (DWORD)SysGetTick();
|
return (DWORD)SysGetTick() * 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@@ -1041,35 +1042,103 @@ __declspec(dllexport) void WakeAllConditionVariable(CONDITION_VARIABLE* cv) { (v
|
|||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Timing & Performance Counters
|
// Timing & Performance Counters
|
||||||
// We report a 1 MHz counter so QPC / QPF is consistent with GetTickCount.
|
//
|
||||||
|
// We use the CPU's Time Stamp Counter (TSC) for QueryPerformanceCounter so
|
||||||
|
// that callers like Bink get a truly high-resolution, continuously-advancing
|
||||||
|
// clock. The TSC frequency is measured once on first use.
|
||||||
|
//
|
||||||
|
// Calibration strategy:
|
||||||
|
// 1. Try CPUID leaf 0x15 (TSC / Crystal-clock ratio). If the crystal
|
||||||
|
// frequency (ECX) is non-zero, compute TSC Hz = crystal_hz * EBX / EAX
|
||||||
|
// with no blocking at all.
|
||||||
|
// 2. Otherwise fall back to measuring TSC ticks over a known wall-clock
|
||||||
|
// interval supplied by SysGetTick(). SysGetTick() returns raw LAPIC
|
||||||
|
// interrupt counts; each unit represents QUANTUM_MS = 10 ms. We wait
|
||||||
|
// for two consecutive tick-boundary crossings and divide.
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define QUANTUM_MS 10 // must match hal_timer.c QUANTUM_MS
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
struct { DWORD LowPart; long HighPart; } u;
|
struct { DWORD LowPart; long HighPart; } u;
|
||||||
long long QuadPart;
|
long long QuadPart;
|
||||||
} LARGE_INTEGER;
|
} LARGE_INTEGER;
|
||||||
|
|
||||||
#define QPC_FREQUENCY 1000000LL // 1 MHz
|
static volatile long long gTscFreq = 0; // TSC ticks per second; 0 = uninitialised
|
||||||
|
|
||||||
|
// Attempt to read TSC frequency from CPUID leaf 0x15.
|
||||||
|
// Returns 0 if the leaf is absent or the crystal frequency is not enumerated.
|
||||||
|
static long long TscFreqFromCpuid(void) {
|
||||||
|
int info[4];
|
||||||
|
__cpuid(info, 0);
|
||||||
|
if ((unsigned)info[0] < 0x15) return 0;
|
||||||
|
|
||||||
|
__cpuid(info, 0x15);
|
||||||
|
unsigned denom = (unsigned)info[0]; // EAX – TSC/crystal denominator
|
||||||
|
unsigned numer = (unsigned)info[1]; // EBX – TSC/crystal numerator
|
||||||
|
unsigned crystal_hz = (unsigned)info[2]; // ECX – crystal clock in Hz
|
||||||
|
|
||||||
|
if (!denom || !numer || !crystal_hz) return 0;
|
||||||
|
return (long long)crystal_hz * numer / denom;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calibrate TSC frequency by timing over two LAPIC-tick boundaries.
|
||||||
|
// Each SysGetTick() unit = QUANTUM_MS ms; we measure across N_TICKS units
|
||||||
|
// for a total gate time of N_TICKS * QUANTUM_MS ms.
|
||||||
|
static long long TscFreqCalibrate(void) {
|
||||||
|
const uint64_t N_TICKS = 10; // 10 * 10 ms = 100 ms gate time
|
||||||
|
|
||||||
|
// Synchronise to the leading edge of a tick.
|
||||||
|
uint64_t t = SysGetTick();
|
||||||
|
while (SysGetTick() == t) { _mm_pause(); }
|
||||||
|
|
||||||
|
uint64_t tsc0 = __rdtsc();
|
||||||
|
uint64_t t0 = SysGetTick();
|
||||||
|
|
||||||
|
// Wait for N_TICKS more ticks.
|
||||||
|
while ((SysGetTick() - t0) < N_TICKS) { _mm_pause(); }
|
||||||
|
|
||||||
|
uint64_t tsc1 = __rdtsc();
|
||||||
|
uint64_t ticks_got = SysGetTick() - t0; // actual ticks elapsed (>= N_TICKS)
|
||||||
|
|
||||||
|
// ticks_got LAPIC ticks = ticks_got * QUANTUM_MS ms = ticks_got * QUANTUM_MS / 1000 s
|
||||||
|
// TSC Hz = (tsc1-tsc0) / (ticks_got * QUANTUM_MS / 1000)
|
||||||
|
// = (tsc1-tsc0) * 1000 / (ticks_got * QUANTUM_MS)
|
||||||
|
return (long long)((tsc1 - tsc0) * 1000ULL / (ticks_got * (uint64_t)QUANTUM_MS));
|
||||||
|
}
|
||||||
|
|
||||||
|
static long long TscFreqGet(void) {
|
||||||
|
if (gTscFreq) return gTscFreq;
|
||||||
|
|
||||||
|
long long f = TscFreqFromCpuid();
|
||||||
|
if (!f) f = TscFreqCalibrate();
|
||||||
|
|
||||||
|
gTscFreq = f;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
__declspec(dllexport) BOOL QueryPerformanceFrequency(LARGE_INTEGER* lpFrequency) {
|
__declspec(dllexport) BOOL QueryPerformanceFrequency(LARGE_INTEGER* lpFrequency) {
|
||||||
if (lpFrequency) lpFrequency->QuadPart = QPC_FREQUENCY;
|
if (lpFrequency) lpFrequency->QuadPart = TscFreqGet();
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
__declspec(dllexport) BOOL QueryPerformanceCounter(LARGE_INTEGER* lpPerformanceCount) {
|
__declspec(dllexport) BOOL QueryPerformanceCounter(LARGE_INTEGER* lpPerformanceCount) {
|
||||||
// SysGetTick returns milliseconds; scale to microseconds for 1 MHz QPC.
|
// Ensure frequency is measured before the first counter read so that the
|
||||||
|
// baseline TSC and the frequency come from the same calibration window.
|
||||||
|
TscFreqGet();
|
||||||
if (lpPerformanceCount)
|
if (lpPerformanceCount)
|
||||||
lpPerformanceCount->QuadPart = (long long)SysGetTick() * 1000LL;
|
lpPerformanceCount->QuadPart = (long long)__rdtsc();
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
__declspec(dllexport) void GetSystemTimeAsFileTime(void* lpSystemTimeAsFileTime) {
|
__declspec(dllexport) void GetSystemTimeAsFileTime(void* lpSystemTimeAsFileTime) {
|
||||||
// Return a fixed FILETIME representing 2024-01-01 00:00:00 UTC.
|
// Return a fixed FILETIME representing 2024-01-01 00:00:00 UTC.
|
||||||
// FILETIME = 100-nanosecond intervals since 1601-01-01.
|
// FILETIME = 100-nanosecond intervals since 1601-01-01.
|
||||||
// 2024-01-01 offset from 1601 in 100ns units: 133186080000000000
|
// 2024-01-01 offset: 133186080000000000 * 100 ns
|
||||||
if (!lpSystemTimeAsFileTime) return;
|
if (!lpSystemTimeAsFileTime) return;
|
||||||
|
// SysGetTick() units = QUANTUM_MS ms = QUANTUM_MS * 10000 * 100-ns intervals.
|
||||||
unsigned long long ft = 133186080000000000ULL
|
unsigned long long ft = 133186080000000000ULL
|
||||||
+ (unsigned long long)SysGetTick() * 10000ULL;
|
+ SysGetTick() * ((unsigned long long)QUANTUM_MS * 10000ULL);
|
||||||
unsigned char* p = (unsigned char*)lpSystemTimeAsFileTime;
|
unsigned char* p = (unsigned char*)lpSystemTimeAsFileTime;
|
||||||
for (int i = 0; i < 8; i++) p[i] = (unsigned char)(ft >> (i * 8));
|
for (int i = 0; i < 8; i++) p[i] = (unsigned char)(ft >> (i * 8));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user