i think it works
This commit is contained in:
commit
0e1479b168
167 files changed
+27008
No files matched your search
@@ -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,
|
||||
};
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
// hal_debug.h - HAL debug output function
|
||||
// Do not include outside HAL.
|
||||
void HalDbgPrint(const char* fmt, ...);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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; }
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
Reference in new issue
Block a user