i think it works

This commit is contained in:
maksw committed 2026-04-30 23:52:46 +02:00
commit 0e1479b168
167 files changed
+27008

No files matched your search

+199
View File
@@ -0,0 +1,199 @@
#pragma once
// 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>
static const uint8_t Font8x16[95 * 16] = {
// 0x20 ' '
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x21 '!'
0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,
// 0x22 '"'
0x00,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x23 '#'
0x00,0x36,0x36,0x7F,0x36,0x36,0x36,0x7F,0x36,0x36,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x24 '$'
0x18,0x18,0x3E,0x63,0x03,0x03,0x1E,0x30,0x30,0x63,0x3E,0x18,0x18,0x00,0x00,0x00,
// 0x25 '%'
0x00,0x00,0x63,0x33,0x18,0x0C,0x06,0x31,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x26 '&'
0x00,0x1C,0x36,0x1C,0x0E,0x3B,0x33,0x33,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x27 '\''
0x00,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x28 '('
0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x29 ')'
0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x2A '*'
0x00,0x00,0x00,0x33,0x1E,0xFF,0x1E,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x2B '+'
0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x2C ','
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x2D '-'
0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x2E '.'
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x2F '/'
0x00,0x60,0x30,0x18,0x0C,0x06,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x30 '0'
0x00,0x3C,0x66,0x66,0x76,0x6E,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x31 '1'
0x00,0x18,0x1C,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x32 '2'
0x00,0x3C,0x66,0x60,0x30,0x18,0x0C,0x66,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x33 '3'
0x00,0x3C,0x66,0x60,0x38,0x60,0x60,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x34 '4'
0x00,0x30,0x38,0x3C,0x36,0x33,0x7F,0x30,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x35 '5'
0x00,0x7E,0x06,0x06,0x3E,0x60,0x60,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x36 '6'
0x00,0x38,0x0C,0x06,0x3E,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x37 '7'
0x00,0x7E,0x60,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x38 '8'
0x00,0x3C,0x66,0x66,0x3C,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x39 '9'
0x00,0x3C,0x66,0x66,0x7C,0x60,0x30,0x18,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x3A ':'
0x00,0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x3B ';'
0x00,0x00,0x18,0x18,0x00,0x00,0x18,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x3C '<'
0x00,0x60,0x30,0x18,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x3D '='
0x00,0x00,0x00,0x7E,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x3E '>'
0x00,0x06,0x0C,0x18,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x3F '?'
0x00,0x3C,0x66,0x60,0x30,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x40 '@'
0x00,0x3E,0x63,0x7B,0x7B,0x7B,0x3B,0x03,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x41 'A'
0x00,0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x42 'B'
0x00,0x3E,0x66,0x66,0x3E,0x66,0x66,0x66,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x43 'C'
0x00,0x3C,0x66,0x06,0x06,0x06,0x06,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x44 'D'
0x00,0x1E,0x36,0x66,0x66,0x66,0x66,0x36,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x45 'E'
0x00,0x7E,0x06,0x06,0x3E,0x06,0x06,0x06,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x46 'F'
0x00,0x7E,0x06,0x06,0x3E,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x47 'G'
0x00,0x3C,0x66,0x06,0x06,0x76,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x48 'H'
0x00,0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x49 'I'
0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x4A 'J'
0x00,0x78,0x30,0x30,0x30,0x30,0x36,0x36,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x4B 'K'
0x00,0x66,0x36,0x1E,0x0E,0x1E,0x36,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x4C 'L'
0x00,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x4D 'M'
0x00,0x63,0x77,0x7F,0x6B,0x63,0x63,0x63,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x4E 'N'
0x00,0x63,0x67,0x6F,0x7B,0x73,0x63,0x63,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x4F 'O'
0x00,0x3C,0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x50 'P'
0x00,0x3E,0x66,0x66,0x3E,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x51 'Q'
0x00,0x3C,0x66,0x66,0x66,0x66,0x6E,0x3C,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x52 'R'
0x00,0x3E,0x66,0x66,0x3E,0x36,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x53 'S'
0x00,0x3C,0x66,0x06,0x1C,0x30,0x60,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x54 'T'
0x00,0xFF,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x55 'U'
0x00,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x56 'V'
0x00,0x66,0x66,0x66,0x66,0x66,0x3C,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x57 'W'
0x00,0x63,0x63,0x63,0x6B,0x7F,0x77,0x63,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x58 'X'
0x00,0x66,0x66,0x3C,0x18,0x3C,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x59 'Y'
0x00,0x66,0x66,0x66,0x3C,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x5A 'Z'
0x00,0x7E,0x60,0x30,0x18,0x0C,0x06,0x06,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x5B '['
0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x5C '\'
0x00,0x03,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x5D ']'
0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x5E '^'
0x08,0x1C,0x36,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x5F '_'
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 'a'
0x00,0x00,0x00,0x1C,0x30,0x3C,0x33,0x33,0x6E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x62 'b'
0x00,0x06,0x06,0x1E,0x36,0x66,0x66,0x66,0x3E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x63 'c'
0x00,0x00,0x00,0x3C,0x06,0x06,0x06,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x64 'd'
0x00,0x60,0x60,0x7C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x65 'e'
0x00,0x00,0x00,0x3C,0x66,0x7E,0x06,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x66 'f'
0x00,0x38,0x0C,0x0C,0x3E,0x0C,0x0C,0x0C,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x67 'g'
0x00,0x00,0x7C,0x66,0x66,0x66,0x7C,0x60,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x68 'h'
0x00,0x06,0x06,0x3E,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x69 'i'
0x00,0x18,0x00,0x1C,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x6A 'j'
0x00,0x30,0x00,0x38,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x6B 'k'
0x00,0x06,0x06,0x66,0x36,0x1E,0x36,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x6C 'l'
0x00,0x1C,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x6D 'm'
0x00,0x00,0x00,0x37,0x7F,0x6B,0x6B,0x6B,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x6E 'n'
0x00,0x00,0x00,0x1E,0x36,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x6F 'o'
0x00,0x00,0x00,0x3C,0x66,0x66,0x66,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x70 'p'
0x00,0x00,0x3E,0x66,0x66,0x3E,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x71 'q'
0x00,0x00,0x7C,0x66,0x66,0x7C,0x60,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x72 'r'
0x00,0x00,0x00,0x3E,0x06,0x06,0x06,0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x73 's'
0x00,0x00,0x00,0x3C,0x06,0x1C,0x30,0x66,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x74 't'
0x00,0x0C,0x0C,0x3E,0x0C,0x0C,0x0C,0x0C,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x75 'u'
0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x76 'v'
0x00,0x00,0x00,0x66,0x66,0x66,0x66,0x3C,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x77 'w'
0x00,0x00,0x00,0x63,0x6B,0x6B,0x7F,0x77,0x63,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x78 'x'
0x00,0x00,0x00,0x66,0x3C,0x18,0x3C,0x66,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x79 'y'
0x00,0x00,0x66,0x66,0x66,0x7C,0x60,0x30,0x1E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x7A 'z'
0x00,0x00,0x00,0x7E,0x30,0x18,0x0C,0x06,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x7B '{'
0x00,0x30,0x18,0x18,0x0C,0x18,0x18,0x18,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x7C '|'
0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x7D '}'
0x00,0x0C,0x18,0x18,0x30,0x18,0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// 0x7E '~'
0x00,0x6E,0x3B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
+95
View File
@@ -0,0 +1,95 @@
#pragma once
// hal_api.h - HAL interface table exported as HalGetApi()
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "ke_status.h"
typedef struct BOOT_INFO BOOT_INFO;
typedef struct HAL_SCREEN {
void (*Clear)(uint32_t color);
void (*PutPixel)(int x, int y, uint32_t color);
void (*Blit)(int x, int y, int w, int h, const uint32_t* pixels);
void (*GetSize)(int* width, int* height);
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);
} HAL_SCREEN;
typedef struct HAL_KEYBOARD {
bool (*Poll)(void);
uint8_t (*ReadScancode)(void);
char (*ReadChar)(void);
void (*SetCallback)(void (*cb)(uint8_t scancode));
void (*Isr)(void);
uint8_t IrqNumber;
} HAL_KEYBOARD;
typedef struct HAL_DISK {
KSTATUS (*ReadSectors)(uint8_t drive, uint64_t lba,
uint32_t count, void* buf);
KSTATUS (*WriteSectors)(uint8_t drive, uint64_t lba,
uint32_t count, const void* buf);
bool (*DrivePresent)(uint8_t drive);
uint64_t (*DriveSectorCount)(uint8_t drive);
} HAL_DISK;
typedef struct HAL_TIMER {
uint64_t (*QueryTicks)(void);
void (*Stall)(uint32_t us);
void (*Isr)(void);
uint8_t IrqNumber;
} HAL_TIMER;
typedef struct HAL_PCI {
uint32_t (*ConfigRead32)(uint8_t bus, uint8_t dev,
uint8_t fn, uint8_t reg);
void (*ConfigWrite32)(uint8_t bus, uint8_t dev,
uint8_t fn, uint8_t reg, uint32_t val);
bool (*FindDevice)(uint16_t vendor, uint16_t device,
uint8_t* bus, uint8_t* dev, uint8_t* fn);
bool (*FindClass)(uint8_t classCode, uint8_t subclass,
uint8_t* bus, uint8_t* dev, uint8_t* fn);
} HAL_PCI;
typedef struct HAL_INTC {
void (*RouteIrq)(uint8_t irq);
void (*MaskIrq)(uint8_t irq);
void (*UnmaskIrq)(uint8_t irq);
void (*SendEoi)(void);
} HAL_INTC;
typedef struct HAL_API {
uint32_t Version;
void *(*PhysToVirt)(uint64_t physAddr);
HAL_SCREEN Screen;
HAL_KEYBOARD Keyboard;
HAL_DISK Disk;
HAL_TIMER Timer;
HAL_PCI Pci;
HAL_INTC Intc;
} HAL_API;
typedef struct HAL_INIT_PARAMS {
// Framebuffer
uintptr_t FramebufferBase;
uint32_t FramebufferWidth;
uint32_t FramebufferHeight;
uint32_t FramebufferStride;
// ACPI
uintptr_t RsdpPhysical;
// Memory
uint64_t PhysicalWindowBase;
// Debug
int DebugEnabled;
} HAL_INIT_PARAMS;
#define HAL_API_VERSION 1
const HAL_API* HalGetApi(void);
void HalRegisterScheduler(void (*pKeSchedulerTick)(void));
KSTATUS HalInitialize(const HAL_INIT_PARAMS* params);
+74
View File
@@ -0,0 +1,74 @@
// hal_apic.c - Local APIC + I/O APIC
#include "hal_apic.h"
#include "hal_api.h"
#include <stdint.h>
extern HAL_API gApi;
// ---- Local APIC ----
static volatile uint32_t* gLapic = (volatile uint32_t *)0;
#define LAPIC_REG(off) (*(volatile uint32_t *)((uint8_t *)gLapic + (off)))
#define LAPIC_EOI 0x0B0
#define LAPIC_SPURIOUS 0x0F0
#define LAPIC_ENABLE 0x100 // bit in spurious vector register
// ---- I/O APIC ----
static volatile uint32_t* gIoapic = (volatile uint32_t *)0;
#define IOAPIC_IDX 0x00
#define IOAPIC_DATA 0x10
static uint32_t IoapicRead(uint8_t reg) {
*(volatile uint32_t *)((uint8_t *)gIoapic + IOAPIC_IDX) = reg;
return *(volatile uint32_t *)((uint8_t *)gIoapic + IOAPIC_DATA);
}
static void IoapicWrite(uint8_t reg, uint32_t val) {
*(volatile uint32_t *)((uint8_t *)gIoapic + IOAPIC_IDX) = reg;
*(volatile uint32_t *)((uint8_t *)gIoapic + IOAPIC_DATA) = val;
}
// IRQ n -> redirection table at register 0x10 + 2*n (low), 0x11 + 2*n (high).
#define IOREDTBL_LO(n) (0x10 + 2*(n))
#define IOREDTBL_HI(n) (0x11 + 2*(n))
// Interrupt vector base: IRQ 0 -> vector 0x20, IRQ 1 -> 0x21, ...
#define IRQ_VECTOR_BASE 0x20
void HalApicRouteIrq(uint8_t irq) {
// Full initial setup of the redirection entry.
// Sets the vector and clears the mask bit in one write.
uint32_t vector = IRQ_VECTOR_BASE + irq; // e.g. IRQ 1 -> vector 0x21
IoapicWrite(IOREDTBL_LO(irq), vector); // unmasked (bit 16 = 0), edge, fixed
IoapicWrite(IOREDTBL_HI(irq), 0); // deliver to LAPIC id 0
}
void HalApicMaskIrq(uint8_t irq) {
uint32_t lo = IoapicRead(IOREDTBL_LO(irq));
lo |= (1 << 16);
IoapicWrite(IOREDTBL_LO(irq), lo);
}
void HalApicUnmaskIrq(uint8_t irq) {
uint32_t lo = IoapicRead(IOREDTBL_LO(irq));
lo &= ~(1 << 16); // clear mask bit
lo = (lo & ~0xFF) | (IRQ_VECTOR_BASE + irq);
IoapicWrite(IOREDTBL_LO(irq), lo);
IoapicWrite(IOREDTBL_HI(irq), 0); // LAPIC id 0
}
void HalApicSendEoi(void) {
LAPIC_REG(LAPIC_EOI) = 0;
}
void HalApicInitialize(uintptr_t lapicPhys, uintptr_t ioapicPhys) {
gLapic = (volatile uint32_t *)(gApi.PhysToVirt(lapicPhys));
gIoapic = (volatile uint32_t *)(gApi.PhysToVirt(ioapicPhys));
// Enable Local APIC, set spurious vector to 0xFF.
LAPIC_REG(LAPIC_SPURIOUS) = LAPIC_ENABLE | 0xFF;
// Mask all IOAPIC lines initially.
uint32_t maxRedir = (IoapicRead(1) >> 16) & 0xFF;
for (uint8_t i = 0; i <= maxRedir; i++) {
IoapicWrite(IOREDTBL_LO(i), (1 << 16) | (IRQ_VECTOR_BASE + i));
IoapicWrite(IOREDTBL_HI(i), 0);
}
}
+9
View File
@@ -0,0 +1,9 @@
// hal_apic.h
#pragma once
#include <stdint.h>
void HalApicRouteIrq(uint8_t irq);
void HalApicMaskIrq(uint8_t irq);
void HalApicUnmaskIrq(uint8_t irq);
void HalApicSendEoi(void);
void HalApicInitialize(uintptr_t lapicPhys, uintptr_t ioapicPhys);
+4
View File
@@ -0,0 +1,4 @@
#pragma once
// hal_debug.h - HAL debug output function
// Do not include outside HAL.
void HalDbgPrint(const char* fmt, ...);
+43
View File
@@ -0,0 +1,43 @@
// hal_disk.c - drive registry; drivers register themselves via IoRegisterDisk
#include "hal_api.h"
#include "io_driver.h"
#include <stdint.h>
#include <stdbool.h>
#define MAX_DRIVES 8
static DISK_DRIVER gDrives[MAX_DRIVES];
static bool gPresent[MAX_DRIVES];
KSTATUS IoRegisterDisk(uint8_t index, const DISK_DRIVER* driver) {
if (index >= MAX_DRIVES || !driver) return STATUS_INVALID_PARAMETER;
if (gPresent[index]) return STATUS_ALREADY_EXISTS;
gDrives[index] = *driver;
gPresent[index] = true;
return STATUS_SUCCESS;
}
static KSTATUS DiskRead(uint8_t drive, uint64_t lba,
uint32_t count, void* buf) {
if (drive >= MAX_DRIVES || !gPresent[drive]) return STATUS_NOT_FOUND;
return gDrives[drive].ReadSectors(lba, count, buf);
}
static KSTATUS DiskWrite(uint8_t drive, uint64_t lba,
uint32_t count, const void* buf) {
if (drive >= MAX_DRIVES || !gPresent[drive]) return STATUS_NOT_FOUND;
return gDrives[drive].WriteSectors(lba, count, buf);
}
static bool DiskPresent(uint8_t drive) {
return drive < MAX_DRIVES && gPresent[drive];
}
static uint64_t DiskSectorCount(uint8_t drive) {
if (drive >= MAX_DRIVES || !gPresent[drive]) return 0;
return gDrives[drive].SectorCount;
}
void HalDiskInitialize(HAL_DISK* out) {
out->ReadSectors = DiskRead;
out->WriteSectors = DiskWrite;
out->DrivePresent = DiskPresent;
out->DriveSectorCount = DiskSectorCount;
}
+71
View File
@@ -0,0 +1,71 @@
// hal_keyboard.c - PS/2 keyboard, interrupt-driven, 256-entry ring buffer
#include "hal_api.h"
#include "hal_apic.h"
#include <stdint.h>
#include <stdbool.h>
#include <intrin.h>
#define PS2_DATA 0x60
#define PS2_STAT 0x64
#define PS2_CMD 0x64
#define KBD_BUF_SIZE 256
static uint8_t gBuf[KBD_BUF_SIZE];
static volatile int gHead = 0, gTail = 0;
static void (*gCallback)(uint8_t) = (void *)0;
// Minimal Set-2 to ASCII translation (unshifted only).
static const char gScanToAscii[128] = {
0,0,'1','2','3','4','5','6','7','8','9','0','-','=','\b',
'\t','q','w','e','r','t','y','u','i','o','p','[',']','\n',
0,'a','s','d','f','g','h','j','k','l',';','\'','`',
0,'\\','z','x','c','v','b','n','m',',','.','/',0,'*',
0,' ',0,0,0,0,0,0,0,0,0,0,0,0,0,
'7','8','9','-','4','5','6','+','1','2','3','0','.',0,0,0,
};
static void KbdIsr(void) {
uint8_t sc = __inbyte(PS2_DATA);
if (sc & 0x80) return; // key-up, ignore
int next = (gTail + 1) % KBD_BUF_SIZE;
if (next != gHead) {
gBuf[gTail] = sc;
gTail = next;
}
if (gCallback) gCallback(sc);
}
static bool KbdPoll(void) {
return gHead != gTail;
}
static uint8_t KbdReadScancode(void) {
while (gHead == gTail) { _mm_pause(); }
uint8_t sc = gBuf[gHead];
gHead = (gHead + 1) % KBD_BUF_SIZE;
return sc;
}
static char KbdReadChar(void) {
if (gHead == gTail) return 0;
uint8_t sc = KbdReadScancode();
if (sc < 128) return gScanToAscii[sc];
return 0;
}
static void KbdSetCallback(void (*cb)(uint8_t sc)) {
gCallback = cb;
}
void HalKeyboardInitialize(HAL_KEYBOARD *out) {
// Flush PS/2 output buffer
while (__inbyte(PS2_STAT) & 1) __inbyte(PS2_DATA);
out->Poll = KbdPoll;
out->ReadScancode = KbdReadScancode;
out->ReadChar = KbdReadChar;
out->SetCallback = KbdSetCallback;
out->Isr = KbdIsr;
out->IrqNumber = 1;
}
+250
View File
@@ -0,0 +1,250 @@
// hal_main.c - HAL initialisation and HalGetApi
#include "hal_api.h"
#include "hal_apic.h"
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#include "printf.h"
// 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);
KSTATUS HalTimerInitialize(uintptr_t lapicPhys, uintptr_t hpetPhys, HAL_TIMER *out);
void HalPciInitialize(HAL_PCI* out);
void HalDiskInitialize(HAL_DISK* out);
extern void HalSetDebugEnabled(int v);
// Defined in mm_virt.c - HAL needs it for MMIO window access.
static uint64_t gPhysBase = 0xFFFF880000000000ULL;
HAL_API gApi;
static int gInitialised = 0;
extern void (*gTimerCallback)(void);
// ---------------------------------------------------------------------------
// ACPI table walker - minimal, just enough to find APIC and HPET addresses.
// ---------------------------------------------------------------------------
#define ACPI_SIG(a,b,c,d) ((uint32_t)(a)|((uint32_t)(b)<<8)|((uint32_t)(c)<<16)|((uint32_t)(d)<<24))
#pragma pack(push, 1)
#pragma warning(disable : 4200)
// ACPI RSDP (Root System Description Pointer)
typedef struct {
char Signature[8];
uint8_t Checksum;
char OEMID[6];
uint8_t Revision;
uint32_t RsdtAddress;
uint32_t Length;
uint64_t XsdtAddress;
uint8_t ExtendedChecksum;
uint8_t Reserved[3];
} RSDP;
// ACPI SDT Header
typedef struct {
char Signature[4];
uint32_t Length;
uint8_t Revision;
uint8_t Checksum;
char OEMID[6];
char OEMTableID[8];
uint32_t OEMRevision;
uint32_t CreatorID;
uint32_t CreatorRevision;
} ACPISDTHeader;
// RSDT (Root System Description Table)
typedef struct {
ACPISDTHeader Header;
uint32_t PointerToOtherSDT[];
} RSDT;
// XSDT (Extended System Description Table)
typedef struct {
ACPISDTHeader Header;
uint64_t PointerToOtherSDT[];
} XSDT;
// MADT (Multiple APIC Description Table)
typedef struct {
ACPISDTHeader Header;
uint32_t LocalAPICAddress;
uint32_t Flags;
uint8_t Entries[];
} MADT;
#pragma pack(pop)
static uintptr_t gLapicPhys = 0xFEE00000;
static uintptr_t gIoapicPhys = 0xFEC00000;
static uintptr_t gHpetPhys = 0xFED00000;
int debugEnabled = 0;
int _fltused; // fuckass
static void hal_putchar(char c) {
gApi.Screen.PrintChar(c, 0x00FF00, 0x000000);
}
void HalDbgPrint(const char* fmt, ...) {
if (!debugEnabled) return;
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
static void *HalPhysToVirt(uint64_t phys) {
return (void *)(phys + gPhysBase);
}
static void ParseMadt(MADT* madt) {
gLapicPhys = madt->LocalAPICAddress;
uint8_t* p = (uint8_t *)(madt + 1);
uint8_t* end = (uint8_t *)madt + madt->Header.Length;
while (p < end) {
uint8_t type = p[0], len = p[1];
if (type == 1) { // I/O APIC entry
gIoapicPhys = *(uint32_t *)(p + 4);
}
p += len ? len : 1;
}
}
static int validate_checksum(void* table, uint32_t length) {
uint8_t sum = 0;
uint8_t* bytes = (uint8_t*)table;
for (uint32_t i = 0; i < length; i++) {
sum += bytes[i];
}
return sum == 0;
}
static void WalkAcpi(uintptr_t rsdpPhys) {
if (!rsdpPhys) return;
// Map RSDP into virtual memory
RSDP* rsdp = (RSDP*)(rsdpPhys + gPhysBase);
if (memcmp(rsdp->Signature, "RSD PTR ", 8) != 0) {
HalDbgPrint("HAL: Invalid RSDP signature!\n");
return;
}
ACPISDTHeader* sdtHeader = NULL;
uint32_t count = 0;
int isXsdt = 0;
// Safely find and validate the XSDT (ACPI 2.0+)
if (rsdp->Revision >= 2 && rsdp->XsdtAddress != 0) {
XSDT* xsdt = (XSDT*)(rsdp->XsdtAddress + gPhysBase);
if (validate_checksum(xsdt, xsdt->Header.Length) &&
memcmp(xsdt->Header.Signature, "XSDT", 4) == 0) {
sdtHeader = &xsdt->Header;
count = (xsdt->Header.Length - sizeof(ACPISDTHeader)) / 8;
isXsdt = 1;
}
}
// Fallback to safely finding and validating the RSDT (ACPI 1.0)
if (sdtHeader == NULL && rsdp->RsdtAddress != 0) {
RSDT* rsdt = (RSDT*)((uintptr_t)rsdp->RsdtAddress + gPhysBase);
if (validate_checksum(rsdt, rsdt->Header.Length) &&
memcmp(rsdt->Header.Signature, "RSDT", 4) == 0) {
sdtHeader = &rsdt->Header;
count = (rsdt->Header.Length - sizeof(ACPISDTHeader)) / 4;
isXsdt = 0;
}
}
if (sdtHeader == NULL) {
HalDbgPrint("HAL: No valid XSDT or RSDT found!\n");
return;
}
// Walk the tables
for (uint32_t i = 0; i < count; i++) {
uintptr_t tablePhys = 0;
if (isXsdt) {
tablePhys = ((XSDT*)sdtHeader)->PointerToOtherSDT[i];
} else {
tablePhys = ((RSDT*)sdtHeader)->PointerToOtherSDT[i];
}
// Paranoid alignment check to reject firmware garbage pointers
if (!tablePhys || (tablePhys & 3) != 0) continue;
ACPISDTHeader* header = (ACPISDTHeader*)(tablePhys + gPhysBase);
// Ensure the table isn't corrupt before parsing
if (!validate_checksum(header, header->Length)) continue;
// Parse MADT
if (memcmp(header->Signature, "APIC", 4) == 0) {
ParseMadt((MADT*)header);
}
// Parse HPET
else if (memcmp(header->Signature, "HPET", 4) == 0) {
// HPET base address block is located at offset 44
// (which is 8 bytes past the 36-byte ACPISDTHeader)
gHpetPhys = *(uint64_t*)((uint8_t*)header + 44) & ~0xFFFULL;
}
}
}
// ---------------------------------------------------------------------------
KSTATUS HalInitialize(const HAL_INIT_PARAMS* initParams) {
if (gInitialised) return STATUS_ALREADY_EXISTS;
gPhysBase = initParams->PhysicalWindowBase;
gApi.PhysToVirt = HalPhysToVirt;
debugEnabled = initParams->DebugEnabled;
// Screen first so DbgPrint works immediately.
HalScreenInitialize(initParams->FramebufferBase + initParams->PhysicalWindowBase,
(int)initParams->FramebufferWidth,
(int)initParams->FramebufferHeight,
(int)initParams->FramebufferStride,
&gApi.Screen);
printf_set_putchar(hal_putchar);
HalDbgPrint("HAL: screen %dx%d\n",
initParams->FramebufferWidth, initParams->FramebufferHeight);
// Parse ACPI to find LAPIC / IOAPIC / HPET addresses.
if (initParams->RsdpPhysical) WalkAcpi(initParams->RsdpPhysical);
HalDbgPrint("HAL: LAPIC=%016llx IOAPIC=%016llx HPET=%016llx\n",
gLapicPhys, gIoapicPhys, gHpetPhys);
HalApicInitialize(gLapicPhys, gIoapicPhys);
HalKeyboardInitialize(&gApi.Keyboard);
KSTATUS ts = HalTimerInitialize(gLapicPhys, gHpetPhys, &gApi.Timer);
if (!KSUCCESS(ts)) HalDbgPrint("HAL: HPET unavailable, using fallback\n");
HalPciInitialize(&gApi.Pci);
HalDiskInitialize(&gApi.Disk);
gApi.Intc.RouteIrq = HalApicRouteIrq;
gApi.Intc.MaskIrq = HalApicMaskIrq;
gApi.Intc.UnmaskIrq = HalApicUnmaskIrq;
gApi.Intc.SendEoi = HalApicSendEoi;
gApi.Version = HAL_API_VERSION;
gInitialised = 1;
HalDbgPrint("HAL: initialisation complete.\n");
return STATUS_SUCCESS;
}
void HalRegisterScheduler(void (*pKeSchedulerTick)(void)) {
gTimerCallback = pKeSchedulerTick;
}
const HAL_API* HalGetApi(void) { return &gApi; }
+63
View File
@@ -0,0 +1,63 @@
// hal_pci.c - PCI configuration space via Mechanism 1 port I/O
#include "hal_api.h"
#include <stdint.h>
#define PCI_CONFIG_ADDR 0xCF8
#define PCI_CONFIG_DATA 0xCFC
static uint32_t MakeAddr(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t reg) {
return 0x80000000UL
| ((uint32_t)bus << 16)
| ((uint32_t)(dev & 0x1F) << 11)
| ((uint32_t)(fn & 0x07) << 8)
| (reg & 0xFC);
}
static uint32_t PciRead32(uint8_t bus, uint8_t dev, uint8_t fn, uint8_t reg) {
__outdword(PCI_CONFIG_ADDR, MakeAddr(bus, dev, fn, reg));
return __indword(PCI_CONFIG_DATA);
}
static void PciWrite32(uint8_t bus, uint8_t dev, uint8_t fn,
uint8_t reg, uint32_t val) {
__outdword(PCI_CONFIG_ADDR, MakeAddr(bus, dev, fn, reg));
__outdword(PCI_CONFIG_DATA, val);
}
static bool PciFindDevice(uint16_t vendor, uint16_t device,
uint8_t* outBus, uint8_t* outDev, uint8_t* outFn) {
for (int bus = 0; bus < 256; bus++)
for (int dev = 0; dev < 32; dev++)
for (int fn = 0; fn < 8; fn++) {
uint32_t id = PciRead32((uint8_t)bus, (uint8_t)dev, (uint8_t)fn, 0);
if ((id & 0xFFFF) == vendor && (id >> 16) == device) {
*outBus = (uint8_t)bus; *outDev = (uint8_t)dev; *outFn = (uint8_t)fn;
return true;
}
}
return false;
}
static bool PciFindClass(uint8_t classCode, uint8_t subclass,
uint8_t* outBus, uint8_t* outDev, uint8_t* outFn) {
for (int bus = 0; bus < 256; bus++)
for (int dev = 0; dev < 32; dev++)
for (int fn = 0; fn < 8; fn++) {
uint32_t id = PciRead32((uint8_t)bus,(uint8_t)dev,(uint8_t)fn,0);
if ((id & 0xFFFF) == 0xFFFF) continue; // no device
uint32_t cc = PciRead32((uint8_t)bus,(uint8_t)dev,(uint8_t)fn,8);
if (((cc >> 24) & 0xFF) == classCode &&
((cc >> 16) & 0xFF) == subclass) {
*outBus = (uint8_t)bus; *outDev = (uint8_t)dev; *outFn = (uint8_t)fn;
return true;
}
}
return false;
}
void HalPciInitialize(HAL_PCI* out) {
out->ConfigRead32 = PciRead32;
out->ConfigWrite32 = PciWrite32;
out->FindDevice = PciFindDevice;
out->FindClass = PciFindClass;
}
+118
View File
@@ -0,0 +1,118 @@
// hal_screen.c - GOP framebuffer screen driver with embedded 8x16 font
//
// The 8x16 bitmap font is a standard VGA/PC font. We embed just the
// printable ASCII range (0x20–0x7E). Each glyph is 16 bytes; bit 7 of
// each byte is the leftmost pixel.
#include "hal_api.h"
#include <stdint.h>
#include <string.h>
#include <intrin.h>
static uint32_t* gFb = (uint32_t *)0;
static int gWidth = 0;
static int gHeight = 0;
static int gStride = 0; // pixels per row
static int gCursorX = 0, gCursorY = 0;
#define FONT_W 8
#define FONT_H 16
// ---------------------------------------------------------------------------
// 8x16 VGA font - printable ASCII only (glyph 0 = space = 0x20)
// ---------------------------------------------------------------------------
#include "font8x16.h" // see font8x16.h below
// ---------------------------------------------------------------------------
// Internals
// ---------------------------------------------------------------------------
static inline void PutPixelRaw(int x, int y, uint32_t color) {
if ((unsigned)x < (unsigned)gWidth && (unsigned)y < (unsigned)gHeight)
gFb[y * gStride + x] = color;
}
// ---------------------------------------------------------------------------
// HAL_SCREEN implementations
// ---------------------------------------------------------------------------
static void ScreenClear(uint32_t color) {
for (int y = 0; y < gHeight; y++)
for (int x = 0; x < gWidth; x++)
gFb[y * gStride + x] = color;
gCursorX = 0; gCursorY = 0;
}
static void ScreenPutPixel(int x, int y, uint32_t color) {
PutPixelRaw(x, y, color);
}
static void ScreenBlit(int x, int y, int w, int h, const uint32_t* pixels) {
for (int row = 0; row < h; row++)
for (int col = 0; col < w; col++)
PutPixelRaw(x + col, y + row, pixels[row * w + col]);
}
static void ScreenGetSize(int* w, int* h) { *w = gWidth; *h = gHeight; }
static void ScreenScroll(int lines) {
if (lines <= 0 || lines >= gHeight) { ScreenClear(0); return; }
int rowBytes = gStride * sizeof(uint32_t);
memmove(gFb, gFb + lines * gStride,
(size_t)(gHeight - lines) * rowBytes);
// Clear the revealed rows at the bottom.
memset(gFb + (gHeight - lines) * gStride, 0,
(size_t)lines * rowBytes);
}
static void ScreenPutChar(char c, int x, int y, uint32_t fg, uint32_t bg) {
if ((unsigned char)c < 0x20 || (unsigned char)c > 0x7E) c = '?';
const uint8_t* glyph = Font8x16 + ((unsigned char)c - 0x20) * 16;
for (int row = 0; row < 16; row++) {
uint8_t bits = glyph[row];
for (int col = 0; col < 8; col++) {
uint32_t color = (bits & (1 << col)) ? fg : bg; // i don't know why, i don't want to know why, i shouldn't have to wonder why but the font is backwards unless we do this terriblness
PutPixelRaw(x + col, y + row, color);
}
}
}
static void ScreenPrintChar(char c, uint32_t fg, uint32_t bg) {
int cols = gWidth / FONT_W;
int rows = gHeight / FONT_H;
// Mirror to serial
while ((__inbyte(0x3FD) & 0x20) == 0);
if (c == '\n') __outbyte(0x3F8, '\r');
__outbyte(0x3F8, c);
if (c == '\n') {
gCursorX = 0;
gCursorY++;
} else if (c == '\r') {
gCursorX = 0;
} else {
ScreenPutChar(c, gCursorX * FONT_W, gCursorY * FONT_H, fg, bg);
if (++gCursorX >= cols) { gCursorX = 0; gCursorY++; }
}
if (gCursorY >= rows) {
ScreenScroll(FONT_H);
gCursorY = rows - 1;
}
}
// ---------------------------------------------------------------------------
// Populate the HAL_SCREEN vtable
// ---------------------------------------------------------------------------
void HalScreenInitialize(uintptr_t fb, int w, int h, int stride,
HAL_SCREEN* out) {
gFb = (uint32_t *)fb;
gWidth = w;
gHeight = h;
gStride = stride;
out->Clear = ScreenClear;
out->PutPixel = ScreenPutPixel;
out->Blit = ScreenBlit;
out->GetSize = ScreenGetSize;
out->Scroll = ScreenScroll;
out->PutChar = ScreenPutChar;
out->PrintChar = ScreenPrintChar;
ScreenClear(0x000000);
}
+136
View File
@@ -0,0 +1,136 @@
// hal_timer.c - Local APIC timer, calibrated against PIT channel 2
#include "hal_api.h"
#include "hal_apic.h"
#include "hal_debug.h"
#include <stdint.h>
#include <intrin.h>
#define LAPIC_TIMER_LVT 0x320
#define LAPIC_TIMER_INIT 0x380
#define LAPIC_TIMER_CUR 0x390
#define LAPIC_TIMER_DIV 0x3E0
#define TIMER_VECTOR 0x20 // vector 0x20 = IRQ 0 slot in IDT
#define TIMER_PERIODIC (1 << 17)
#define TIMER_MASKED (1 << 16)
#define TIMER_DIV16 0x3
#define QUANTUM_MS 10
#define PIT_HZ 1193182UL
extern HAL_API gApi;
static volatile uint32_t* gLapic = NULL;
#define LAPIC_REG(off) (*(volatile uint32_t *)((uint8_t *)gLapic + (off)))
static volatile uint64_t gTicks = 0;
void (*gTimerCallback)(void) = NULL;
static inline void outb(uint16_t port, uint8_t val) { __outbyte(port, val); }
static inline uint8_t inb(uint16_t port) { return __inbyte(port); }
static void TimerIsr(void) {
gTicks++;
if (gTimerCallback) gTimerCallback();
// EOI is sent by KeIrqDispatch after this returns
}
static uint64_t QueryTicks(void) { return gTicks; }
static void Stall(uint32_t us) {
uint64_t start = gTicks;
uint64_t ms = (us + 999) / 1000;
while ((gTicks - start) < ms) _mm_pause();
}
// Returns HPET ticks/second, or 0 if HPET is unavailable.
static uint64_t HpetInit(uintptr_t hpetPhys) {
// HPET register block, accessed through physical window
volatile uint64_t *hpet = (volatile uint64_t *)gApi.PhysToVirt(hpetPhys);
// General Capabilities register (offset 0):
// Bits 63:32 = counter clock period in femtoseconds
uint64_t caps = hpet[0];
uint32_t periodFs = (uint32_t)(caps >> 32);
if (!periodFs) return 0;
// Enable the HPET main counter (General Configuration, offset 0x10, bit 0)
hpet[2] |= 1; // offset 0x10 / 8 = index 2
return (uint64_t)1e15 / periodFs; // ticks per second
}
// Use PIT channel 2 one-shot to measure how many APIC ticks elapse in 10 ms, then return ticks/ms.
static uint32_t CalibrateApicTimerViaPit(void) {
// Divide by 16
LAPIC_REG(LAPIC_TIMER_DIV) = TIMER_DIV16;
// Mask, set vector - leave masked during calibration
LAPIC_REG(LAPIC_TIMER_LVT) = TIMER_MASKED | TIMER_VECTOR;
// Load max count
LAPIC_REG(LAPIC_TIMER_INIT) = 0xFFFFFFFF;
// PIT channel 2: one-shot, ~10 ms
uint16_t pit_count = (uint16_t)(PIT_HZ / 100); // 11931 ≈ 10 ms
outb(0x61, (inb(0x61) & ~0x02) | 0x01); // gate on, speaker off
outb(0x43, 0xB0); // ch2, lo/hi, mode 0, binary
outb(0x42, (uint8_t)(pit_count & 0xFF));
outb(0x42, (uint8_t)(pit_count >> 8));
// Wait for OUT2 (bit 5 of port 0x61) to go high
while (!(inb(0x61) & 0x20)) _mm_pause();
uint32_t elapsed = 0xFFFFFFFF - LAPIC_REG(LAPIC_TIMER_CUR);
return elapsed / 10; // ticks per ms
}
// Use HPET main counter to measure how many APIC ticks elapse in 10 ms, then return ticks/ms.
static uint32_t CalibrateApicTimerViaHpet(uintptr_t hpetPhys) {
volatile uint64_t *hpet = (volatile uint64_t *)gApi.PhysToVirt(hpetPhys);
uint64_t hpetHz = HpetInit(hpetPhys);
if (!hpetHz) return 0;
// Ticks in 10 ms = hpetHz / 100
uint64_t ticksFor10ms = hpetHz / 100;
LAPIC_REG(LAPIC_TIMER_DIV) = TIMER_DIV16;
LAPIC_REG(LAPIC_TIMER_LVT) = TIMER_MASKED | TIMER_VECTOR;
LAPIC_REG(LAPIC_TIMER_INIT) = 0xFFFFFFFF;
// HPET main counter is at offset 0xF0, index 0xF0/8 = 30
uint64_t hpetStart = hpet[30];
while ((hpet[30] - hpetStart) < ticksFor10ms) _mm_pause();
uint32_t elapsed = 0xFFFFFFFF - LAPIC_REG(LAPIC_TIMER_CUR);
return elapsed / 10; // APIC ticks per ms
}
KSTATUS HalTimerInitialize(uintptr_t lapicPhys, uintptr_t hpetPhys, HAL_TIMER *out) {
gLapic = (volatile uint32_t *)gApi.PhysToVirt(lapicPhys);
HalDbgPrint("HAL: lapicPhys=0x%llX, lapicVirt=0x%llX, hpetPhys=0x%llX\n", lapicPhys, (uintptr_t)gLapic, hpetPhys);
uint32_t ticksPerMs = 0;
if (hpetPhys) {
HalDbgPrint("HAL: Attempting to calibrate APIC timer via HPET...\n");
ticksPerMs = CalibrateApicTimerViaHpet(hpetPhys);
}
if (!ticksPerMs) {
HalDbgPrint("HAL: HPET unavailable or calibration failed. Falling back to PIT...\n");
ticksPerMs = CalibrateApicTimerViaPit();
}
if (!ticksPerMs) {
HalDbgPrint("HAL: APIC calibration failed. How?\n");
return STATUS_DEVICE_ERROR;
}
HalDbgPrint("HAL: APIC timer: %u ticks/ms\n", ticksPerMs);
// Configure LAPIC timer in periodic mode
LAPIC_REG(LAPIC_TIMER_DIV) = TIMER_DIV16;
LAPIC_REG(LAPIC_TIMER_LVT) = TIMER_PERIODIC | TIMER_VECTOR;
LAPIC_REG(LAPIC_TIMER_INIT) = ticksPerMs * QUANTUM_MS;
out->QueryTicks = QueryTicks;
out->Stall = Stall;
out->Isr = TimerIsr;
out->IrqNumber = 0;
return STATUS_SUCCESS;
}
+17
View File
@@ -0,0 +1,17 @@
#pragma once
// io_driver.h - driver-side interface for registering disk controllers
#include "hal_api.h"
#include "ke_status.h"
#include "../kernel/io_file.h"
#include <stdint.h>
typedef KSTATUS (*DRIVER_ENTRY_FN)(const HAL_API* hal);
typedef void (*DRIVER_UNLOAD_FN)(void);
typedef struct DISK_DRIVER {
KSTATUS (*ReadSectors)(uint64_t lba, uint32_t count, void* buf);
KSTATUS (*WriteSectors)(uint64_t lba, uint32_t count, const void* buf);
uint64_t SectorCount;
} DISK_DRIVER;
KSTATUS IoRegisterDisk(uint8_t driveIndex, const DISK_DRIVER* driver);