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
+287
-74
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))) {
|
||||
Print(L"Failed to resolve imports. System halted.\n");
|
||||
Print(L"Failed to resolve imports.\n");
|
||||
while(true);
|
||||
}
|
||||
|
||||
@@ -804,6 +804,5 @@ EFI_STATUS EFIAPI UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable
|
||||
KernelMain(bi);
|
||||
|
||||
// Never returns.
|
||||
_disable(); __halt();
|
||||
return EFI_SUCCESS;
|
||||
_disable(); while (true) __halt();
|
||||
}
|
||||
+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
|
||||
|
||||
@@ -32,9 +32,9 @@ __declspec(dllexport) void DbgPrint(const char* fmt, ...) {
|
||||
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, ...) {
|
||||
// We are done, go away
|
||||
// Silence! Stop the world!
|
||||
_disable();
|
||||
|
||||
// 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);
|
||||
va_end(va);
|
||||
|
||||
// Halt it!
|
||||
// Die!
|
||||
while (true) __halt();
|
||||
}
|
||||
|
||||
|
||||
@@ -54,21 +54,13 @@ static const HAL_API* gHal;
|
||||
|
||||
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.
|
||||
// Bumps the refcount on success; caller must ObDereferenceObject when done.
|
||||
// Returns NULL if the handle is invalid or the type does not match.
|
||||
// ---------------------------------------------------------------------------
|
||||
static OBJECT* HandleToObject(uint32_t handle, OBJECT_TYPE expected) {
|
||||
PROCESS* proc = CurrentProcess();
|
||||
PROCESS* proc = KeGetCurrentProcess();
|
||||
if (!proc) return NULL;
|
||||
OBJECT* obj = KeLookupHandle(proc, handle); // bumps refcount
|
||||
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.
|
||||
// ---------------------------------------------------------------------------
|
||||
static KSTATUS AllocHandleForCurrent(OBJECT* obj, uint32_t* handleOut) {
|
||||
PROCESS* proc = CurrentProcess();
|
||||
PROCESS* proc = KeGetCurrentProcess();
|
||||
if (!proc) return STATUS_FAILURE;
|
||||
KSTATUS s = KeAllocateHandle(proc, obj, handleOut);
|
||||
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,
|
||||
uint64_t a3, uint64_t a4, uint64_t a5) {
|
||||
(void)a4; (void)a5;
|
||||
PROCESS* proc = CurrentProcess();
|
||||
PROCESS* proc = KeGetCurrentProcess();
|
||||
if (!proc) return STATUS_FAILURE;
|
||||
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,
|
||||
uint64_t a3, uint64_t a4, uint64_t a5) {
|
||||
(void)a0; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
||||
PROCESS* p = CurrentProcess();
|
||||
PROCESS* p = KeGetCurrentProcess();
|
||||
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,
|
||||
uint64_t a3, uint64_t a4, uint64_t a5) {
|
||||
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
||||
PROCESS* proc = CurrentProcess();
|
||||
PROCESS* proc = KeGetCurrentProcess();
|
||||
if (!proc) return STATUS_FAILURE;
|
||||
KeCloseHandle(proc, (uint32_t)a0);
|
||||
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; }
|
||||
|
||||
// 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; }
|
||||
|
||||
uint32_t handle;
|
||||
|
||||
+9
-5
@@ -113,7 +113,7 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// memcpy manouvers
|
||||
// memcpy maneuvers
|
||||
memcpy(path, "drivers\\", 8);
|
||||
memcpy(path + 8, runtimeKeys[i], len + 1);
|
||||
|
||||
@@ -340,7 +340,10 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
|
||||
//
|
||||
// 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();
|
||||
MmInitializeVirtual(pml4, 4 * 1024 * 1024 /* 4 MB initial pool */);
|
||||
|
||||
@@ -368,11 +371,12 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
|
||||
.RsdpPhysical = bootInfo->RsdpPhysical,
|
||||
.DebugEnabled = bootInfo->DebugEnabled
|
||||
};
|
||||
|
||||
KSTATUS s = HalInitialize(&halParams);
|
||||
if (!KSUCCESS(s)) {
|
||||
_disable();
|
||||
while (true) __halt(); // there's nothing we can do.
|
||||
_disable(); while (true) __halt(); // there's nothing we can do.
|
||||
}
|
||||
|
||||
const HAL_API* hal = HalGetApi();
|
||||
gKmainHal = hal;
|
||||
|
||||
@@ -416,7 +420,7 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
|
||||
|
||||
DbgPrint("KernelMain: Handing over to scheduler...\n");
|
||||
|
||||
// Ignite the system
|
||||
// Ignite the system!
|
||||
_enable();
|
||||
|
||||
// The Idle Loop: The CPU rests here whenever all other threads are waiting on events.
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
// bootloader at PhysicalWindowBase (always 0xFFFF880000000000).
|
||||
//
|
||||
// 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 <ke_spinlock.h>
|
||||
|
||||
@@ -47,7 +44,7 @@ static void PushFrame(PHYSICAL_ADDRESS frame) {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Initialisation
|
||||
// ---------------------------------------------------------------------------
|
||||
void MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) {
|
||||
bool MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) {
|
||||
gPhysBase = physicalWindowBase;
|
||||
|
||||
// --- 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) {
|
||||
while (true) { __halt(); }
|
||||
return false;
|
||||
}
|
||||
|
||||
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.
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <memory_map.h>
|
||||
|
||||
#define PAGE_SIZE 4096ULL
|
||||
@@ -11,7 +12,7 @@
|
||||
typedef uint64_t PHYSICAL_ADDRESS;
|
||||
|
||||
// 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);
|
||||
|
||||
// Allocate / free a single 4 KB frame.
|
||||
|
||||
+64
-5
@@ -21,7 +21,9 @@ typedef int BOOL;
|
||||
|
||||
// File I/O constants
|
||||
#define GENERIC_READ 0x80000000L
|
||||
#define GENERIC_WRITE 0x40000000L
|
||||
#define OPEN_EXISTING 3
|
||||
#define CREATE_ALWAYS 2
|
||||
#define FILE_SHARE_READ 0x00000001
|
||||
#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
|
||||
|
||||
@@ -75,9 +77,9 @@ typedef struct _WIN32_FIND_DATAA {
|
||||
} WIN32_FIND_DATAA;
|
||||
|
||||
BOOL CreateProcessA(const char* lpApp, char* lpCmdLine,
|
||||
void* lpPA, void* lpTA, BOOL bInherit,
|
||||
DWORD dwFlags, void* lpEnv, const char* lpDir,
|
||||
STARTUPINFOA* lpSI, PROCESS_INFORMATION* lpPI);
|
||||
void* lpPA, void* lpTA, BOOL bInherit,
|
||||
DWORD dwFlags, void* lpEnv, const char* lpDir,
|
||||
STARTUPINFOA* lpSI, PROCESS_INFORMATION* lpPI);
|
||||
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMs);
|
||||
BOOL GetExitCodeProcess(HANDLE hProcess, DWORD* lpExitCode);
|
||||
BOOL CloseHandle(HANDLE hObject);
|
||||
@@ -89,10 +91,12 @@ BOOL FindClose(HANDLE hFindFile);
|
||||
BOOL SetCurrentDirectoryA(const char* lpPathName);
|
||||
BOOL DeleteFileA(const char* lpFileName);
|
||||
HANDLE CreateFileA(const char* lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
void* lpSecurityAttributes, DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
|
||||
void* lpSecurityAttributes, DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
|
||||
BOOL ReadFile(HANDLE hFile, void* lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
DWORD* lpNumberOfBytesRead, void* lpOverlapped);
|
||||
BOOL WriteFile(HANDLE hFile, const void* lpBuffer, DWORD nNumberOfBytesToWrite,
|
||||
DWORD* lpNumberOfBytesWritten, void* lpOverlapped);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Global handles
|
||||
@@ -172,6 +176,51 @@ static char* trim(char* s) {
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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() {
|
||||
WIN32_FIND_DATAA fd;
|
||||
HANDLE hFind = FindFirstFileA("*", &fd);
|
||||
@@ -226,6 +275,11 @@ static int runCommand(const char* cmd) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp(cmd, "help") == 0) {
|
||||
cmd_help();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(cmd, "dir") == 0) {
|
||||
cmd_dir();
|
||||
return 0;
|
||||
@@ -256,6 +310,11 @@ static int runCommand(const char* cmd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strncmp(cmd, "write ", 6) == 0) {
|
||||
cmd_write(cmd + 6);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// --- External Process Execution ---
|
||||
STARTUPINFOA si;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
+16
-12
@@ -102,17 +102,17 @@ int main() {
|
||||
|
||||
CloseHandle(h);
|
||||
|
||||
HBINK bink = BinkOpen(buf, BINKFROMMEMORY);
|
||||
if (!bink) {
|
||||
HBINK b = BinkOpen(buf, BINKFROMMEMORY);
|
||||
if (!b) {
|
||||
WriteConsoleA(h, "video: BinkOpen failed: ", 24, 0, 0);
|
||||
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);
|
||||
ExitProcess(1);
|
||||
}
|
||||
|
||||
uint32_t width = bink->Width;
|
||||
uint32_t height = bink->Height;
|
||||
uint32_t width = b->Width;
|
||||
uint32_t height = b->Height;
|
||||
|
||||
uint32_t* fb = HeapAlloc(0, 0, width * height * sizeof(uint32_t));
|
||||
if (!fb) {
|
||||
@@ -131,19 +131,20 @@ int main() {
|
||||
bmi.bmiHeader.biCompression = BI_RGB;
|
||||
|
||||
while (1) {
|
||||
if (BinkWait(bink)) {
|
||||
if (BinkWait(b)) {
|
||||
_mm_pause();
|
||||
continue;
|
||||
}
|
||||
|
||||
BinkDoFrame(bink);
|
||||
BinkDoFrame(b);
|
||||
|
||||
if (BinkShouldSkip(bink)) {
|
||||
BinkNextFrame(bink);
|
||||
if (BinkShouldSkip(b)) {
|
||||
BinkNextFrame(b);
|
||||
BinkDoFrame(b);
|
||||
continue;
|
||||
}
|
||||
|
||||
BinkCopyToBuffer(bink, fb, width * 4, height, 0, 0,
|
||||
BinkCopyToBuffer(b, fb, width * 4, height, 0, 0,
|
||||
BINKSURFACE32);
|
||||
|
||||
// Welcome to the GDI pipeline!
|
||||
@@ -163,10 +164,13 @@ int main() {
|
||||
|
||||
EndPaint((HWND)0, &ps);
|
||||
|
||||
BinkNextFrame(bink);
|
||||
if (b->FrameNum == b->Frames)
|
||||
break;
|
||||
|
||||
BinkNextFrame(b);
|
||||
}
|
||||
|
||||
WriteConsoleA(h, "shell: goodbye\n", 15, 0, 0);
|
||||
|
||||
return 0;
|
||||
ExitProcess(0);
|
||||
}
|
||||
+77
-8
@@ -23,6 +23,7 @@
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <intrin.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Syscall stubs (from syscall.dll, assembled from syscall_stubs.asm)
|
||||
@@ -155,7 +156,7 @@ __declspec(dllexport) void OutputDebugStringA(const char* str) {
|
||||
// Timer
|
||||
// ---------------------------------------------------------------------------
|
||||
__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
|
||||
// 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 {
|
||||
struct { DWORD LowPart; long HighPart; } u;
|
||||
long long QuadPart;
|
||||
} 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) {
|
||||
if (lpFrequency) lpFrequency->QuadPart = QPC_FREQUENCY;
|
||||
if (lpFrequency) lpFrequency->QuadPart = TscFreqGet();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
__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)
|
||||
lpPerformanceCount->QuadPart = (long long)SysGetTick() * 1000LL;
|
||||
lpPerformanceCount->QuadPart = (long long)__rdtsc();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
__declspec(dllexport) void GetSystemTimeAsFileTime(void* lpSystemTimeAsFileTime) {
|
||||
// Return a fixed FILETIME representing 2024-01-01 00:00:00 UTC.
|
||||
// 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;
|
||||
// SysGetTick() units = QUANTUM_MS ms = QUANTUM_MS * 10000 * 100-ns intervals.
|
||||
unsigned long long ft = 133186080000000000ULL
|
||||
+ (unsigned long long)SysGetTick() * 10000ULL;
|
||||
+ SysGetTick() * ((unsigned long long)QUANTUM_MS * 10000ULL);
|
||||
unsigned char* p = (unsigned char*)lpSystemTimeAsFileTime;
|
||||
for (int i = 0; i < 8; i++) p[i] = (unsigned char)(ft >> (i * 8));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user