add mouse and cursor

This commit is contained in:
maksw committed 2026-05-04 09:17:00 +02:00
1 parent cbb9ff469c
commit a5f0acfac8
10 files changed
+406 -35

No files matched your search

Binary file not shown.
+2 -2
View File
@@ -1,5 +1,5 @@
#pragma once
// font8x16.h - embedded 8x16 VGA bitmap font, printable ASCII (0x20–0x7E)
// font8x16.h - embedded 8x16 VGA bitmap font, printable ASCII (0x20-0x7E)
// 95 glyphs × 16 bytes = 1520 bytes total.
// Each byte is one scanline; bit 7 = leftmost pixel.
#include <stdint.h>
@@ -135,7 +135,7 @@ static const uint8_t Font8x16[95 * 16] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x60 '`'
0x0C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x61–0x7A lowercase - condensed to save space, using same shapes as upper offset by 32
// 0x61-0x7A lowercase - condensed to save space, using same shapes as upper offset by 32
// 0x61 'a'
0x00,0x00,0x00,0x1C,0x30,0x3C,0x33,0x33,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x62 'b'
+25
View File
@@ -15,6 +15,9 @@ typedef struct HAL_SCREEN {
void (*Scroll)(int lines);
void (*PutChar)(char c, int x, int y, uint32_t fg, uint32_t bg);
void (*PrintChar)(char c, uint32_t fg, uint32_t bg);
// Hardware mouse cursor: save/restore background and blit sprite
void (*DrawCursor)(int x, int y);
void (*EraseCursor)(void);
} HAL_SCREEN;
typedef struct HAL_KEYBOARD {
@@ -27,6 +30,27 @@ typedef struct HAL_KEYBOARD {
uint8_t IrqNumber;
} HAL_KEYBOARD;
// HAL_MOUSE – PS/2 auxiliary mouse on IRQ 12.
// Packet format: standard 3-byte PS/2 (buttons, deltaX, deltaY).
// Y is already screen-oriented (positive = down) after ISR inversion.
typedef struct HAL_MOUSE {
// Non-blocking: returns true if a packet is waiting in the ring buffer.
bool (*Poll)(void);
// Non-blocking dequeue. Returns false when buffer is empty.
// buttons: bit0=left, bit1=right, bit2=middle
bool (*Read)(int* dx, int* dy, uint8_t* buttons);
// Callback invoked from ISR context after every completed packet.
void (*SetCallback)(void (*cb)(int dx, int dy, uint8_t buttons));
// Absolute cursor position, clamped to screen bounds.
void (*GetPosition)(int* x, int* y);
void (*SetPosition)(int x, int y);
// Update the clamping rectangle (call after mode change / resize).
void (*SetBounds)(int w, int h);
// Raw ISR – called by KeIrqDispatch for IRQ 12.
void (*Isr)(void);
uint8_t IrqNumber; // always 12
} HAL_MOUSE;
typedef struct HAL_DISK {
KSTATUS (*ReadSectors)(uint8_t drive, uint64_t lba,
uint32_t count, void* buf);
@@ -75,6 +99,7 @@ typedef struct HAL_API {
void *(*PhysToVirt)(uint64_t physAddr);
HAL_SCREEN Screen;
HAL_KEYBOARD Keyboard;
HAL_MOUSE Mouse;
HAL_DISK Disk;
HAL_TIMER Timer;
HAL_PCI Pci;
+28 -23
View File
@@ -1,4 +1,4 @@
// hal_keyboard.c – PS/2 keyboard, interrupt-driven, 256-entry ring buffer
// 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 /
@@ -17,7 +17,7 @@
// -----------------------
// 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.
// wrapper - not inside KbdIsr itself.
// 3. Unmask IRQ 1 in the APIC or 8259 before expecting any interrupts.
//
#include <stdint.h>
@@ -68,7 +68,7 @@ static volatile bool gNextExtended = false; // previous byte was 0xE0
// 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 --------
// -- 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.
@@ -78,58 +78,58 @@ static void (* volatile gCallback)(uint8_t) = NULL;
static const char gUnshifted[128] = {
/*00*/ 0,
/*01*/ 0, // ESC
/*02*/ '1','2','3','4','5','6','7','8','9','0','-','=', // 02–0D
/*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
/*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
/*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
/*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)
/*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
/*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
/*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
/*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
/*02*/ '!','@','#','$','%','^','&','*','(',')','_','+', // 02-0D
/*0E*/ '\b',
/*0F*/ '\t',
/*10*/ 'Q','W','E','R','T','Y','U','I','O','P','{','}', // 10–1B
/*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
/*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
/*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
/*3B*/ 0,0,0,0,0,0,0,0,0,0, // F1-F10
/*45*/ 0,
/*46*/ 0,
/*47*/ '7','8','9',
@@ -184,10 +184,10 @@ static void KbdIsr(void) {
gModifiers = is_break ? (gModifiers & ~MOD_LALT)
: (gModifiers | MOD_LALT);
return;
case 0x3A: // Caps Lock – toggle on make only
case 0x3A: // Caps Lock - toggle on make only
if (!is_break) gModifiers ^= MOD_CAPS;
return;
case 0x45: // Num Lock – toggle on make only
case 0x45: // Num Lock - toggle on make only
if (!is_break) gModifiers ^= MOD_NUMLOCK;
return;
default:
@@ -250,7 +250,7 @@ static uint8_t KbdReadScancode(void) {
// 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
// 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 make = KbdReadScancode();
@@ -282,6 +282,11 @@ static uint32_t KbdGetModifiers(void) {
// -- Initializer ---------------------------------------------------------------
void HalKeyboardInitialize(HAL_KEYBOARD *out) {
// Enable PS/2 auxiliary port so the mouse driver can claim IRQ 12.
// The 8042 must have an empty input buffer before we can issue commands.
while (__inbyte(PS2_STAT) & 2) { /* wait for input buffer empty */ }
__outbyte(PS2_CMD, 0xA8); // enable aux port
// 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) {
+4
View File
@@ -9,6 +9,7 @@
// Declared in other hal_*.c files:
void HalScreenInitialize(uintptr_t fb, int w, int h, int stride, HAL_SCREEN* out);
void HalKeyboardInitialize(HAL_KEYBOARD* out);
void HalMouseInitialize(HAL_MOUSE* out, int screenW, int screenH);
KSTATUS HalTimerInitialize(uintptr_t lapicPhys, uintptr_t hpetPhys, HAL_TIMER *out);
void HalPciInitialize(HAL_PCI* out);
void HalDiskInitialize(HAL_DISK* out);
@@ -339,6 +340,9 @@ __declspec(dllexport) KSTATUS HalInitialize(const HAL_INIT_PARAMS* initParams) {
HalApicInitialize(gLapicPhys, gIoapicPhys);
HalKeyboardInitialize(&gApi.Keyboard);
HalMouseInitialize(&gApi.Mouse,
(int)initParams->FramebufferWidth,
(int)initParams->FramebufferHeight);
KSTATUS ts = HalTimerInitialize(gLapicPhys, gHpetPhys, &gApi.Timer);
if (!KSUCCESS(ts)) HalDbgPrint("HAL: HPET unavailable, using fallback\n");
+245
View File
@@ -0,0 +1,245 @@
// hal_mouse.c - PS/2 auxiliary mouse driver
//
// Sits on IRQ 12, sharing the 8042 controller with the keyboard (IRQ 1).
// hal_keyboard.c has already issued command 0xA8 (enable aux port) by the
// time HalMouseInitialize is called, so we only need to:
// 1. Enable aux interrupts in the 8042 command byte (bit 1, clears bit 5).
// 2. Send the standard mouse init sequence (reset → defaults → enable).
// 3. Wire up the ISR and expose the HAL_MOUSE vtable.
//
// Packet format - standard 3-byte PS/2 mouse (no scroll wheel):
// Byte 0: [YOV][XOV][YS][XS][1][M][R][L]
// Byte 1: delta-X unsigned magnitude (sign in byte-0 bit 4)
// Byte 2: delta-Y unsigned magnitude (sign in byte-0 bit 5); PS/2 Y+ = up
//
// The ISR accumulates the 3-byte packet, converts it to a screen-space delta
// (Y-axis flipped), clamps the absolute position to [0, bounds), enqueues a
// MOUSE_EVENT, and then calls EraseOldCursor / DrawNewCursor via the two
// screen helpers that hal_screen.c exports.
//
// Threading model
// ---------------
// Single-producer (ISR on IRQ 12) / single-consumer ring buffer.
// All ISR-written fields are volatile; on a uniprocessor this is sufficient.
// On SMP, add acquire/release barriers around gHead / gTail.
#include <stdint.h>
#include <stdbool.h>
#include <intrin.h>
#include <hal_api.h>
// -- PS/2 port addresses -------------------------------------------------------
#define PS2_DATA 0x60u
#define PS2_STAT 0x64u
#define PS2_CMD 0x64u
// -- Ring buffer ---------------------------------------------------------------
#define MOUSE_BUF_SIZE 64u
#define MOUSE_BUF_MASK (MOUSE_BUF_SIZE - 1u)
typedef struct {
int dx, dy;
uint8_t buttons; // bit0=left, bit1=right, bit2=middle
} MOUSE_EVENT;
static MOUSE_EVENT gBuf[MOUSE_BUF_SIZE];
static volatile int gHead = 0; // consumer read pointer
static volatile int gTail = 0; // producer write pointer (updated by ISR)
// -- Absolute cursor position & screen bounds ----------------------------------
static volatile int gMouseX = 0;
static volatile int gMouseY = 0;
static volatile int gBoundsW = 1920;
static volatile int gBoundsH = 1080;
// -- 3-byte packet assembly ----------------------------------------------------
static volatile uint8_t gPacket[3];
static volatile int gPacketIdx = 0; // 0, 1, or 2
// -- Optional callback (called from ISR) ---------------------------------------
static void (* volatile gCallback)(int dx, int dy, uint8_t buttons) = NULL;
// -- Cursor helpers provided by hal_screen.c -----------------------------------
// Declared here; defined in hal_screen.c.
extern void HalScreenDrawCursor(int x, int y);
extern void HalScreenEraseCursor(void);
// -- 8042 low-level helpers ----------------------------------------------------
// Wait until the 8042's input buffer is empty (bit 1 of status = 0) so we
// can safely write to PS2_DATA or PS2_CMD.
static void Ps2WaitInput(void) {
int timeout = 100000;
while ((__inbyte(PS2_STAT) & 0x02u) && --timeout) { /* spin */ }
}
// Wait until the 8042's output buffer has data (bit 0 of status = 1).
static void Ps2WaitOutput(void) {
int timeout = 100000;
while (!(__inbyte(PS2_STAT) & 0x01u) && --timeout) { /* spin */ }
}
// Route the next write to the auxiliary (mouse) device rather than the keyboard.
static void MouseSendByte(uint8_t byte) {
Ps2WaitInput();
__outbyte(PS2_CMD, 0xD4u); // "write to mouse" prefix
Ps2WaitInput();
__outbyte(PS2_DATA, byte);
}
// Read one byte from the PS/2 output buffer (shared by keyboard and mouse).
static uint8_t MouseRecvByte(void) {
Ps2WaitOutput();
return __inbyte(PS2_DATA);
}
// -- Interrupt service routine --------------------------------------------------
// Called with interrupts disabled by KeIrqDispatch (IRQ 12).
// The dispatcher sends the APIC EOI before this function is invoked.
static void MouseIsr(void) {
uint8_t data = __inbyte(PS2_DATA);
// Synchronisation guard: the first byte of every packet has bit 3 set.
// If we lose sync, wait for the next valid first byte before assembling.
if (gPacketIdx == 0) {
if (!(data & 0x08u)) return; // not a valid first byte - discard
}
gPacket[gPacketIdx++] = data;
if (gPacketIdx < 3) return; // packet not yet complete
gPacketIdx = 0;
// -- Decode flags ----------------------------------------------------------
uint8_t flags = gPacket[0];
// Overflow bits: if either is set the movement data is meaningless.
if (flags & 0xC0u) return;
uint8_t buttons = flags & 0x07u;
// Convert unsigned magnitudes + sign bits to signed 9-bit values.
int dx = (int)gPacket[1] - ((flags & 0x10u) ? 256 : 0);
int dy = (int)gPacket[2] - ((flags & 0x20u) ? 256 : 0);
dy = -dy; // PS/2 Y+ = up; screen Y+ = down, so invert.
// -- Update absolute position (clamped to screen bounds) ------------------
HalScreenEraseCursor();
int nx = gMouseX + dx;
int ny = gMouseY + dy;
if (nx < 0) nx = 0;
if (nx >= gBoundsW) nx = gBoundsW - 1;
if (ny < 0) ny = 0;
if (ny >= gBoundsH) ny = gBoundsH - 1;
gMouseX = nx;
gMouseY = ny;
HalScreenDrawCursor(nx, ny);
// -- Enqueue event; silently drop if buffer is full -----------------------
int next = (gTail + 1) & (int)MOUSE_BUF_MASK;
if (next != gHead) {
gBuf[gTail].dx = dx;
gBuf[gTail].dy = dy;
gBuf[gTail].buttons = buttons;
gTail = next;
}
// -- Optional callback (raw ISR context) -----------------------------------
void (*cb)(int, int, uint8_t) = (void (*)(int, int, uint8_t))gCallback;
if (cb) cb(dx, dy, buttons);
}
// -- Consumer API --------------------------------------------------------------
static bool MousePoll(void) {
return gHead != gTail;
}
static bool MouseRead(int* dx, int* dy, uint8_t* buttons) {
if (gHead == gTail) return false;
*dx = gBuf[gHead].dx;
*dy = gBuf[gHead].dy;
*buttons = gBuf[gHead].buttons;
gHead = (gHead + 1) & (int)MOUSE_BUF_MASK;
return true;
}
static void MouseGetPosition(int* x, int* y) {
*x = gMouseX;
*y = gMouseY;
}
static void MouseSetPosition(int x, int y) {
gMouseX = x;
gMouseY = y;
}
static void MouseSetBounds(int w, int h) {
gBoundsW = w;
gBoundsH = h;
}
static void MouseSetCallback(void (*cb)(int dx, int dy, uint8_t buttons)) {
gCallback = cb;
}
// -- Initializer ---------------------------------------------------------------
// Called from HalInitialize in hal_main.c after the screen is ready.
// hal_keyboard.c has already sent 0xA8 (enable aux port) to port 0x64.
void HalMouseInitialize(HAL_MOUSE* out, int screenW, int screenH) {
gBoundsW = screenW;
gBoundsH = screenH;
gMouseX = screenW / 2;
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.
// -----------------------------------------------------------------
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);
// -----------------------------------------------------------------
// Step 2: Reset mouse (0xFF).
// Mouse replies: ACK (0xFA), self-test pass (0xAA), ID (0x00).
// -----------------------------------------------------------------
MouseSendByte(0xFFu); // reset
MouseRecvByte(); // 0xFA - ACK
MouseRecvByte(); // 0xAA - BAT passed
MouseRecvByte(); // 0x00 - device ID
// -----------------------------------------------------------------
// Step 3: Set default parameters (sampling rate 100, 4 counts/mm).
// Mouse replies: ACK.
// -----------------------------------------------------------------
MouseSendByte(0xF6u); // set defaults
MouseRecvByte(); // ACK
// -----------------------------------------------------------------
// Step 4: Enable data reporting.
// Mouse will now send 3-byte packets on every movement/button event.
// -----------------------------------------------------------------
MouseSendByte(0xF4u); // enable data reporting
MouseRecvByte(); // ACK
// Draw the initial cursor at the centre of the screen.
HalScreenDrawCursor(gMouseX, gMouseY);
// Populate vtable.
out->Poll = MousePoll;
out->Read = MouseRead;
out->SetCallback = MouseSetCallback;
out->GetPosition = MouseGetPosition;
out->SetPosition = MouseSetPosition;
out->SetBounds = MouseSetBounds;
out->Isr = MouseIsr;
out->IrqNumber = 12;
}
+91
View File
@@ -144,6 +144,95 @@ static void ScreenPrintChar(char c, uint32_t fg, uint32_t bg) {
}
}
// ---------------------------------------------------------------------------
// Mouse cursor – 12×19 monochrome arrow sprite
// 0 = transparent 1 = black outline 2 = white fill
// The hotspot is at (0,0) (top-left pixel = tip of the arrow).
// ---------------------------------------------------------------------------
#define CURSOR_W 12
#define CURSOR_H 19
static const uint8_t gCursorBitmap[CURSOR_H][CURSOR_W] = {
{1,0,0,0,0,0,0,0,0,0,0,0},
{1,1,0,0,0,0,0,0,0,0,0,0},
{1,2,1,0,0,0,0,0,0,0,0,0},
{1,2,2,1,0,0,0,0,0,0,0,0},
{1,2,2,2,1,0,0,0,0,0,0,0},
{1,2,2,2,2,1,0,0,0,0,0,0},
{1,2,2,2,2,2,1,0,0,0,0,0},
{1,2,2,2,2,2,2,1,0,0,0,0},
{1,2,2,2,2,2,2,2,1,0,0,0},
{1,2,2,2,2,2,2,2,2,1,0,0},
{1,2,2,2,2,2,2,2,2,2,1,0},
{1,2,2,2,2,2,1,1,1,1,1,1},
{1,2,2,2,1,2,2,1,0,0,0,0},
{1,2,2,1,0,1,2,2,1,0,0,0},
{1,2,1,0,0,0,1,2,2,1,0,0},
{1,1,0,0,0,0,0,1,2,2,1,0},
{1,0,0,0,0,0,0,0,1,2,1,0},
{0,0,0,0,0,0,0,0,0,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0},
};
// Saved framebuffer pixels beneath the current cursor position.
static uint32_t gCursorSavedBg[CURSOR_W * CURSOR_H];
static int gCursorDrawX = -1; // -1 = cursor not yet drawn
static int gCursorDrawY = -1;
// Save the background rectangle [x,y,CURSOR_W,CURSOR_H] from the framebuffer.
static void CursorSaveBg(int x, int y) {
for (int row = 0; row < CURSOR_H; row++) {
int fy = y + row;
for (int col = 0; col < CURSOR_W; col++) {
int fx = x + col;
uint32_t px = 0;
if ((unsigned)fx < (unsigned)gWidth && (unsigned)fy < (unsigned)gHeight)
px = gFb[fy * gStride + fx];
gCursorSavedBg[row * CURSOR_W + col] = px;
}
}
}
// Restore the background previously saved by CursorSaveBg.
static void CursorRestoreBg(int x, int y) {
for (int row = 0; row < CURSOR_H; row++) {
int fy = y + row;
for (int col = 0; col < CURSOR_W; col++) {
int fx = x + col;
if ((unsigned)fx < (unsigned)gWidth && (unsigned)fy < (unsigned)gHeight)
gFb[fy * gStride + fx] = gCursorSavedBg[row * CURSOR_W + col];
}
}
}
// Draw the arrow sprite at (x,y), saving the background first.
// Called from hal_mouse.c via extern declaration.
void HalScreenDrawCursor(int x, int y) {
CursorSaveBg(x, y);
gCursorDrawX = x;
gCursorDrawY = y;
for (int row = 0; row < CURSOR_H; row++) {
int fy = y + row;
for (int col = 0; col < CURSOR_W; col++) {
uint8_t p = gCursorBitmap[row][col];
if (!p) continue;
int fx = x + col;
if ((unsigned)fx < (unsigned)gWidth && (unsigned)fy < (unsigned)gHeight) {
uint32_t color = (p == 1) ? 0x000000u : 0xFFFFFFu;
gFb[fy * gStride + fx] = color;
}
}
}
}
// Erase the cursor by restoring the saved background.
void HalScreenEraseCursor(void) {
if (gCursorDrawX < 0) return; // never drawn
CursorRestoreBg(gCursorDrawX, gCursorDrawY);
gCursorDrawX = -1;
gCursorDrawY = -1;
}
// ---------------------------------------------------------------------------
// Populate the HAL_SCREEN vtable
// ---------------------------------------------------------------------------
@@ -160,5 +249,7 @@ void HalScreenInitialize(uintptr_t fb, int w, int h, int stride,
out->Scroll = ScreenScroll;
out->PutChar = ScreenPutChar;
out->PrintChar = ScreenPrintChar;
out->DrawCursor = HalScreenDrawCursor;
out->EraseCursor = HalScreenEraseCursor;
ScreenClear(0x000000);
}
+1
View File
@@ -382,6 +382,7 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
KeIrqRegister(hal->Timer.IrqNumber, hal->Timer.Isr);
KeIrqRegister(hal->Keyboard.IrqNumber, hal->Keyboard.Isr);
KeIrqRegister(hal->Mouse.IrqNumber, hal->Mouse.Isr);
HalRegisterScheduler(KeSchedulerTick);
+8 -8
View File
@@ -289,7 +289,7 @@ __declspec(dllexport) BOOL WriteFile(HANDLE hFile, const void* buf, DWORD toWrit
}
// ===========================================================================
// Extended shims – funcs.txt additions
// Extended shims - funcs.txt additions
// All functions here return plausible values; no real implementation exists
// unless a matching syscall stub is available.
// ===========================================================================
@@ -341,7 +341,7 @@ __declspec(dllexport) HANDLE GetCurrentThread(void) {
__declspec(dllexport) DWORD GetCurrentThreadId(void) { return (DWORD)SysGetCurrentTid(); }
__declspec(dllexport) DWORD GetCurrentProcessId(void) { return (DWORD)SysGetCurrentPid(); }
// GetModuleHandleA/W – no PE map; return NULL so callers that check can fail
// GetModuleHandleA/W - no PE map; return NULL so callers that check can fail
// gracefully. GetModuleHandleA(NULL) on Windows returns the exe base; we
// return a recognisable non-NULL sentinel so code that just passes it to
// GetProcAddress doesn't immediately crash.
@@ -353,14 +353,14 @@ __declspec(dllexport) HANDLE GetModuleHandleW(const unsigned short* lpModuleName
return lpModuleName ? NULL : (HANDLE)(uintptr_t)0x00400000UL;
}
// GetProcAddress – no dynamic linker; always fail.
// GetProcAddress - no dynamic linker; always fail.
__declspec(dllexport) void* GetProcAddress(HANDLE hModule, const char* lpProcName) {
(void)hModule; (void)lpProcName;
gLastError = 127; // ERROR_PROC_NOT_FOUND
return NULL;
}
// LoadLibraryA – no dynamic loader; always fail.
// LoadLibraryA - no dynamic loader; always fail.
__declspec(dllexport) HANDLE LoadLibraryA(const char* lpLibFileName) {
(void)lpLibFileName;
gLastError = 2; // ERROR_FILE_NOT_FOUND
@@ -385,7 +385,7 @@ __declspec(dllexport) BOOL TerminateProcess(HANDLE hProcess, unsigned int uExitC
while (true) ;
}
// STARTUPINFOA – only cb matters for our stub.
// STARTUPINFOA - only cb matters for our stub.
typedef struct {
DWORD cb;
char* lpReserved;
@@ -437,7 +437,7 @@ __declspec(dllexport) HANDLE CreateThread(void* lpThreadAttributes,
return KH_TO_HANDLE(tid);
}
// WaitForSingleObject – blocks on process handles via SysWaitForProcess;
// WaitForSingleObject - blocks on process handles via SysWaitForProcess;
// thread and other handle types are not yet waitable so return immediately.
__declspec(dllexport) DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) {
(void)dwMilliseconds;
@@ -614,7 +614,7 @@ __declspec(dllexport) BOOL ReleaseSemaphore(HANDLE hSemaphore, long lReleaseCoun
// Single-threaded: all locks are no-ops.
// ---------------------------------------------------------------------------
// Minimal opaque types; callers allocate these from their Windows headers –
// Minimal opaque types; callers allocate these from their Windows headers -
// we just need the pointer to be accepted by our stubs.
typedef struct { uintptr_t _opaque[5]; } CRITICAL_SECTION;
typedef struct { void* _ptr; } CONDITION_VARIABLE;
@@ -862,7 +862,7 @@ __declspec(dllexport) BOOL IsDebuggerPresent(void) {
}
// ---------------------------------------------------------------------------
// RTL Exception / Unwind (SEH infrastructure – all stubs)
// RTL Exception / Unwind (SEH infrastructure - all stubs)
// ---------------------------------------------------------------------------
typedef struct _RUNTIME_FUNCTION {
+2 -2
View File
@@ -14,7 +14,7 @@ It boots into a shell.
- UEFI bootloader
- physical memory manager
- virtual memory manager with kernel pool
- HAL (screen, keyboard, timer, disk, PCI, APIC)
- HAL (screen, keyboard, mouse, timer, disk, PCI, APIC)
- preemptive scheduler with priority levels
- processes and threads
- VFS with IRPs
@@ -85,7 +85,7 @@ currently shipping: AHCI (interrupts), IDE (PIO/DMA), FAT32 (read-only).
"2:\data\config.ini" -> drive 2
```
drives 0–7. a drive only works if a filesystem registered on it.
drives 0-7. a drive only works if a filesystem registered on it.
## screenshots