major refactorings

Signed-off-by: kaguya3311 <kaguya3311@national.shitposting.agency>
This commit is contained in:
kaguya
2026-05-18 04:02:59 -04:00
parent f7aa6f913a
commit b28a6bcf29
211 changed files with 17699 additions and 8107 deletions
+44
View File
@@ -0,0 +1,44 @@
#include "asm.h"
#include <stdbool.h>
void halt(void) {
asm("hlt");
}
void cli(void) {
asm("cli");
}
void sti(void) {
asm("sti");
}
void pause(void) {
asm("pause");
}
void nop(void) {
asm("nop");
}
void dbgbrk(void) {
asm("int 3");
}
bool int_state(void) {
uint64_t flags;
asm volatile("pushfq; pop %0" : "=rm"(flags)::"memory");
return flags & (1 << 9);
}
bool int_toggle(bool state) {
bool ret = int_state();
if (state) {
sti();
} else {
cli();
}
return ret;
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#define FLAT_PTR(PTR) (*((uintptr_t(*)[])(PTR)))
#define BYTE_PTR(PTR) (*((uint8_t *)(PTR)))
#define WORD_PTR(PTR) (*((uint16_t *)(PTR)))
#define DWORD_PTR(PTR) (*((uint32_t *)(PTR)))
#define QWORD_PTR(PTR) (*((uint64_t *)(PTR)))
void halt(void);
void cli(void);
void sti(void);
void pause(void);
void nop(void);
void dbgbrk(void);
bool int_state(void);
bool int_toggle(bool state);
+66
View File
@@ -0,0 +1,66 @@
; Taken from Limine
; Added memset32
section .text
global memcpy
memcpy:
mov rcx, rdx
mov rax, rdi
rep movsb
ret
global memset
memset:
push rdi
mov rax, rsi
mov rcx, rdx
rep stosb
pop rax
ret
global memset32
memset32:
push rdi
mov rax, rsi
mov rcx, rdx
rep stosd
pop rax
ret
global memmove
memmove:
mov rcx, rdx
mov rax, rdi
cmp rdi, rsi
ja .copy_backwards
rep movsb
jmp .done
.copy_backwards:
lea rdi, [rdi+rcx-1]
lea rsi, [rsi+rcx-1]
std
rep movsb
cld
.done:
ret
global memcmp
memcmp:
mov rcx, rdx
repe cmpsb
je .equal
mov al, byte [rdi-1]
sub al, byte [rsi-1]
movsx rax, al
jmp .done
.equal:
xor eax, eax
.done:
ret
+15 -29
View File
@@ -2,8 +2,7 @@
#include "mm/memory.h"
#include "mp/spinlock.h"
#include <stddef.h>
#include "libk/debug.h"
struct gdt_desc {
uint16_t limit;
@@ -37,40 +36,28 @@ struct gdtr {
struct gdtr gdt = {0};
struct gdt_ptr gdt_pointer = {0};
struct tss kernel_tss = {0};
spinlock_t s_gdt_lock = SPINLOCK_INIT;
spinlock_t gdt_lock;
extern void gdt_reload(void);
extern void tss_reload(void);
void x86_64_GDT_Initialize(void) {
uint64_t flags;
spinlock_acquire_irqsave(&s_gdt_lock, &flags);
// null desc
memset(&gdt.entries[0], 0, sizeof(struct gdt_desc));
void gdt_init(void) {
spinlock_acquire_or_wait(&gdt_lock);
// Kernel code
gdt.entries[1].limit = 0xFFFF;
gdt.entries[1].access = 0x9A;
gdt.entries[1].granularity = 0x20;
gdt.entries[1].access = 0b10011010;
gdt.entries[1].granularity = 0b00100000;
// Kernel data
gdt.entries[2].limit = 0xFFFF;
gdt.entries[2].access = 0x92;
gdt.entries[2].granularity = 0x00;
gdt.entries[2].access = 0b10010010;
// User data
gdt.entries[3].limit = 0xFFFF;
gdt.entries[3].access = 0xF2;
gdt.entries[3].granularity = 0x00;
gdt.entries[3].access = 0b11110010;
// User code
gdt.entries[4].limit = 0xFFFF;
gdt.entries[4].access = 0xFA;
gdt.entries[4].granularity = 0x20;
gdt.entries[4].access = 0b11111010;
gdt.entries[4].granularity = 0b00100000;
// TSS 0x28
// TSS
gdt.tss.length = sizeof(struct tss);
gdt.tss.flags1 = 0b10001001;
@@ -80,12 +67,11 @@ void x86_64_GDT_Initialize(void) {
gdt_reload();
tss_reload();
spinlock_release_irqrestore(&s_gdt_lock, flags);
spinlock_drop(&gdt_lock);
}
void gdt_load_tss(size_t addr) {
uint64_t flags;
spinlock_acquire_irqsave(&s_gdt_lock, &flags);
spinlock_acquire_or_wait(&gdt_lock);
gdt.tss.base_low = (uint16_t)addr;
gdt.tss.base_mid = (uint8_t)(addr >> 16);
gdt.tss.flags1 = 0b10001001;
@@ -93,5 +79,5 @@ void gdt_load_tss(size_t addr) {
gdt.tss.base_upper32 = (uint32_t)(addr >> 32);
tss_reload();
spinlock_release_irqrestore(&s_gdt_lock, flags);
spinlock_drop(&gdt_lock);
}
+5 -6
View File
@@ -3,14 +3,13 @@
#include <stddef.h>
#define GDT_KERNEL_BASE 0x0
#define GDT_KERNEL_CODE64 0x8
#define GDT_KERNEL_DATA64 0x10
#define GDT_USER_BASE 0x18
#define GDT_USER_DATA64 0x18
#define GDT_USER_CODE64 0x20
#define GDT_TSS 0x28
#define GDT_USER_DATA64 0x20
#define GDT_USER_CODE64 0x28
#define GDT_TSS 0x30
struct tss {
uint32_t reserved;
@@ -30,7 +29,7 @@ struct tss {
uint16_t iomap_base;
} __attribute__((packed));
extern struct tss kernel_tss;
extern void gdt_reload(void);
void x86_64_GDT_Initialize(void);
void gdt_init(void);
void gdt_load_tss(size_t addr);
-27
View File
@@ -1,27 +0,0 @@
.intel_syntax noprefix
.global x86_64_GDT_Load
.extern gdt_pointer
.global gdt_reload
gdt_reload:
lgdt [rip + gdt_pointer]
push 0x08
lea rax, [rip + .flush]
push rax
lretq
.flush:
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
ret
.global tss_reload
tss_reload:
mov ax, 0x2B
ltr ax
ret
+23
View File
@@ -0,0 +1,23 @@
extern gdt_pointer
global gdt_reload
gdt_reload:
lgdt [rel gdt_pointer]
push 8
lea rax, [rel .flush]
push rax
retfq
.flush:
mov eax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
ret
global tss_reload
tss_reload:
mov ax, 0x2B
ltr ax
ret
+30 -27
View File
@@ -1,35 +1,38 @@
#include "idt.h"
#include "libk/binary.h"
#include <stddef.h>
#include <stdint.h>
struct idt_entry {
uint16_t offset_lo;
uint16_t selector;
uint8_t ist;
uint8_t flags;
uint16_t offset_mid;
uint32_t offset_hi;
uint32_t zero;
} __attribute__((packed));
IDTEntry g_IDT[256];
IDTDescriptor g_IDTDescriptor = { sizeof(g_IDT) - 1, g_IDT };
struct idt_register {
uint16_t size;
uint64_t address;
} __attribute__((packed));
extern void x86_64_IDT_Load(IDTDescriptor* descriptor);
struct idt_entry idt[256] = {0};
void x86_64_IDT_SetGate(int interrupt, void* base, uint16_t segmentDescriptor, uint8_t flags)
{
uintptr_t addr = (uintptr_t)base;
g_IDT[interrupt].BaseLow = addr & 0xFFFF;
g_IDT[interrupt].SegmentSelector = segmentDescriptor;
g_IDT[interrupt].IST = 0;
g_IDT[interrupt].Flags = flags;
g_IDT[interrupt].BaseMid = (addr >> 16) & 0xFFFF;
g_IDT[interrupt].BaseHigh = (addr >> 32) & 0xFFFFFFFF;
g_IDT[interrupt].Reserved = 0;
}
void x86_64_IDT_EnableGate(int interrupt)
{
FLAG_SET(g_IDT[interrupt].Flags, IDT_FLAG_PRESENT);
void idt_set_gate(size_t vec, void *handler, uint8_t ist) {
uint64_t p = (uint64_t)handler;
idt[vec].offset_lo = (uint16_t)p;
idt[vec].selector = 8;
idt[vec].ist = ist;
idt[vec].flags = 0x8E;
idt[vec].offset_mid = (uint16_t)(p >> 16);
idt[vec].offset_hi = (uint32_t)(p >> 32);
idt[vec].zero = 0;
}
void x86_64_IDT_DisableGate(int interrupt)
{
FLAG_UNSET(g_IDT[interrupt].Flags, IDT_FLAG_PRESENT);
void idt_reload(void) {
struct idt_register idt_ptr = {sizeof(idt) - 1, (uint64_t)idt};
asm volatile("lidtq %0" : : "m"(idt_ptr));
}
void x86_64_IDT_Initialize(void)
{
x86_64_IDT_Load(&g_IDTDescriptor);
}
+3 -40
View File
@@ -1,44 +1,7 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
typedef enum
{
IDT_FLAG_GATE_TASK = 0x5,
IDT_FLAG_GATE_16BIT_INT = 0x6,
IDT_FLAG_GATE_16BIT_TRAP = 0x7,
IDT_FLAG_GATE_32BIT_INT = 0xE,
IDT_FLAG_GATE_32BIT_TRAP = 0xF,
IDT_FLAG_RING0 = (0 << 5),
IDT_FLAG_RING1 = (1 << 5),
IDT_FLAG_RING2 = (2 << 5),
IDT_FLAG_RING3 = (3 << 5),
IDT_FLAG_PRESENT = 0x80,
} IDT_FLAGS;
typedef struct
{
uint16_t BaseLow;
uint16_t SegmentSelector;
uint8_t IST; // Interrupt Stack Table (0 = default)
uint8_t Flags;
uint16_t BaseMid;
uint32_t BaseHigh;
uint32_t Reserved;
} __attribute__((packed)) IDTEntry;
typedef struct
{
uint16_t Limit;
IDTEntry* Ptr;
} __attribute__((packed)) IDTDescriptor;
void x86_64_IDT_Initialize(void);
void x86_64_IDT_SetGate(int interrupt, void* base, uint16_t segmentDescriptor, uint8_t flags);
void x86_64_IDT_EnableGate(int interrupt);
void x86_64_IDT_DisableGate(int interrupt);
void idt_set_gate(size_t vec, void *handler, uint8_t ist);
void idt_reload(void);
-6
View File
@@ -1,6 +0,0 @@
.intel_syntax noprefix
.global x86_64_IDT_Load
x86_64_IDT_Load:
lidt [rdi] # descriptor in RDI
ret
+348 -110
View File
@@ -1,124 +1,362 @@
// ... includes ...
#include "arch/x86_64/cpu/io.h"
#include "libk/debug.h"
#include "arch/x86_64/boot/isr.h"
#include "idt.h"
#define MODULE "ISR"
#include "mm/vmm.h"
#include "arch/x86_64/cpu/reg.h"
#include "mp/mp.h"
#include "mm/memory.h"
#include "mm/pmm.h"
#include "arch/x86_64/sys/halt.h"
#include "sched/sched.h"
static inline uint64_t x86_64_read_cr2(void)
{
uint64_t value;
__asm__ volatile ("mov %%cr2, %0" : "=r"(value));
return value;
void isr_install(void) {
idt_set_gate(0, isr0, 0);
idt_set_gate(1, isr1, 0);
idt_set_gate(2, isr2, 0);
idt_set_gate(3, isr3, 0);
idt_set_gate(4, isr4, 0);
idt_set_gate(5, isr5, 0);
idt_set_gate(6, isr6, 0);
idt_set_gate(7, isr7, 0);
idt_set_gate(8, isr8, 0);
idt_set_gate(9, isr9, 0);
idt_set_gate(10, isr10, 0);
idt_set_gate(11, isr11, 0);
idt_set_gate(12, isr12, 0);
idt_set_gate(13, isr13, 0);
idt_set_gate(14, isr14, 2);
idt_set_gate(15, isr15, 0);
idt_set_gate(16, isr16, 0);
idt_set_gate(17, isr17, 0);
idt_set_gate(18, isr18, 0);
idt_set_gate(19, isr19, 0);
idt_set_gate(20, isr20, 0);
idt_set_gate(21, isr21, 0);
idt_set_gate(22, isr22, 0);
idt_set_gate(23, isr23, 0);
idt_set_gate(24, isr24, 0);
idt_set_gate(25, isr25, 0);
idt_set_gate(26, isr26, 0);
idt_set_gate(27, isr27, 0);
idt_set_gate(28, isr28, 0);
idt_set_gate(29, isr29, 0);
idt_set_gate(30, isr30, 0);
idt_set_gate(31, isr31, 0);
idt_set_gate(32, isr32, 0);
idt_set_gate(33, isr33, 0);
idt_set_gate(34, isr34, 0);
idt_set_gate(35, isr35, 0);
idt_set_gate(36, isr36, 0);
idt_set_gate(37, isr37, 0);
idt_set_gate(38, isr38, 0);
idt_set_gate(39, isr39, 0);
idt_set_gate(40, isr40, 0);
idt_set_gate(41, isr41, 0);
idt_set_gate(42, isr42, 0);
idt_set_gate(43, isr43, 0);
idt_set_gate(44, isr44, 0);
idt_set_gate(45, isr45, 0);
idt_set_gate(46, isr46, 0);
idt_set_gate(47, isr47, 0);
idt_set_gate(48, isr48, 1);
idt_set_gate(49, isr49, 0);
idt_set_gate(50, isr50, 0);
idt_set_gate(51, isr51, 0);
idt_set_gate(52, isr52, 0);
idt_set_gate(53, isr53, 0);
idt_set_gate(54, isr54, 0);
idt_set_gate(55, isr55, 0);
idt_set_gate(56, isr56, 0);
idt_set_gate(57, isr57, 0);
idt_set_gate(58, isr58, 0);
idt_set_gate(59, isr59, 0);
idt_set_gate(60, isr60, 0);
idt_set_gate(61, isr61, 0);
idt_set_gate(62, isr62, 0);
idt_set_gate(63, isr63, 0);
idt_set_gate(64, isr64, 0);
idt_set_gate(65, isr65, 0);
idt_set_gate(66, isr66, 0);
idt_set_gate(67, isr67, 0);
idt_set_gate(68, isr68, 0);
idt_set_gate(69, isr69, 0);
idt_set_gate(70, isr70, 0);
idt_set_gate(71, isr71, 0);
idt_set_gate(72, isr72, 0);
idt_set_gate(73, isr73, 0);
idt_set_gate(74, isr74, 0);
idt_set_gate(75, isr75, 0);
idt_set_gate(76, isr76, 0);
idt_set_gate(77, isr77, 0);
idt_set_gate(78, isr78, 0);
idt_set_gate(79, isr79, 0);
idt_set_gate(80, isr80, 0);
idt_set_gate(81, isr81, 0);
idt_set_gate(82, isr82, 0);
idt_set_gate(83, isr83, 0);
idt_set_gate(84, isr84, 0);
idt_set_gate(85, isr85, 0);
idt_set_gate(86, isr86, 0);
idt_set_gate(87, isr87, 0);
idt_set_gate(88, isr88, 0);
idt_set_gate(89, isr89, 0);
idt_set_gate(90, isr90, 0);
idt_set_gate(91, isr91, 0);
idt_set_gate(92, isr92, 0);
idt_set_gate(93, isr93, 0);
idt_set_gate(94, isr94, 0);
idt_set_gate(95, isr95, 0);
idt_set_gate(96, isr96, 0);
idt_set_gate(97, isr97, 0);
idt_set_gate(98, isr98, 0);
idt_set_gate(99, isr99, 0);
idt_set_gate(100, isr100, 0);
idt_set_gate(101, isr101, 0);
idt_set_gate(102, isr102, 0);
idt_set_gate(103, isr103, 0);
idt_set_gate(104, isr104, 0);
idt_set_gate(105, isr105, 0);
idt_set_gate(106, isr106, 0);
idt_set_gate(107, isr107, 0);
idt_set_gate(108, isr108, 0);
idt_set_gate(109, isr109, 0);
idt_set_gate(110, isr110, 0);
idt_set_gate(111, isr111, 0);
idt_set_gate(112, isr112, 0);
idt_set_gate(113, isr113, 0);
idt_set_gate(114, isr114, 0);
idt_set_gate(115, isr115, 0);
idt_set_gate(116, isr116, 0);
idt_set_gate(117, isr117, 0);
idt_set_gate(118, isr118, 0);
idt_set_gate(119, isr119, 0);
idt_set_gate(120, isr120, 0);
idt_set_gate(121, isr121, 0);
idt_set_gate(122, isr122, 0);
idt_set_gate(123, isr123, 0);
idt_set_gate(124, isr124, 0);
idt_set_gate(125, isr125, 0);
idt_set_gate(126, isr126, 0);
idt_set_gate(127, isr127, 0);
idt_set_gate(128, isr128, 0);
idt_set_gate(129, isr129, 0);
idt_set_gate(130, isr130, 0);
idt_set_gate(131, isr131, 0);
idt_set_gate(132, isr132, 0);
idt_set_gate(133, isr133, 0);
idt_set_gate(134, isr134, 0);
idt_set_gate(135, isr135, 0);
idt_set_gate(136, isr136, 0);
idt_set_gate(137, isr137, 0);
idt_set_gate(138, isr138, 0);
idt_set_gate(139, isr139, 0);
idt_set_gate(140, isr140, 0);
idt_set_gate(141, isr141, 0);
idt_set_gate(142, isr142, 0);
idt_set_gate(143, isr143, 0);
idt_set_gate(144, isr144, 0);
idt_set_gate(145, isr145, 0);
idt_set_gate(146, isr146, 0);
idt_set_gate(147, isr147, 0);
idt_set_gate(148, isr148, 0);
idt_set_gate(149, isr149, 0);
idt_set_gate(150, isr150, 0);
idt_set_gate(151, isr151, 0);
idt_set_gate(152, isr152, 0);
idt_set_gate(153, isr153, 0);
idt_set_gate(154, isr154, 0);
idt_set_gate(155, isr155, 0);
idt_set_gate(156, isr156, 0);
idt_set_gate(157, isr157, 0);
idt_set_gate(158, isr158, 0);
idt_set_gate(159, isr159, 0);
idt_set_gate(160, isr160, 0);
idt_set_gate(161, isr161, 0);
idt_set_gate(162, isr162, 0);
idt_set_gate(163, isr163, 0);
idt_set_gate(164, isr164, 0);
idt_set_gate(165, isr165, 0);
idt_set_gate(166, isr166, 0);
idt_set_gate(167, isr167, 0);
idt_set_gate(168, isr168, 0);
idt_set_gate(169, isr169, 0);
idt_set_gate(170, isr170, 0);
idt_set_gate(171, isr171, 0);
idt_set_gate(172, isr172, 0);
idt_set_gate(173, isr173, 0);
idt_set_gate(174, isr174, 0);
idt_set_gate(175, isr175, 0);
idt_set_gate(176, isr176, 0);
idt_set_gate(177, isr177, 0);
idt_set_gate(178, isr178, 0);
idt_set_gate(179, isr179, 0);
idt_set_gate(180, isr180, 0);
idt_set_gate(181, isr181, 0);
idt_set_gate(182, isr182, 0);
idt_set_gate(183, isr183, 0);
idt_set_gate(184, isr184, 0);
idt_set_gate(185, isr185, 0);
idt_set_gate(186, isr186, 0);
idt_set_gate(187, isr187, 0);
idt_set_gate(188, isr188, 0);
idt_set_gate(189, isr189, 0);
idt_set_gate(190, isr190, 0);
idt_set_gate(191, isr191, 0);
idt_set_gate(192, isr192, 0);
idt_set_gate(193, isr193, 0);
idt_set_gate(194, isr194, 0);
idt_set_gate(195, isr195, 0);
idt_set_gate(196, isr196, 0);
idt_set_gate(197, isr197, 0);
idt_set_gate(198, isr198, 0);
idt_set_gate(199, isr199, 0);
idt_set_gate(200, isr200, 0);
idt_set_gate(201, isr201, 0);
idt_set_gate(202, isr202, 0);
idt_set_gate(203, isr203, 0);
idt_set_gate(204, isr204, 0);
idt_set_gate(205, isr205, 0);
idt_set_gate(206, isr206, 0);
idt_set_gate(207, isr207, 0);
idt_set_gate(208, isr208, 0);
idt_set_gate(209, isr209, 0);
idt_set_gate(210, isr210, 0);
idt_set_gate(211, isr211, 0);
idt_set_gate(212, isr212, 0);
idt_set_gate(213, isr213, 0);
idt_set_gate(214, isr214, 0);
idt_set_gate(215, isr215, 0);
idt_set_gate(216, isr216, 0);
idt_set_gate(217, isr217, 0);
idt_set_gate(218, isr218, 0);
idt_set_gate(219, isr219, 0);
idt_set_gate(220, isr220, 0);
idt_set_gate(221, isr221, 0);
idt_set_gate(222, isr222, 0);
idt_set_gate(223, isr223, 0);
idt_set_gate(224, isr224, 0);
idt_set_gate(225, isr225, 0);
idt_set_gate(226, isr226, 0);
idt_set_gate(227, isr227, 0);
idt_set_gate(228, isr228, 0);
idt_set_gate(229, isr229, 0);
idt_set_gate(230, isr230, 0);
idt_set_gate(231, isr231, 0);
idt_set_gate(232, isr232, 0);
idt_set_gate(233, isr233, 0);
idt_set_gate(234, isr234, 0);
idt_set_gate(235, isr235, 0);
idt_set_gate(236, isr236, 0);
idt_set_gate(237, isr237, 0);
idt_set_gate(238, isr238, 0);
idt_set_gate(239, isr239, 0);
idt_set_gate(240, isr240, 0);
idt_set_gate(241, isr241, 0);
idt_set_gate(242, isr242, 0);
idt_set_gate(243, isr243, 0);
idt_set_gate(244, isr244, 0);
idt_set_gate(245, isr245, 0);
idt_set_gate(246, isr246, 0);
idt_set_gate(247, isr247, 0);
idt_set_gate(248, isr248, 0);
idt_set_gate(249, isr249, 0);
idt_set_gate(250, isr250, 0);
idt_set_gate(251, isr251, 0);
idt_set_gate(252, isr252, 0);
idt_set_gate(253, isr253, 0);
idt_set_gate(254, isr254, 0);
idt_set_gate(255, isr255, 0);
idt_reload();
}
ISRHandler g_ISRHandlers[256];
static const char* const g_Exceptions[] = {
"Divide by zero error",
"Debug",
"Non-maskable Interrupt",
"Breakpoint",
"Overflow",
"Bound Range Exceeded",
"Invalid Opcode",
"Device Not Available",
"Double Fault",
"Coprocessor Segment Overrun",
"Invalid TSS",
"Segment Not Present",
"Stack-Segment Fault",
"General Protection Fault",
"Page Fault",
"",
"x87 Floating-Point Exception",
"Alignment Check",
"Machine Check",
"SIMD Floating-Point Exception",
"Virtualization Exception",
"Control Protection Exception ",
"",
"",
"",
"",
"",
"",
"Hypervisor Injection Exception",
"VMM Communication Exception",
"Security Exception",
""
};
static const char *isr_exception_messages[] = {"Divide by zero",
"Debug",
"NMI",
"Breakpoint",
"Overflow",
"Bound Range Exceeded",
"Invalid Opcode",
"Device Not Available",
"Double fault",
"Co-processor Segment Overrun",
"Invalid TSS",
"Segment not present",
"Stack-Segment Fault",
"GPF",
"Page Fault",
"Reserved",
"x87 Floating Point Exception",
"alignment check",
"Machine check",
"SIMD floating-point exception",
"Virtualization Exception",
"Deadlock",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Reserved",
"Security Exception",
"Reserved",
"Triple Fault",
"FPU error"};
extern void x86_64_ISR_InitializeGates(void); // defined in isrs_gen.c
static event_handlers_t event_handlers[256] = {NULL};
void x86_64_ISR_Initialize(void)
{
x86_64_ISR_InitializeGates();
for (int i = 0; i < 256; i++)
x86_64_IDT_EnableGate(i);
x86_64_IDT_DisableGate(0x80); // syscall gate
void isr_register_handler(int n, void *handler) {
event_handlers[n] = handler;
}
void page_fault_handler(Registers* regs, uint64_t cr2)
{
void isr_handle(registers_t *r) {
if (r->cs & 0x3) {
swapgs();
}
if (r->isrNumber < 256 && event_handlers[r->isrNumber] != NULL) {
event_handlers[r->isrNumber](r);
} else {
if (r->isrNumber < 32) {
if (r->cs & 0x3) {
struct thread *thrd = sched_get_running_thread();
kprintf(
"Killing user thread tid %d under process %s for exception "
"%s\n",
thrd->tid, thrd->mother_proc->name,
isr_exception_messages[r->isrNumber]);
kprintf("User thread crashed at address: %p\n", r->rip);
thread_kill(thrd, true);
} else {
halt_other_cpus();
kprintffos(0, "AH! UNHANDLED EXCEPTION!\n");
kprintffos(0, "RIP: %p RBP: %p RSP: %p\n", r->rip, r->rbp,
r->rsp);
kprintffos(0, "RAX: %p RBX: %p RCX: %p\n", r->rax, r->rbx,
r->rcx);
kprintffos(0, "RDX: %p RDI: %p RSI: %p\n", r->rdx, r->rdi,
r->rsi);
kprintffos(0, "R8 : %p R9 : %p R10: %p\n", r->r8, r->r9,
r->r10);
kprintffos(0, "R11: %p R12: %p R13: %p\n", r->r11, r->r12,
r->r13);
kprintffos(0, "R14: %p R15: %p ERR: 0b%b\n", r->r14, r->r15,
r->errorCode);
kprintffos(0, "CS : %p SS : %p RFLAGS: %p\n", r->cs, r->ss,
r->rflags);
kprintffos(0, "FS : %p UGS: %p KGS: %p\n", read_fs_base(),
read_user_gs(), read_kernel_gs());
panic_((void *)r->rip, (void *)r->rbp,
"Unhandled Exception: %s\n",
isr_exception_messages[r->isrNumber]);
}
}
}
// bit 0: present
// bit 1: write
// bit 2: user-mode
// bit 3: reserved overwrite
// bit 4: instruction fetch
log_crit(MODULE, "KERNEL PANIC! Exception %d (%s)", regs->interrupt, g_Exceptions[regs->interrupt]);
log_crit(MODULE, " rax=%x rbx=%x rcx=%x rdx=%x rsi=%x rdi=%x",
regs->rax, regs->rbx, regs->rcx, regs->rdx, regs->rsi, regs->rdi);
log_crit(MODULE, " rsp=%x rbp=%x rip=%x rflags=%x cs=%x ss=%x",
regs->rsp, regs->rbp, regs->rip, regs->rflags, regs->cs, regs->ss);
log_crit(MODULE, " interrupt=%x errorcode=%x", regs->interrupt, regs->error);
log_crit("PAGEFAULT", "Fault at address %lx (rip=%lx, err=%x)",
cr2, regs->rip, regs->error);
log_crit(MODULE, "KERNEL PANIC!");
x86_64_Panic(); // or attempt recovery
if (r->cs & 0x3) {
swapgs();
}
}
void __attribute__((used)) x86_64_ISR_Handler(Registers* regs)
{
if (regs->interrupt == 14)
{
uint64_t cr2 = x86_64_read_cr2();
page_fault_handler(regs, cr2);
}
if (g_ISRHandlers[regs->interrupt])
g_ISRHandlers[regs->interrupt](regs);
else if (regs->interrupt >= 32)
log_err(MODULE, "Unhandled interrupt %d!", regs->interrupt);
else {
// panic log (use regs->rax etc. now)
log_crit(MODULE, "KERNEL PANIC! Exception %d (%s)", regs->interrupt, g_Exceptions[regs->interrupt]);
// ... print registers with rax/rbx etc. ...
log_crit(MODULE, " rax=%x rbx=%x rcx=%x rdx=%x rsi=%x rdi=%x",
regs->rax, regs->rbx, regs->rcx, regs->rdx, regs->rsi, regs->rdi);
log_crit(MODULE, " rsp=%x rbp=%x rip=%x rflags=%x cs=%x ss=%x",
regs->rsp, regs->rbp, regs->rip, regs->rflags, regs->cs, regs->ss);
log_crit(MODULE, " interrupt=%x errorcode=%x", regs->interrupt, regs->error);
log_crit(MODULE, "KERNEL PANIC!");
x86_64_Panic();
}
}
void x86_64_ISR_RegisterHandler(int interrupt, ISRHandler handler)
{
g_ISRHandlers[interrupt] = handler;
x86_64_IDT_EnableGate(interrupt);
}
+41 -10
View File
@@ -1,15 +1,46 @@
#pragma once
#include <stdint.h>
#include "arch/x86_64/cpu/reg.h"
typedef struct
{
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
uint64_t rdi, rsi, rbp, rdx, rcx, rbx, rax;
uint64_t interrupt, error;
uint64_t rip, cs, rflags, rsp, ss;
} __attribute__((packed)) Registers;
#define PASTER(x, y) x##y
#define EVALUATOR(x, y) PASTER(x, y)
// This first macro makes functions like "void isr0(void)"
// But the number is summed up on each call
#define ONE EVALUATOR(void isr, __COUNTER__)(void)
// Different granularities
#define TWO \
ONE; \
ONE
#define TEN \
TWO; \
TWO; \
TWO; \
TWO; \
TWO
#define TWENTY \
TEN; \
TEN
#define HUNDRED \
TWENTY; \
TWENTY; \
TWENTY; \
TWENTY; \
TWENTY
// Define 255 ISRs based on previous granularities
#define DEFISR \
HUNDRED; \
HUNDRED; \
TWENTY; \
TWENTY; \
TEN; \
TWO; \
TWO; \
TWO
typedef void (*ISRHandler)(Registers* regs);
DEFISR;
void x86_64_ISR_Initialize(void);
void x86_64_ISR_RegisterHandler(int interrupt, ISRHandler handler);
typedef void (*event_handlers_t)(registers_t *);
void isr_install(void);
extern void isr_handle(registers_t *r);
void isr_register_handler(int n, void *handler);
-58
View File
@@ -1,58 +0,0 @@
.intel_syntax noprefix
.extern x86_64_ISR_Handler
.macro ISR_NOERRORCODE num
.global x86_64_ISR\num
x86_64_ISR\num:
push 0
push \num
jmp isr_common
.endm
.macro ISR_ERRORCODE num
.global x86_64_ISR\num
x86_64_ISR\num:
push \num
jmp isr_common
.endm
.include "arch/x86_64/boot/isrs_gen.inc"
isr_common:
push rax
push rbx
push rcx
push rdx
push rbp
push rsi
push rdi
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
mov rdi, rsp // Registers* in RDI
call x86_64_ISR_Handler
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rdi
pop rsi
pop rbp
pop rdx
pop rcx
pop rbx
pop rax
add rsp, 16 // pop interrupt + error code
iretq
+87
View File
@@ -0,0 +1,87 @@
%macro pushall 0
push rax
push rbx
push rcx
push rdx
push rbp
push rdi
push rsi
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
%endmacro
%macro popall 0
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rsi
pop rdi
pop rbp
pop rdx
pop rcx
pop rbx
pop rax
%endmacro
extern isr_handle
; Common handler for the ISRs
isr_common_format:
pushall
cld
mov rdi, rsp
xor rbp, rbp
call isr_handle
popall
add rsp, 24
iretq
%macro isr 1
global isr%1
isr%1:
push 0
push %1
push fs
jmp isr_common_format
%endmacro
%macro error_isr 1
global isr%1
isr%1:
push %1
push fs
jmp isr_common_format
%endmacro
%define has_errcode(i) (i == 8 || (i >= 10 && i <= 14) || i == 17 || i == 21 || i == 29 || i == 30)
; Define ISRs
%assign i 0
%rep 256
%if !has_errcode(i)
isr i
%else
error_isr i
%endif
%assign i i + 1
%endrep
-520
View File
@@ -1,520 +0,0 @@
// !!! THIS FILE IS AUTOGENERATED !!!
#include "idt.h"
#include "gdt.h"
void x86_64_ISR0();
void x86_64_ISR1();
void x86_64_ISR2();
void x86_64_ISR3();
void x86_64_ISR4();
void x86_64_ISR5();
void x86_64_ISR6();
void x86_64_ISR7();
void x86_64_ISR8();
void x86_64_ISR9();
void x86_64_ISR10();
void x86_64_ISR11();
void x86_64_ISR12();
void x86_64_ISR13();
void x86_64_ISR14();
void x86_64_ISR15();
void x86_64_ISR16();
void x86_64_ISR17();
void x86_64_ISR18();
void x86_64_ISR19();
void x86_64_ISR20();
void x86_64_ISR21();
void x86_64_ISR22();
void x86_64_ISR23();
void x86_64_ISR24();
void x86_64_ISR25();
void x86_64_ISR26();
void x86_64_ISR27();
void x86_64_ISR28();
void x86_64_ISR29();
void x86_64_ISR30();
void x86_64_ISR31();
void x86_64_ISR32();
void x86_64_ISR33();
void x86_64_ISR34();
void x86_64_ISR35();
void x86_64_ISR36();
void x86_64_ISR37();
void x86_64_ISR38();
void x86_64_ISR39();
void x86_64_ISR40();
void x86_64_ISR41();
void x86_64_ISR42();
void x86_64_ISR43();
void x86_64_ISR44();
void x86_64_ISR45();
void x86_64_ISR46();
void x86_64_ISR47();
void x86_64_ISR48();
void x86_64_ISR49();
void x86_64_ISR50();
void x86_64_ISR51();
void x86_64_ISR52();
void x86_64_ISR53();
void x86_64_ISR54();
void x86_64_ISR55();
void x86_64_ISR56();
void x86_64_ISR57();
void x86_64_ISR58();
void x86_64_ISR59();
void x86_64_ISR60();
void x86_64_ISR61();
void x86_64_ISR62();
void x86_64_ISR63();
void x86_64_ISR64();
void x86_64_ISR65();
void x86_64_ISR66();
void x86_64_ISR67();
void x86_64_ISR68();
void x86_64_ISR69();
void x86_64_ISR70();
void x86_64_ISR71();
void x86_64_ISR72();
void x86_64_ISR73();
void x86_64_ISR74();
void x86_64_ISR75();
void x86_64_ISR76();
void x86_64_ISR77();
void x86_64_ISR78();
void x86_64_ISR79();
void x86_64_ISR80();
void x86_64_ISR81();
void x86_64_ISR82();
void x86_64_ISR83();
void x86_64_ISR84();
void x86_64_ISR85();
void x86_64_ISR86();
void x86_64_ISR87();
void x86_64_ISR88();
void x86_64_ISR89();
void x86_64_ISR90();
void x86_64_ISR91();
void x86_64_ISR92();
void x86_64_ISR93();
void x86_64_ISR94();
void x86_64_ISR95();
void x86_64_ISR96();
void x86_64_ISR97();
void x86_64_ISR98();
void x86_64_ISR99();
void x86_64_ISR100();
void x86_64_ISR101();
void x86_64_ISR102();
void x86_64_ISR103();
void x86_64_ISR104();
void x86_64_ISR105();
void x86_64_ISR106();
void x86_64_ISR107();
void x86_64_ISR108();
void x86_64_ISR109();
void x86_64_ISR110();
void x86_64_ISR111();
void x86_64_ISR112();
void x86_64_ISR113();
void x86_64_ISR114();
void x86_64_ISR115();
void x86_64_ISR116();
void x86_64_ISR117();
void x86_64_ISR118();
void x86_64_ISR119();
void x86_64_ISR120();
void x86_64_ISR121();
void x86_64_ISR122();
void x86_64_ISR123();
void x86_64_ISR124();
void x86_64_ISR125();
void x86_64_ISR126();
void x86_64_ISR127();
void x86_64_ISR128();
void x86_64_ISR129();
void x86_64_ISR130();
void x86_64_ISR131();
void x86_64_ISR132();
void x86_64_ISR133();
void x86_64_ISR134();
void x86_64_ISR135();
void x86_64_ISR136();
void x86_64_ISR137();
void x86_64_ISR138();
void x86_64_ISR139();
void x86_64_ISR140();
void x86_64_ISR141();
void x86_64_ISR142();
void x86_64_ISR143();
void x86_64_ISR144();
void x86_64_ISR145();
void x86_64_ISR146();
void x86_64_ISR147();
void x86_64_ISR148();
void x86_64_ISR149();
void x86_64_ISR150();
void x86_64_ISR151();
void x86_64_ISR152();
void x86_64_ISR153();
void x86_64_ISR154();
void x86_64_ISR155();
void x86_64_ISR156();
void x86_64_ISR157();
void x86_64_ISR158();
void x86_64_ISR159();
void x86_64_ISR160();
void x86_64_ISR161();
void x86_64_ISR162();
void x86_64_ISR163();
void x86_64_ISR164();
void x86_64_ISR165();
void x86_64_ISR166();
void x86_64_ISR167();
void x86_64_ISR168();
void x86_64_ISR169();
void x86_64_ISR170();
void x86_64_ISR171();
void x86_64_ISR172();
void x86_64_ISR173();
void x86_64_ISR174();
void x86_64_ISR175();
void x86_64_ISR176();
void x86_64_ISR177();
void x86_64_ISR178();
void x86_64_ISR179();
void x86_64_ISR180();
void x86_64_ISR181();
void x86_64_ISR182();
void x86_64_ISR183();
void x86_64_ISR184();
void x86_64_ISR185();
void x86_64_ISR186();
void x86_64_ISR187();
void x86_64_ISR188();
void x86_64_ISR189();
void x86_64_ISR190();
void x86_64_ISR191();
void x86_64_ISR192();
void x86_64_ISR193();
void x86_64_ISR194();
void x86_64_ISR195();
void x86_64_ISR196();
void x86_64_ISR197();
void x86_64_ISR198();
void x86_64_ISR199();
void x86_64_ISR200();
void x86_64_ISR201();
void x86_64_ISR202();
void x86_64_ISR203();
void x86_64_ISR204();
void x86_64_ISR205();
void x86_64_ISR206();
void x86_64_ISR207();
void x86_64_ISR208();
void x86_64_ISR209();
void x86_64_ISR210();
void x86_64_ISR211();
void x86_64_ISR212();
void x86_64_ISR213();
void x86_64_ISR214();
void x86_64_ISR215();
void x86_64_ISR216();
void x86_64_ISR217();
void x86_64_ISR218();
void x86_64_ISR219();
void x86_64_ISR220();
void x86_64_ISR221();
void x86_64_ISR222();
void x86_64_ISR223();
void x86_64_ISR224();
void x86_64_ISR225();
void x86_64_ISR226();
void x86_64_ISR227();
void x86_64_ISR228();
void x86_64_ISR229();
void x86_64_ISR230();
void x86_64_ISR231();
void x86_64_ISR232();
void x86_64_ISR233();
void x86_64_ISR234();
void x86_64_ISR235();
void x86_64_ISR236();
void x86_64_ISR237();
void x86_64_ISR238();
void x86_64_ISR239();
void x86_64_ISR240();
void x86_64_ISR241();
void x86_64_ISR242();
void x86_64_ISR243();
void x86_64_ISR244();
void x86_64_ISR245();
void x86_64_ISR246();
void x86_64_ISR247();
void x86_64_ISR248();
void x86_64_ISR249();
void x86_64_ISR250();
void x86_64_ISR251();
void x86_64_ISR252();
void x86_64_ISR253();
void x86_64_ISR254();
void x86_64_ISR255();
void x86_64_ISR_InitializeGates()
{
x86_64_IDT_SetGate(0, x86_64_ISR0, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(1, x86_64_ISR1, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(2, x86_64_ISR2, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(3, x86_64_ISR3, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(4, x86_64_ISR4, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(5, x86_64_ISR5, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(6, x86_64_ISR6, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(7, x86_64_ISR7, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(8, x86_64_ISR8, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(9, x86_64_ISR9, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(10, x86_64_ISR10, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(11, x86_64_ISR11, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(12, x86_64_ISR12, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(13, x86_64_ISR13, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(14, x86_64_ISR14, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(15, x86_64_ISR15, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(16, x86_64_ISR16, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(17, x86_64_ISR17, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(18, x86_64_ISR18, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(19, x86_64_ISR19, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(20, x86_64_ISR20, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(21, x86_64_ISR21, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(22, x86_64_ISR22, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(23, x86_64_ISR23, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(24, x86_64_ISR24, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(25, x86_64_ISR25, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(26, x86_64_ISR26, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(27, x86_64_ISR27, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(28, x86_64_ISR28, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(29, x86_64_ISR29, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(30, x86_64_ISR30, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(31, x86_64_ISR31, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(32, x86_64_ISR32, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(33, x86_64_ISR33, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(34, x86_64_ISR34, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(35, x86_64_ISR35, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(36, x86_64_ISR36, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(37, x86_64_ISR37, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(38, x86_64_ISR38, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(39, x86_64_ISR39, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(40, x86_64_ISR40, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(41, x86_64_ISR41, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(42, x86_64_ISR42, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(43, x86_64_ISR43, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(44, x86_64_ISR44, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(45, x86_64_ISR45, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(46, x86_64_ISR46, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(47, x86_64_ISR47, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(48, x86_64_ISR48, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(49, x86_64_ISR49, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(50, x86_64_ISR50, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(51, x86_64_ISR51, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(52, x86_64_ISR52, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(53, x86_64_ISR53, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(54, x86_64_ISR54, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(55, x86_64_ISR55, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(56, x86_64_ISR56, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(57, x86_64_ISR57, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(58, x86_64_ISR58, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(59, x86_64_ISR59, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(60, x86_64_ISR60, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(61, x86_64_ISR61, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(62, x86_64_ISR62, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(63, x86_64_ISR63, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(64, x86_64_ISR64, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(65, x86_64_ISR65, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(66, x86_64_ISR66, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(67, x86_64_ISR67, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(68, x86_64_ISR68, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(69, x86_64_ISR69, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(70, x86_64_ISR70, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(71, x86_64_ISR71, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(72, x86_64_ISR72, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(73, x86_64_ISR73, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(74, x86_64_ISR74, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(75, x86_64_ISR75, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(76, x86_64_ISR76, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(77, x86_64_ISR77, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(78, x86_64_ISR78, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(79, x86_64_ISR79, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(80, x86_64_ISR80, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(81, x86_64_ISR81, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(82, x86_64_ISR82, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(83, x86_64_ISR83, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(84, x86_64_ISR84, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(85, x86_64_ISR85, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(86, x86_64_ISR86, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(87, x86_64_ISR87, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(88, x86_64_ISR88, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(89, x86_64_ISR89, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(90, x86_64_ISR90, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(91, x86_64_ISR91, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(92, x86_64_ISR92, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(93, x86_64_ISR93, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(94, x86_64_ISR94, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(95, x86_64_ISR95, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(96, x86_64_ISR96, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(97, x86_64_ISR97, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(98, x86_64_ISR98, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(99, x86_64_ISR99, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(100, x86_64_ISR100, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(101, x86_64_ISR101, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(102, x86_64_ISR102, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(103, x86_64_ISR103, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(104, x86_64_ISR104, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(105, x86_64_ISR105, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(106, x86_64_ISR106, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(107, x86_64_ISR107, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(108, x86_64_ISR108, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(109, x86_64_ISR109, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(110, x86_64_ISR110, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(111, x86_64_ISR111, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(112, x86_64_ISR112, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(113, x86_64_ISR113, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(114, x86_64_ISR114, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(115, x86_64_ISR115, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(116, x86_64_ISR116, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(117, x86_64_ISR117, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(118, x86_64_ISR118, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(119, x86_64_ISR119, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(120, x86_64_ISR120, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(121, x86_64_ISR121, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(122, x86_64_ISR122, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(123, x86_64_ISR123, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(124, x86_64_ISR124, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(125, x86_64_ISR125, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(126, x86_64_ISR126, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(127, x86_64_ISR127, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(128, x86_64_ISR128, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(129, x86_64_ISR129, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(130, x86_64_ISR130, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(131, x86_64_ISR131, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(132, x86_64_ISR132, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(133, x86_64_ISR133, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(134, x86_64_ISR134, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(135, x86_64_ISR135, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(136, x86_64_ISR136, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(137, x86_64_ISR137, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(138, x86_64_ISR138, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(139, x86_64_ISR139, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(140, x86_64_ISR140, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(141, x86_64_ISR141, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(142, x86_64_ISR142, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(143, x86_64_ISR143, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(144, x86_64_ISR144, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(145, x86_64_ISR145, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(146, x86_64_ISR146, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(147, x86_64_ISR147, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(148, x86_64_ISR148, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(149, x86_64_ISR149, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(150, x86_64_ISR150, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(151, x86_64_ISR151, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(152, x86_64_ISR152, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(153, x86_64_ISR153, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(154, x86_64_ISR154, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(155, x86_64_ISR155, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(156, x86_64_ISR156, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(157, x86_64_ISR157, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(158, x86_64_ISR158, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(159, x86_64_ISR159, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(160, x86_64_ISR160, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(161, x86_64_ISR161, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(162, x86_64_ISR162, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(163, x86_64_ISR163, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(164, x86_64_ISR164, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(165, x86_64_ISR165, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(166, x86_64_ISR166, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(167, x86_64_ISR167, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(168, x86_64_ISR168, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(169, x86_64_ISR169, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(170, x86_64_ISR170, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(171, x86_64_ISR171, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(172, x86_64_ISR172, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(173, x86_64_ISR173, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(174, x86_64_ISR174, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(175, x86_64_ISR175, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(176, x86_64_ISR176, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(177, x86_64_ISR177, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(178, x86_64_ISR178, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(179, x86_64_ISR179, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(180, x86_64_ISR180, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(181, x86_64_ISR181, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(182, x86_64_ISR182, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(183, x86_64_ISR183, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(184, x86_64_ISR184, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(185, x86_64_ISR185, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(186, x86_64_ISR186, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(187, x86_64_ISR187, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(188, x86_64_ISR188, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(189, x86_64_ISR189, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(190, x86_64_ISR190, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(191, x86_64_ISR191, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(192, x86_64_ISR192, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(193, x86_64_ISR193, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(194, x86_64_ISR194, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(195, x86_64_ISR195, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(196, x86_64_ISR196, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(197, x86_64_ISR197, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(198, x86_64_ISR198, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(199, x86_64_ISR199, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(200, x86_64_ISR200, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(201, x86_64_ISR201, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(202, x86_64_ISR202, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(203, x86_64_ISR203, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(204, x86_64_ISR204, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(205, x86_64_ISR205, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(206, x86_64_ISR206, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(207, x86_64_ISR207, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(208, x86_64_ISR208, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(209, x86_64_ISR209, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(210, x86_64_ISR210, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(211, x86_64_ISR211, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(212, x86_64_ISR212, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(213, x86_64_ISR213, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(214, x86_64_ISR214, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(215, x86_64_ISR215, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(216, x86_64_ISR216, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(217, x86_64_ISR217, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(218, x86_64_ISR218, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(219, x86_64_ISR219, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(220, x86_64_ISR220, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(221, x86_64_ISR221, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(222, x86_64_ISR222, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(223, x86_64_ISR223, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(224, x86_64_ISR224, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(225, x86_64_ISR225, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(226, x86_64_ISR226, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(227, x86_64_ISR227, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(228, x86_64_ISR228, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(229, x86_64_ISR229, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(230, x86_64_ISR230, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(231, x86_64_ISR231, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(232, x86_64_ISR232, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(233, x86_64_ISR233, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(234, x86_64_ISR234, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(235, x86_64_ISR235, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(236, x86_64_ISR236, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(237, x86_64_ISR237, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(238, x86_64_ISR238, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(239, x86_64_ISR239, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(240, x86_64_ISR240, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(241, x86_64_ISR241, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(242, x86_64_ISR242, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(243, x86_64_ISR243, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(244, x86_64_ISR244, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(245, x86_64_ISR245, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(246, x86_64_ISR246, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(247, x86_64_ISR247, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(248, x86_64_ISR248, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(249, x86_64_ISR249, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(250, x86_64_ISR250, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(251, x86_64_ISR251, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(252, x86_64_ISR252, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(253, x86_64_ISR253, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(254, x86_64_ISR254, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
x86_64_IDT_SetGate(255, x86_64_ISR255, GDT_KERNEL_CODE64, IDT_FLAG_RING0 | IDT_FLAG_GATE_32BIT_INT);
}
-256
View File
@@ -1,256 +0,0 @@
ISR_NOERRORCODE 0
ISR_NOERRORCODE 1
ISR_NOERRORCODE 2
ISR_NOERRORCODE 3
ISR_NOERRORCODE 4
ISR_NOERRORCODE 5
ISR_NOERRORCODE 6
ISR_NOERRORCODE 7
ISR_ERRORCODE 8
ISR_NOERRORCODE 9
ISR_ERRORCODE 10
ISR_ERRORCODE 11
ISR_ERRORCODE 12
ISR_ERRORCODE 13
ISR_ERRORCODE 14
ISR_NOERRORCODE 15
ISR_NOERRORCODE 16
ISR_ERRORCODE 17
ISR_NOERRORCODE 18
ISR_NOERRORCODE 19
ISR_NOERRORCODE 20
ISR_ERRORCODE 21
ISR_NOERRORCODE 22
ISR_NOERRORCODE 23
ISR_NOERRORCODE 24
ISR_NOERRORCODE 25
ISR_NOERRORCODE 26
ISR_NOERRORCODE 27
ISR_NOERRORCODE 28
ISR_NOERRORCODE 29
ISR_NOERRORCODE 30
ISR_NOERRORCODE 31
ISR_NOERRORCODE 32
ISR_NOERRORCODE 33
ISR_NOERRORCODE 34
ISR_NOERRORCODE 35
ISR_NOERRORCODE 36
ISR_NOERRORCODE 37
ISR_NOERRORCODE 38
ISR_NOERRORCODE 39
ISR_NOERRORCODE 40
ISR_NOERRORCODE 41
ISR_NOERRORCODE 42
ISR_NOERRORCODE 43
ISR_NOERRORCODE 44
ISR_NOERRORCODE 45
ISR_NOERRORCODE 46
ISR_NOERRORCODE 47
ISR_NOERRORCODE 48
ISR_NOERRORCODE 49
ISR_NOERRORCODE 50
ISR_NOERRORCODE 51
ISR_NOERRORCODE 52
ISR_NOERRORCODE 53
ISR_NOERRORCODE 54
ISR_NOERRORCODE 55
ISR_NOERRORCODE 56
ISR_NOERRORCODE 57
ISR_NOERRORCODE 58
ISR_NOERRORCODE 59
ISR_NOERRORCODE 60
ISR_NOERRORCODE 61
ISR_NOERRORCODE 62
ISR_NOERRORCODE 63
ISR_NOERRORCODE 64
ISR_NOERRORCODE 65
ISR_NOERRORCODE 66
ISR_NOERRORCODE 67
ISR_NOERRORCODE 68
ISR_NOERRORCODE 69
ISR_NOERRORCODE 70
ISR_NOERRORCODE 71
ISR_NOERRORCODE 72
ISR_NOERRORCODE 73
ISR_NOERRORCODE 74
ISR_NOERRORCODE 75
ISR_NOERRORCODE 76
ISR_NOERRORCODE 77
ISR_NOERRORCODE 78
ISR_NOERRORCODE 79
ISR_NOERRORCODE 80
ISR_NOERRORCODE 81
ISR_NOERRORCODE 82
ISR_NOERRORCODE 83
ISR_NOERRORCODE 84
ISR_NOERRORCODE 85
ISR_NOERRORCODE 86
ISR_NOERRORCODE 87
ISR_NOERRORCODE 88
ISR_NOERRORCODE 89
ISR_NOERRORCODE 90
ISR_NOERRORCODE 91
ISR_NOERRORCODE 92
ISR_NOERRORCODE 93
ISR_NOERRORCODE 94
ISR_NOERRORCODE 95
ISR_NOERRORCODE 96
ISR_NOERRORCODE 97
ISR_NOERRORCODE 98
ISR_NOERRORCODE 99
ISR_NOERRORCODE 100
ISR_NOERRORCODE 101
ISR_NOERRORCODE 102
ISR_NOERRORCODE 103
ISR_NOERRORCODE 104
ISR_NOERRORCODE 105
ISR_NOERRORCODE 106
ISR_NOERRORCODE 107
ISR_NOERRORCODE 108
ISR_NOERRORCODE 109
ISR_NOERRORCODE 110
ISR_NOERRORCODE 111
ISR_NOERRORCODE 112
ISR_NOERRORCODE 113
ISR_NOERRORCODE 114
ISR_NOERRORCODE 115
ISR_NOERRORCODE 116
ISR_NOERRORCODE 117
ISR_NOERRORCODE 118
ISR_NOERRORCODE 119
ISR_NOERRORCODE 120
ISR_NOERRORCODE 121
ISR_NOERRORCODE 122
ISR_NOERRORCODE 123
ISR_NOERRORCODE 124
ISR_NOERRORCODE 125
ISR_NOERRORCODE 126
ISR_NOERRORCODE 127
ISR_NOERRORCODE 128
ISR_NOERRORCODE 129
ISR_NOERRORCODE 130
ISR_NOERRORCODE 131
ISR_NOERRORCODE 132
ISR_NOERRORCODE 133
ISR_NOERRORCODE 134
ISR_NOERRORCODE 135
ISR_NOERRORCODE 136
ISR_NOERRORCODE 137
ISR_NOERRORCODE 138
ISR_NOERRORCODE 139
ISR_NOERRORCODE 140
ISR_NOERRORCODE 141
ISR_NOERRORCODE 142
ISR_NOERRORCODE 143
ISR_NOERRORCODE 144
ISR_NOERRORCODE 145
ISR_NOERRORCODE 146
ISR_NOERRORCODE 147
ISR_NOERRORCODE 148
ISR_NOERRORCODE 149
ISR_NOERRORCODE 150
ISR_NOERRORCODE 151
ISR_NOERRORCODE 152
ISR_NOERRORCODE 153
ISR_NOERRORCODE 154
ISR_NOERRORCODE 155
ISR_NOERRORCODE 156
ISR_NOERRORCODE 157
ISR_NOERRORCODE 158
ISR_NOERRORCODE 159
ISR_NOERRORCODE 160
ISR_NOERRORCODE 161
ISR_NOERRORCODE 162
ISR_NOERRORCODE 163
ISR_NOERRORCODE 164
ISR_NOERRORCODE 165
ISR_NOERRORCODE 166
ISR_NOERRORCODE 167
ISR_NOERRORCODE 168
ISR_NOERRORCODE 169
ISR_NOERRORCODE 170
ISR_NOERRORCODE 171
ISR_NOERRORCODE 172
ISR_NOERRORCODE 173
ISR_NOERRORCODE 174
ISR_NOERRORCODE 175
ISR_NOERRORCODE 176
ISR_NOERRORCODE 177
ISR_NOERRORCODE 178
ISR_NOERRORCODE 179
ISR_NOERRORCODE 180
ISR_NOERRORCODE 181
ISR_NOERRORCODE 182
ISR_NOERRORCODE 183
ISR_NOERRORCODE 184
ISR_NOERRORCODE 185
ISR_NOERRORCODE 186
ISR_NOERRORCODE 187
ISR_NOERRORCODE 188
ISR_NOERRORCODE 189
ISR_NOERRORCODE 190
ISR_NOERRORCODE 191
ISR_NOERRORCODE 192
ISR_NOERRORCODE 193
ISR_NOERRORCODE 194
ISR_NOERRORCODE 195
ISR_NOERRORCODE 196
ISR_NOERRORCODE 197
ISR_NOERRORCODE 198
ISR_NOERRORCODE 199
ISR_NOERRORCODE 200
ISR_NOERRORCODE 201
ISR_NOERRORCODE 202
ISR_NOERRORCODE 203
ISR_NOERRORCODE 204
ISR_NOERRORCODE 205
ISR_NOERRORCODE 206
ISR_NOERRORCODE 207
ISR_NOERRORCODE 208
ISR_NOERRORCODE 209
ISR_NOERRORCODE 210
ISR_NOERRORCODE 211
ISR_NOERRORCODE 212
ISR_NOERRORCODE 213
ISR_NOERRORCODE 214
ISR_NOERRORCODE 215
ISR_NOERRORCODE 216
ISR_NOERRORCODE 217
ISR_NOERRORCODE 218
ISR_NOERRORCODE 219
ISR_NOERRORCODE 220
ISR_NOERRORCODE 221
ISR_NOERRORCODE 222
ISR_NOERRORCODE 223
ISR_NOERRORCODE 224
ISR_NOERRORCODE 225
ISR_NOERRORCODE 226
ISR_NOERRORCODE 227
ISR_NOERRORCODE 228
ISR_NOERRORCODE 229
ISR_NOERRORCODE 230
ISR_NOERRORCODE 231
ISR_NOERRORCODE 232
ISR_NOERRORCODE 233
ISR_NOERRORCODE 234
ISR_NOERRORCODE 235
ISR_NOERRORCODE 236
ISR_NOERRORCODE 237
ISR_NOERRORCODE 238
ISR_NOERRORCODE 239
ISR_NOERRORCODE 240
ISR_NOERRORCODE 241
ISR_NOERRORCODE 242
ISR_NOERRORCODE 243
ISR_NOERRORCODE 244
ISR_NOERRORCODE 245
ISR_NOERRORCODE 246
ISR_NOERRORCODE 247
ISR_NOERRORCODE 248
ISR_NOERRORCODE 249
ISR_NOERRORCODE 250
ISR_NOERRORCODE 251
ISR_NOERRORCODE 252
ISR_NOERRORCODE 253
ISR_NOERRORCODE 254
ISR_NOERRORCODE 255
+11 -11
View File
@@ -1,7 +1,7 @@
#include "ata.h"
#include "arch/x86_64/cpu/io.h"
#include "libk/stdio.h"
#include <stdbool.h>
#include "libk/debug.h"
@@ -56,7 +56,7 @@ void ata_init(void)
ata_wait_ready();
x86_64_outb(ATA_PRIMARY_DRIVE, 0xA0); // select master
ata_wait_ready();
printf("ATA: Primary master (hda) initialized\n");
kprintf("ATA: Primary master (hda) initialized\n");
}
void ata_identify(void)
@@ -71,30 +71,30 @@ void ata_identify(void)
x86_64_outb(ATA_PRIMARY_COMMAND, ATA_CMD_IDENTIFY);
if (x86_64_inb(ATA_PRIMARY_STATUS) == 0) {
printf("ATA: No primary master drive detected\n");
kprintf("ATA: No primary master drive detected\n");
return;
}
if (!ata_poll()) {
printf("ATA poll failed at ATA_IDENTIFY\n");
kprintf("ATA poll failed at ATA_IDENTIFY\n");
}
if (x86_64_inb(ATA_PRIMARY_STATUS) & ATA_STATUS_ERR) {
printf("ATA: Identify error\n");
kprintf("ATA: Identify error\n");
return;
}
x86_64_insw(ATA_PRIMARY_DATA, buffer, 256);
printf("ATA: Disk model: ");
kprintf("ATA: Disk model: ");
for (int i = 27; i <= 46; i++) {
uint16_t w = buffer[i];
char high = w >> 8;
char low = w & 0xFF;
printf("%c%c", high, low); // swap bytes
kprintf("%c%c", high, low); // swap bytes
}
printf("\n");
printf("ATA: Total sectors: %lu\n", (uint64_t)buffer[60] | ((uint64_t)buffer[61] << 16));
kprintf("\n");
kprintf("ATA: Total sectors: %lu\n", (uint64_t)buffer[60] | ((uint64_t)buffer[61] << 16));
}
bool ata_read_sectors(uint64_t lba, uint8_t sector_count, void* buffer)
@@ -114,11 +114,11 @@ bool ata_read_sectors(uint64_t lba, uint8_t sector_count, void* buffer)
uint16_t* buf = buffer;
for (uint8_t i = 0; i < sector_count; i++) {
if (!ata_poll()) {
printf("ATA poll failed at ATA_read_sectors\n");
kprintf("ATA poll failed at ATA_read_sectors\n");
}
if (x86_64_inb(ATA_PRIMARY_STATUS) & ATA_STATUS_ERR) {
printf("ATA read error at LBA %lu\n", lba + i);
kprintf("ATA read error at LBA %lu\n", lba + i);
return false;
}
+61
View File
@@ -0,0 +1,61 @@
#pragma once
#include <stdint.h>
#include "arch/x86_64/asm/asm.h"
static inline void mmoutb(void *addr, uint8_t value) {
asm volatile("mov %0, %1\n\t"
: "=m"(BYTE_PTR(addr))
: "r"(value)
: "memory");
}
static inline void mmoutw(void *addr, uint16_t value) {
asm volatile("mov %0, %1\n\t"
: "=m"(WORD_PTR(addr))
: "r"(value)
: "memory");
}
static inline void mmoutd(void *addr, uint32_t value) {
asm volatile("mov %0, %1\n\t"
: "=m"(DWORD_PTR(addr))
: "r"(value)
: "memory");
}
static inline void mmoutq(void *addr, uint64_t value) {
asm volatile("mov %0, %1\n\t"
: "=m"(QWORD_PTR(addr))
: "r"(value)
: "memory");
}
static inline uint8_t mminb(void *addr) {
uint8_t ret;
asm volatile("mov %0, %1\n\t" : "=r"(ret) : "m"(BYTE_PTR(addr)) : "memory");
return ret;
}
static inline uint16_t mminw(void *addr) {
uint16_t ret;
asm volatile("mov %0, %1\n\t" : "=r"(ret) : "m"(WORD_PTR(addr)) : "memory");
return ret;
}
static inline uint32_t mmind(void *addr) {
uint32_t ret;
asm volatile("mov %0, %1\n\t"
: "=r"(ret)
: "m"(DWORD_PTR(addr))
: "memory");
return ret;
}
static inline uint64_t mminq(void *addr) {
uint64_t ret;
asm volatile("mov %0, %1\n\t"
: "=r"(ret)
: "m"(QWORD_PTR(addr))
: "memory");
return ret;
}
+3 -3
View File
@@ -1,6 +1,6 @@
#include "pci.h"
#include "arch/x86_64/cpu/io.h"
#include "libk/stdio.h"
#include "libk/debug.h"
#define PCI_CFG_ADDR 0x0CF8
#define PCI_CFG_DATA 0x0CFC
@@ -69,7 +69,7 @@ static void pci_read_bars(pci_device_t* dev)
void pci_init(void)
{
printf("[PCI] Scanning bus 0...\n");
kprintf("[PCI] Scanning bus 0...\n");
pci_print_all();
}
@@ -101,7 +101,7 @@ void pci_print_all(void)
};
pci_read_bars(&d);
printf("[PCI] %02x:%02x.%x %04x:%04x class %04x rev %02x\n",
kprintf("[PCI] %02x:%02x.%x %04x:%04x class %04x rev %02x\n",
bus, dev, func, vendor, device_id, class_sub, revision);
if (func == 0 && (pci_read8(addr, 0x0E) & 0x80) == 0)
+63
View File
@@ -0,0 +1,63 @@
section .text
extern syscall_handler
global amd_syscall_entry
amd_syscall_entry:
swapgs
mov qword [gs:0016], rsp
mov rsp, qword [gs:0008]
push 0x1b ; ss
push qword [gs:0016] ; rsp
push r11 ; rflags
push 0x23 ; cs
push rcx ; rip
sub rsp, 24
push rax
push rbx
push rcx
push rdx
push rbp
push rdi
push rsi
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
mov rdi, rsp
sti
call syscall_handler
cli
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rsi
pop rdi
pop rbp
pop rdx
pop rcx
pop rbx
pop rax
add rsp, 24
mov rsp, qword [gs:0016]
swapgs
o64 sysret
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#define write_cr(reg, val) \
asm volatile("mov cr" reg ", %0" ::"r"(val) : "memory");
#define read_cr(reg) \
({ \
size_t cr; \
asm volatile("mov %0, cr" reg : "=r"(cr)::"memory"); \
cr; \
})
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#define CPUID_INVARIANT_TSC (1 << 8)
#define CPUID_TSC_DEADLINE (1 << 24)
#define CPUID_SMEP (1 << 7)
#define CPUID_SMAP (1 << 20)
#define CPUID_UMIP (1 << 2)
#define CPUID_X2APIC (1 << 21)
#define CPUID_GBPAGE (1 << 26)
+1 -1
View File
@@ -13,4 +13,4 @@ void x86_64_iowait(void);
void x86_64_Panic(void) __attribute__((noreturn));
void x86_64_EnableInterrupts(void);
void x86_64_DisableInterrupts(void);
void x86_64_crashme(void);
void x86_64_crashme(void);
@@ -1,96 +1,102 @@
.intel_syntax noprefix
section .text
.global x86_64_outb
global x86_64_outb
x86_64_outb:
mov dx, di
mov al, sil
out dx, al
ret
.global x86_64_inb
global x86_64_inb
x86_64_inb:
mov dx, di
xor eax, eax
in al, dx
ret
.global x86_64_inw
global x86_64_inw
x86_64_inw:
mov dx, di
xor eax, eax
in ax, dx
ret
.global x86_64_outw
global x86_64_outw
x86_64_outw:
mov dx, di
mov ax, si
out dx, ax
ret
.global x86_64_outl
global x86_64_outl
x86_64_outl:
mov dx, di
mov eax, esi
out dx, eax
ret
.global x86_64_inl
global x86_64_inl
x86_64_inl:
mov dx, di
xor eax, eax
in eax, dx
ret
.global x86_64_insw
global x86_64_insw
x86_64_insw:
test rdx, rdx
jz .inswdone
jz .done
mov rcx, rdx
mov dx, di
mov rdi, rsi
cld
rep insw
.inswdone:
.done:
ret
.global x86_64_outsw
global x86_64_outsw
x86_64_outsw:
test rdx, rdx
jz .outswdone
jz .done
mov rcx, rdx
mov dx, di
mov rsi, rsi
; RSI already contains source pointer
cld
rep outsw
.outswdone:
.done:
ret
.global x86_64_Panic
global x86_64_Panic
x86_64_Panic:
cli
hlt
1: jmp 1b
.global x86_64_EnableInterrupts
.hang:
jmp .hang
global x86_64_EnableInterrupts
x86_64_EnableInterrupts:
sti
ret
.global x86_64_DisableInterrupts
global x86_64_DisableInterrupts
x86_64_DisableInterrupts:
cli
ret
.global x86_64_iowait
global x86_64_iowait
x86_64_iowait:
out 0x80, al // classic I/O wait
out 0x80, al ; classic I/O wait
ret
.global x86_64_crashme
global x86_64_crashme
x86_64_crashme:
xor rdx, rdx
mov rax, 1
mov rbx, 0
xor rbx, rbx
div rbx
ret
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
static inline uint64_t rdmsr(uint32_t msr) {
uint32_t edx, eax;
asm volatile("rdmsr" : "=a"(eax), "=d"(edx) : "c"(msr) : "memory");
return ((uint64_t)edx << 32) | eax;
}
static inline void wrmsr(uint32_t msr, uint64_t value) {
uint32_t edx = value >> 32;
uint32_t eax = (uint32_t)value;
asm volatile("wrmsr" ::"a"(eax), "c"(msr), "d"(edx) : "memory");
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <stdint.h>
typedef struct {
uint64_t r15;
uint64_t r14;
uint64_t r13;
uint64_t r12;
uint64_t r11;
uint64_t r10;
uint64_t r9;
uint64_t r8;
uint64_t rsi;
uint64_t rdi;
uint64_t rbp;
uint64_t rdx;
uint64_t rcx;
uint64_t rbx;
uint64_t rax;
uint64_t core;
uint64_t isrNumber;
uint64_t errorCode;
uint64_t rip;
uint64_t cs;
uint64_t rflags;
uint64_t rsp;
uint64_t ss;
} __attribute__((packed)) registers_t;
+85
View File
@@ -0,0 +1,85 @@
#include "mp/mp.h"
#include "libk/debug.h"
#include "libk/errno.h"
#include "mm/vmm.h"
#include "sched/sched.h"
#include "sched/syscall.h"
#include "arch/x86_64/boot/isr.h"
#include "arch/x86_64/sys/prcb.h"
void syscall_handler(registers_t *reg) {
cli();
prcb_return_current_cpu()->running_thread->reg = *reg;
prcb_return_current_cpu()->running_thread->stack =
prcb_return_current_cpu()->user_stack;
prcb_return_current_cpu()->fpu_save(
prcb_return_current_cpu()->running_thread->fpu_storage);
sti();
struct syscall_arguments args = {.syscall_nr = reg->rax,
.args0 = reg->rdi,
.args1 = reg->rsi,
.args2 = reg->rdx,
.args3 = reg->r10,
.args4 = reg->r8,
.args5 = reg->r9,
.ret = reg->rax};
syscall_handle(&args);
int64_t ret = (int64_t)args.ret;
if (ret < 0) {
ret = -((int)errno);
reg->rax = ret;
} else
reg->rax = args.ret;
}
void syscall_install_handler(void) {
isr_register_handler(0x80, syscall_handler);
}
uint64_t syscall_helper_user_to_kernel_address(uintptr_t user_addr) {
struct process *proc = sched_get_running_thread()->mother_proc;
struct pagemap *target_pagemap = proc->process_pagemap;
uint64_t kernel_addr = vmm_virt_to_kernel(target_pagemap, user_addr);
return kernel_addr;
}
bool syscall_helper_copy_to_user(uintptr_t user_addr, void *buffer,
size_t count) {
vmm_switch_pagemap(kernel_pagemap);
struct process *proc = sched_get_running_thread()->mother_proc;
struct pagemap *target_pagemap = proc->process_pagemap;
uint64_t kernel_addr = vmm_virt_to_kernel(target_pagemap, user_addr);
if (!kernel_addr) {
errno = EFAULT;
return false;
}
memcpy((void *)kernel_addr, buffer, count);
vmm_switch_pagemap(target_pagemap);
return true;
}
bool syscall_helper_copy_from_user(uintptr_t user_addr, void *buffer,
size_t count) {
vmm_switch_pagemap(kernel_pagemap);
struct process *proc = sched_get_running_thread()->mother_proc;
struct pagemap *target_pagemap = proc->process_pagemap;
uint64_t kernel_addr = vmm_virt_to_kernel(target_pagemap, user_addr);
if (!kernel_addr) {
errno = EFAULT;
return false;
}
memcpy(buffer, (void *)kernel_addr, count);
vmm_switch_pagemap(target_pagemap);
return true;
}
-131
View File
@@ -1,131 +0,0 @@
#include <stdint.h>
#include "libk/string.h"
#include "mm/pmm.h"
#include "mm/vmm.h"
#include "mm/memory.h"
#include "libk/stdio.h"
#include "fs/elf.h"
#include "sched/scheduler.h"
extern uintptr_t g_hhdm_offset;
#define USER_STACK_TOP 0x00007FFFFFFFE000ULL
#define USER_STACK_PAGES 8
#define USER_STACK_SIZE (USER_STACK_PAGES * PAGE_SIZE)
static uint64_t user_stack_phys_base = 0;
//extern struct pagemap *kernel_pagemap;
struct pagemap *create_user_pagemap(void)
{
struct pagemap *pm = kmalloc(sizeof(struct pagemap));
if (!pm) {
printf("Failed to allocate user pagemap struct!\n");
return NULL;
}
spinlock_init(&pm->lock);
/* Allocate a fresh PML4 (physical page) */
pm->top_level = (uint64_t *)((uintptr_t)pmm_allocz(1) + MEM_PHYS_OFFSET);
if (!pm->top_level) {
printf("Failed to allocate user PML4!\n");
kfree(pm);
return NULL;
}
/* Copy kernel higher-half mappings (kernel + HHDM) */
for (size_t i = 0; i < 512; i++) {
pm->top_level[i] = kernel_pagemap->top_level[i];
}
for (size_t i = 0; i < 256; i++) {
pm->top_level[i] = 0;
}
/* Lower half remains zero (user address space) */
printf("[usermode] user pagemap created (PML4 phys = 0x%lx)\n",
(uint64_t)pm->top_level - MEM_PHYS_OFFSET);
return pm;
}
uintptr_t setup_user_stack(struct pagemap *pagemap)
{
user_stack_phys_base = (uint64_t)pmm_allocz(USER_STACK_PAGES);
if (!user_stack_phys_base) {
printf("Failed to allocate user stack pages!\n");
for (;;);
}
uintptr_t stack_bottom = USER_STACK_TOP - USER_STACK_SIZE;
for (int i = 0; i < USER_STACK_PAGES; i++) {
uintptr_t virt = stack_bottom + i * PAGE_SIZE;
uintptr_t phys = user_stack_phys_base + i * PAGE_SIZE;
if (!vmm_map_page(pagemap,
virt,
phys,
PAGE_READ | PAGE_WRITE | PAGE_USER,
Size4KiB))
{
printf("Failed mapping user stack page\n");
for (;;);
}
}
uintptr_t rsp = USER_STACK_TOP;
rsp &= ~0xFULL;
return rsp;
}
void start_userspace(void)
{
struct pagemap *user_pagemap = create_user_pagemap();
if (!user_pagemap) {
printf("Failed to create user pagemap\n");
for (;;);
}
void *elf_entry = NULL;
uint64_t tls_fs_base = 0;
uint64_t phdr_va = 0;
uint16_t phent = 0;
uint16_t phnum = 0;
if (!ELF_Read("helloworld.elf",
&elf_entry,
user_pagemap,
&tls_fs_base,
&phdr_va,
&phent,
&phnum)) {
printf("Failed to load helloworld.elf\n");
for(;;);
}
printf("ELF: entry=0x%lx TLS_FS=0x%lx PHDR=0x%lx PHENT=0x%x PHNUM=%u\n",
(uint64_t)elf_entry, tls_fs_base, phdr_va, phent, phnum);
uintptr_t user_rsp = setup_user_stack(user_pagemap);
printf("Entering usermode RIP=%p RSP=%p\n", elf_entry, (void*)user_rsp);
sched_create_user_task("init",
(uint64_t)elf_entry,
user_rsp,
user_pagemap,
tls_fs_base,
phdr_va,
phent,
phnum);
}
-4
View File
@@ -1,4 +0,0 @@
#pragma once
#include <stdint.h>
void start_userspace(void);
+54
View File
@@ -0,0 +1,54 @@
#include "libk/debug.h"
#include <stddef.h>
#include "mm/vmm.h"
void backtrace(uintptr_t *bp) {
kprintf("Stack trace:\n");
uintptr_t *rbp = (uintptr_t *)bp;
if (rbp == NULL)
asm volatile("mov %%rbp, %0" : "=g"(rbp)::"memory");
if (rbp == NULL || (uintptr_t)(rbp) < MEM_PHYS_OFFSET)
return;
for (;;) {
uintptr_t *old_rbp = (uintptr_t *)rbp[0];
uintptr_t *rip = (uintptr_t *)rbp[1];
if (rip == NULL || old_rbp == NULL ||
((uintptr_t)rip) < MEM_PHYS_OFFSET)
break;
kprintf("%p\n", rip);
rbp = old_rbp;
}
kprintf("Kernel base: %p Mem phys base: %p\n", KERNEL_BASE,
MEM_PHYS_OFFSET);
}
void backtrace_unsafe(uintptr_t *bp) {
kprintf("Stack trace:\n");
uintptr_t *rbp = (uintptr_t *)bp;
if (rbp == NULL)
asm volatile("mov %%rbp, %0" : "=g"(rbp)::"memory");
if (rbp == NULL)
return;
for (;;) {
uintptr_t *old_rbp = (uintptr_t *)rbp[0];
uintptr_t *rip = (uintptr_t *)rbp[1];
if (rip == NULL || old_rbp == NULL)
break;
kprintf("%p\n", rip);
rbp = old_rbp;
}
}
View File
+153
View File
@@ -0,0 +1,153 @@
#include <stddef.h>
#include <stdint.h>
#include "arch/x86_64/boot/isr.h"
#include "libk/debug.h"
#include "arch/x86_64/sys/halt.h"
#include "mp/mp.h"
#include "sched/sched.h"
#include "arch/x86_64/serial/serial.h"
static void backtrace_dump(registers_t *reg) {
kprintffos(0, "============ Backtrace ==========\n");
kprintffos(0, "-> %p\n", reg->rip);
uintptr_t *rbp = (uintptr_t *)reg->rbp;
if (rbp == NULL)
asm volatile("mov %%rbp, %0" : "=g"(rbp)::"memory");
if (rbp == NULL)
return;
for (;;) {
uintptr_t *old_rbp = (uintptr_t *)rbp[0];
uintptr_t *rip = (uintptr_t *)rbp[1];
if (rip == NULL || old_rbp == NULL)
break;
kprintffos(0, "%p\n", rip);
rbp = old_rbp;
}
kprintffos(0, "============ End of dumps ==========\n");
}
static void register_dump(registers_t *reg) {
kprintffos(0, "========= Register dumps =========\n");
kprintffos(0, "RIP: %p RBP: %p RSP: %p\n", reg->rip, reg->rbp, reg->rsp);
kprintffos(0, "RAX: %p RBX: %p RCX: %p\n", reg->rax, reg->rbx, reg->rcx);
kprintffos(0, "RDX: %p RDI: %p RSI: %p\n", reg->rdx, reg->rdi, reg->rsi);
kprintffos(0, "R8 : %p R9 : %p R10: %p\n", reg->r8, reg->r9, reg->r10);
kprintffos(0, "R11: %p R12: %p R13: %p\n", reg->r11, reg->r12, reg->r13);
kprintffos(0, "R14: %p R15: %p\n", reg->r14, reg->r15);
kprintffos(0, "CS : %p SS : %p RFLAGS: %p\n", reg->cs, reg->ss,
reg->rflags);
kprintffos(0, "FS: %p UGS: %p KGS: %p\n", read_fs_base(), read_user_gs(),
read_kernel_gs());
kprintffos(0, "============ End of dumps ==========\n");
}
static void tss_dump(void) {
kprintffos(0, "============ TSS Dumps ==========\n");
kprintffos(0, "tss.rsp0: %p\n", prcb_return_current_cpu()->cpu_tss.rsp0);
kprintffos(0, "tss.rsp1: %p\n", prcb_return_current_cpu()->cpu_tss.rsp1);
kprintffos(0, "tss.rsp2: %p\n", prcb_return_current_cpu()->cpu_tss.rsp2);
kprintffos(0, "tss.ist1: %p\n", prcb_return_current_cpu()->cpu_tss.ist1);
kprintffos(0, "tss.ist2: %p\n", prcb_return_current_cpu()->cpu_tss.ist2);
kprintffos(0, "tss.ist3: %p\n", prcb_return_current_cpu()->cpu_tss.ist3);
kprintffos(0, "tss.ist4: %p\n", prcb_return_current_cpu()->cpu_tss.ist4);
kprintffos(0, "tss.ist5: %p\n", prcb_return_current_cpu()->cpu_tss.ist5);
kprintffos(0, "tss.ist6: %p\n", prcb_return_current_cpu()->cpu_tss.ist6);
kprintffos(0, "tss.ist7: %p\n", prcb_return_current_cpu()->cpu_tss.ist7);
kprintffos(0, "tss.iomap_base: %p\n",
prcb_return_current_cpu()->cpu_tss.iomap_base);
kprintffos(0, "============ End of dumps ==========\n");
}
static void prcb_dump(void) {
kprintffos(0, "============ PRCB Dumps ==========\n");
kprintffos(0, "prcb->cpu_number: %u\n",
prcb_return_current_cpu()->cpu_number);
kprintffos(0, "prcb->kernel_stack: %p\n",
prcb_return_current_cpu()->kernel_stack);
kprintffos(0, "prcb->user_stack: %p\n",
prcb_return_current_cpu()->user_stack);
kprintffos(0, "prcb->running_thread: %p\n",
prcb_return_current_cpu()->running_thread);
kprintffos(0, "prcb->sched_ticks: %p\n",
prcb_return_current_cpu()->user_stack);
kprintffos(0, "prcb->lapic_id: %u\n", prcb_return_current_cpu()->lapic_id);
kprintffos(0, "prcb->fpu_storage_size: %p\n",
prcb_return_current_cpu()->fpu_storage_size);
kprintffos(0, "prcb->fpu_save: %p\n", prcb_return_current_cpu()->fpu_save);
kprintffos(0, "prcb->fpu_restore: %p\n",
prcb_return_current_cpu()->fpu_restore);
kprintffos(0, "============ End of dumps ==========\n");
}
void breakpoint_handler(registers_t *reg) {
if (reg->cs & 0x3) {
kprintffos(0, "Breakpoint hit in user!\n");
thread_kill(prcb_return_current_cpu()->running_thread, true);
return;
} else {
kprintffos(0, "Breakpoint hit in kernel!\n");
}
pause_other_cpus();
kprintffos(0, "=========== Start of dumps =========\n");
kprintffos(0, "Breakpoint hit on CPU%u\n",
prcb_return_current_cpu()->cpu_number);
kprintffos(0, "========= Register dumps =========\n");
kprintffos(0, "RIP: %p RBP: %p RSP: %p\n", reg->rip, reg->rbp, reg->rsp);
kprintffos(0, "RAX: %p RBX: %p RCX: %p\n", reg->rax, reg->rbx, reg->rcx);
kprintffos(0, "RDX: %p RDI: %p RSI: %p\n", reg->rdx, reg->rdi, reg->rsi);
kprintffos(0, "R8 : %p R9 : %p R10: %p\n", reg->r8, reg->r9, reg->r10);
kprintffos(0, "R11: %p R12: %p R13: %p\n", reg->r11, reg->r12, reg->r13);
kprintffos(0, "R14: %p R15: %p\n", reg->r14, reg->r15);
kprintffos(0, "CS : %p SS : %p RFLAGS: %p\n", reg->cs, reg->ss,
reg->rflags);
kprintffos(0, "FS: %p UGS: %p KGS: %p\n", read_fs_base(), read_user_gs(),
read_kernel_gs());
kprintffos(0, "============ End of dumps ==========\n");
char option = 0;
while (option != 'C') {
kprintffos(0, "(C)ontinue, Dump (P)RCB, Dump (R)egisters, Dump (T)SS, "
"(B)acktrace?\n");
option = serial_getchar();
serial_putchar('\n');
switch (option) {
case 'P':
prcb_dump();
break;
case 'R':
register_dump(reg);
break;
case 'T':
tss_dump();
break;
case 'B':
backtrace_dump(reg);
default:
break;
}
}
unpause_other_cpus();
}
+159
View File
@@ -0,0 +1,159 @@
#include "libk/debug.h"
#include "libk/kargs.h"
#include <stdint.h>
struct tu_source_location {
const char *file;
uint32_t line;
uint32_t column;
};
struct tu_type_descriptor {
uint16_t kind;
uint16_t info;
char name[];
};
struct tu_overflow_data {
struct tu_source_location location;
struct tu_type_descriptor *type;
};
struct tu_shift_out_of_bounds_data {
struct tu_source_location location;
struct tu_type_descriptor *left_type;
struct tu_type_descriptor *right_type;
};
struct tu_invalid_value_data {
struct tu_source_location location;
struct tu_type_descriptor *type;
};
struct tu_array_out_of_bounds_data {
struct tu_source_location location;
struct tu_type_descriptor *array_type;
struct tu_type_descriptor *index_type;
};
struct tu_type_mismatch_v1_data {
struct tu_source_location location;
struct tu_type_descriptor *type;
unsigned char log_alignment;
unsigned char type_check_kind;
};
struct tu_negative_vla_data {
struct tu_source_location location;
struct tu_type_descriptor *type;
};
struct tu_nonnull_return_data {
struct tu_source_location location;
};
struct tu_nonnull_arg_data {
struct tu_source_location location;
};
struct tu_unreachable_data {
struct tu_source_location location;
};
struct tu_invalid_builtin_data {
struct tu_source_location location;
unsigned char kind;
};
#ifdef __cplusplus
extern "C" {
#endif
extern bool print_now;
extern bool put_to_fb;
static void tu_print_location(const char *message,
struct tu_source_location loc) {
if (print_now &&
!(kernel_arguments.kernel_args & KERNEL_ARGS_SUPPRESS_UBSAN)) {
kprintffos(0, "tinyubsan: %s at file %s, line %d, column %d\n", message,
loc.file, loc.line, loc.column);
put_to_fb = 1;
}
}
void __ubsan_handle_add_overflow(struct tu_overflow_data *data) {
tu_print_location("addition overflow", data->location);
}
void __ubsan_handle_sub_overflow(struct tu_overflow_data *data) {
tu_print_location("subtraction overflow", data->location);
}
void __ubsan_handle_mul_overflow(struct tu_overflow_data *data) {
tu_print_location("multiplication overflow", data->location);
}
void __ubsan_handle_divrem_overflow(struct tu_overflow_data *data) {
tu_print_location("division overflow", data->location);
}
void __ubsan_handle_negate_overflow(struct tu_overflow_data *data) {
tu_print_location("negation overflow", data->location);
}
void __ubsan_handle_pointer_overflow(struct tu_overflow_data *data) {
tu_print_location("pointer overflow", data->location);
}
void __ubsan_handle_shift_out_of_bounds(
struct tu_shift_out_of_bounds_data *data) {
tu_print_location("shift out of bounds", data->location);
}
void __ubsan_handle_load_invalid_value(struct tu_invalid_value_data *data) {
tu_print_location("invalid load value", data->location);
}
void __ubsan_handle_out_of_bounds(struct tu_array_out_of_bounds_data *data) {
tu_print_location("array out of bounds", data->location);
}
void __ubsan_handle_type_mismatch_v1(struct tu_type_mismatch_v1_data *data,
uintptr_t ptr) {
if (!ptr) {
tu_print_location("use of NULL pointer", data->location);
}
else if (ptr & ((1 << data->log_alignment) - 1)) {
// tu_print_location("use of misaligned pointer", data->location);
} else {
tu_print_location("no space for object", data->location);
}
}
void __ubsan_handle_vla_bound_not_positive(struct tu_negative_vla_data *data) {
tu_print_location("variable-length argument is negative", data->location);
}
void __ubsan_handle_nonnull_return(struct tu_nonnull_return_data *data) {
tu_print_location("non-null return is null", data->location);
}
void __ubsan_handle_nonnull_arg(struct tu_nonnull_arg_data *data) {
tu_print_location("non-null argument is null", data->location);
}
void __ubsan_handle_builtin_unreachable(struct tu_unreachable_data *data) {
tu_print_location("unreachable code reached", data->location);
}
void __ubsan_handle_invalid_builtin(struct tu_invalid_builtin_data *data) {
tu_print_location("invalid builtin", data->location);
}
#ifdef __cplusplus
}
#endif
+66
View File
@@ -0,0 +1,66 @@
#include "arch/x86_64/sys/tsc.h"
#include <uacpi/uacpi.h>
#include <uacpi/event.h>
#include <uacpi/sleep.h>
#include <uacpi/tables.h>
#include "arch/x86_64/sys/timer.h"
#include "madt.h"
#include "libk/debug.h"
void acpi_init() {
calibrate_tsc();
/*
* Start with this as the first step of the initialization. This loads all
* tables, brings the event subsystem online, and enters ACPI mode. We pass
* in 0 as the flags as we don't want to override any default behavior for now.
*/
uacpi_status ret = uacpi_initialize(0);
if (uacpi_unlikely_error(ret)) {
kprintf("uacpi_initialize error: %s", uacpi_status_to_string(ret));
}
/*
* Load the AML namespace. This feeds DSDT and all SSDTs to the interpreter
* for execution.
*/
ret = uacpi_namespace_load();
if (uacpi_unlikely_error(ret)) {
kprintf("uacpi_namespace_load error: %s", uacpi_status_to_string(ret));
}
/*
* Initialize the namespace. This calls all necessary _STA/_INI AML methods,
* as well as _REG for registered operation region handlers.
*/
ret = uacpi_namespace_initialize();
if (uacpi_unlikely_error(ret)) {
kprintf("uacpi_namespace_initialize error: %s", uacpi_status_to_string(ret));
}
/*
* Tell uACPI that we have marked all GPEs we wanted for wake (even though we haven't
* actually marked any, as we have no power management support right now). This is
* needed to let uACPI enable all unmarked GPEs that have a corresponding AML handler.
* These handlers are used by the firmware to dynamically execute AML code at runtime
* to e.g. react to thermal events or device hotplug.
*/
ret = uacpi_finalize_gpe_initialization();
if (uacpi_unlikely_error(ret)) {
kprintf("uACPI GPE initialization error: %s", uacpi_status_to_string(ret));
}
timer_init();
madt_init();
}
void *acpi_find_sdt(const char *signature) {
struct uacpi_table sdt;
uacpi_status st = uacpi_table_find_by_signature(signature, &sdt);
if (uacpi_unlikely_error(st)) {
panic("Could not find %s: %s\n", signature, uacpi_status_to_string(st));
}
return (void *)sdt.ptr;
}
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include <stdint.h>
typedef struct acpi_header_t {
char signature[4];
uint32_t length;
uint8_t revision;
uint8_t checksum;
char oem[6];
char oem_table[8];
uint32_t oem_revision;
uint32_t creator_id;
uint32_t creator_revision;
} __attribute__((packed)) acpi_header_t;
typedef struct acpi_gas_t {
uint8_t address_space;
uint8_t bit_width;
uint8_t bit_offset;
uint8_t access_size;
uint64_t base;
} __attribute__((packed)) acpi_gas_t;
void acpi_init();
void *acpi_find_sdt(const char *signature);
+68
View File
@@ -0,0 +1,68 @@
#include <uacpi/tables.h>
#include "madt.h"
#include <stddef.h>
#include "libk/debug.h"
#include "arch/x86_64/asm/asm.h"
struct madt *madt;
lapic_vec_t madt_local_apics;
ioapic_vec_t madt_io_apics;
iso_vec_t madt_isos;
nmi_vec_t madt_nmis;
uintptr_t lapic_addr = 0;
uintptr_t acpi_get_lapic(void) {
return lapic_addr;
}
void madt_init(void) {
vec_init(&madt_local_apics);
vec_init(&madt_io_apics);
vec_init(&madt_isos);
vec_init(&madt_nmis);
struct uacpi_table madt_table;
uacpi_status st = uacpi_table_find_by_signature("APIC", &madt_table);
if (uacpi_unlikely_error(st)) {
panic("Could not find MADT: %s\n", uacpi_status_to_string(st));
}
madt = (struct madt *)madt_table.ptr;
lapic_addr = madt->local_controller_addr;
kprintf("MADT: MADT at %p\n", madt);
for (uint8_t *madt_ptr = (uint8_t *)madt->madt_entries_begin;
(uintptr_t)madt_ptr < (uintptr_t)madt + madt->sdt.length;
madt_ptr += *(madt_ptr + 1)) {
switch (*(madt_ptr)) {
case 0:
// Processor local APIC
kprintf("MADT: Got local APIC 0x%x\n", madt_local_apics.length);
vec_push(&madt_local_apics, (void *)madt_ptr);
break;
case 1:
// I/O APIC
kprintf("MADT: Got IO APIC 0x%x\n", madt_io_apics.length);
vec_push(&madt_io_apics, (void *)madt_ptr);
break;
case 2:
// Interrupt source override
kprintf("MADT: Got ISO 0x%x\n", madt_isos.length);
vec_push(&madt_isos, (void *)madt_ptr);
break;
case 4:
// NMI
kprintf("MADT: Got NMI 0x%x\n", madt_nmis.length);
vec_push(&madt_nmis, (void *)madt_ptr);
break;
case 5:
// Local APIC address override
lapic_addr = QWORD_PTR(madt_ptr + 4);
break;
}
}
}
+64
View File
@@ -0,0 +1,64 @@
#pragma once
#include <stdint.h>
#include "libk/vec.h"
#include <uacpi/acpi.h>
#include "acpi.h"
struct madt {
acpi_header_t sdt;
uint32_t local_controller_addr;
uint32_t flags;
char madt_entries_begin[];
} __attribute__((packed));
struct madt_header {
uint8_t type;
uint8_t length;
} __attribute__((packed));
struct madt_lapic {
struct madt_header madt_header;
uint8_t processor_id;
uint8_t apic_id;
uint32_t flags;
} __attribute__((packed));
struct madt_ioapic {
struct madt_header madt_header;
uint8_t apic_id;
uint8_t reserved;
uint32_t addr;
uint32_t gsib;
} __attribute__((packed));
struct madt_iso {
struct madt_header madt_header;
uint8_t bus_source;
uint8_t irq_source;
uint32_t gsi;
uint16_t flags;
} __attribute__((packed));
struct madt_nmi {
struct madt_header madt_header;
uint8_t processor;
uint16_t flags;
uint8_t lint;
} __attribute__((packed));
typedef vec_t(struct madt_lapic *) lapic_vec_t;
typedef vec_t(struct madt_ioapic *) ioapic_vec_t;
typedef vec_t(struct madt_iso *) iso_vec_t;
typedef vec_t(struct madt_nmi *) nmi_vec_t;
extern struct madt *madt;
extern lapic_vec_t madt_local_apics;
extern ioapic_vec_t madt_io_apics;
extern iso_vec_t madt_isos;
extern nmi_vec_t madt_nmis;
uintptr_t acpi_get_lapic(void);
void madt_init(void);
+297
View File
@@ -0,0 +1,297 @@
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "mm/vmm.h"
#include "mm/memory.h"
#include "mm/pmm.h"
#include "mm/slab.h"
#include "mp/mp.h"
#include "mp/spinlock.h"
#include "fs/elf.h"
#include "sched/sched_types.h"
#include "sched/sched.h"
#include "arch/x86_64/cpu/reg.h"
#include "mm/mmap.h"
#include "libk/string.h"
#include "libk/misc.h"
void thread_setup_context(struct thread *thrd, uintptr_t pc_address,
uint64_t arguments, bool user) {
bool old_state = int_toggle(false);
thrd->reg.rip = pc_address;
thrd->reg.rdi = arguments;
thrd->kernel_stack = ((uint64_t)pmm_allocz(CPU_STACK_SIZE / PAGE_SIZE) +
MEM_PHYS_OFFSET + CPU_STACK_SIZE);
thrd->fpu_storage =
(void *)((uintptr_t)pmm_allocz(DIV_ROUNDUP(
prcb_return_current_cpu()->fpu_storage_size, PAGE_SIZE)) +
MEM_PHYS_OFFSET);
thrd->pf_stack = ((uint64_t)pmm_allocz(CPU_STACK_SIZE / PAGE_SIZE) +
MEM_PHYS_OFFSET + CPU_STACK_SIZE);
struct process *proc = thrd->mother_proc;
if (user) {
thrd->reg.cs = 0x23;
thrd->reg.ss = 0x1b;
thrd->reg.rsp = (uint64_t)pmm_allocz(STACK_SIZE / PAGE_SIZE);
thrd->stack = thrd->reg.rsp;
mmap_range(proc->process_pagemap, proc->stack_top - STACK_SIZE,
(uintptr_t)thrd->reg.rsp, STACK_SIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS);
thrd->reg.rsp = proc->stack_top;
proc->stack_top -= STACK_SIZE;
prcb_return_current_cpu()->fpu_restore(thrd->fpu_storage);
uint16_t default_fcw = 0b1100111111;
asm volatile("fldcw %0" ::"m"(default_fcw) : "memory");
uint32_t default_mxcsr = 0b1111110000000;
asm volatile("ldmxcsr %0" ::"m"(default_mxcsr) : "memory");
prcb_return_current_cpu()->fpu_save(thrd->fpu_storage);
thrd->fs_base = 0;
thrd->gs_base = 0;
} else {
thrd->reg.cs = 0x08;
thrd->reg.ss = 0x10;
thrd->stack = thrd->kernel_stack;
thrd->reg.rsp = thrd->stack;
thrd->fs_base = read_fs_base();
thrd->gs_base = read_kernel_gs();
}
thrd->reg.rflags = 0x202;
int_toggle(old_state);
}
void thread_setup_context_from_user(struct thread *thrd, uintptr_t pc_address,
uintptr_t sp) {
bool old_state = int_toggle(false);
thrd->reg.rip = pc_address;
thrd->kernel_stack = ((uint64_t)pmm_allocz(CPU_STACK_SIZE / PAGE_SIZE) +
MEM_PHYS_OFFSET + CPU_STACK_SIZE);
thrd->fpu_storage =
(void *)((uintptr_t)pmm_allocz(DIV_ROUNDUP(
prcb_return_current_cpu()->fpu_storage_size, PAGE_SIZE)) +
MEM_PHYS_OFFSET);
struct process *proc = thrd->mother_proc;
thrd->reg.cs = 0x23;
thrd->reg.ss = 0x1b;
thrd->reg.rsp = sp;
thrd->stack = thrd->reg.rsp;
thrd->pf_stack = ((uint64_t)pmm_allocz(CPU_STACK_SIZE / PAGE_SIZE) +
MEM_PHYS_OFFSET + CPU_STACK_SIZE);
prcb_return_current_cpu()->fpu_restore(thrd->fpu_storage);
uint16_t default_fcw = 0b1100111111;
asm volatile("fldcw %0" ::"m"(default_fcw) : "memory");
uint32_t default_mxcsr = 0b1111110000000;
asm volatile("ldmxcsr %0" ::"m"(default_mxcsr) : "memory");
prcb_return_current_cpu()->fpu_save(thrd->fpu_storage);
thrd->fs_base = 0;
thrd->gs_base = 0;
thrd->reg.rflags = 0x202;
int_toggle(old_state);
}
// I am still surprised that I still know how this works.
// I will properly document it sometime soon.
void thread_setup_context_for_execve(struct thread *thrd, uintptr_t pc_address,
char **argv, char **envp) {
bool old_state = int_toggle(false);
struct process *proc = thrd->mother_proc;
thrd->reg.rip = pc_address;
thrd->reg.rsp = (uint64_t)pmm_allocz(STACK_SIZE / PAGE_SIZE);
thrd->stack = thrd->reg.rsp;
thrd->reg.cs = 0x23;
thrd->reg.ss = 0x1b;
mmap_range(proc->process_pagemap, proc->stack_top - STACK_SIZE,
(uintptr_t)thrd->reg.rsp, STACK_SIZE + 1, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS);
thrd->reg.rsp = proc->stack_top;
thrd->reg.rflags = 0x202;
prcb_return_current_cpu()->fpu_restore(thrd->fpu_storage);
uint16_t default_fcw = 0b1100111111;
asm volatile("fldcw %0" ::"m"(default_fcw) : "memory");
uint32_t default_mxcsr = 0b1111110000000;
asm volatile("ldmxcsr %0" ::"m"(default_mxcsr) : "memory");
prcb_return_current_cpu()->fpu_save(thrd->fpu_storage);
thrd->fs_base = 0;
thrd->gs_base = 0;
struct auxval auxv = proc->auxv;
// the stack structure.
// the address values are not accurate.
/*
* 0x70000000000 - "USER=root\0" // envp[0][9]
* 0x6fffffffff6 - proc->name // argv[0][255]
* 0x6fffffffef6 - 0x0, 0x0 // zeros
* 0x6fffffffee6 - AT_ENTRY
* 0x6fffffffede - 0x400789 // example values
* 0x6fffffffed6 - AT_PHDR
* 0x6fffffffece - 2
* 0x6fffffffec6 - AT_PHENT
* 0x6fffffffebe - 7
* 0x6fffffffeb6 - AT_PHNUM
* 0x6fffffffeae - 5
* 0x6fffffffea6 - 0x0 // START OF ENVP
* 0x6fffffffe9e - 0x6fffffffff6 // pointer to envp[0]
* 0x6fffffffe96 - 0x0 // START OF ARGV
* 0x6fffffffe8e - 0x6fffffffef6 // pointer to argv[0]
* 0x6fffffffe86 - 1 // argc
*/
uint64_t *stack = (uint64_t *)(thrd->stack + STACK_SIZE + MEM_PHYS_OFFSET);
int envp_len = 0;
uint64_t address_difference = 0;
uint8_t *stack_but_in_bytes = (uint8_t *)stack;
for (envp_len = 0; envp[envp_len] != NULL; envp_len++) {
stack_but_in_bytes -= (strlen(envp[envp_len]) + 1);
memcpy((void *)stack_but_in_bytes, envp[envp_len],
strlen(envp[envp_len]) + 1);
}
stack = (uint64_t *)stack_but_in_bytes;
address_difference =
(thrd->stack + STACK_SIZE) - ((uint64_t)stack - MEM_PHYS_OFFSET);
uint64_t addr_to_env = (uint64_t)proc->stack_top - address_difference;
int argv_len;
for (argv_len = 0; argv[argv_len] != NULL; argv_len++) {
stack_but_in_bytes -= (strlen(argv[argv_len]) + 1);
memcpy((void *)stack_but_in_bytes, argv[argv_len],
strlen(argv[argv_len]) + 1);
}
stack = (uint64_t *)stack_but_in_bytes;
address_difference =
(thrd->stack + STACK_SIZE) - ((uint64_t)stack - MEM_PHYS_OFFSET);
uint64_t addr_to_arg = (uint64_t)proc->stack_top - address_difference;
// alignments
stack = (uintptr_t *)ALIGN_DOWN((uintptr_t)stack, 16);
if (((argv_len + envp_len + 1) & 1) != 0)
stack--;
*(--stack) = 0;
*(--stack) = 0;
stack -= 2;
stack[0] = 23; // AT_SECURE
stack[1] = 0;
stack -= 2;
stack[0] = 9;
stack[1] = auxv.at_entry;
stack -= 2;
stack[0] = 3;
stack[1] = auxv.at_phdr;
stack -= 2;
stack[0] = 4;
stack[1] = auxv.at_phent;
stack -= 2;
stack[0] = 5;
stack[1] = auxv.at_phnum;
*(--stack) = 0;
stack -= envp_len;
uint64_t offset = 0;
for (int i = envp_len - 1; i >= 0; i--) {
if (i != envp_len - 1) {
offset += strlen(envp[i + 1]) + 1;
}
stack[i] = addr_to_env + offset;
}
*(--stack) = 0;
stack -= argv_len;
offset = 0;
for (int i = argv_len - 1; i >= 0; i--) {
if (i != argv_len - 1) {
offset += strlen(argv[i + 1]) + 1;
}
stack[i] = addr_to_arg + offset;
}
*(--stack) = argv_len;
address_difference =
(thrd->stack + STACK_SIZE) - ((uint64_t)stack - MEM_PHYS_OFFSET);
thrd->reg.rsp -= address_difference;
proc->stack_top -= STACK_SIZE;
int_toggle(old_state);
}
void thread_fork_context(struct thread *thrd, struct thread *fthrd) {
bool old_state = int_toggle(false);
fthrd->kernel_stack = ((uint64_t)pmm_allocz(CPU_STACK_SIZE / PAGE_SIZE) +
MEM_PHYS_OFFSET + CPU_STACK_SIZE);
fthrd->pf_stack = ((uint64_t)pmm_allocz(CPU_STACK_SIZE / PAGE_SIZE) +
MEM_PHYS_OFFSET + CPU_STACK_SIZE);
fthrd->reg = thrd->reg;
fthrd->reg.rax = 0;
fthrd->reg.rbx = 0;
fthrd->fs_base = thrd->fs_base;
fthrd->gs_base = thrd->gs_base;
fthrd->fpu_storage =
(void *)((uintptr_t)pmm_allocz(DIV_ROUNDUP(
prcb_return_current_cpu()->fpu_storage_size, PAGE_SIZE)) +
MEM_PHYS_OFFSET);
memcpy(fthrd->fpu_storage, thrd->fpu_storage,
prcb_return_current_cpu()->fpu_storage_size);
int_toggle(old_state);
}
void thread_destroy_context(struct thread *thrd) {
bool old_state = int_toggle(false);
pmm_free((void *)(thrd->kernel_stack - MEM_PHYS_OFFSET - CPU_STACK_SIZE),
CPU_STACK_SIZE / PAGE_SIZE);
pmm_free((void *)(thrd->pf_stack - MEM_PHYS_OFFSET - CPU_STACK_SIZE),
CPU_STACK_SIZE / PAGE_SIZE);
pmm_free(
(void *)((uint64_t)thrd->fpu_storage - MEM_PHYS_OFFSET),
DIV_ROUNDUP(prcb_return_current_cpu()->fpu_storage_size, PAGE_SIZE));
int_toggle(old_state);
}
void process_setup_context(struct process *proc, bool user) {
if (user) {
proc->process_pagemap = vmm_new_pagemap();
} else {
proc->process_pagemap = kernel_pagemap;
}
}
void process_fork_context(struct process *proc, struct process *fproc) {
fproc->process_pagemap = vmm_fork_pagemap(proc->process_pagemap);
}
void process_destroy_context(struct process *proc) {
(void)proc;
vmm_destroy_pagemap(proc->process_pagemap);
}
+43
View File
@@ -0,0 +1,43 @@
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "mm/vmm.h"
#include "mm/memory.h"
#include "mm/pmm.h"
#include "mm/slab.h"
#include "mp/mp.h"
#include "mp/spinlock.h"
#include "sched/syscall.h"
#include "sched/sched.h"
#include "libk/errno.h"
#define ARCH_SET_GS 0x1001
#define ARCH_SET_FS 0x1002
#define ARCH_GET_FS 0x1003
#define ARCH_GET_GS 0x1004
void syscall_prctl(struct syscall_arguments *args) {
int option = (int)args->args0;
uint64_t value = args->args1;
switch (option) {
case ARCH_SET_GS: {
sched_get_running_thread()->gs_base = value;
// set_user_gs(prcb_return_current_cpu()->running_thread->gs_base);
break;
}
case ARCH_GET_GS:
args->ret = read_user_gs();
break;
case ARCH_SET_FS: {
sched_get_running_thread()->fs_base = value;
set_fs_base(sched_get_running_thread()->fs_base);
break;
}
case ARCH_GET_FS:
args->ret = read_fs_base();
break;
default:
errno = EINVAL;
break;
}
}
+125
View File
@@ -0,0 +1,125 @@
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "mm/vmm.h"
#include "mm/memory.h"
#include "mm/pmm.h"
#include "mm/slab.h"
#include "mp/mp.h"
#include "mp/spinlock.h"
#include "arch/x86_64/cpu/reg.h"
#include "arch/x86_64/sys/timer.h"
#include "sched/sched.h"
#include "arch/x86_64/sys/apic.h"
#include "libk/time.h"
#include "arch/x86_64/sys/prcb.h"
extern uint32_t smp_bsp_lapic_id;
extern void resched_context_switch(registers_t *reg);
void sched_yield(bool save) {
cli();
timer_stop_sched();
struct thread *thrd = sched_get_running_thread();
if (save) {
spinlock_acquire_or_wait(&thrd->yield_lock);
} else {
spinlock_drop(&thrd->lock);
prcb_return_current_cpu()->running_thread = NULL;
}
apic_send_ipi(prcb_return_current_cpu()->lapic_id, 48);
sti();
if (save) {
spinlock_acquire_or_wait(
&thrd->yield_lock); // the lock is released when the thread is
// rescheduled
spinlock_drop(&thrd->yield_lock);
} else {
for (;;) {
halt();
}
}
}
void sched_trigger_yield(uint64_t cpu_number) {
struct prcb *target = NULL;
for (size_t i = 0; i < prcb_return_installed_cpus(); i++) {
if (prcbs[i].cpu_number == cpu_number) {
target = &prcbs[i];
break;
}
}
if (target) {
apic_send_ipi(target->lapic_id, 48);
}
}
uint64_t last = 0;
void resched(registers_t *reg) {
vmm_switch_pagemap(kernel_pagemap);
prcb_return_current_cpu()->sched_ticks++;
timer_stop_sched();
struct thread *running_thrd = prcb_return_current_cpu()->running_thread;
if (prcb_return_current_cpu()->lapic_id == smp_bsp_lapic_id) {
uint64_t current = timer_count();
if (timer_handler((current - last) * 1000000)) {
last = current;
}
}
if (running_thrd) {
spinlock_drop(&running_thrd->yield_lock);
running_thrd->reg = *reg;
running_thrd->fs_base = read_fs_base();
running_thrd->gs_base = read_user_gs();
prcb_return_current_cpu()->fpu_save(running_thrd->fpu_storage);
running_thrd->last_scheduled = timer_count();
running_thrd->running_on_cpu = -1;
running_thrd->stack = prcb_return_current_cpu()->user_stack;
if (running_thrd->state == THREAD_NORMAL) {
running_thrd->state = THREAD_READY_TO_RUN;
}
spinlock_drop(&running_thrd->lock);
}
running_thrd = sched_get_next_thread(running_thrd);
if (running_thrd == NULL) {
apic_eoi();
prcb_return_current_cpu()->running_thread = NULL;
timer_sched_oneshot(48, 20000);
for (;;) {
sti();
halt();
}
}
prcb_return_current_cpu()->running_thread = running_thrd;
prcb_return_current_cpu()->cpu_tss.ist2 = running_thrd->pf_stack;
prcb_return_current_cpu()->kernel_stack = running_thrd->kernel_stack;
prcb_return_current_cpu()->user_stack = running_thrd->stack;
prcb_return_current_cpu()->running_thread->state = THREAD_NORMAL;
prcb_return_current_cpu()->fpu_restore(running_thrd->fpu_storage);
running_thrd->running_on_cpu = prcb_return_current_cpu()->cpu_number;
set_fs_base(running_thrd->fs_base);
// set_user_gs(running_thrd->gs_base);
vmm_switch_pagemap(running_thrd->mother_proc->process_pagemap);
apic_eoi();
timer_sched_oneshot(48, running_thrd->runtime);
resched_context_switch(&running_thrd->reg);
}
+21
View File
@@ -0,0 +1,21 @@
global resched_context_switch
resched_context_switch:
mov rsp, rdi
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rsi
pop rdi
pop rbp
pop rdx
pop rcx
pop rbx
pop rax
add rsp, 24
iretq
+64
View File
@@ -0,0 +1,64 @@
#include "serial.h"
#include <stdbool.h>
#include <stdint.h>
#include "arch/x86_64/cpu/io.h"
void serial_init(void) {
x86_64_outb(COM1 + 1, 0x1);
x86_64_outb(COM1 + 3, 0x80);
x86_64_outb(COM1, 0x1);
x86_64_outb(COM1 + 1, 0x0);
x86_64_outb(COM1 + 3, 0x3);
x86_64_outb(COM1 + 2, 0xC7);
x86_64_outb(COM1 + 4, 0xB);
}
static inline bool is_transmit_empty(void) {
return (x86_64_inb(COM1 + 5) & 0b1000000) != 0;
}
static inline void transmit_data(uint8_t value) {
while (!is_transmit_empty()) {
asm volatile("pause");
}
x86_64_outb(COM1, value);
}
void serial_putchar(char ch) {
transmit_data(ch);
}
void serial_puts(char *str) {
while (*str) {
if (*str == '\n')
transmit_data('\r');
transmit_data(*str++);
}
}
int serial_received(void) {
return x86_64_inb(COM1 + 5) & 1;
}
char serial_get_byte(void) {
while (serial_received() == 0)
;
return x86_64_inb(COM1);
}
char serial_getchar(void) {
char c = '\0';
char last_c = c;
while (1) {
if (c != '\0')
serial_putchar('\b');
serial_putchar(c);
c = serial_get_byte();
if (c == '\r')
break;
last_c = c;
}
return last_c;
}
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#define COM1 0x3F8
void serial_init(void);
void serial_putchar(char ch);
void serial_puts(char *str);
char serial_get_byte(void);
char serial_getchar(void);
+219 -116
View File
@@ -2,146 +2,249 @@
#include "mm/vmm.h"
#include "mm/memory.h"
#include "arch/x86_64/cpu/io.h"
#include "libk/stdio.h"
/* ── Internal state ───────────────────────────────────────────────────────── */
static volatile uint32_t *g_lapic = NULL; /* Virtual address of LAPIC MMIO */
#include "arch/x86_64/cpu/features.h"
#include "libk/debug.h"
#include "mp/mp.h"
#include "arch/x86_64/sys/prcb.h"
#include "arch/x86_64/fw/madt.h"
#include "pic.h"
#include "timer.h"
#include <cpuid.h>
#include "arch/x86_64/bus/mmio.h"
/* ── Low-level helpers ────────────────────────────────────────────────────── */
static uintptr_t lapic_addr = 0;
static bool x2apic = false;
static inline uint32_t lapic_read(uint32_t reg) {
return g_lapic[reg >> 2];
// Converts xAPIC MMIO offset into x2APIC MSR
static inline uint32_t reg_to_x2apic(uint32_t reg) {
uint32_t x2apic_reg = 0;
// MSR 831H is reserved; read/write operations cause general-protection
// exceptions. The contents of the APIC register at MMIO offset 310H are
// accessible in x2APIC mode through the MSR at address 830H
// -- Intel SDM Volume 3A 10.12.1.2 Note 4
if (reg == 0x310) {
x2apic_reg = 0x30;
} else {
x2apic_reg = reg >> 4;
}
return x2apic_reg + 0x800;
}
static inline void lapic_write(uint32_t reg, uint32_t val) {
g_lapic[reg >> 2] = val;
/* Serialise: read back a read-only register to ensure the write landed
* before we continue (required by the APIC spec). */
(void)g_lapic[LAPIC_ID >> 2];
uint32_t lapic_read(uint32_t reg) {
if (x2apic) {
return rdmsr(reg_to_x2apic(reg));
}
return mmind((void *)lapic_addr + MEM_PHYS_OFFSET + reg);
}
static inline void rdmsr(uint32_t msr, uint32_t *lo, uint32_t *hi) {
asm volatile("rdmsr" : "=a"(*lo), "=d"(*hi) : "c"(msr));
void lapic_write(uint32_t reg, uint32_t value) {
if (x2apic) {
wrmsr(reg_to_x2apic(reg), value);
} else {
mmoutd((void *)lapic_addr + MEM_PHYS_OFFSET + reg, value);
}
}
static inline void wrmsr(uint32_t msr, uint32_t lo, uint32_t hi) {
asm volatile("wrmsr" : : "a"(lo), "d"(hi), "c"(msr));
static void lapic_set_nmi(uint8_t vec, uint8_t current_processor_id,
uint8_t processor_id, uint16_t flags, uint8_t lint) {
// A value of 0xFF means all the processors
if (processor_id != 0xFF) {
if (current_processor_id != processor_id) {
return;
}
}
// Set to raise in vector number "vec" and set NMI flag
uint32_t nmi = 0x400 | vec;
// Set to active low if needed
if (flags & 2) {
nmi |= 1 << 13;
}
// Set to level triggered if needed
if (flags & 8) {
nmi |= 1 << 15;
}
// Use the proper LINT register
if (lint == 0) {
lapic_write(0x350, nmi);
} else if (lint == 1) {
lapic_write(0x360, nmi);
}
}
/* ── Public API ───────────────────────────────────────────────────────────── */
uint64_t lapic_get_phys_base(void) {
uint32_t lo, hi;
rdmsr(IA32_APIC_BASE_MSR, &lo, &hi);
/* Physical base is in bits [35:12] of the 64-bit MSR */
return ((uint64_t)(hi & 0xFu) << 32) | (lo & 0xFFFFF000u);
uint8_t lapic_get_id(void) {
return (uint8_t)(lapic_read(0x20) >> 24);
}
void lapic_eoi(void) {
lapic_write(LAPIC_EOI, 0);
void lapic_init(uint8_t processor_id) {
kprintf("LAPIC: Setting up LAPIC on Processor %u\n", processor_id);
uint64_t apic_msr = rdmsr(0x1B);
// Set APIC enable flag
apic_msr |= 1 << 11;
uint32_t a = 0, b = 0, c = 0, d = 0;
if (__get_cpuid(1, &a, &b, &c, &d)) {
if (c & CPUID_X2APIC) {
x2apic = true;
// Set x2APIC flag if support is detected
apic_msr |= 1 << 10;
}
}
wrmsr(0x1B, apic_msr);
// Initialize local APIC
lapic_write(0x80, 0);
lapic_write(0xF0, lapic_read(0xF0) | 0x100);
if (!x2apic) {
lapic_write(0xE0, 0xF0000000);
lapic_write(0xD0, lapic_read(0x20));
}
// Set NMIs according to the MADT
for (int i = 0; i < madt_nmis.length; i++) {
struct madt_nmi *nmi = madt_nmis.data[i];
lapic_set_nmi(2, processor_id, nmi->processor, nmi->flags, nmi->lint);
}
// Set up APIC timer
// Tell APIC timer to divide by 16
lapic_write(0x3E0, 3);
// Set timer init counter to -1
lapic_write(0x380, 0xFFFFFFFF);
timer_sleep(10);
// Stop the APIC timer
lapic_write(0x320, 0x10000);
// How much the APIC timer ticked in 10ms
prcb_return_current_cpu()->tick_in_10ms = 0xFFFFFFFF - lapic_read(0x390);
// With divider 16
lapic_write(0x3E0, 3);
lapic_write(0x380, prcb_return_current_cpu()->tick_in_10ms / 10);
}
uint32_t lapic_id(void) {
/* On xAPIC the LAPIC ID sits in bits [31:24] of the ID register */
return lapic_read(LAPIC_ID) >> 24;
static uint32_t ioapic_read(uintptr_t ioapic_address, size_t reg) {
mmoutd((void *)ioapic_address + MEM_PHYS_OFFSET, reg & 0xFF);
return mmind((void *)ioapic_address + MEM_PHYS_OFFSET + 16);
}
void lapic_init(void) {
/*
* ── Step 1: Re-enable the APIC global enable bit ─────────────────────
*
* Earlier in kmain (before pmm_init) we cleared bit 11 of IA32_APIC_BASE
* so that the i8259 PIC would raise interrupts properly under Limine.
* Now that the LAPIC is being brought online we must restore that bit;
* without it the LAPIC is completely off and nothing below will work.
*/
uint32_t lo, hi;
rdmsr(IA32_APIC_BASE_MSR, &lo, &hi);
lo |= IA32_APIC_BASE_ENABLE;
wrmsr(IA32_APIC_BASE_MSR, lo, hi);
static void ioapic_write(uintptr_t ioapic_address, size_t reg, uint32_t data) {
mmoutd((void *)ioapic_address + MEM_PHYS_OFFSET, reg & 0xFF);
mmoutd((void *)ioapic_address + MEM_PHYS_OFFSET + 16, data);
}
/*
* ── Step 2: Locate the LAPIC MMIO window ─────────────────────────────
*
* The physical address is almost always 0xFEE00000 but we read it from
* the MSR to be correct. vmm_init() already identity-maps all physical
* memory through the HHDM (up to 256 GiB), so the MMIO page is reachable
* at phys + MEM_PHYS_OFFSET with no extra mapping needed.
*
* TODO: For strict correctness the LAPIC page should be mapped as
* uncacheable (PAT / PCD). In practice, QEMU / BOCHS work fine
* because MTRRs mark the 0xFEE00000 range as UC by default.
*/
uint64_t phys_base = ((uint64_t)(hi & 0xFu) << 32) | (lo & 0xFFFFF000u);
printf("[LAPIC] Physical base: 0x%08x%08x\n",
(uint32_t)(phys_base >> 32), (uint32_t)phys_base);
static uint32_t get_gsi_count(uintptr_t ioapic_address) {
return (ioapic_read(ioapic_address, 1) & 0xFF0000) >> 16;
}
g_lapic = (volatile uint32_t *)(phys_base + MEM_PHYS_OFFSET);
static struct madt_ioapic *get_ioapic_by_gsi(uint32_t gsi) {
// Search through every I/O APIC to find its GSI
for (int i = 0; i < madt_io_apics.length; i++) {
struct madt_ioapic *ioapic = madt_io_apics.data[i];
if (ioapic->gsib <= gsi &&
ioapic->gsib + get_gsi_count(ioapic->addr) > gsi) {
return ioapic;
}
}
/*
* ── Step 3: Software-enable the LAPIC via the SVR ────────────────────
*
* Bit 8 = Software Enable. The lower 8 bits are the "spurious interrupt
* vector" delivered if the CPU acknowledges an interrupt that was
* retracted by the LAPIC; 0xFF is the conventional choice.
*/
lapic_write(LAPIC_SVR, LAPIC_SVR_ENABLE | 0xFF);
// Return NULL if none was found
return NULL;
}
/*
* ── Step 4: Configure LINT0 as ExtINT (i8259 pass-through) ──────────
*
* On a standard PC the i8259 INTR pin is wired to the BSP's LINT0.
* Setting LINT0 to ExtINT delivery mode makes the LAPIC act as a
* transparent relay: the i8259 interrupt acknowledge cycle goes through
* normally, the full 8-bit vector comes from the i8259, and the CPU's
* existing IDT entries + irq.c EOI code all keep working unchanged.
*
* This is the "Virtual Wire" mode described in the Intel MP Spec.
*/
lapic_write(LAPIC_LVT_LINT0, LAPIC_LVT_DM_EXTINT);
void ioapic_redirect_gsi(uint32_t gsi, uint8_t vec, uint16_t flags) {
// Get I/O APIC address of the GSI
size_t io_apic = get_ioapic_by_gsi(gsi)->addr;
/*
* ── Step 5: Configure LINT1 as NMI ───────────────────────────────────
*
* LINT1 is the NMI pin on standard PCs. Delivery mode = 4 (NMI),
* unmasked, edge-triggered (the default when LAPIC_LVT_LEVEL is clear).
*/
lapic_write(LAPIC_LVT_LINT1, LAPIC_LVT_DM_NMI);
uint32_t low_index = 0x10 + (gsi - get_ioapic_by_gsi(gsi)->gsib) * 2;
uint32_t high_index = low_index + 1;
/*
* ── Step 6: Mask LVT entries we are not yet using ────────────────────
*
* Timer, error, and (if present) thermal / perf entries all start masked.
* Assign distinct vectors in the 0xF0-0xFE range so that if one fires
* spuriously the IDT handler can identify it and send EOI.
*/
lapic_write(LAPIC_LVT_TIMER, LAPIC_LVT_MASKED | 0xFD);
lapic_write(LAPIC_LVT_ERROR, LAPIC_LVT_MASKED | 0xFE);
uint32_t high = ioapic_read(io_apic, high_index);
/* Version register: bits [23:16] = max LVT entry index */
uint32_t ver = lapic_read(LAPIC_VER);
uint32_t max_lvt = (ver >> 16) & 0xFF;
if (max_lvt >= 4) lapic_write(LAPIC_LVT_THERMAL, LAPIC_LVT_MASKED | 0xFC);
if (max_lvt >= 5) lapic_write(LAPIC_LVT_PERF, LAPIC_LVT_MASKED | 0xFB);
// Set APIC ID
high &= ~0xFF000000;
high |= ioapic_read(io_apic, 0) << 24;
ioapic_write(io_apic, high_index, high);
/*
* ── Step 7: Clear the Error Status Register ───────────────────────────
*
* The APIC spec requires writing ESR twice to clear stale error bits.
*/
lapic_write(LAPIC_ESR, 0);
lapic_write(LAPIC_ESR, 0);
uint32_t low = ioapic_read(io_apic, low_index);
/* Dismiss any stale in-service interrupt */
lapic_write(LAPIC_EOI, 0);
// Unmask the IRQ
low &= ~(1 << 16);
/*
* ── Step 8: Set Task Priority to 0 ───────────────────────────────────
*
* TPR = 0 means the CPU will accept all interrupt priorities.
* Raise this later if need to block lower-priority interrupts.
*/
lapic_write(LAPIC_TPR, 0);
// Set to physical delivery mode
low &= ~(1 << 11);
// Set to fixed delivery mode
low &= ~0x700;
// Set delivery vector
low &= ~0xFF;
low |= vec;
// Active high(0) or low(1)
if (flags & 2) {
low |= 1 << 13;
}
// Edge(0) or level(1) triggered
if (flags & 8) {
low |= 1 << 15;
}
ioapic_write(io_apic, low_index, low);
}
void ioapic_redirect_irq(uint32_t irq, uint8_t vect) {
// Use ISO table to find flags and interrupt overrides
for (int i = 0; i < madt_isos.length; i++) {
if (madt_isos.data[i]->irq_source == irq) {
ioapic_redirect_gsi(madt_isos.data[i]->gsi, vect,
madt_isos.data[i]->flags);
return;
}
}
ioapic_redirect_gsi(irq, vect, 0);
}
void apic_send_ipi(uint32_t lapic_id, uint32_t flags) {
if (x2apic) {
// Write MSR directly, because lapic_write receives a 32-bit argument
// Whilst in x2APIC, 0x830 is a 64-bit register
wrmsr(0x830, ((uint64_t)lapic_id << 32) | flags);
} else {
lapic_write(0x310, (lapic_id << 24));
lapic_write(0x300, flags);
}
}
void apic_eoi(void) {
// Writing any other value different than 0 may cause a #GP exception
lapic_write(0xB0, 0);
}
void timer_stop_sched(void) {
lapic_write(0x380, 0);
lapic_write(0x320, (1 << 16));
}
void timer_sched_oneshot(uint8_t isr, uint32_t us) {
timer_stop_sched();
lapic_write(0x320, isr | 0x20000);
lapic_write(0x3E0, 3);
lapic_write(0x380,
((prcb_return_current_cpu()->tick_in_10ms * (us / 1000))) / 10);
}
void apic_init(void) {
pic_init();
lapic_addr = acpi_get_lapic();
ioapic_redirect_irq(0, 48);
}
printf("[LAPIC] Online. ID=%u version=0x%02x max_lvt=%u\n",
lapic_id(), ver & 0xFF, max_lvt);
}
+9 -69
View File
@@ -2,73 +2,13 @@
#include <stdint.h>
#include <stdbool.h>
/*
* Local APIC (xAPIC mode, MMIO access)
* Register offsets are byte offsets; we shift right by 2 for uint32_t indexing.
*/
/* ── Register offsets ─────────────────────────────────────────────────────── */
#define LAPIC_ID 0x020 /* LAPIC ID (bits [27:24] on P4, [31:24] on modern) */
#define LAPIC_VER 0x030 /* Version register */
#define LAPIC_TPR 0x080 /* Task Priority Register */
#define LAPIC_APR 0x090 /* Arbitration Priority (RO) */
#define LAPIC_PPR 0x0A0 /* Processor Priority (RO) */
#define LAPIC_EOI 0x0B0 /* End-Of-Interrupt (write 0 to ack) */
#define LAPIC_RRD 0x0C0 /* Remote Read (RO) */
#define LAPIC_LDR 0x0D0 /* Logical Destination */
#define LAPIC_DFR 0x0E0 /* Destination Format */
#define LAPIC_SVR 0x0F0 /* Spurious Interrupt Vector */
#define LAPIC_ESR 0x280 /* Error Status Register */
#define LAPIC_ICR_LO 0x300 /* Interrupt Command (low 32 bits) */
#define LAPIC_ICR_HI 0x310 /* Interrupt Command (high 32 bits) */
#define LAPIC_LVT_TIMER 0x320 /* LVT: APIC timer */
#define LAPIC_LVT_THERMAL 0x330 /* LVT: Thermal sensor */
#define LAPIC_LVT_PERF 0x340 /* LVT: Performance monitoring */
#define LAPIC_LVT_LINT0 0x350 /* LVT: Local interrupt pin 0 */
#define LAPIC_LVT_LINT1 0x360 /* LVT: Local interrupt pin 1 */
#define LAPIC_LVT_ERROR 0x370 /* LVT: Error */
#define LAPIC_TIMER_ICR 0x380 /* Timer Initial Count */
#define LAPIC_TIMER_CCR 0x390 /* Timer Current Count (RO) */
#define LAPIC_TIMER_DCR 0x3E0 /* Timer Divide Configuration */
/* ── SVR flags ────────────────────────────────────────────────────────────── */
#define LAPIC_SVR_ENABLE (1u << 8) /* Software-enable the LAPIC */
/* ── LVT delivery modes (bits [10:8]) ────────────────────────────────────── */
#define LAPIC_LVT_DM_FIXED (0u << 8) /* Fixed delivery */
#define LAPIC_LVT_DM_SMI (2u << 8)
#define LAPIC_LVT_DM_NMI (4u << 8) /* NMI */
#define LAPIC_LVT_DM_EXTINT (7u << 8) /* ExtINT: pass-through from i8259 */
/* ── LVT misc flags ───────────────────────────────────────────────────────── */
#define LAPIC_LVT_MASKED (1u << 16) /* Mask this LVT entry */
#define LAPIC_LVT_LEVEL (1u << 15) /* Level-triggered (vs edge) */
#define LAPIC_LVT_ACTIVE_LOW (1u << 13) /* Active-low polarity */
/* ── IA32_APIC_BASE MSR ───────────────────────────────────────────────────── */
#define IA32_APIC_BASE_MSR 0x1B
#define IA32_APIC_BASE_ENABLE (1u << 11) /* APIC global enable bit */
#define IA32_APIC_BASE_BSP (1u << 8) /* Bootstrap processor flag */
/* ── Public API ───────────────────────────────────────────────────────────── */
/**
* lapic_init - Map the LAPIC MMIO, re-enable the APIC global bit in the MSR
* (which was cleared earlier to let the i8259 work), then bring
* the LAPIC online with LINT0=ExtINT so the i8259/PIT path is
* completely preserved.
*
* Call AFTER uacpi_initialize() so that paging and the heap are live.
*/
void lapic_init(void);
/**
* lapic_eoi - Signal end-of-interrupt to the LAPIC.
*/
void lapic_eoi(void);
/** lapic_id - Return the LAPIC ID of the current CPU. */
uint32_t lapic_id(void);
/** lapic_get_phys_base - Return the physical base address from the MSR. */
uint64_t lapic_get_phys_base(void);
void apic_eoi(void);
void apic_init(void);
void apic_send_ipi(uint32_t lapic_id, uint32_t flags);
void ioapic_redirect_irq(uint32_t irq, uint8_t vect);
uint32_t lapic_read(uint32_t reg);
void lapic_write(uint32_t reg, uint32_t value);
uint8_t lapic_get_id(void);
void lapic_init(uint8_t processor_id);
void timer_sched_oneshot(uint8_t isr, uint32_t us);
+59
View File
@@ -0,0 +1,59 @@
#include <stdint.h>
#include <stdbool.h>
#include "arch/x86_64/asm/asm.h"
#include "halt.h"
#include "arch/x86_64/sys/apic.h"
extern bool is_smp;
bool is_halting = false;
uint8_t is_pausing = false;
void halt_current_cpu(void) {
for (;;) {
cli();
halt();
}
}
void halt_other_cpus(void) {
if (!is_smp)
return;
is_halting = true;
uint64_t icr = 0;
icr |= (0b100) << 8; // set delivery mode to nmi
icr |= (0b11) << 18; // set destination shorthand to all excluding self
lapic_write(0x300, icr);
lapic_write(0x310, icr >> 32);
}
void pause_other_cpus(void) {
if (!is_smp)
return;
is_pausing = 0;
is_pausing |= PAUSING;
uint64_t icr = 0;
icr |= (0b100) << 8;
icr |= (0b11) << 18;
lapic_write(0x300, icr);
lapic_write(0x310, icr >> 32);
}
void unpause_other_cpus(void) {
if (!is_smp)
return;
is_pausing = 0;
is_pausing |= UNPAUSING;
uint64_t icr = 0;
icr |= (0b100) << 8;
icr |= (0b11) << 18;
lapic_write(0x300, icr);
lapic_write(0x310, icr >> 32);
}
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#define PAUSING (1 << 0)
#define UNPAUSING (1 << 1)
void halt_current_cpu(void);
void halt_other_cpus(void);
void pause_other_cpus(void);
void unpause_other_cpus(void);
+32
View File
@@ -0,0 +1,32 @@
#include <uacpi/uacpi.h>
#include <stdint.h>
#include "arch/x86_64/fw/acpi.h"
struct hpet_table {
acpi_header_t header;
uint8_t hardware_rev_id;
uint8_t comparator_count : 5;
uint8_t counter_size : 1;
uint8_t reserved : 1;
uint8_t legacy_replacement : 1;
uint16_t pci_vendor_id;
acpi_gas_t address;
uint8_t hpet_number;
uint16_t minimum_tick;
uint8_t page_protection;
} __attribute__((packed));
struct hpet {
uint64_t general_capabilities;
uint64_t reserved;
uint64_t general_configuration;
uint64_t reserved2;
uint64_t general_int_status;
uint64_t reserved3;
uint64_t reserved4[24];
uint64_t main_counter_value;
uint64_t reserved5;
};
uint64_t hpet_counter_value(void);
void hpet_sleep(uint64_t us);
-166
View File
@@ -1,166 +0,0 @@
#include "pic.h"
#include "arch/x86_64/cpu/io.h"
#include <stdbool.h>
#define PIC1_COMMAND_PORT 0x20
#define PIC1_DATA_PORT 0x21
#define PIC2_COMMAND_PORT 0xA0
#define PIC2_DATA_PORT 0xA1
// Initialization Control Word 1
// -----------------------------
// 0 IC4 if set, the PIC expects to receive ICW4 during initialization
// 1 SGNL if set, only 1 PIC in the system; if unset, the PIC is cascaded with slave PICs
// and ICW3 must be sent to controller
// 2 ADI call address interval, set: 4, not set: 8; ignored on x86, set to 0
// 3 LTIM if set, operate in level triggered mode; if unset, operate in edge triggered mode
// 4 INIT set to 1 to initialize PIC
// 5-7 ignored on x86, set to 0
enum {
PIC_ICW1_ICW4 = 0x01,
PIC_ICW1_SINGLE = 0x02,
PIC_ICW1_INTERVAL4 = 0x04,
PIC_ICW1_LEVEL = 0x08,
PIC_ICW1_INITIALIZE = 0x10
} PIC_ICW1;
// Initialization Control Word 4
// -----------------------------
// 0 uPM if set, PIC is in 80x86 mode; if cleared, in MCS-80/85 mode
// 1 AEOI if set, on last interrupt acknowledge pulse, controller automatically performs
// end of interrupt operation
// 2 M/S only use if BUF is set; if set, selects buffer master; otherwise, selects buffer slave
// 3 BUF if set, controller operates in buffered mode
// 4 SFNM specially fully nested mode; used in systems with large number of cascaded controllers
// 5-7 reserved, set to 0
enum {
PIC_ICW4_8086 = 0x1,
PIC_ICW4_AUTO_EOI = 0x2,
PIC_ICW4_BUFFER_MASTER = 0x4,
PIC_ICW4_BUFFER_SLAVE = 0x0,
PIC_ICW4_BUFFERRED = 0x8,
PIC_ICW4_SFNM = 0x10,
} PIC_ICW4;
enum {
PIC_CMD_END_OF_INTERRUPT = 0x20,
PIC_CMD_READ_IRR = 0x0A,
PIC_CMD_READ_ISR = 0x0B,
} PIC_CMD;
static uint16_t g_PicMask = 0xffff;
static bool g_AutoEoi = false;
void i8259_SetMask(uint16_t newMask)
{
g_PicMask = newMask;
x86_64_outb(PIC1_DATA_PORT, g_PicMask & 0xFF);
x86_64_iowait();
x86_64_outb(PIC2_DATA_PORT, g_PicMask >> 8);
x86_64_iowait();
}
uint16_t i8259_GetMask()
{
return x86_64_inb(PIC1_DATA_PORT) | (x86_64_inb(PIC2_DATA_PORT) << 8);
}
void i8259_Configure(uint8_t offsetPic1, uint8_t offsetPic2, bool autoEoi)
{
// Mask everything
i8259_SetMask(0xFFFF);
// initialization control word 1
x86_64_outb(PIC1_COMMAND_PORT, PIC_ICW1_ICW4 | PIC_ICW1_INITIALIZE);
x86_64_iowait();
x86_64_outb(PIC2_COMMAND_PORT, PIC_ICW1_ICW4 | PIC_ICW1_INITIALIZE);
x86_64_iowait();
// initialization control word 2 - the offsets
x86_64_outb(PIC1_DATA_PORT, offsetPic1);
x86_64_iowait();
x86_64_outb(PIC2_DATA_PORT, offsetPic2);
x86_64_iowait();
// initialization control word 3
x86_64_outb(PIC1_DATA_PORT, 0x4); // tell PIC1 that it has a slave at IRQ2 (0000 0100)
x86_64_iowait();
x86_64_outb(PIC2_DATA_PORT, 0x2); // tell PIC2 its cascade identity (0000 0010)
x86_64_iowait();
// initialization control word 4
uint8_t icw4 = PIC_ICW4_8086;
if (autoEoi) {
icw4 |= PIC_ICW4_AUTO_EOI;
}
x86_64_outb(PIC1_DATA_PORT, icw4);
x86_64_iowait();
x86_64_outb(PIC2_DATA_PORT, icw4);
x86_64_iowait();
// mask all interrupts until they are enabled by the device driver
i8259_SetMask(0xFFFF);
}
void i8259_SendEndOfInterrupt(int irq)
{
if (irq >= 8)
x86_64_outb(PIC2_COMMAND_PORT, PIC_CMD_END_OF_INTERRUPT);
x86_64_outb(PIC1_COMMAND_PORT, PIC_CMD_END_OF_INTERRUPT);
}
void i8259_Disable()
{
i8259_SetMask(0xFFFF);
}
void i8259_Mask(int irq)
{
i8259_SetMask(g_PicMask | (1 << irq));
}
void i8259_Unmask(int irq)
{
i8259_SetMask(g_PicMask & ~(1 << irq));
}
uint16_t i8259_ReadIrqRequestRegister()
{
x86_64_outb(PIC1_COMMAND_PORT, PIC_CMD_READ_IRR);
x86_64_outb(PIC2_COMMAND_PORT, PIC_CMD_READ_IRR);
return ((uint16_t)x86_64_inb(PIC2_COMMAND_PORT)) | (((uint16_t)x86_64_inb(PIC2_COMMAND_PORT)) << 8);
}
uint16_t i8259_ReadInServiceRegister()
{
x86_64_outb(PIC1_COMMAND_PORT, PIC_CMD_READ_ISR);
x86_64_outb(PIC2_COMMAND_PORT, PIC_CMD_READ_ISR);
return ((uint16_t)x86_64_inb(PIC2_COMMAND_PORT)) | (((uint16_t)x86_64_inb(PIC2_COMMAND_PORT)) << 8);
}
bool i8259_Probe()
{
i8259_Disable();
i8259_SetMask(0x1337);
return i8259_GetMask() == 0x1337;
}
static const PICDriver g_PicDriver = {
.Name = "8259 PIC",
.Probe = &i8259_Probe,
.Initialize = &i8259_Configure,
.Disable = &i8259_Disable,
.SendEndOfInterrupt = &i8259_SendEndOfInterrupt,
.Mask = &i8259_Mask,
.Unmask = &i8259_Unmask,
};
const PICDriver* i8259_GetDriver()
{
return &g_PicDriver;
}
-10
View File
@@ -1,10 +0,0 @@
#pragma once
#include "pic.h"
const PICDriver* i8259_GetDriver();
uint16_t i8259_GetMask();
void i8259_SetMask(uint16_t newMask);
void i8259_Configure(uint8_t offsetPic1, uint8_t offsetPic2, bool autoEoi);
void i8259_Disable();
-359
View File
@@ -1,359 +0,0 @@
#include "ioapic.h"
#include "apic.h"
#include "mm/vmm.h"
#include "mm/memory.h"
#include "libk/stdio.h"
#include <uacpi/tables.h> /* uacpi_table_find_by_signature / uacpi_table_unref */
#include "pic.h"
/* ══════════════════════════════════════════════════════════════════════════
* ACPI MADT structures
* (Defined locally so we don't depend on uACPI's internal acpi.h layout.)
* ══════════════════════════════════════════════════════════════════════════ */
extern const PICDriver* g_Driver; // old pic driver
bool g_IOAPIC = false; // IOAPIC enabled
typedef struct {
uint8_t signature[4]; /* "APIC" */
uint32_t length;
uint8_t revision;
uint8_t checksum;
uint8_t oem_id[6];
uint8_t oem_table_id[8];
uint32_t oem_revision;
uint32_t creator_id;
uint32_t creator_revision;
/* --- MADT-specific -------------------------------------------------- */
uint32_t local_apic_addr; /* Default LAPIC physical address (32-bit) */
uint32_t flags; /* bit 0 = dual 8259 PICs present */
/* followed by variable-length Interrupt Controller Structure entries */
} __attribute__((packed)) madt_t;
typedef struct {
uint8_t type;
uint8_t length;
} __attribute__((packed)) madt_entry_hdr_t;
/* Type 0: Processor Local APIC */
typedef struct {
madt_entry_hdr_t hdr;
uint8_t uid;
uint8_t apic_id;
uint32_t flags; /* bit 0 = enabled */
} __attribute__((packed)) madt_lapic_t;
/* Type 1: I/O APIC */
typedef struct {
madt_entry_hdr_t hdr;
uint8_t id;
uint8_t reserved;
uint32_t address; /* Physical MMIO base */
uint32_t gsi_base; /* First GSI handled by this IOAPIC */
} __attribute__((packed)) madt_ioapic_t;
/* Type 2: Interrupt Source Override */
typedef struct {
madt_entry_hdr_t hdr;
uint8_t bus; /* 0 = ISA */
uint8_t source; /* ISA IRQ number */
uint32_t gsi; /* Remapped GSI */
uint16_t flags; /* bits [1:0] = polarity, bits [3:2] = trigger mode */
} __attribute__((packed)) madt_iso_t;
/* Type 4: Local APIC NMI */
typedef struct {
madt_entry_hdr_t hdr;
uint8_t uid; /* 0xFF = all processors */
uint16_t flags;
uint8_t lint; /* 0 or 1 */
} __attribute__((packed)) madt_nmi_t;
/* ══════════════════════════════════════════════════════════════════════════
* Internal state
* ══════════════════════════════════════════════════════════════════════════ */
typedef struct {
volatile uint32_t *base; /* Virtual address of IOAPIC MMIO */
uint32_t gsi_base;
uint32_t gsi_count; /* Number of redirection entries */
} ioapic_t;
static ioapic_t g_ioapics[IOAPIC_MAX];
static int g_ioapic_count = 0;
/* ISA interrupt source overrides (max 16 ISA IRQs) */
typedef struct {
bool present;
uint32_t gsi;
bool active_low;
bool level;
} iso_t;
static iso_t g_iso[16]; /* indexed by ISA IRQ (source) */
/* ══════════════════════════════════════════════════════════════════════════
* Low-level IOAPIC MMIO access
*
* The IOAPIC has two MMIO registers:
* base+0x00 IOREGSEL index register (write which register to access)
* base+0x10 IOWIN data window (read/write the selected register)
* ══════════════════════════════════════════════════════════════════════════ */
static uint32_t ioapic_read(const ioapic_t *io, uint8_t reg) {
*((volatile uint32_t *)(io->base + (0x00 >> 2))) = reg;
return *((volatile uint32_t *)(io->base + (0x10 >> 2)));
}
static void ioapic_write(const ioapic_t *io, uint8_t reg, uint32_t val) {
*((volatile uint32_t *)(io->base + (0x00 >> 2))) = reg;
*((volatile uint32_t *)(io->base + (0x10 >> 2))) = val;
}
/* ── Find which IOAPIC owns a given GSI ─────────────────────────────────── */
static ioapic_t *ioapic_for_gsi(uint32_t gsi) {
for (int i = 0; i < g_ioapic_count; i++) {
ioapic_t *io = &g_ioapics[i];
if (gsi >= io->gsi_base && gsi < io->gsi_base + io->gsi_count)
return io;
}
return NULL;
}
/* ══════════════════════════════════════════════════════════════════════════
* Public API
* ══════════════════════════════════════════════════════════════════════════ */
uint32_t ioapic_gsi_for_isa_irq(uint8_t isa_irq) {
if (isa_irq < 16 && g_iso[isa_irq].present)
return g_iso[isa_irq].gsi;
return isa_irq;
}
void ioapic_redirect(uint32_t gsi, uint8_t vector, uint8_t dest_lapic,
bool active_low, bool level, bool masked) {
ioapic_t *io = ioapic_for_gsi(gsi);
if (!io) {
printf("[IOAPIC] No IOAPIC for GSI %u\n", gsi);
return;
}
uint8_t idx = (uint8_t)(gsi - io->gsi_base);
uint32_t lo = (uint32_t)vector
| IOAPIC_RTE_DM_FIXED
| (active_low ? IOAPIC_RTE_ACTIVE_LOW : 0)
| (level ? IOAPIC_RTE_LEVEL : 0)
| (masked ? IOAPIC_RTE_MASKED : 0);
uint32_t hi = (uint32_t)dest_lapic << 24;
/* Write high word first, then low (avoids momentary spurious delivery) */
ioapic_write(io, IOAPIC_REDTBL_HI(idx), hi);
ioapic_write(io, IOAPIC_REDTBL_LO(idx), lo);
}
void ioapic_mask_gsi(uint32_t gsi) {
ioapic_t *io = ioapic_for_gsi(gsi);
if (!io) return;
uint8_t idx = (uint8_t)(gsi - io->gsi_base);
uint32_t lo = ioapic_read(io, IOAPIC_REDTBL_LO(idx));
ioapic_write(io, IOAPIC_REDTBL_LO(idx), lo | IOAPIC_RTE_MASKED);
}
void ioapic_unmask_gsi(uint32_t gsi) {
ioapic_t *io = ioapic_for_gsi(gsi);
if (!io) return;
uint8_t idx = (uint8_t)(gsi - io->gsi_base);
uint32_t lo = ioapic_read(io, IOAPIC_REDTBL_LO(idx));
ioapic_write(io, IOAPIC_REDTBL_LO(idx), lo & ~IOAPIC_RTE_MASKED);
}
/* ══════════════════════════════════════════════════════════════════════════
* Initialisation
* ══════════════════════════════════════════════════════════════════════════ */
void ioapic_init(void) {
/*
* ── Step 1: Find the MADT via uACPI ──────────────────────────────────
*
* The MADT signature in ACPI is "APIC" (not "MADT").
* uacpi_table_find_by_signature returns a handle whose .ptr field points
* to the raw table data in (HHDM-mapped) physical memory.
*/
struct uacpi_table madt_table;
uacpi_status st = uacpi_table_find_by_signature("APIC", &madt_table);
if (uacpi_unlikely_error(st)) {
printf("[IOAPIC] Could not find MADT: %s\n", uacpi_status_to_string(st));
return;
}
madt_t *madt = (madt_t *)madt_table.ptr;
printf("[IOAPIC] MADT @ virt 0x%lx len=%u lapic_addr=0x%08x\n",
(uint64_t)madt, madt->length, madt->local_apic_addr);
/*
* ── Step 2: Walk the MADT entry list ─────────────────────────────────
*
* Entries start immediately after the fixed 44-byte MADT header and run
* until madt->length bytes from the table base.
*/
const uint8_t *entry_ptr = (const uint8_t *)madt + sizeof(madt_t);
const uint8_t *madt_end = (const uint8_t *)madt + madt->length;
while (entry_ptr < madt_end) {
const madt_entry_hdr_t *hdr = (const madt_entry_hdr_t *)entry_ptr;
if (hdr->length < 2) {
printf("[IOAPIC] MADT entry with length < 2, stopping parse\n");
break;
}
switch (hdr->type) {
/* ── Type 0: Processor Local APIC ──────────────────────────────── */
case 0: {
const madt_lapic_t *e = (const madt_lapic_t *)entry_ptr;
printf("[IOAPIC] MADT[0] Processor UID=%u LAPIC ID=%u flags=0x%x%s\n",
e->uid, e->apic_id, e->flags,
(e->flags & 1) ? "" : " (disabled)");
break;
}
/* ── Type 1: I/O APIC ───────────────────────────────────────────── */
case 1: {
const madt_ioapic_t *e = (const madt_ioapic_t *)entry_ptr;
if (g_ioapic_count >= IOAPIC_MAX) {
printf("[IOAPIC] Too many IOAPICs, skipping ID=%u\n", e->id);
break;
}
ioapic_t *io = &g_ioapics[g_ioapic_count];
io->gsi_base = e->gsi_base;
/*
* Map the IOAPIC MMIO page. Like the LAPIC, the HHDM covers the
* IOAPIC's physical address (typically 0xFEC00000) so we just add
* MEM_PHYS_OFFSET. Two MMIO registers are accessed (offsets 0 and
* 0x10) so one 4 KiB page is sufficient.
*
* TODO: Mark the page UC (cache-disable) in the PTE when VMM
* gains support for PAT / PCD flags.
*/
uint64_t phys = (uint64_t)e->address;
uintptr_t virt = (uintptr_t)phys + MEM_PHYS_OFFSET;
/* The HHDM loop in vmm_init already covered this range; if not,
* uncomment the explicit map call below: */
/* vmm_map_page(kernel_pagemap, virt, phys,
PAGE_READ | PAGE_WRITE | PAGE_NO_EXECUTE, Size4KiB); */
io->base = (volatile uint32_t *)virt;
/* Read version register to discover number of redirection entries */
uint32_t ver = ioapic_read(io, IOAPIC_REG_VER);
io->gsi_count = ((ver >> 16) & 0xFF) + 1; /* bits [23:16] = max entry index */
printf("[IOAPIC] MADT[1] ID=%u phys=0x%08x GSI base=%u entries=%u\n",
e->id, e->address, io->gsi_base, io->gsi_count);
/*
* ── Mask every redirection entry ─────────────────────────────
*
* We keep all entries masked at boot time. Legacy ISA IRQs are
* handled by the i8259 → LAPIC LINT0 ExtINT path, not via the
* IOAPIC. PCI devices can be connected later with ioapic_redirect().
*/
for (uint32_t n = 0; n < io->gsi_count; n++) {
ioapic_write(io, IOAPIC_REDTBL_HI(n), 0);
ioapic_write(io, IOAPIC_REDTBL_LO(n), IOAPIC_RTE_MASKED | 0xFF);
}
g_ioapic_count++;
break;
}
/* ── Type 2: Interrupt Source Override ──────────────────────────── */
case 2: {
const madt_iso_t *e = (const madt_iso_t *)entry_ptr;
/* flags bits [1:0]: 00/11 = conforms to bus (ISA = active high edge)
* 01 = active high, 11 = active low
* flags bits [3:2]: 00/11 = conforms to bus (ISA = edge)
* 01 = edge, 11 = level */
bool active_low = ((e->flags & 0x3) == 3);
bool level = ((e->flags >> 2) & 0x3) == 3;
printf("[IOAPIC] MADT[2] ISA IRQ %u -> GSI %u %s %s\n",
e->source, e->gsi,
active_low ? "active-low" : "active-high",
level ? "level" : "edge");
if (e->source < 16) {
g_iso[e->source].present = true;
g_iso[e->source].gsi = e->gsi;
g_iso[e->source].active_low = active_low;
g_iso[e->source].level = level;
}
break;
}
/* ── Type 4: Local APIC NMI ─────────────────────────────────────── */
case 4: {
const madt_nmi_t *e = (const madt_nmi_t *)entry_ptr;
printf("[IOAPIC] MADT[4] NMI UID=0x%02x LINT%u\n",
e->uid, e->lint);
break;
}
default:
printf("[IOAPIC] MADT entry type=%u length=%u (skipped)\n",
hdr->type, hdr->length);
break;
}
entry_ptr += hdr->length;
}
uacpi_table_unref(&madt_table);
printf("[IOAPIC] Init done: %d IOAPIC(s) found\n", g_ioapic_count);
}
void irq_redirect_to_apic(uint8_t isa_irq, uint8_t vector,
uint8_t dest_lapic, bool masked)
{
if (isa_irq >= 16) {
printf("[IRQ] irq_redirect_to_apic: ISA IRQ %u out of range\n", isa_irq);
return;
}
uint32_t gsi = ioapic_gsi_for_isa_irq(isa_irq);
/* Get polarity/trigger from MADT ISO or use ISA defaults */
bool active_low = false;
bool level = false;
if (isa_irq < 16 && g_iso[isa_irq].present) {
active_low = g_iso[isa_irq].active_low;
level = g_iso[isa_irq].level;
} else {
/* Standard ISA: active-high, edge-triggered (except some like IRQ0/8) */
if (isa_irq == 0 || isa_irq == 8) {
level = true; /* often level on real hardware */
}
}
/* Mask in the 8259 so it stops firing through LINT0 */
if (g_Driver) {
g_Driver->Mask(isa_irq);
}
/* Programme IOAPIC redirection entry */
ioapic_redirect(gsi, vector, dest_lapic,
active_low, level, masked);
printf("[IRQ] Redirected ISA IRQ %u -> GSI %u vector 0x%02x LAPIC %u %s %s\n",
isa_irq, gsi, vector, dest_lapic,
active_low ? "active-low" : "active-high",
level ? "level" : "edge");
g_IOAPIC = true;
}
-76
View File
@@ -1,76 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
/*
* I/O APIC driver
*
* The IOAPIC is found by parsing the ACPI MADT table via uACPI.
* All redirection entries are masked at init time; use ioapic_redirect() /
* ioapic_unmask_irq() to enable individual GSIs for PCI devices later.
*
* Legacy ISA IRQs (0-15) are intentionally left masked here because they are
* delivered through the i8259 → LAPIC LINT0 ExtINT path instead.
*/
/* Maximum IOAPICs supported (1 is typical for QEMU/BOCHS) */
#define IOAPIC_MAX 4
/* ── IOAPIC MMIO register indices (written to IOREGSEL) ─────────────────── */
#define IOAPIC_REG_ID 0x00 /* APIC ID */
#define IOAPIC_REG_VER 0x01 /* Version / max redirection entries */
#define IOAPIC_REG_ARB 0x02 /* Arbitration ID */
#define IOAPIC_REDTBL_LO(n) (0x10 + (n) * 2) /* Redirection entry n, low */
#define IOAPIC_REDTBL_HI(n) (0x10 + (n) * 2 + 1) /* Redirection entry n, high */
/* ── Redirection table entry flags (low 32-bit word) ────────────────────── */
#define IOAPIC_RTE_MASKED (1u << 16) /* 1 = masked (disabled) */
#define IOAPIC_RTE_LEVEL (1u << 15) /* 1 = level-triggered, 0 = edge */
#define IOAPIC_RTE_ACTIVE_LOW (1u << 13) /* 1 = active low, 0 = active high */
#define IOAPIC_RTE_LOGICAL (1u << 11) /* 1 = logical destination mode */
#define IOAPIC_RTE_DM_FIXED (0u << 8) /* Fixed delivery */
#define IOAPIC_RTE_DM_NMI (4u << 8) /* NMI */
/* bits [7:0] hold the IDT vector */
/* ── Public API ──────────────────────────────────────────────────────────── */
/**
* ioapic_init - Parse the ACPI MADT, locate all I/O APICs and their GSI
* bases, record any ISA interrupt source overrides, then mask
* every redirection entry.
*
* Must be called after uacpi_initialize() (needs MADT accessible).
*/
void ioapic_init(void);
/**
* ioapic_redirect - Programme a single redirection table entry.
*
* @gsi Global System Interrupt number (from MADT or known fixed GSI).
* @vector IDT vector the CPU will see (e.g. 0x20 + irq_number).
* @dest_lapic Physical LAPIC ID of the target CPU.
* @active_low true if device uses active-low polarity.
* @level true if device uses level-triggered signalling.
* @masked true to programme the entry but leave it masked.
*/
void ioapic_redirect(uint32_t gsi, uint8_t vector, uint8_t dest_lapic,
bool active_low, bool level, bool masked);
/**
* ioapic_mask_gsi - Mask (disable) a GSI redirection entry.
* ioapic_unmask_gsi - Unmask (enable) a GSI redirection entry.
*/
void ioapic_mask_gsi(uint32_t gsi);
void ioapic_unmask_gsi(uint32_t gsi);
/**
* ioapic_gsi_for_isa_irq - Look up the GSI that corresponds to an ISA IRQ
* number, accounting for any MADT interrupt source
* overrides (e.g. ISA IRQ 0 → GSI 2 on BOCHS).
*
* Returns the GSI, or the IRQ number itself if no override is defined.
*/
uint32_t ioapic_gsi_for_isa_irq(uint8_t isa_irq);
void irq_redirect_to_apic(uint8_t isa_irq, uint8_t vector, uint8_t dest_lapic, bool masked);
-112
View File
@@ -1,112 +0,0 @@
#include "irq.h"
#include "i8259.h"
#include "arch/x86_64/cpu/io.h"
#include <stddef.h>
#include "libk/arrays.h"
#include "libk/stdio.h"
#include "libk/debug.h"
#include "apic.h"
#include "ioapic.h"
#define PIC_REMAP_OFFSET 0x20
#define MODULE "PIC"
IRQHandler g_IRQHandlers[16];
static IRQHandler g_APICHandlers[256];
const PICDriver* g_Driver = NULL;
extern bool g_IOAPIC;
void x86_64_IRQ_Handler(Registers *regs)
{
int irq = regs->interrupt - PIC_REMAP_OFFSET;
g_Driver->SendEndOfInterrupt(irq);
if (g_IRQHandlers[irq] != NULL)
{
// handle IRQ
g_IRQHandlers[irq](regs);
}
else
{
log_warn(MODULE, "Unhandled IRQ %d...", irq);
}
}
void x86_64_APIC_IRQ_Handler(Registers* regs)
{
uint8_t vector = regs->interrupt;
lapic_eoi();
if (g_APICHandlers[vector] != NULL) {
g_APICHandlers[vector](regs);
} else {
log_warn("APIC", "Unhandled vector 0x%02x", vector);
}
// ← This is the key difference from PIC!
}
void x86_64_IRQ_Initialize(void)
{
const PICDriver* drivers[] = {
i8259_GetDriver(),
};
for (int i = 0; i < SIZE(drivers); i++) {
if (drivers[i]->Probe()) {
g_Driver = drivers[i];
}
}
if (g_Driver == NULL) {
log_warn(MODULE, "No PIC found!");
return;
}
log_info(MODULE, "Found %s PIC.", g_Driver->Name);
g_Driver->Initialize(PIC_REMAP_OFFSET, PIC_REMAP_OFFSET + 8, false);
// register ISR handlers for each of the 16 irq lines
for (int i = 0; i < 16; i++)
x86_64_ISR_RegisterHandler(PIC_REMAP_OFFSET + i, x86_64_IRQ_Handler);
g_Driver->Unmask(0);
}
void x86_64_IRQ_RegisterHandler(int irq, IRQHandler handler)
{
g_IRQHandlers[irq] = handler;
}
void x86_64_APIC_IRQ_RegisterHandler(uint8_t vector, IRQHandler handler)
{
if (vector < 32) {
printf("[APIC] Warning: vector %u is in reserved range!\n", vector);
}
g_APICHandlers[vector] = handler;
x86_64_ISR_RegisterHandler(vector, x86_64_APIC_IRQ_Handler);
}
void x86_64_APIC_IRQ_RedirectAndRegister(uint8_t isa_irq,
uint8_t vector,
IRQHandler handler)
{
x86_64_APIC_IRQ_RegisterHandler(vector, handler);
irq_redirect_to_apic(isa_irq, vector, lapic_id(), false);
}
void x86_64_IRQ_Unmask(int irq)
{
if (g_Driver) g_Driver->Unmask(irq);
}
-13
View File
@@ -1,13 +0,0 @@
#pragma once
#include "arch/x86_64/boot/isr.h"
typedef void (*IRQHandler)(Registers* regs);
void x86_64_IRQ_Initialize();
void x86_64_IRQ_RegisterHandler(int irq, IRQHandler handler);
void x86_64_IRQ_Unmask(int irq);
void x86_64_APIC_IRQ_RegisterHandler(uint8_t vector, IRQHandler handler);
void x86_64_APIC_IRQ_RedirectAndRegister(uint8_t isa_irq,
uint8_t vector,
IRQHandler handler);
+29
View File
@@ -0,0 +1,29 @@
#include "pic.h"
#include "arch/x86_64/cpu/io.h"
#include <stdbool.h>
#include "arch/x86_64/fw/madt.h"
static void pic_disable(void) {
x86_64_outb(0xA1, 0xFF);
x86_64_outb(0x21, 0xFF);
}
void pic_init(void) {
// There isn't any PIC
if (!(madt->flags & 1)) {
return;
}
// Remap the PIC
x86_64_outb(0x20, 0x11);
x86_64_outb(0xA0, 0x11);
x86_64_outb(0x21, 0x20);
x86_64_outb(0xA1, 0x28);
x86_64_outb(0x21, 4);
x86_64_outb(0xA1, 2);
x86_64_outb(0x21, 1);
x86_64_outb(0xA1, 1);
x86_64_outb(0x21, 0);
x86_64_outb(0xA1, 0);
pic_disable();
}
+1 -12
View File
@@ -1,14 +1,3 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
typedef struct {
const char* Name;
bool (*Probe)();
void (*Initialize)(uint8_t offsetPic1, uint8_t offsetPic2, bool autoEoi);
void (*Disable)();
void (*SendEndOfInterrupt)(int irq);
void (*Mask)(int irq);
void (*Unmask)(int irq);
} PICDriver;
void pic_init(void);
-74
View File
@@ -1,74 +0,0 @@
#include "pit.h"
#include "irq.h"
#include "arch/x86_64/cpu/io.h"
#include <stdint.h>
#include "libk/stdio.h"
#include "e9.h"
#include "limine.h"
#include "apic.h"
#include "sched/scheduler.h"
__attribute__((used, section(".limine_requests")))
volatile struct limine_date_at_boot_request boot_request = {
.id = LIMINE_DATE_AT_BOOT_REQUEST_ID,
.revision = 6,
};
#define PIT_BASE_FREQUENCY 1193182
#define PIT_COMMAND_PORT 0x43
#define PIT_CHANNEL0_PORT 0x40
volatile uint64_t g_Ticks = 0;
volatile uint64_t ticks = 0;
uint64_t g_Unixseconds = 0;
extern bool g_IOAPIC;
/* ========================= */
/* IRQ0 Handler (Timer Tick) */
/* ========================= */
void PIT_IRQ_Handler(Registers* regs)
{
(void)regs;
g_Ticks++;
ticks++;
if (ticks >= 1000) {
g_Unixseconds++;
ticks = 0;
}
if (g_IOAPIC == true) {
lapic_eoi();
}
sched_tick();
}
/* ========================= */
/* Initialize PIT */
/* ========================= */
void x86_64_PIT_Initialize(uint32_t frequency)
{
uint16_t divisor = (uint16_t)(PIT_BASE_FREQUENCY / frequency);
printf("PIT divisor = %u\n", divisor);
// Send command byte:
// Channel 0 | lobyte/hibyte | mode 3 (square wave) | binary
x86_64_outb(PIT_COMMAND_PORT, 0x36);
// Send divisor (low byte then high byte)
x86_64_outb(PIT_CHANNEL0_PORT, divisor & 0xFF);
x86_64_outb(PIT_CHANNEL0_PORT, (divisor >> 8) & 0xFF);
g_Unixseconds = boot_request.response->timestamp;
// Register IRQ0 handler (IRQ0 = timer)
x86_64_IRQ_RegisterHandler(0, PIT_IRQ_Handler);
}
/* ========================= */
/* Get tick count */
/* ========================= */
uint64_t PIT_GetTicks(void)
{
return g_Ticks;
}
+5 -7
View File
@@ -1,13 +1,11 @@
#pragma once
#include <stdint.h>
#include "irq.h"
#include "arch/x86_64/cpu/io.h"
#include "libk/stdio.h"
#include "e9.h"
extern volatile uint64_t g_Ticks;
extern uint64_t g_Unixseconds;
#define PIT_DIVIDEND ((uint64_t)1193182)
void x86_64_PIT_Initialize(uint32_t frequency);
uint64_t PIT_GetTicks(void);
void PIT_IRQ_Handler(Registers* regs);
uint16_t pit_counter_value(void);
void pit_set_reload_value(uint16_t new_count);
void pit_set_frequency(uint64_t frequency);
void pit_init();
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include "arch/x86_64/boot/gdt.h"
struct prcb {
uint64_t cpu_number;
uint64_t kernel_stack;
uint64_t user_stack;
struct thread *running_thread;
uint64_t sched_ticks;
struct tss cpu_tss;
uint32_t lapic_id;
size_t fpu_storage_size;
void (*fpu_save)(void *);
void (*fpu_restore)(void *);
uint32_t tick_in_10ms;
};
extern struct prcb *prcbs;
struct prcb *prcb_return_current_cpu(void);
size_t prcb_return_installed_cpus(void);
+127
View File
@@ -0,0 +1,127 @@
#include <stdbool.h>
#include <stdint.h>
#include "pit.h"
#include <limine.h>
#include "arch/x86_64/cpu/io.h"
#include "libk/time.h"
#include "arch/x86_64/asm/asm.h"
#include "mm/vmm.h"
#include "hpet.h"
#include "arch/x86_64/bus/mmio.h"
#include "libk/debug.h"
static struct hpet_table *hpet_table = NULL;
static struct hpet *hpet = NULL;
static uint32_t clk = 0;
static bool timer_installed_b = false;
extern uint32_t smp_bsp_lapic_id;
static volatile struct limine_boot_time_request boot_time_request = {
.id = LIMINE_BOOT_TIME_REQUEST, .revision = 0};
bool hpet_init(void) {
hpet_table = acpi_find_sdt("HPET");
if (!hpet_table) {
kprintf("HPET: No HPET found!\n");
return false;
}
hpet = (struct hpet *)(hpet_table->address.base + MEM_PHYS_OFFSET);
kprintf("HPET: HPET at %p\n", (void *)hpet);
clk = hpet->general_capabilities >> 32;
/*
* General Configuration Register
* 0 - main counter is halted, timer interrupts are disabled
* 1 - main counter is running, timer interrupts are allowed if enabled
*/
mmoutq(&hpet->general_configuration, 0);
mmoutq(&hpet->main_counter_value, 0);
mmoutq(&hpet->general_configuration, 1);
timer_installed_b = true;
return true;
}
uint64_t hpet_counter_value(void) {
return mminq(&hpet->main_counter_value);
}
void hpet_sleep(uint64_t us) {
uint64_t target = hpet_counter_value() + (us * 1000000000) / clk;
while (hpet_counter_value() < target)
pause();
}
void pit_set_frequency(uint64_t frequency) {
uint64_t new_divisor = PIT_DIVIDEND / frequency;
if (PIT_DIVIDEND % frequency > frequency / 2) {
new_divisor++;
}
pit_set_reload_value((uint16_t)new_divisor);
}
void pit_set_reload_value(uint16_t new_count) {
x86_64_outb(0x43, 0x34);
x86_64_outb(0x40, (uint8_t)new_count);
x86_64_outb(0x40, (uint8_t)(new_count >> 8));
}
void pit_init(void) {
timer_installed_b = true;
pit_set_reload_value(0xffff);
pit_set_frequency(TIMER_FREQ);
}
uint16_t pit_counter_value(void) {
x86_64_outb(0x43, 0x00);
uint8_t lo = x86_64_inb(0x40);
uint8_t hi = x86_64_inb(0x40);
return ((uint16_t)hi << 8) | lo;
}
void pit_sleep(uint64_t ms) {
uint64_t target = pit_counter_value() + ms;
while (pit_counter_value() < target)
pause();
}
void timer_init(void) {
struct limine_boot_time_response *boot_time_resp =
boot_time_request.response;
time_realtime.tv_sec = boot_time_resp->boot_time;
if (hpet_init()) {
return;
}
pit_init();
}
bool timer_installed(void) {
return timer_installed_b;
}
void timer_sleep(uint64_t ms) {
if (hpet_table) {
return hpet_sleep(ms * 1000);
}
pit_sleep(ms);
}
uint64_t timer_count(void) {
if (hpet_table) {
return (hpet_counter_value() * clk) / (1000000000000);
}
return pit_counter_value();
}
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
bool timer_installed(void);
void timer_init(void);
void timer_sleep(uint64_t ms);
uint64_t timer_count(void);
void timer_stop_sched(void);
void timer_sched_oneshot(uint8_t isr, uint32_t us);
+31 -22
View File
@@ -1,49 +1,58 @@
#include <stdint.h>
#include "arch/x86_64/sys/pit.h"
#include "arch/x86_64/cpu/io.h"
#include "libk/stdio.h"
#include "tsc.h"
extern uint64_t PIT_GetTicks(void);
#include "libk/debug.h"
#include "arch/x86_64/asm/asm.h"
#include "libk/time.h"
volatile uint64_t tsc_cycles_per_us = 0;
uint64_t rdtsc(void)
inline uint64_t rdtsc(void)
{
uint32_t lo, hi;
__asm__ volatile ("rdtsc" : "=a"(lo), "=d"(hi));
return ((uint64_t)hi << 32) | lo;
}
void calibrate_tsc(void)
{
// Use a stable PIT rate for calibration
const uint32_t pit_freq = 1000; // 1000 Hz = 1ms per tick
const uint32_t calibration_ticks = 1000; // 1 second total
// We measure over one full PIT cycle (~54.9 ms at max reload)
const uint16_t pit_start = 0xFFFF;
pit_set_reload_value(pit_start);
// Wait for PIT to stabilize
uint64_t start_ticks = PIT_GetTicks();
while (PIT_GetTicks() == start_ticks)
;
// latch initial state
uint64_t start_tsc = rdtsc();
uint64_t target_ticks = start_ticks + calibration_ticks;
uint16_t start = pit_counter_value();
// Wait for known number of PIT ticks
while (PIT_GetTicks() < target_ticks)
;
uint16_t current;
// wait for wrap-around (start > current)
do {
current = pit_counter_value();
pause();
} while (current <= start);
uint64_t end_tsc = rdtsc();
// Compute elapsed time
uint64_t tsc_delta = end_tsc - start_tsc;
uint16_t ticks = (start - current);
uint64_t elapsed_us = 1000000ULL;
// PIT frequency = 1193182 Hz
// so each tick = 1 / 1193182 seconds
// convert PIT ticks -> microseconds:
uint64_t elapsed_us =
(ticks * 1000000ULL) / PIT_DIVIDEND;
uint64_t tsc_delta = end_tsc - start_tsc;
tsc_cycles_per_us = tsc_delta / elapsed_us;
printf("TSC calibration complete: %lu cycles/us\n", tsc_cycles_per_us);
kprintf("TSC calibrated: %lu cycles/us\n", tsc_cycles_per_us);
// restore PIT frequency for system timer
pit_set_frequency(TIMER_FREQ);
}
-1
View File
@@ -1,7 +1,6 @@
#include <stdint.h>
#include "arch/x86_64/sys/pit.h"
#include "arch/x86_64/cpu/io.h"
#include "libk/stdio.h"
uint64_t rdtsc(void);
-536
View File
@@ -1,536 +0,0 @@
#include "hda.h"
#include "mm/vmm.h"
#include "mm/pmm.h"
#include "mm/memory.h"
#include "libk/stdio.h"
/* ── Module globals ─────────────────────────────────────────────────────────── */
static uintptr_t g_mmio = 0; /* virtual MMIO base */
static uint32_t *g_corb = NULL; /* CORB ring buffer (virtual) */
static uint64_t *g_rirb = NULL; /* RIRB ring buffer (virtual) */
static uintptr_t g_corb_phys = 0;
static uintptr_t g_rirb_phys = 0;
static uint32_t g_corb_wp = 0; /* shadow of hardware CORBWP (starts at 0) */
static uint32_t g_rirb_rp = 0; /* our RIRB read pointer (starts at 0) */
/* Codec state discovered during enumeration */
static uint8_t g_codec = 0; /* codec address (0-15) */
static uint8_t g_afg = 0; /* Audio Function Group NID */
static uint8_t g_dac = 0; /* Output Converter NID */
static uint8_t g_pin = 0; /* Output Pin Widget NID */
static uint8_t g_iss = 0; /* number of input stream descriptors */
/* BDL (allocated once in hda_init, reused each play call) */
static hda_bdl_entry_t *g_bdl = NULL;
static uintptr_t g_bdl_phys = 0;
/* MMIO offset of the output stream descriptor we're using */
static uint32_t g_sd_base = 0;
/* ── MMIO helpers ───────────────────────────────────────────────────────────── */
static inline uint8_t r8 (uint32_t r) { return *(volatile uint8_t *)(g_mmio+r); }
static inline uint16_t r16(uint32_t r) { return *(volatile uint16_t*)(g_mmio+r); }
static inline uint32_t r32(uint32_t r) { return *(volatile uint32_t*)(g_mmio+r); }
static inline void w8 (uint32_t r, uint8_t v){ *(volatile uint8_t *)(g_mmio+r)=v; }
static inline void w16(uint32_t r, uint16_t v){ *(volatile uint16_t*)(g_mmio+r)=v; }
static inline void w32(uint32_t r, uint32_t v){ *(volatile uint32_t*)(g_mmio+r)=v; }
/* Stream descriptor helpers operate relative to g_sd_base */
static inline uint8_t sd_r8 (uint32_t o){ return r8 (g_sd_base+o); }
static inline uint16_t sd_r16(uint32_t o){ return r16(g_sd_base+o); }
static inline uint32_t sd_r32(uint32_t o){ return r32(g_sd_base+o); }
static inline void sd_w8 (uint32_t o,uint8_t v){ w8 (g_sd_base+o,v); }
static inline void sd_w16(uint32_t o,uint16_t v){ w16(g_sd_base+o,v); }
static inline void sd_w32(uint32_t o,uint32_t v){ w32(g_sd_base+o,v); }
/* ── Busy-wait delay ────────────────────────────────────────────────────────── */
static void hda_udelay(uint32_t us)
{
/* ~400 pause iterations ≈ 1 µs on a modern core (generous upper bound) */
volatile uint32_t n = us * 400;
while (n--) asm volatile("pause");
}
/* ── CORB / RIRB verb engine ────────────────────────────────────────────────── */
/*
* hda_send_verb write one 32-bit command word to the CORB and wait for the
* corresponding RIRB response. Returns the 64-bit RIRB entry (response in the
* low 32 bits).
*/
static uint64_t hda_send_verb(uint32_t cmd)
{
g_corb_wp = (g_corb_wp + 1) & 0xFF; /* 256-entry ring */
g_corb[g_corb_wp] = cmd;
/* Tell the hardware there is a new entry */
w16(HDA_CORBWP, (uint16_t)g_corb_wp);
/* Poll until RIRBWP advances (hardware writes one response per command) */
for (uint32_t i = 0; i < 1000000; i++) {
asm volatile("pause");
if ((r8(HDA_RIRBWP) & 0xFF) != (uint8_t)g_rirb_rp) {
g_rirb_rp = (g_rirb_rp + 1) & 0xFF;
return g_rirb[g_rirb_rp];
}
}
printf("[HDA] verb timeout cmd=%08x\n", cmd);
return (uint64_t)-1;
}
/*
* hda_verb build and send a codec verb, return the 32-bit response.
*
* Verb encoding:
* verb <= 0x0F : 4-bit verb [19:16], 16-bit payload [15:0] (SET_FMT, SET_AMP …)
* verb >= 0x100: 12-bit verb [19:8], 8-bit payload [7:0] (GET_PARAM, SET_* …)
*/
static uint32_t hda_verb(uint8_t cad, uint8_t nid, uint32_t verb, uint32_t payload)
{
uint32_t cmd;
if (verb <= 0xF)
cmd = ((uint32_t)cad << 28) | ((uint32_t)nid << 20)
| (verb << 16) | (payload & 0xFFFF);
else
cmd = ((uint32_t)cad << 28) | ((uint32_t)nid << 20)
| ((verb & 0xFFF) << 8) | (payload & 0xFF);
return (uint32_t)hda_send_verb(cmd);
}
static uint32_t hda_get_param(uint8_t cad, uint8_t nid, uint8_t param)
{
return hda_verb(cad, nid, 0xF00, param);
}
/* ── CORB initialisation ────────────────────────────────────────────────────── */
static bool corb_init(void)
{
/* Stop DMA engine */
w8(HDA_CORBCTL, r8(HDA_CORBCTL) & ~0x02u);
for (int i = 0; i < 50000 && (r8(HDA_CORBCTL) & 0x02); i++)
asm volatile("pause");
/* Allocate ring: 256 entries × 4 bytes = 1 KB, lives in one page */
void *phys = pmm_allocz(1);
if (!phys) return false;
g_corb_phys = (uintptr_t)phys;
g_corb = (uint32_t *)((uintptr_t)phys + MEM_PHYS_OFFSET);
/* Select 256-entry size (bits[1:0] = 0b10) */
w8(HDA_CORBSIZE, (r8(HDA_CORBSIZE) & ~0x03u) | 0x02u);
/* Program base address */
w32(HDA_CORBLBASE, (uint32_t)(g_corb_phys & 0xFFFFFFFF));
w32(HDA_CORBUBASE, (uint32_t)(g_corb_phys >> 32));
/* Reset WP to 0 */
w16(HDA_CORBWP, 0);
g_corb_wp = 0;
/* Reset RP: set CORBRPRST, wait, clear */
w16(HDA_CORBRP, 0x8000);
hda_udelay(100);
w16(HDA_CORBRP, 0x0000);
hda_udelay(100);
/* Start DMA */
w8(HDA_CORBCTL, r8(HDA_CORBCTL) | 0x02u);
for (int i = 0; i < 50000; i++) {
if (r8(HDA_CORBCTL) & 0x02) return true;
asm volatile("pause");
}
printf("[HDA] CORB DMA failed to start\n");
return false;
}
/* ── RIRB initialisation ────────────────────────────────────────────────────── */
static bool rirb_init(void)
{
/* Stop DMA engine */
w8(HDA_RIRBCTL, r8(HDA_RIRBCTL) & ~0x02u);
for (int i = 0; i < 50000 && (r8(HDA_RIRBCTL) & 0x02); i++)
asm volatile("pause");
/* Allocate ring: 256 entries × 8 bytes = 2 KB, one page */
void *phys = pmm_allocz(1);
if (!phys) return false;
g_rirb_phys = (uintptr_t)phys;
g_rirb = (uint64_t *)((uintptr_t)phys + MEM_PHYS_OFFSET);
/* 256-entry size */
w8(HDA_RIRBSIZE, (r8(HDA_RIRBSIZE) & ~0x03u) | 0x02u);
/* Base address */
w32(HDA_RIRBLBASE, (uint32_t)(g_rirb_phys & 0xFFFFFFFF));
w32(HDA_RIRBUBASE, (uint32_t)(g_rirb_phys >> 32));
/* Reset WP (write RIRBWPRST bit) */
w16(HDA_RIRBWP, 0x8000);
g_rirb_rp = 0;
/* Set interrupt count to 0xFF (we poll anyway, so this is a safety valve) */
w16(HDA_RINTCNT, 0xFF);
/* Start DMA */
w8(HDA_RIRBCTL, r8(HDA_RIRBCTL) | 0x02u);
for (int i = 0; i < 50000; i++) {
if (r8(HDA_RIRBCTL) & 0x02) return true;
asm volatile("pause");
}
printf("[HDA] RIRB DMA failed to start\n");
return false;
}
/* ── Codec enumeration ──────────────────────────────────────────────────────── */
/*
* Return the NID of connection-list entry `idx` for widget `nid` on codec `cad`.
* Assumes short form (8-bit entries) which covers all common HDA codecs.
*/
static uint8_t conn_entry(uint8_t cad, uint8_t nid, uint8_t idx)
{
/* GET_CONN_LIST_ENTRY (0xF02): payload = starting index, returns 4 packed entries */
uint32_t r = hda_verb(cad, nid, 0xF02, idx & ~3u);
return (uint8_t)(r >> ((idx & 3) * 8));
}
/*
* Walk the AFG widgets to find the first output converter (DAC) and the first
* output-capable pin that connects to it (or to any DAC if the first one is
* not in the pin's connection list).
*/
static bool enumerate_codec(uint8_t cad)
{
/* Root node: get function group range */
uint32_t root_cnt = hda_get_param(cad, 0, HDA_PARAM_NODE_COUNT);
uint8_t fg_start = (root_cnt >> 16) & 0xFF;
uint8_t fg_count = (root_cnt >> 0) & 0xFF;
/* Find the Audio Function Group */
uint8_t afg = 0;
for (uint8_t n = fg_start; n < fg_start + fg_count; n++) {
uint32_t type = hda_get_param(cad, n, HDA_PARAM_FUNC_GROUP_TYPE) & 0xFF;
if (type == 0x01) { afg = n; break; }
}
if (!afg) { printf("[HDA] no AFG on codec %u\n", cad); return false; }
/* Enumerate widgets */
uint32_t w_info = hda_get_param(cad, afg, HDA_PARAM_NODE_COUNT);
uint8_t w_start = (w_info >> 16) & 0xFF;
uint8_t w_count = (w_info >> 0) & 0xFF;
uint8_t dac = 0, pin = 0;
for (uint8_t w = w_start; w < w_start + w_count; w++) {
uint32_t wcap = hda_get_param(cad, w, HDA_PARAM_AUDIO_WIDGET_CAP);
uint8_t wtype = (wcap >> 20) & 0xF;
if (wtype == HDA_WTYPE_AUDIO_OUT && !dac) {
dac = w;
} else if (wtype == HDA_WTYPE_PIN) {
uint32_t pcap = hda_get_param(cad, w, HDA_PARAM_PIN_CAPABILITIES);
if ((pcap & HDA_PINCAP_OUTPUT) && !pin) {
pin = w;
}
}
}
if (!dac) { printf("[HDA] no DAC found\n"); return false; }
if (!pin) { printf("[HDA] no output pin found\n"); return false; }
g_afg = afg; g_dac = dac; g_pin = pin;
printf("[HDA] codec=%u AFG=%u DAC=%u Pin=%u\n", cad, afg, dac, pin);
/* Select DAC in pin's connection list if needed */
uint8_t clen = (uint8_t)(hda_get_param(cad, pin, HDA_PARAM_CONN_LIST_LEN) & 0x7F);
for (uint8_t i = 0; i < clen; i++) {
if (conn_entry(cad, pin, i) == dac) {
hda_verb(cad, pin, 0x701, i); /* SET_CONN_SELECT */
break;
}
}
return true;
}
/* ── HDA format word calculation ────────────────────────────────────────────── */
static uint16_t calc_format(hda_format_t f)
{
uint16_t fmt = 0;
/* Channels: field value = channels 1 */
fmt |= (f.channels - 1) & 0xF;
/* Bits per sample in bits [6:4] */
switch (f.bits_per_sample) {
case 8: fmt |= (0u << 4); break;
case 16: fmt |= (1u << 4); break;
case 20: fmt |= (2u << 4); break;
case 24: fmt |= (3u << 4); break;
case 32: fmt |= (4u << 4); break;
default: fmt |= (1u << 4);
printf("[HDA] unknown bit depth %u, using 16-bit\n", f.bits_per_sample);
}
/*
* Sample rate: bit14 = base (0 = 48 kHz, 1 = 44.1 kHz),
* bits[13:11] = multiplier 1,
* bits[10:8] = divisor 1.
*/
switch (f.sample_rate) {
case 8000: fmt |= (0u << 14) | (0u << 11) | (5u << 8); break; /* 48000 / 6 */
case 11025: fmt |= (1u << 14) | (0u << 11) | (3u << 8); break; /* 44100 / 4 */
case 16000: fmt |= (0u << 14) | (0u << 11) | (2u << 8); break; /* 48000 / 3 */
case 22050: fmt |= (1u << 14) | (0u << 11) | (1u << 8); break; /* 44100 / 2 */
case 24000: fmt |= (0u << 14) | (0u << 11) | (1u << 8); break; /* 48000 / 2 */
case 32000: fmt |= (0u << 14) | (1u << 11) | (2u << 8); break; /* 48000*2/ 3 */
case 44100: fmt |= (1u << 14) | (0u << 11) | (0u << 8); break; /* 44100 / 1 */
case 48000: break; /* 48000 / 1 */
case 88200: fmt |= (1u << 14) | (1u << 11) | (0u << 8); break; /* 44100*2/ 1 */
case 96000: fmt |= (0u << 14) | (1u << 11) | (0u << 8); break; /* 48000*2/ 1 */
case 176400: fmt |= (1u << 14) | (3u << 11) | (0u << 8); break; /* 44100*4/ 1 */
case 192000: fmt |= (0u << 14) | (3u << 11) | (0u << 8); break; /* 48000*4/ 1 */
default:
printf("[HDA] unsupported sample rate %u, defaulting to 48000\n",
f.sample_rate);
}
return fmt;
}
/* ── Stream descriptor reset helper ────────────────────────────────────────── */
static void sd_reset(void)
{
/* Assert stream reset */
sd_w8(HDA_SD_CTL0, sd_r8(HDA_SD_CTL0) | HDA_SD_CTL_SRST);
for (int i = 0; i < 100000; i++) {
if (sd_r8(HDA_SD_CTL0) & HDA_SD_CTL_SRST) break;
asm volatile("pause");
}
/* Deassert stream reset */
sd_w8(HDA_SD_CTL0, sd_r8(HDA_SD_CTL0) & ~HDA_SD_CTL_SRST);
for (int i = 0; i < 100000; i++) {
if (!(sd_r8(HDA_SD_CTL0) & HDA_SD_CTL_SRST)) break;
asm volatile("pause");
}
}
/* ══════════════════════════════════════════════════════════════════════════════
* Public API
* ══════════════════════════════════════════════════════════════════════════════ */
bool hda_init(pci_device_t *dev)
{
/* ── 1. Enable PCI Memory Space + Bus Master ────────────────────────────── */
uint16_t pci_cmd = pci_read16(dev->addr, 0x04);
pci_cmd |= (1u << 1) | (1u << 2); /* Memory Space Enable | Bus Master Enable */
pci_write16(dev->addr, 0x04, pci_cmd);
/* ── 2. Read BAR0 (HDA MMIO, may be 64-bit) ─────────────────────────────── */
uint32_t bar0_raw = dev->bar[0];
uint64_t mmio_phys;
if ((bar0_raw & 0x6u) == 0x4u) {
/* 64-bit BAR: combine BAR0 (lower) and BAR1 (upper) */
mmio_phys = ((uint64_t)(bar0_raw & ~0xFu))
| ((uint64_t)dev->bar[1] << 32);
} else {
mmio_phys = bar0_raw & ~0xFu;
}
if (!mmio_phys) {
printf("[HDA] BAR0 is zero, controller not properly enumerated by firmware\n");
return false;
}
/* Map via HHDM (all physical memory is already mapped with MEM_PHYS_OFFSET) */
g_mmio = mmio_phys + MEM_PHYS_OFFSET;
printf("[HDA] MMIO phys=%lx virt=%lx\n", (uint64_t)mmio_phys, (uint64_t)g_mmio);
/* ── 3. Controller reset ─────────────────────────────────────────────────── */
/* Assert reset */
w32(HDA_GCTL, r32(HDA_GCTL) & ~HDA_GCTL_CRST);
for (int i = 0; i < 500000; i++) {
if (!(r32(HDA_GCTL) & HDA_GCTL_CRST)) break;
asm volatile("pause");
}
hda_udelay(100);
/* Release reset */
w32(HDA_GCTL, r32(HDA_GCTL) | HDA_GCTL_CRST);
for (int i = 0; i < 500000; i++) {
if (r32(HDA_GCTL) & HDA_GCTL_CRST) break;
asm volatile("pause");
}
/* Wait ≥ 521 µs for codecs to come out of reset */
hda_udelay(1000);
/* ── 4. GCAP: discover stream counts ─────────────────────────────────────── */
uint16_t gcap = r16(HDA_GCAP);
g_iss = (gcap >> 8) & 0xF; /* number of input SDs */
uint8_t oss = (gcap >> 12) & 0xF; /* number of output SDs */
printf("[HDA] gcap=%04x ISS=%u OSS=%u\n", gcap, g_iss, oss);
if (!oss) { printf("[HDA] no output streams\n"); return false; }
/* Output SD 0 starts immediately after all input SDs */
g_sd_base = 0x80u + (uint32_t)g_iss * HDA_SD_STRIDE;
/* ── 5. CORB + RIRB ─────────────────────────────────────────────────────── */
if (!corb_init()) { printf("[HDA] CORB init failed\n"); return false; }
if (!rirb_init()) { printf("[HDA] RIRB init failed\n"); return false; }
/* ── 6. Detect and enumerate codecs ─────────────────────────────────────── */
uint16_t statests = r16(HDA_STATESTS);
if (!statests) { printf("[HDA] no codecs detected\n"); return false; }
bool found = false;
for (uint8_t c = 0; c < 15; c++) {
if (!(statests & (1u << c))) continue;
printf("[HDA] codec %u present\n", c);
if (!found && enumerate_codec(c)) {
g_codec = c;
found = true;
}
}
if (!found) { printf("[HDA] no usable codec\n"); return false; }
/* ── 7. Allocate persistent BDL (1 page, 256 possible entries × 16 bytes) ─ */
void *bdl_phys = pmm_allocz(1);
if (!bdl_phys) { printf("[HDA] OOM: BDL\n"); return false; }
g_bdl_phys = (uintptr_t)bdl_phys;
g_bdl = (hda_bdl_entry_t *)((uintptr_t)bdl_phys + MEM_PHYS_OFFSET);
printf("[HDA] init complete\n");
return true;
}
bool hda_play_pcm(uintptr_t phys_buf, uint32_t size, hda_format_t fmt)
{
if (!g_mmio || !g_dac || !g_pin) {
printf("[HDA] not initialised\n");
return false;
}
if (!phys_buf || !size) return false;
uint16_t format_word = calc_format(fmt);
/* ── 1. Wake up codec nodes ─────────────────────────────────────────────── */
/* SET_POWER_STATE D0 (fully on) for AFG, DAC, and Pin */
hda_verb(g_codec, g_afg, 0x705, 0x00);
hda_verb(g_codec, g_dac, 0x705, 0x00);
hda_verb(g_codec, g_pin, 0x705, 0x00);
hda_udelay(100);
/* ── 2. Assign stream tag 1, channel 0 to the DAC ──────────────────────── */
/* SET_STREAM_CHANNEL: bits[7:4]=stream_tag, bits[3:0]=channel */
hda_verb(g_codec, g_dac, 0x706, (1u << 4) | 0u);
/* ── 3. Set sample format on DAC ───────────────────────────────────────── */
hda_verb(g_codec, g_dac, 0x2, format_word); /* SET_CONVERTER_FORMAT (4-bit verb) */
/* ── 4. Unmute DAC output amp to maximum gain ───────────────────────────── */
/*
* SET_AMP_GAIN_MUTE (4-bit verb 0x3) payload:
* bit 15 = output amp
* bit 14 = input amp
* bit 13 = left channel
* bit 12 = right channel
* bit 7 = mute (0 = unmuted)
* bits[6:0] = gain
*/
uint32_t dac_outcap = hda_get_param(g_codec, g_dac, HDA_PARAM_AMP_CAP_OUTPUT);
uint8_t max_gain = (dac_outcap >> 8) & 0x7F;
hda_verb(g_codec, g_dac, 0x3, 0xB000u | max_gain);
/* ── 5. Enable pin output + unmute pin amp ──────────────────────────────── */
/* SET_PIN_WIDGET_CONTROL: bit6=Out Enable */
hda_verb(g_codec, g_pin, 0x707, 0x40u);
/* If the pin has an output amp, unmute it too */
uint32_t pin_outcap = hda_get_param(g_codec, g_pin, HDA_PARAM_AMP_CAP_OUTPUT);
if (pin_outcap & (1u << 31)) { /* has output amp */
uint8_t pin_max = (pin_outcap >> 8) & 0x7F;
hda_verb(g_codec, g_pin, 0x3, 0xB000u | pin_max);
}
/* ── 6. Reset output stream descriptor ─────────────────────────────────── */
sd_reset();
/* ── 7. Build BDL (single entry covering the entire buffer) ─────────────── */
memset(g_bdl, 0, sizeof(hda_bdl_entry_t) * 2);
g_bdl[0].addr = (uint64_t)phys_buf;
g_bdl[0].length = size;
g_bdl[0].flags = 0x1; /* IOC */
/* ── 8. Program stream descriptor ──────────────────────────────────────── */
/* Cyclic Buffer Length = total audio data */
sd_w32(HDA_SD_CBL, size);
/* Last Valid Index = 0 (one BDL entry, index 0) */
sd_w16(HDA_SD_LVI, 0);
/* BDL base address */
sd_w32(HDA_SD_BDPL, (uint32_t)(g_bdl_phys & 0xFFFFFFFF));
sd_w32(HDA_SD_BDPU, (uint32_t)(g_bdl_phys >> 32));
/* Format */
sd_w16(HDA_SD_FMT, format_word);
/* Stream tag = 1 in SD CTL byte 2 bits [7:4] */
sd_w8(HDA_SD_CTL2, (sd_r8(HDA_SD_CTL2) & 0x0Fu) | (1u << 4));
/* Clear any stale status bits (write-1-to-clear) */
sd_w8(HDA_SD_STS, HDA_SD_STS_BCIS | HDA_SD_STS_FIFOE | HDA_SD_STS_DESE);
/* ── 9. Enable stream-level interrupt-on-completion and run ─────────────── */
uint8_t ctl = sd_r8(HDA_SD_CTL0);
ctl |= HDA_SD_CTL_IOCE | HDA_SD_CTL_RUN;
ctl &= ~HDA_SD_CTL_SRST;
sd_w8(HDA_SD_CTL0, ctl);
printf("[HDA] playback started: %u Hz %u-bit %uch %u bytes\n",
fmt.sample_rate, fmt.bits_per_sample, fmt.channels, size);
return true;
}
void hda_stop(void)
{
if (!g_mmio) return;
/* Clear RUN bit */
sd_w8(HDA_SD_CTL0, sd_r8(HDA_SD_CTL0) & ~HDA_SD_CTL_RUN);
/* Wait for hardware to acknowledge */
for (int i = 0; i < 100000; i++) {
if (!(sd_r8(HDA_SD_CTL0) & HDA_SD_CTL_RUN)) break;
asm volatile("pause");
}
/* Clear status */
sd_w8(HDA_SD_STS, HDA_SD_STS_BCIS | HDA_SD_STS_FIFOE | HDA_SD_STS_DESE);
}
void hda_wait_complete(void)
{
if (!g_mmio) return;
/* Poll BCIS (Buffer Completion Interrupt Status) */
while (!(sd_r8(HDA_SD_STS) & HDA_SD_STS_BCIS))
asm volatile("pause");
hda_stop();
printf("[HDA] playback complete\n");
}
bool hda_is_playing(void)
{
if (!g_mmio) return false;
if (!(sd_r8(HDA_SD_CTL0) & HDA_SD_CTL_RUN)) return false;
if ( sd_r8(HDA_SD_STS) & HDA_SD_STS_BCIS) return false; /* finished */
return true;
}
-133
View File
@@ -1,133 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "arch/x86_64/bus/pci.h"
/* ── HDA MMIO register offsets ─────────────────────────────────────────────── */
#define HDA_GCAP 0x00 /* u16 Global Capabilities */
#define HDA_VMIN 0x02 /* u8 Minor Version */
#define HDA_VMAJ 0x03 /* u8 Major Version */
#define HDA_OUTPAY 0x04 /* u16 Output Payload Capability */
#define HDA_INPAY 0x06 /* u16 Input Payload Capability */
#define HDA_GCTL 0x08 /* u32 Global Control */
#define HDA_WAKEEN 0x0C /* u16 Wake Enable */
#define HDA_STATESTS 0x0E /* u16 State Change Status (one bit per codec) */
#define HDA_GSTS 0x10 /* u16 Global Status */
#define HDA_INTCTL 0x20 /* u32 Interrupt Control */
#define HDA_INTSTS 0x24 /* u32 Interrupt Status */
#define HDA_WALCLK 0x30 /* u32 Wall Clock Counter */
#define HDA_SSYNC 0x38 /* u32 Stream Synchronisation */
/* CORB */
#define HDA_CORBLBASE 0x40 /* u32 CORB Lower Base Address */
#define HDA_CORBUBASE 0x44 /* u32 CORB Upper Base Address */
#define HDA_CORBWP 0x48 /* u16 CORB Write Pointer */
#define HDA_CORBRP 0x4A /* u16 CORB Read Pointer */
#define HDA_CORBCTL 0x4C /* u8 CORB Control */
#define HDA_CORBSTS 0x4D /* u8 CORB Status */
#define HDA_CORBSIZE 0x4E /* u8 CORB Size */
/* RIRB */
#define HDA_RIRBLBASE 0x50 /* u32 RIRB Lower Base Address */
#define HDA_RIRBUBASE 0x54 /* u32 RIRB Upper Base Address */
#define HDA_RIRBWP 0x58 /* u16 RIRB Write Pointer (hardware-maintained)*/
#define HDA_RINTCNT 0x5A /* u16 Response Interrupt Count */
#define HDA_RIRBCTL 0x5C /* u8 RIRB Control */
#define HDA_RIRBSTS 0x5D /* u8 RIRB Status */
#define HDA_RIRBSIZE 0x5E /* u8 RIRB Size */
/* Stream Descriptor register offsets (relative to the SD's MMIO base) */
#define HDA_SD_CTL0 0x00 /* u8 Control byte 0 (SRST, RUN, IOCE …) */
#define HDA_SD_CTL1 0x01 /* u8 Control byte 1 */
#define HDA_SD_CTL2 0x02 /* u8 Control byte 2 bits[7:4] = stream tag */
#define HDA_SD_STS 0x03 /* u8 Status bit2=BCIS bit3=FIFOE bit4=DESE */
#define HDA_SD_LPIB 0x04 /* u32 Link Position in Buffer */
#define HDA_SD_CBL 0x08 /* u32 Cyclic Buffer Length */
#define HDA_SD_LVI 0x0C /* u16 Last Valid Index */
#define HDA_SD_FIFOS 0x10 /* u16 FIFO Size (read-only) */
#define HDA_SD_FMT 0x12 /* u16 Format */
#define HDA_SD_BDPL 0x18 /* u32 BDL Lower Base Address */
#define HDA_SD_BDPU 0x1C /* u32 BDL Upper Base Address */
#define HDA_SD_STRIDE 0x20 /* Each stream descriptor is 0x20 bytes wide */
/* GCTL bits */
#define HDA_GCTL_CRST (1u << 0) /* Controller Reset (0 = reset, 1 = run) */
#define HDA_GCTL_UNSOL (1u << 8) /* Accept Unsolicited Responses */
/* SD CTL byte-0 bits */
#define HDA_SD_CTL_SRST (1u << 0) /* Stream Reset */
#define HDA_SD_CTL_RUN (1u << 1) /* Stream Run */
#define HDA_SD_CTL_IOCE (1u << 2) /* Interrupt on Completion Enable */
#define HDA_SD_CTL_FEIE (1u << 3) /* FIFO Error Interrupt Enable */
#define HDA_SD_CTL_DEIE (1u << 4) /* Descriptor Error Interrupt Enable */
/* SD STS bits */
#define HDA_SD_STS_BCIS (1u << 2) /* Buffer Completion Interrupt Status */
#define HDA_SD_STS_FIFOE (1u << 3) /* FIFO Error */
#define HDA_SD_STS_DESE (1u << 4) /* Descriptor Error */
/* Codec widget types (from AUDIO_WIDGET_CAP bits[23:20]) */
#define HDA_WTYPE_AUDIO_OUT 0x0
#define HDA_WTYPE_AUDIO_IN 0x1
#define HDA_WTYPE_AUDIO_MIXER 0x2
#define HDA_WTYPE_AUDIO_SEL 0x3
#define HDA_WTYPE_PIN 0x4
/* Codec parameter IDs (used with GET_PARAM verb 0xF00) */
#define HDA_PARAM_VENDOR_ID 0x00
#define HDA_PARAM_NODE_COUNT 0x04
#define HDA_PARAM_FUNC_GROUP_TYPE 0x05
#define HDA_PARAM_AUDIO_WIDGET_CAP 0x09
#define HDA_PARAM_SUPPORTED_PCM 0x0A
#define HDA_PARAM_PIN_CAPABILITIES 0x0C
#define HDA_PARAM_CONN_LIST_LEN 0x0E
#define HDA_PARAM_AMP_CAP_OUTPUT 0x12
/* Pin capability bits */
#define HDA_PINCAP_OUTPUT (1u << 4)
#define HDA_PINCAP_INPUT (1u << 5)
/* ── Types ─────────────────────────────────────────────────────────────────── */
typedef struct {
uint32_t sample_rate;
uint8_t channels; /* 1 = mono, 2 = stereo */
uint8_t bits_per_sample; /* 8 / 16 / 20 / 24 / 32 */
} hda_format_t;
/* Buffer Descriptor List entry (must be 128-byte aligned; page-aligned is fine) */
typedef struct __attribute__((packed)) {
uint64_t addr; /* Physical address of the audio buffer */
uint32_t length; /* Length in bytes */
uint32_t flags; /* Bit 0 = IOC (Interrupt on Completion) */
} hda_bdl_entry_t;
/* ── Public API ─────────────────────────────────────────────────────────────── */
/**
* hda_init - find, map, and initialise the first HDA controller on the bus.
* @dev: PCI device struct returned by pci_find_hda().
* Returns true on success.
*/
bool hda_init(pci_device_t *dev);
/**
* hda_play_pcm - set up an output stream and start playback.
* @phys_buf : physical address of the audio data (from pmm_alloc).
* @size : byte count of the audio data.
* @fmt : sample rate / channel count / bit depth.
* Returns true if the stream was started successfully.
*/
bool hda_play_pcm(uintptr_t phys_buf, uint32_t size, hda_format_t fmt);
/**
* hda_wait_complete - block until the current stream finishes (polls BCIS).
* Stops and resets the stream when done.
*/
void hda_wait_complete(void);
/** hda_stop - immediately stop the output stream. */
void hda_stop(void);
/** hda_is_playing - returns true while the stream is running and not done. */
bool hda_is_playing(void);
-173
View File
@@ -1,173 +0,0 @@
#include "pcm.h"
#include "hda.h"
#include "fs/ext2.h"
#include "mm/pmm.h"
#include "mm/vmm.h"
#include "mm/memory.h"
#include "stdio.h"
/* ── WAV chunk scanner ──────────────────────────────────────────────────────── */
/*
* Scan a buffer for RIFF/WAVE format. If it is a valid PCM WAV file, fills
* in *fmt_out, *data_offset and *data_size and returns true.
*
* WAV chunks are word-padded (each chunk rounds up to an even byte count), so
* we skip through them by (8 + ALIGN_UP(chunk_size, 2)) bytes at a time.
*/
static bool parse_wav(const uint8_t *buf, uint32_t buf_size,
hda_format_t *fmt_out,
uint32_t *data_offset,
uint32_t *data_size)
{
if (buf_size < 12) return false;
/* Check RIFF header */
if (buf[0]!='R'||buf[1]!='I'||buf[2]!='F'||buf[3]!='F') return false;
if (buf[8]!='W'||buf[9]!='A'||buf[10]!='V'||buf[11]!='E') return false;
uint32_t pos = 12;
bool got_fmt = false;
bool got_data = false;
hda_format_t fmt = {0};
while (pos + 8 <= buf_size) {
/* Read chunk ID and size (little-endian) */
const char *id = (const char *)(buf + pos);
uint32_t chunk_size = *(const uint32_t *)(buf + pos + 4);
pos += 8;
if (pos + chunk_size > buf_size) break; /* truncated */
if (id[0]=='f' && id[1]=='m' && id[2]=='t' && id[3]==' ') {
if (chunk_size < 16) { pos += chunk_size; continue; }
uint16_t audio_fmt = *(uint16_t *)(buf + pos + 0);
if (audio_fmt != 1) {
printf("[PCM] WAV audio format %u not supported (only PCM=1)\n",
audio_fmt);
return false;
}
fmt.channels = (uint8_t)*(uint16_t *)(buf + pos + 2);
fmt.sample_rate = *(uint32_t *)(buf + pos + 4);
fmt.bits_per_sample = (uint8_t)*(uint16_t *)(buf + pos + 14);
got_fmt = true;
} else if (id[0]=='d' && id[1]=='a' && id[2]=='t' && id[3]=='a') {
*data_offset = pos;
*data_size = chunk_size;
got_data = true;
break; /* no need to scan further */
}
/* Advance past chunk (WAV chunks are word-aligned) */
pos += chunk_size;
if (chunk_size & 1) pos++; /* skip pad byte */
}
if (!got_fmt || !got_data) return false;
*fmt_out = fmt;
return true;
}
/* ── Shared internal helper ─────────────────────────────────────────────────── */
static bool play_from_ext2(const char *filename,
bool force_fmt,
hda_format_t forced)
{
/* ── 1. Resolve path and read inode ─────────────────────────────────────── */
uint32_t inum = ext2_resolve_path(filename);
if (!inum) {
printf("[PCM] file not found: %s\n", filename);
return false;
}
ext2_inode_t inode;
if (!ext2_read_inode(inum, &inode)) {
printf("[PCM] failed to read inode for %s\n", filename);
return false;
}
uint32_t file_size = inode.i_size;
if (!file_size) {
printf("[PCM] %s is empty\n", filename);
return false;
}
/* ── 2. Allocate physically-contiguous DMA buffer ────────────────────────── */
/*
* pmm_alloc() returns a contiguous run of physical pages, which is exactly
* what HDA's DMA engine needs. We access the data through HHDM.
*/
uint32_t pages = (file_size + PAGE_SIZE - 1) / PAGE_SIZE;
void *phys = pmm_alloc(pages);
if (!phys) {
printf("[PCM] OOM: cannot allocate %u pages for %s\n", pages, filename);
return false;
}
uint8_t *virt = (uint8_t *)((uintptr_t)phys + MEM_PHYS_OFFSET);
/* Zero any padding at the end so stale bytes don't become noise */
memset(virt + file_size, 0, (size_t)(pages * PAGE_SIZE - file_size));
/* ── 3. Read file data ───────────────────────────────────────────────────── */
if (!ext2_read_file(&inode, virt)) {
printf("[PCM] failed to read %s\n", filename);
pmm_free(phys, pages);
return false;
}
/* ── 4. Determine format and audio data region ───────────────────────────── */
hda_format_t fmt;
uintptr_t audio_phys = (uintptr_t)phys;
uint32_t audio_size = file_size;
if (force_fmt) {
fmt = forced;
/* Treat the whole file as raw audio samples */
} else {
uint32_t data_offset = 0, data_size = 0;
if (parse_wav(virt, file_size, &fmt, &data_offset, &data_size)) {
/* Adjust the physical pointer to skip the WAV headers */
audio_phys += data_offset;
audio_size = data_size;
printf("[PCM] WAV: %u Hz %u-bit %u ch %u bytes of audio\n",
fmt.sample_rate, fmt.bits_per_sample, fmt.channels, audio_size);
} else {
/* Not a WAV assume raw 48 kHz, 16-bit stereo */
fmt.sample_rate = 48000;
fmt.bits_per_sample = 16;
fmt.channels = 2;
printf("[PCM] Raw PCM assumed: 48000 Hz 16-bit stereo %u bytes\n",
audio_size);
}
}
/* ── 5. Play ─────────────────────────────────────────────────────────────── */
bool ok = hda_play_pcm(audio_phys, audio_size, fmt);
if (ok)
hda_wait_complete(); /* blocks until the stream finishes */
else
printf("[PCM] hda_play_pcm failed\n");
/* ── 6. Free the DMA buffer ─────────────────────────────────────────────── */
pmm_free(phys, pages);
return ok;
}
/* ══════════════════════════════════════════════════════════════════════════════
* Public API
* ══════════════════════════════════════════════════════════════════════════════ */
bool pcm_play_file(const char *filename)
{
hda_format_t dummy = {0};
return play_from_ext2(filename, false, dummy);
}
bool pcm_play_raw(const char *filename, hda_format_t fmt)
{
return play_from_ext2(filename, true, fmt);
}
-53
View File
@@ -1,53 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "hda.h"
/*
* Minimal WAV (RIFF/WAVE) header types.
* pcm_play_file() autodetects RIFF/WAVE and falls back to raw PCM if the
* magic bytes aren't present.
*/
typedef struct __attribute__((packed)) {
char chunk_id[4]; /* "RIFF" */
uint32_t chunk_size; /* file size 8 */
char format[4]; /* "WAVE" */
} wav_riff_t;
typedef struct __attribute__((packed)) {
char chunk_id[4]; /* "fmt " */
uint32_t chunk_size; /* 16 for PCM */
uint16_t audio_format; /* 1 = PCM (linear) */
uint16_t channels;
uint32_t sample_rate;
uint32_t byte_rate; /* sample_rate * channels * bits_per_sample / 8 */
uint16_t block_align;
uint16_t bits_per_sample;
} wav_fmt_chunk_t;
/*
* pcm_play_file - read a file from the ext2 root directory and play it via HDA.
*
* Supports:
* • WAV any PCM WAV (no compression): sample rate / channels / bit depth
* are read from the "fmt " chunk automatically.
* • Raw no RIFF header; audio is assumed to be 48 000 Hz, 16-bit, stereo.
* Override with pcm_play_raw() if file has a different format.
*
* The function allocates a physically-contiguous DMA buffer, reads the file,
* starts playback, blocks until complete, then frees the buffer.
*
* @filename : name of the file in the ext2 root directory (e.g. "music.wav").
* Returns : true on success.
*/
bool pcm_play_file(const char *filename);
/*
* pcm_play_raw - same as pcm_play_file but forces the given format instead of
* auto-detecting from a WAV header. Useful for headerless .pcm files.
*
* @filename : file in ext2 root.
* @fmt : sample rate / channels / bit depth.
*/
bool pcm_play_raw(const char *filename, hda_format_t fmt);
+106
View File
@@ -0,0 +1,106 @@
#include "terminal/backends/fb.h"
#include "libk/debug.h"
#include "fb.h"
#include "mm/memory.h"
#include "mp/spinlock.h"
#include "mm/slab.h"
#include "libk/string.h"
uint8_t framebuffer_initialised = 0;
struct framebuffer framebuff;
static struct flanterm_context *ctx;
static void kffree(void *addr, size_t sz) {
(void)sz;
kfree(addr);
}
void framebuffer_init(struct framebuffer *fb) {
framebuff.address = fb->address;
framebuff.pitch = fb->pitch;
framebuff.bpp = fb->bpp;
framebuff.width = fb->width;
framebuff.height = fb->height;
framebuff.tex_x = fb->tex_x;
framebuff.tex_y = fb->tex_y;
framebuff.tex_color = fb->tex_color;
framebuff.tex_height = fb->height / 16;
framebuff.tex_width = fb->width / 8;
framebuff.back_address = kmalloc(framebuff.pitch * framebuff.height);
framebuff.bg_color = fb->bg_color;
framebuff.color_masks[0] = fb->color_masks[0];
framebuff.color_masks[1] = fb->color_masks[1];
framebuff.color_masks[2] = fb->color_masks[2];
ctx = flanterm_fb_init(kmalloc, kffree, (void *)fb->address, fb->width,
fb->height, fb->pitch, fb->color_masks[0].length,
fb->color_masks[0].offset, fb->color_masks[1].length,
fb->color_masks[1].offset, fb->color_masks[2].length,
fb->color_masks[2].offset, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, 0, 0, 1, 1, 1, 0);
framebuff.ctx = ctx;
framebuffer_clear(fb->tex_color, fb->bg_color);
framebuffer_initialised = 1;
}
void framebuffer_set_callback(void (*callback)(struct flanterm_context *,
uint64_t, uint64_t, uint64_t,
uint64_t)) {
if (ctx) {
ctx->callback = callback;
}
}
static void ultoa_strcat(char *dest, uint64_t src, bool add_semicolon) {
char buf[65];
strcat(dest, ultoa(src, buf, 10));
if (add_semicolon == true) {
strcat(dest, ";");
}
}
// Format: 0xAARRGGBB, alpha is ignored
void framebuffer_clear(uint32_t foreground, uint32_t background) {
uint8_t red_fg = (foreground & 0xFF0000) >> 16;
uint8_t green_fg = (foreground & 0xFF00) >> 8;
uint8_t blue_fg = foreground & 0xFF;
uint8_t red_bg = (background & 0xFF0000) >> 16;
uint8_t green_bg = (background & 0xFF00) >> 8;
uint8_t blue_bg = background & 0xFF;
char result[128] = "\033[38;2;";
ultoa_strcat(result, red_fg, true);
ultoa_strcat(result, green_fg, true);
ultoa_strcat(result, blue_fg, true);
strcat(result, "48;2;");
ultoa_strcat(result, red_bg, true);
ultoa_strcat(result, green_bg, true);
ultoa_strcat(result, blue_bg, false);
strcat(result, "m");
flanterm_write(ctx, result, strlen(result));
flanterm_write(ctx, "\033[2J", 5);
flanterm_write(ctx, "\033[H", 4);
}
void framebuffer_putchar(char c) {
flanterm_write(ctx, &c, 1);
}
void framebuffer_puts(char *string) {
flanterm_write(ctx, string, strlen(string));
}
struct framebuffer *framebuffer_info(void) {
return &framebuff;
}
+99
View File
@@ -0,0 +1,99 @@
#include "../fb/terminal/flanterm.h"
#include "fs/devtmpfs.h"
#include <stddef.h>
#include <stdint.h>
// taken from linux/include/uapi/linux/fb.h
struct fb_bitfield {
uint32_t offset; /* beginning of bitfield */
uint32_t length; /* length of bitfield */
uint32_t msb_right; /* != 0 : Most significant bit is */
/* right */
};
struct fb_var_screeninfo {
uint32_t xres; /* visible resolution */
uint32_t yres;
uint32_t xres_virtual; /* virtual resolution */
uint32_t yres_virtual;
uint32_t xoffset; /* offset from virtual to visible */
uint32_t yoffset; /* resolution */
uint32_t bits_per_pixel; /* guess what */
uint32_t grayscale; /* 0 = color, 1 = grayscale, */
/* >1 = FOURCC */
struct fb_bitfield red; /* bitfield in fb mem if true color, */
struct fb_bitfield green; /* else only length is significant */
struct fb_bitfield blue;
struct fb_bitfield transp; /* transparency */
uint32_t nonstd; /* != 0 Non standard pixel format */
uint32_t activate; /* see FB_ACTIVATE_* */
uint32_t height; /* height of picture in mm */
uint32_t width; /* width of picture in mm */
uint32_t accel_flags; /* (OBSOLETE) see fb_info.flags */
/* Timing: All values in pixclocks, except pixclock (of course) */
uint32_t pixclock; /* pixel clock in ps (pico seconds) */
uint32_t left_margin; /* time from sync to picture */
uint32_t right_margin; /* time from picture to sync */
uint32_t upper_margin; /* time from sync to picture */
uint32_t lower_margin;
uint32_t hsync_len; /* length of horizontal sync */
uint32_t vsync_len; /* length of vertical sync */
uint32_t sync; /* see FB_SYNC_* */
uint32_t vmode; /* see FB_VMODE_* */
uint32_t rotate; /* angle we rotate counter clockwise */
uint32_t colorspace; /* colorspace for FOURCC-based modes */
uint32_t reserved[4]; /* Reserved for future compatibility */
};
struct fb_fix_screeninfo {
char id[16]; /* identification string eg "TT Builtin" */
unsigned long smem_start; /* Start of frame buffer mem */
/* (physical address) */
uint32_t smem_len; /* Length of frame buffer mem */
uint32_t type; /* see FB_TYPE_* */
uint32_t type_aux; /* Interleave for interleaved Planes */
uint32_t visual; /* see FB_VISUAL_* */
uint16_t xpanstep; /* zero if no hardware panning */
uint16_t ypanstep; /* zero if no hardware panning */
uint16_t ywrapstep; /* zero if no hardware ywrap */
uint32_t line_length; /* length of a line in bytes */
unsigned long mmio_start; /* Start of Memory Mapped I/O */
/* (physical address) */
uint32_t mmio_len; /* Length of Memory Mapped I/O */
uint32_t accel; /* Indicate to driver which */
/* specific chip/card we have */
uint16_t capabilities; /* see FB_CAP_* */
uint16_t reserved[2]; /* Reserved for future compatibility */
};
struct framebuffer {
uint32_t *address;
uint32_t *back_address;
size_t pitch, bpp;
uint16_t width, height;
size_t tex_x, tex_y;
uint16_t tex_width, tex_height;
uint32_t tex_color;
uint32_t bg_color;
struct fb_bitfield color_masks[3];
struct flanterm_context *ctx;
};
extern struct framebuffer framebuff;
void framebuffer_init(struct framebuffer *fb);
void framebuffer_set_callback(void (*callback)(struct flanterm_context *,
uint64_t, uint64_t, uint64_t,
uint64_t));
void framebuffer_clear(uint32_t foreground, uint32_t background);
void framebuffer_putchar(char c);
void framebuffer_puts(char *string);
struct framebuffer *framebuffer_info(void);
void fbdev_init(void);
+128
View File
@@ -0,0 +1,128 @@
#include "libk/debug.h"
#include "libk/errno.h"
#include "fb.h"
#include "fs/vfs.h"
#include "mm/memory.h"
#include "mm/mmap.h"
#define FB_ACTIVATE_NOW 0 /* set values immediately (or vbl)*/
#define FB_ACTIVATE_NXTOPEN 1 /* activate on next open */
#define FB_ACTIVATE_TEST 2 /* don't set, round up impossible */
#define FB_ACTIVATE_MASK 15
#define FB_VMODE_NONINTERLACED 0 /* non interlaced */
#define FB_VMODE_INTERLACED 1 /* interlaced */
#define FB_VMODE_DOUBLE 2 /* double scan */
#define FB_VMODE_ODD_FLD_FIRST 4 /* interlaced: top line first */
#define FB_VMODE_MASK 255
#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */
#define FB_TYPE_PLANES 1 /* Non interleaved planes */
#define FB_TYPE_INTERLEAVED_PLANES 2 /* Interleaved planes */
#define FB_TYPE_TEXT 3 /* Text/attributes */
#define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */
#define FB_TYPE_FOURCC 5 /* Type identified by a V4L2 FOURCC */
#define FB_VISUAL_MONO01 0 /* Monochr. 1=Black 0=White */
#define FB_VISUAL_MONO10 1 /* Monochr. 1=White 0=Black */
#define FB_VISUAL_TRUECOLOR 2 /* True color */
#define FB_VISUAL_PSEUDOCOLOR 3 /* Pseudo color (like atari) */
#define FB_VISUAL_DIRECTCOLOR 4 /* Direct color */
#define FB_VISUAL_STATIC_PSEUDOCOLOR 5 /* Pseudo color readonly */
#define FB_VISUAL_FOURCC 6 /* Visual identified by a V4L2 FOURCC */
#define FBIOGET_VSCREENINFO 0x4600
#define FBIOPUT_VSCREENINFO 0x4601
#define FBIOGET_FSCREENINFO 0x4602
#define FBIOBLANK 0x4611
static struct fb_var_screeninfo framebuffer_var_info = {0};
static struct fb_fix_screeninfo framebuffer_fix_info = {0};
static struct resource *framebuff_res;
static ssize_t fbdev_write(struct resource *this,
struct f_description *description, const void *buf,
off_t offset, size_t count) {
(void)description;
spinlock_acquire_or_wait(&this->lock);
memcpy((void *)(framebuff.address + offset), buf, count);
spinlock_drop(&this->lock);
return 0;
}
static void *fbdev_mmap(struct resource *this, size_t file_page, int flags) {
(void)flags;
spinlock_acquire_or_wait(&this->lock);
size_t offset = file_page * PAGE_SIZE;
if (offset >= (framebuff.height * framebuff.pitch)) {
return NULL;
}
spinlock_drop(&this->lock);
return (void *)(((uint64_t)(framebuff.address) - MEM_PHYS_OFFSET) + offset);
}
static int fbdev_ioctl(struct resource *this, struct f_description *description,
uint64_t request, uint64_t arg) {
switch (request) {
case FBIOGET_VSCREENINFO:
*(struct fb_var_screeninfo *)arg = framebuffer_var_info;
return 0;
case FBIOGET_FSCREENINFO:
*(struct fb_fix_screeninfo *)arg = framebuffer_fix_info;
return 0;
case FBIOPUT_VSCREENINFO:
spinlock_acquire_or_wait(&this->lock);
framebuffer_var_info = *(struct fb_var_screeninfo *)arg;
spinlock_drop(&this->lock);
return 0;
case FBIOBLANK:
return 0;
}
return resource_default_ioctl(this, description, request, arg);
}
void fbdev_init(void) {
extern uint8_t framebuffer_initialised;
if (!framebuffer_initialised)
return;
framebuffer_fix_info.smem_len = framebuff.pitch * framebuff.height;
framebuffer_fix_info.mmio_len = framebuff.pitch * framebuff.height;
framebuffer_fix_info.line_length = framebuff.pitch;
framebuffer_fix_info.type = FB_TYPE_PACKED_PIXELS;
framebuffer_fix_info.visual = FB_VISUAL_TRUECOLOR;
framebuffer_var_info.xres = framebuff.width;
framebuffer_var_info.yres = framebuff.height;
framebuffer_var_info.xres_virtual = framebuff.width;
framebuffer_var_info.yres_virtual = framebuff.height;
framebuffer_var_info.bits_per_pixel = framebuff.bpp;
framebuffer_var_info.red = framebuff.color_masks[0];
framebuffer_var_info.green = framebuff.color_masks[1];
framebuffer_var_info.blue = framebuff.color_masks[2];
framebuffer_var_info.activate = FB_ACTIVATE_NOW;
framebuffer_var_info.vmode = FB_VMODE_NONINTERLACED;
framebuffer_var_info.width = -1;
framebuffer_var_info.height = -1;
framebuff_res = resource_create(sizeof(struct resource));
framebuff_res->ioctl = fbdev_ioctl;
framebuff_res->write = fbdev_write;
framebuff_res->mmap = fbdev_mmap;
framebuff_res->can_mmap = true;
framebuff_res->stat.st_size = 0;
framebuff_res->stat.st_blocks = 0;
framebuff_res->stat.st_blksize = 4096;
framebuff_res->stat.st_rdev = resource_create_dev_id();
framebuff_res->stat.st_mode = 0666 | S_IFCHR;
devtmpfs_add_device(framebuff_res, "fbdev");
vfs_symlink(vfs_root, "/dev/fbdev", "/dev/fb0");
}
+2
View File
@@ -0,0 +1,2 @@
*.d
*.o
+22
View File
@@ -0,0 +1,22 @@
Copyright (C) 2022-2024 mintsuki and contributors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+43
View File
@@ -0,0 +1,43 @@
# Flanterm
Flanterm is a fast and reasonably complete terminal emulator with support for
multiple output backends. Included is a fast framebuffer backend.
### Quick usage
To quickly set up and use a framebuffer Flanterm instance, it is possible to
use the `flanterm_fb_init()` function as such:
```c
#include <flanterm/flanterm.h>
#include <flanterm/backends/fb.h>
struct flanterm_context *ft_ctx = flanterm_fb_init(
NULL,
NULL,
framebuffer_ptr, width, height, pitch,
red_mask_size, red_mask_shift,
green_mask_size, green_mask_shift,
blue_mask_size, blue_mask_shift,
NULL,
NULL, NULL,
NULL, NULL,
NULL, NULL,
NULL, 0, 0, 1,
0, 0,
0
);
```
Where `framebuffer_ptr, width, height, pitch` and `{red,green,blue}_mask_{size,shift}`
represent the corresponding info about the framebuffer to use for this given instance.
The meaning of the other arguments can be found in `backends/fb.h`.
To then print to the terminal instance, simply use the `flanterm_write()`
function on the given instance. For example:
```c
#include <flanterm/flanterm.h>
const char msg[] = "Hello world\n";
flanterm_write(ft_ctx, msg, sizeof(msg));
```
File diff suppressed because it is too large Load Diff
+136
View File
@@ -0,0 +1,136 @@
/* Copyright (C) 2022-2024 mintsuki and contributors.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLANTERM_FB_H
#define FLANTERM_FB_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include "../flanterm.h"
#define FLANTERM_FB_FONT_GLYPHS 256
struct flanterm_fb_char {
uint32_t c;
uint32_t fg;
uint32_t bg;
};
struct flanterm_fb_queue_item {
size_t x, y;
struct flanterm_fb_char c;
};
struct flanterm_fb_context {
struct flanterm_context term;
size_t font_width;
size_t font_height;
size_t glyph_width;
size_t glyph_height;
size_t font_scale_x;
size_t font_scale_y;
size_t offset_x, offset_y;
volatile uint32_t *framebuffer;
size_t pitch;
size_t width;
size_t height;
size_t bpp;
uint8_t red_mask_size, red_mask_shift;
uint8_t green_mask_size, green_mask_shift;
uint8_t blue_mask_size, blue_mask_shift;
size_t font_bits_size;
uint8_t *font_bits;
size_t font_bool_size;
bool *font_bool;
uint32_t ansi_colours[8];
uint32_t ansi_bright_colours[8];
uint32_t default_fg, default_bg;
uint32_t default_fg_bright, default_bg_bright;
size_t canvas_size;
uint32_t *canvas;
size_t grid_size;
size_t queue_size;
size_t map_size;
struct flanterm_fb_char *grid;
struct flanterm_fb_queue_item *queue;
size_t queue_i;
struct flanterm_fb_queue_item **map;
uint32_t text_fg;
uint32_t text_bg;
size_t cursor_x;
size_t cursor_y;
uint32_t saved_state_text_fg;
uint32_t saved_state_text_bg;
size_t saved_state_cursor_x;
size_t saved_state_cursor_y;
size_t old_cursor_x;
size_t old_cursor_y;
};
struct flanterm_context *flanterm_fb_init(
/* If _malloc and _free are nulled, use the bump allocated instance (1 use only). */
void *(*_malloc)(size_t),
void (*_free)(void *, size_t),
uint32_t *framebuffer, size_t width, size_t height, size_t pitch,
uint8_t red_mask_size, uint8_t red_mask_shift,
uint8_t green_mask_size, uint8_t green_mask_shift,
uint8_t blue_mask_size, uint8_t blue_mask_shift,
uint32_t *canvas, /* If nulled, no canvas. */
uint32_t *ansi_colours, uint32_t *ansi_bright_colours, /* If nulled, default. */
uint32_t *default_bg, uint32_t *default_fg, /* If nulled, default. */
uint32_t *default_bg_bright, uint32_t *default_fg_bright, /* If nulled, default. */
/* If font is null, use default font and font_width and font_height ignored. */
void *font, size_t font_width, size_t font_height, size_t font_spacing,
/* If scale_x and scale_y are 0, automatically scale font based on resolution. */
size_t font_scale_x, size_t font_scale_y,
size_t margin
);
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large Load Diff
+137
View File
@@ -0,0 +1,137 @@
/* Copyright (C) 2022-2024 mintsuki and contributors.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FLANTERM_H
#define FLANTERM_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#define FLANTERM_MAX_ESC_VALUES 16
#define FLANTERM_CB_DEC 10
#define FLANTERM_CB_BELL 20
#define FLANTERM_CB_PRIVATE_ID 30
#define FLANTERM_CB_STATUS_REPORT 40
#define FLANTERM_CB_POS_REPORT 50
#define FLANTERM_CB_KBD_LEDS 60
#define FLANTERM_CB_MODE 70
#define FLANTERM_CB_LINUX 80
#define FLANTERM_OOB_OUTPUT_OCRNL (1 << 0)
#define FLANTERM_OOB_OUTPUT_OFDEL (1 << 1)
#define FLANTERM_OOB_OUTPUT_OFILL (1 << 2)
#define FLANTERM_OOB_OUTPUT_OLCUC (1 << 3)
#define FLANTERM_OOB_OUTPUT_ONLCR (1 << 4)
#define FLANTERM_OOB_OUTPUT_ONLRET (1 << 5)
#define FLANTERM_OOB_OUTPUT_ONOCR (1 << 6)
#define FLANTERM_OOB_OUTPUT_OPOST (1 << 7)
struct flanterm_context {
/* internal use */
size_t tab_size;
bool autoflush;
bool cursor_enabled;
bool scroll_enabled;
bool control_sequence;
bool escape;
bool osc;
bool osc_escape;
bool rrr;
bool discard_next;
bool bold;
bool bg_bold;
bool reverse_video;
bool dec_private;
bool insert_mode;
uint64_t code_point;
size_t unicode_remaining;
uint8_t g_select;
uint8_t charsets[2];
size_t current_charset;
size_t escape_offset;
size_t esc_values_i;
size_t saved_cursor_x;
size_t saved_cursor_y;
size_t current_primary;
size_t current_bg;
size_t scroll_top_margin;
size_t scroll_bottom_margin;
uint32_t esc_values[FLANTERM_MAX_ESC_VALUES];
uint64_t oob_output;
bool saved_state_bold;
bool saved_state_bg_bold;
bool saved_state_reverse_video;
size_t saved_state_current_charset;
size_t saved_state_current_primary;
size_t saved_state_current_bg;
/* to be set by backend */
size_t rows, cols;
void (*raw_putchar)(struct flanterm_context *, uint8_t c);
void (*clear)(struct flanterm_context *, bool move);
void (*set_cursor_pos)(struct flanterm_context *, size_t x, size_t y);
void (*get_cursor_pos)(struct flanterm_context *, size_t *x, size_t *y);
void (*set_text_fg)(struct flanterm_context *, size_t fg);
void (*set_text_bg)(struct flanterm_context *, size_t bg);
void (*set_text_fg_bright)(struct flanterm_context *, size_t fg);
void (*set_text_bg_bright)(struct flanterm_context *, size_t bg);
void (*set_text_fg_rgb)(struct flanterm_context *, uint32_t fg);
void (*set_text_bg_rgb)(struct flanterm_context *, uint32_t bg);
void (*set_text_fg_default)(struct flanterm_context *);
void (*set_text_bg_default)(struct flanterm_context *);
void (*set_text_fg_default_bright)(struct flanterm_context *);
void (*set_text_bg_default_bright)(struct flanterm_context *);
void (*move_character)(struct flanterm_context *, size_t new_x, size_t new_y, size_t old_x, size_t old_y);
void (*scroll)(struct flanterm_context *);
void (*revscroll)(struct flanterm_context *);
void (*swap_palette)(struct flanterm_context *);
void (*save_state)(struct flanterm_context *);
void (*restore_state)(struct flanterm_context *);
void (*double_buffer_flush)(struct flanterm_context *);
void (*full_refresh)(struct flanterm_context *);
void (*deinit)(struct flanterm_context *, void (*)(void *, size_t));
/* to be set by client */
void (*callback)(struct flanterm_context *, uint64_t, uint64_t, uint64_t, uint64_t);
};
void flanterm_context_reinit(struct flanterm_context *ctx);
void flanterm_write(struct flanterm_context *ctx, const char *buf, size_t count);
#ifdef __cplusplus
}
#endif
#endif
-145
View File
@@ -1,145 +0,0 @@
#include "drivers/input/input.h"
#include "mp/spinlock.h"
#include "libk/stdio.h"
#include "fs/vfs.h"
#include <stddef.h>
#include "mm/memory.h"
#include "libk/string.h"
#include <stddef.h>
/* ------------------------------------------------------------------ *
* Event ring-buffer
* ------------------------------------------------------------------ */
#define INPUT_BUF_SIZE 512
#define CONSOLE_BUF_SIZE 256
static char s_console_buf[CONSOLE_BUF_SIZE];
static size_t s_console_rpos = 0;
static size_t s_console_wpos = 0;
static input_event_t s_buf[INPUT_BUF_SIZE];
static size_t s_rpos = 0;
static size_t s_wpos = 0;
static spinlock_t s_lock = SPINLOCK_INIT;
/* Called from IRQ context */
void input_push_char(char c)
{
spinlock_acquire_or_wait(&s_lock);
size_t next = (s_console_wpos + 1) % CONSOLE_BUF_SIZE;
if (next != s_console_rpos) { /* drop if full */
s_console_buf[s_console_wpos] = c;
s_console_wpos = next;
}
spinlock_drop(&s_lock);
}
int input_read_console(void *buf, size_t len)
{
uint8_t *p = buf;
size_t count = 0;
spinlock_acquire_or_wait(&s_lock);
while (count < len && s_console_rpos != s_console_wpos) {
p[count++] = s_console_buf[s_console_rpos];
s_console_rpos = (s_console_rpos + 1) % CONSOLE_BUF_SIZE;
}
spinlock_drop(&s_lock);
return (int)count; /* 0 = no data yet (non-blocking) */
}
static void push_event(const input_event_t *ev)
{
spinlock_acquire_or_wait(&s_lock);
size_t next = (s_wpos + 1) % INPUT_BUF_SIZE;
if (next != s_rpos) { /* drop if full */
s_buf[s_wpos] = *ev;
s_wpos = next;
}
spinlock_drop(&s_lock);
}
bool input_poll(input_event_t *out)
{
spinlock_acquire_or_wait(&s_lock);
if (s_rpos == s_wpos) {
spinlock_drop(&s_lock);
return false;
}
*out = s_buf[s_rpos];
s_rpos = (s_rpos + 1) % INPUT_BUF_SIZE;
spinlock_drop(&s_lock);
return true;
}
bool input_has_event(void)
{
spinlock_acquire_or_wait(&s_lock);
bool has = (s_rpos != s_wpos);
spinlock_drop(&s_lock);
return has;
}
/* ------------------------------------------------------------------ *
* Driver-facing helpers
* ------------------------------------------------------------------ */
void input_push_key(uint8_t scancode, char ascii, bool pressed)
{
input_event_t ev = {
.type = INPUT_EV_KEY,
.key = { .scancode = scancode, .ascii = ascii, .pressed = pressed },
};
push_event(&ev);
}
void input_push_mouse_rel(int16_t dx, int16_t dy)
{
input_event_t ev = { .type = INPUT_EV_MOUSE_REL, .rel = { dx, dy } };
push_event(&ev);
}
void input_push_mouse_btn(uint8_t button, bool pressed)
{
input_event_t ev = {
.type = INPUT_EV_MOUSE_BTN,
.btn = { .button = button, .pressed = pressed },
};
push_event(&ev);
}
void input_push_mouse_wheel(int8_t delta)
{
input_event_t ev = { .type = INPUT_EV_MOUSE_WHEEL, .wheel = { delta } };
push_event(&ev);
}
static int dev_input_read(void *buf, size_t len)
{
size_t count = 0;
while (count + sizeof(input_event_t) <= len) {
input_event_t ev;
if (!input_poll(&ev)) break;
memcpy((uint8_t*)buf + count, &ev, sizeof(ev));
count += sizeof(ev);
}
return (int)count;
}
static int dev_input_write(const void *buf, size_t len)
{
(void)buf; (void)len;
return -1; /* read-only */
}
void input_register_devnodes(void)
{
VFS_RegisterCharDev("/dev/input/event0", dev_input_read, dev_input_write);
}
void input_init(void)
{
input_register_devnodes();
printf("input: subsystem initialized\n");
}
-65
View File
@@ -1,65 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
/* ------------------------------------------------------------------ *
* Generic input event types
* ------------------------------------------------------------------ */
typedef enum {
INPUT_EV_NONE = 0,
INPUT_EV_KEY, /* key press / release */
INPUT_EV_MOUSE_REL, /* relative mouse movement */
INPUT_EV_MOUSE_BTN, /* mouse button press/release */
INPUT_EV_MOUSE_WHEEL,
} input_ev_type_t;
typedef struct {
input_ev_type_t type;
union {
/* INPUT_EV_KEY */
struct {
uint8_t scancode; /* raw set-1 scancode (break bit cleared) */
char ascii; /* 0 if non-printable */
bool pressed;
} key;
/* INPUT_EV_MOUSE_REL */
struct {
int16_t dx, dy;
} rel;
/* INPUT_EV_MOUSE_BTN */
struct {
uint8_t button; /* 0=left 1=right 2=middle */
bool pressed;
} btn;
/* INPUT_EV_MOUSE_WHEEL */
struct {
int8_t delta;
} wheel;
};
} input_event_t;
/* ------------------------------------------------------------------ *
* Public API
* ------------------------------------------------------------------ */
void input_init(void);
/* Called by drivers (PS/2, USB HID, …) to publish events */
void input_push_key(uint8_t scancode, char ascii, bool pressed);
void input_push_mouse_rel(int16_t dx, int16_t dy);
void input_push_mouse_btn(uint8_t button, bool pressed);
void input_push_mouse_wheel(int8_t delta);
void input_push_char(char c);
int input_read_console(void *buf, size_t len);
/* Consumer API */
bool input_poll(input_event_t *out); /* non-blocking; false if empty */
bool input_has_event(void);
/* VFS helpers — call after VFS is ready */
void input_register_devnodes(void); /* creates /dev/input/event0 */
-200
View File
@@ -1,200 +0,0 @@
#include "ps2.h"
#include "drivers/input/input.h"
#include "arch/x86_64/sys/irq.h"
#include "arch/x86_64/boot/isr.h"
#include "arch/x86_64/cpu/io.h"
#include "arch/x86_64/sys/ioapic.h"
#include "arch/x86_64/sys/apic.h"
#include "libk/stdio.h"
#include "drivers/video/render.h"
/* ── PS/2 I/O ports ───────────────────────────────────────────────────────── */
#define PS2_DATA_PORT 0x60 /* Read: scancode / Write: command data */
#define PS2_STATUS_PORT 0x64 /* Read: controller status */
#define PS2_CMD_PORT 0x64 /* Write: controller command */
/* Status register bits */
#define PS2_STATUS_OBF (1 << 0) /* Output buffer full (data ready to read) */
#define PS2_STATUS_IBF (1 << 1) /* Input buffer full (don't write yet) */
/* ── IRQ number for the keyboard ─────────────────────────────────────────── */
#define KBD_IRQ 1
#define KBD_IDT_VECTOR (0x20 + KBD_IRQ) /* 0x21 with PIC_REMAP_OFFSET=0x20 */
/* ── Modifier state ───────────────────────────────────────────────────────── */
static bool s_shift = false;
static bool s_ctrl = false;
static bool s_alt = false;
static bool s_caps_lock = false;
static bool s_extended = false; /* true after receiving 0xE0 prefix */
/* ══════════════════════════════════════════════════════════════════════════
* Set-1 keycode → ASCII translation tables
*
* Index = Set-1 make code (0x000x58 covers the full AT-101 layout).
* 0x00 = unmapped / non-printable.
* ══════════════════════════════════════════════════════════════════════════ */
static const char s_normal[128] = {
/*00*/ 0, 0, '1', '2', '3', '4', '5', '6',
/*08*/ '7', '8', '9', '0', '-', '=', '\b', '\t',
/*10*/ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
/*18*/ 'o', 'p', '[', ']', '\n', 0, 'a', 's',
/*20*/ 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
/*28*/ '\'','`', 0, '\\','z', 'x', 'c', 'v',
/*30*/ 'b', 'n', 'm', ',', '.', '/', 0, '*',
/*38*/ 0, ' ', 0, 0, 0, 0, 0, 0,
/*40*/ 0, 0, 0, 0, 0, 0, 0, '7',
/*48*/ '8', '9', '-', '4', '5', '6', '+', '1',
/*50*/ '2', '3', '0', '.', 0, 0, 0, 0,
/*58*/ 0
};
static const char s_shifted[128] = {
/*00*/ 0, 0, '!', '@', '#', '$', '%', '^',
/*08*/ '&', '*', '(', ')', '_', '+', '\b', '\t',
/*10*/ 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I',
/*18*/ 'O', 'P', '{', '}', '\n', 0, 'A', 'S',
/*20*/ 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':',
/*28*/ '"', '~', 0, '|', 'Z', 'X', 'C', 'V',
/*30*/ 'B', 'N', 'M', '<', '>', '?', 0, '*',
/*38*/ 0, ' ', 0, 0, 0, 0, 0, 0,
/*40*/ 0, 0, 0, 0, 0, 0, 0, '7',
/*48*/ '8', '9', '-', '4', '5', '6', '+', '1',
/*50*/ '2', '3', '0', '.', 0, 0, 0, 0,
/*58*/ 0
};
/* ══════════════════════════════════════════════════════════════════════════
* Extended (0xE0-prefixed) make codes we care about
* ══════════════════════════════════════════════════════════════════════════ */
typedef enum {
/* Regular Set-1 make codes (non-extended) */
SC_LSHIFT = 0x2A,
SC_RSHIFT = 0x36,
SC_LCTRL = 0x1D,
SC_LALT = 0x38,
SC_CAPSLOCK = 0x3A,
SC_BACKSPACE= 0x0E,
SC_ENTER = 0x1C,
SC_TAB = 0x0F,
SC_ESC = 0x01,
/* Function keys */
SC_F1 = 0x3B, SC_F2 = 0x3C, SC_F3 = 0x3D, SC_F4 = 0x3E,
SC_F5 = 0x3F, SC_F6 = 0x40, SC_F7 = 0x41, SC_F8 = 0x42,
SC_F9 = 0x43, SC_F10 = 0x44, SC_F11 = 0x57, SC_F12 = 0x58,
} scancode_t;
/* ══════════════════════════════════════════════════════════════════════════
* IRQ1 handler
* ══════════════════════════════════════════════════════════════════════════ */
void ps2_kbd_handler(Registers *regs)
{
(void)regs;
/*
* Always drain the output buffer even if we don't handle the byte,
* otherwise the PS/2 controller stalls and stops sending interrupts.
*/
uint8_t status = x86_64_inb(PS2_STATUS_PORT);
if (!(status & PS2_STATUS_OBF)) {
/* Spurious interrupt with no data — just return */
return;
}
uint8_t byte = x86_64_inb(PS2_DATA_PORT);
/* ── Handle 0xE0 extended-key prefix ─────────────────────────────── */
if (byte == 0xE0) {
s_extended = true;
return;
}
/* ── Decode make / break ─────────────────────────────────────────── */
bool pressed = !(byte & 0x80); /* bit 7 = 0 → make, 1 → break */
uint8_t scancode = byte & 0x7F; /* strip the break bit */
bool extended = s_extended;
s_extended = false;
/* ── Update modifier keys ────────────────────────────────────────── */
if (!extended) {
switch (scancode) {
case SC_LSHIFT: case SC_RSHIFT:
s_shift = pressed;
return; /* don't push a key event for bare modifiers */
case SC_LCTRL:
s_ctrl = pressed;
return;
case SC_LALT:
s_alt = pressed;
return;
case SC_CAPSLOCK:
if (pressed) s_caps_lock = !s_caps_lock;
return;
}
}
/* ── Translate to ASCII ──────────────────────────────────────────── */
char ascii = 0;
if (!extended && scancode < 128) {
bool use_upper = s_shift ^ s_caps_lock; /* XOR: caps inverts shift */
ascii = use_upper ? s_shifted[scancode] : s_normal[scancode];
}
/* Extended keys (arrows, home, end, etc.) leave ascii=0 */
/* ── Push event ──────────────────────────────────────────────────── */
input_push_key(scancode, ascii, pressed);
if (pressed && ascii) {
input_push_char(ascii);
if (ascii == '\b') {
backspace();
} else {
putchar(ascii);
}
}
}
/* ══════════════════════════════════════════════════════════════════════════
* Public helpers
* ══════════════════════════════════════════════════════════════════════════ */
uint8_t ps2_kbd_read_scancode(void)
{
/* Spin until data is available (for early/polled use only) */
while (!(x86_64_inb(PS2_STATUS_PORT) & PS2_STATUS_OBF))
asm volatile("pause");
return x86_64_inb(PS2_DATA_PORT);
}
/* ══════════════════════════════════════════════════════════════════════════
* Initialisation
* ══════════════════════════════════════════════════════════════════════════ */
void ps2_kbd_init(void)
{
/*
* ── Step 1: Flush the PS/2 output buffer ─────────────────────────
*
* Any leftover bytes from before boot will cause the controller to
* withhold interrupts. Drain them now.
*/
int attempts = 16;
while (attempts-- && (x86_64_inb(PS2_STATUS_PORT) & PS2_STATUS_OBF))
(void)x86_64_inb(PS2_DATA_PORT);
x86_64_APIC_IRQ_RedirectAndRegister(1, 0x21, ps2_kbd_handler);
printf("[PS2] Keyboard driver initialised (IRQ%d vector 0x%02x)\n",
KBD_IRQ, KBD_IDT_VECTOR);
}
-9
View File
@@ -1,9 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
void ps2_kbd_init(void);
uint8_t ps2_kbd_read_scancode(void);
-202
View File
@@ -1,202 +0,0 @@
#include "random.h"
#include "fs/vfs.h"
#include "libk/stdio.h"
#include "arch/x86_64/sys/tsc.h"
#include "arch/x86_64/sys/pit.h"
#include "errno.h"
#include <stdbool.h>
#include <string.h>
#include "limine.h"
/* ChaCha20 core (public-domain, 20-round) */
static inline void chacha20_quarterround(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) {
*a += *b; *d ^= *a; *d = (*d << 16) | (*d >> 16);
*c += *d; *b ^= *c; *b = (*b << 12) | (*b >> 20);
*a += *b; *d ^= *a; *d = (*d << 8) | (*d >> 24);
*c += *d; *b ^= *c; *b = (*b << 7) | (*b >> 25);
}
static void chacha20_block(uint32_t state[16], uint8_t output[64]) {
uint32_t x[16];
for (int i = 0; i < 16; ++i) x[i] = state[i];
for (int i = 0; i < 10; ++i) { /* 10 double-rounds = 20 rounds */
/* column rounds */
chacha20_quarterround(&x[0], &x[4], &x[8], &x[12]);
chacha20_quarterround(&x[1], &x[5], &x[9], &x[13]);
chacha20_quarterround(&x[2], &x[6], &x[10], &x[14]);
chacha20_quarterround(&x[3], &x[7], &x[11], &x[15]);
/* diagonal rounds */
chacha20_quarterround(&x[0], &x[5], &x[10], &x[15]);
chacha20_quarterround(&x[1], &x[6], &x[11], &x[12]);
chacha20_quarterround(&x[2], &x[7], &x[8], &x[13]);
chacha20_quarterround(&x[3], &x[4], &x[9], &x[14]);
}
for (int i = 0; i < 16; ++i) {
x[i] += state[i];
((uint32_t*)output)[i] = x[i];
}
}
/* Global ChaCha20 PRNG state */
static uint8_t rng_key[32];
static uint64_t rng_counter = 0;
static bool rng_seeded = false;
static void rng_generate(uint8_t *buf, size_t len) {
size_t i = 0;
while (len > 0) {
uint32_t state[16];
static const uint32_t sigma[4] = {0x61707865, 0x3320646e, 0x79622d32, 0x6b206574};
state[0] = sigma[0]; state[1] = sigma[1]; state[2] = sigma[2]; state[3] = sigma[3];
for (int j = 0; j < 8; ++j)
state[4 + j] = ((uint32_t*)rng_key)[j];
state[12] = (uint32_t)rng_counter;
state[13] = (uint32_t)(rng_counter >> 32);
state[14] = 0xdeadbeef; /* fixed nonce (PRNG only) */
state[15] = 0xbeefdead;
uint8_t block[64];
chacha20_block(state, block);
size_t copy = (len < 64) ? len : 64;
for (size_t k = 0; k < copy; ++k)
buf[i + k] = block[k];
i += copy;
len -= copy;
rng_counter++;
}
}
static void rng_add_entropy(const uint8_t *data, size_t len) {
if (len == 0 || !data) return;
for (size_t i = 0; i < len; ++i)
rng_key[i % 32] ^= data[i];
/* stir (forward secrecy) */
uint8_t discard[64];
rng_generate(discard, 64);
rng_seeded = true;
}
int random_read(void* buf, size_t len) {
if (len == 0) return 0;
if (!buf) return -EFAULT;
if (!rng_seeded) return -EAGAIN; /* should never happen after init */
rng_generate((uint8_t*)buf, len);
return (int)len;
}
int random_write(const void* buf, size_t len) {
if (len == 0) return 0;
if (!buf) return -EFAULT;
rng_add_entropy((const uint8_t*)buf, len);
return (int)len;
}
int getrandom(void *buf, size_t buflen, unsigned int flags)
{
if (!buf) return -EFAULT;
if (buflen == 0) return 0;
if (flags & GRND_INSECURE) {
// maybe fall back to weaker RNG?
}
if (!rng_seeded) {
if (flags & GRND_NONBLOCK)
return -EAGAIN;
// could block here in the future
return -EAGAIN;
}
rng_generate((uint8_t*)buf, buflen);
return (int)buflen;
}
void random_init(void) {
printf("Initializing ChaCha20-based CSPRNG for /dev/random and /dev/urandom...\n");
uint8_t entropy[64] = {0};
size_t epos = 0;
/* === SEEDING SOURCES === */
/* 1. Limine boot timestamp (wall-clock) */
extern volatile struct limine_date_at_boot_request boot_request;
if (boot_request.response) {
uint64_t ts = boot_request.response->timestamp;
if (epos + sizeof(ts) <= sizeof(entropy)) {
memcpy(entropy + epos, &ts, sizeof(ts));
epos += sizeof(ts);
}
}
/* 2. Multiple TSC samples (high-resolution jitter) */
for (int i = 0; i < 4; ++i) {
uint64_t tsc_val = rdtsc();
if (epos + sizeof(tsc_val) <= sizeof(entropy)) {
memcpy(entropy + epos, &tsc_val, sizeof(tsc_val));
epos += sizeof(tsc_val);
}
}
/* 3. PIT tick counter */
uint64_t pit_ticks = PIT_GetTicks();
if (epos + sizeof(pit_ticks) <= sizeof(entropy)) {
memcpy(entropy + epos, &pit_ticks, sizeof(pit_ticks));
epos += sizeof(pit_ticks);
}
/* 4. RDRAND (hardware TRNG) if present */
{
uint32_t eax, ebx, ecx, edx;
asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1));
if (ecx & (1u << 30)) {
printf("RDRAND detected - using hardware RNG for seeding\n");
for (int i = 0; i < 4 && epos + 8 <= sizeof(entropy); ++i) {
uint64_t rd;
asm volatile("1: rdrand %0\n\tjnc 1b" : "=r"(rd));
memcpy(entropy + epos, &rd, sizeof(rd));
epos += sizeof(rd);
}
}
}
/* 5. Unix seconds from PIT (time-based entropy) */
extern uint64_t g_Unixseconds;
uint64_t unix_sec = g_Unixseconds;
if (epos + sizeof(unix_sec) <= sizeof(entropy)) {
memcpy(entropy + epos, &unix_sec, sizeof(unix_sec));
epos += sizeof(unix_sec);
}
/* 6. Final TSC padding (extra jitter) */
while (epos < 32) {
uint64_t t = rdtsc();
memcpy(entropy + epos, &t, (epos + 8 <= 32) ? 8 : (32 - epos));
epos += (epos + 8 <= 32) ? 8 : (32 - epos);
}
/* Initialise ChaCha20 key from collected entropy */
memcpy(rng_key, entropy, 32);
rng_counter = rdtsc(); /* random starting counter */
rng_seeded = true;
printf("ChaCha20 RNG seeded with %zu bytes of entropy (TSC, PIT, RDRAND, boot time, unix time, etc.)\n", epos);
/* Register both devices (open as "/dev/random" and "/dev/urandom") */
VFS_RegisterCharDev("/dev/random", random_read, random_write);
VFS_RegisterCharDev("/dev/urandom", random_read, random_write);
printf("Registered chardevs: /dev/random and /dev/urandom (ChaCha20 CSPRNG)\n");
}
-12
View File
@@ -1,12 +0,0 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#define GRND_NONBLOCK 0x0001
#define GRND_RANDOM 0x0002
#define GRND_INSECURE 0x0004
void random_init(void);
int random_read(void* buf, size_t len);
int random_write(const void* buf, size_t len);
int getrandom(void *buf, size_t buflen, unsigned int flags);
+154
View File
@@ -0,0 +1,154 @@
#include "libk/debug.h"
#include "console.h"
#include "termios.h"
#include "libk/errno.h"
#include "drivers/fb/fb.h"
#include "mm/memory.h"
#include "libk/module.h"
#include "libk/resource.h"
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
struct console {
struct resource res;
struct termios term;
size_t width, height;
bool decckm;
};
struct console *console_device = NULL;
static ssize_t console_write(struct resource *this,
struct f_description *description, const void *buf,
off_t offset, size_t count) {
(void)description;
(void)offset;
if (!buf) {
errno = EFAULT;
return -1;
}
spinlock_acquire_or_wait(&this->lock);
char *r = (char *)buf;
for (size_t i = 0; i < count; i++) {
framebuffer_putchar(r[i]);
}
spinlock_drop(&this->lock);
return count;
}
int console_ioctl(struct resource *this, struct f_description *description,
uint64_t request, uint64_t arg) {
(void)description;
spinlock_acquire_or_wait(&this->lock);
int ret = 0;
switch (request) {
case TCGETS: {
struct termios *t = (void *)arg;
if (t)
*t = console_device->term;
break;
}
case TCSETS:
case TCSETSW:
case TCSETSF: {
struct termios *t = (void *)arg;
if (t)
console_device->term = *t;
break;
}
case TIOCGWINSZ: {
struct winsize *w = (void *)arg;
if (w) {
w->ws_row = framebuff.ctx->rows;
w->ws_col = framebuff.ctx->cols;
w->ws_xpixel = framebuff.width;
w->ws_ypixel = framebuff.height;
} else {
errno = EINVAL;
ret = -1;
}
break;
}
default:
errno = EINVAL;
ret = -1;
break;
}
spinlock_drop(&this->lock);
return ret;
}
static void dec_private(uint64_t esc_val_count, uint32_t *esc_values,
uint64_t final) {
(void)esc_val_count;
switch (esc_values[0]) {
case 1:
switch (final) {
case 'h':
console_device->decckm = true;
break;
case 'l':
console_device->decckm = false;
break;
default:
break;
}
}
}
static void term_callback(struct flanterm_context *term, uint64_t t, uint64_t a,
uint64_t b, uint64_t c) {
(void)term;
switch (t) {
case 10:
dec_private(a, (void *)b, c);
}
}
void console_init(void) {
console_device = resource_create(sizeof(struct console));
console_device->res.stat.st_size = 0;
console_device->res.stat.st_blocks = 0;
console_device->res.stat.st_blksize = 4096;
console_device->res.stat.st_rdev = resource_create_dev_id();
console_device->res.stat.st_mode = 0644 | S_IFCHR;
console_device->width = framebuff.width / 8;
console_device->height = framebuff.height / 16;
console_device->term.c_iflag = BRKINT | IGNPAR | ICRNL | IXON | IMAXBEL;
console_device->term.c_oflag = OPOST | ONLCR;
console_device->term.c_cflag = CS8 | CREAD;
console_device->term.c_lflag =
ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE;
console_device->term.c_cc[VINTR] = CTRL('C');
console_device->term.c_cc[VEOF] = CTRL('D');
console_device->term.c_cc[VSUSP] = CTRL('Z');
console_device->term.ibaud = 38400;
console_device->term.obaud = 38400;
console_device->res.status |= POLLOUT;
console_device->res.write = console_write;
console_device->res.ioctl = console_ioctl;
console_device->decckm = false;
devtmpfs_add_device((struct resource *)console_device, "console");
kprintffos(false, "Bye bye!\n");
framebuffer_clear(0x00eee8d5, 0);
framebuff.ctx->callback = term_callback;
}
+3
View File
@@ -0,0 +1,3 @@
#pragma once
void console_init(void);
+518
View File
@@ -0,0 +1,518 @@
#include "libk/debug.h"
#include "pty.h"
#include "libk/errno.h"
#include "mm/memory.h"
#include "sched/sched.h"
#include "fs/devtmpfs.h"
#include <stdint.h>
#include "libk/string.h"
static int pty_number = 0;
static int pty_ioctl(struct resource *this, struct f_description *description,
uint64_t request, uint64_t arg) {
(void)description;
spinlock_acquire_or_wait(&this->lock);
struct pty_slave *ps = (struct pty_slave *)this;
struct pty *p = ps->pty;
int ret = 0;
switch (request) {
case TCGETS: {
struct termios *t = (void *)arg;
if (t)
*t = p->term;
break;
}
case TCSETS:
case TCSETSW:
case TCSETSF: {
struct termios *t = (void *)arg;
if (t)
p->term = *t;
break;
}
case TIOCGWINSZ: {
struct winsize *w = (void *)arg;
if (w)
*w = p->ws;
break;
}
case TIOCSPGRP: {
break;
}
case TIOCSWINSZ: {
struct winsize *w = (void *)arg;
if (w)
p->ws = *w;
break;
}
case TIOCGPGRP: {
int *n = (int *)arg;
if (n)
*n = sched_get_running_thread()->mother_proc->pid;
break;
}
case TIOCGSID: {
int *n = (int *)arg;
if (n)
*n = sched_get_running_thread()->mother_proc->pid;
break;
}
case TIOCGPTN: {
int *n = (int *)arg;
if (n)
*n = p->name;
break;
}
case TIOCSPTLCK: {
break;
}
case TIOCSCTTY: {
break;
}
default:
errno = EINVAL;
ret = -1;
break;
}
spinlock_drop(&this->lock);
return ret;
}
static bool pty_master_unref(struct resource *this,
struct f_description *description) {
(void)description;
struct pty_master *pm = (struct pty_master *)this;
struct pty *p = pm->pty;
this->refcount--;
if (!this->refcount) {
p->pm->res.status |= POLLHUP;
p->pm->res.status &= ~POLLIN;
p->pm->res.status &= ~POLLOUT;
event_trigger(&p->ps->res.event, false);
kfree(p->in.data);
kfree(p->out.data);
}
return true;
}
static ssize_t pty_master_read(struct resource *this,
struct f_description *description, void *buf,
off_t offset, size_t count) {
(void)description;
(void)offset;
spinlock_acquire_or_wait(&this->lock);
struct pty_master *pm = (struct pty_master *)this;
struct pty *p = pm->pty;
ssize_t ret = 0;
while (p->in.used == 0) {
if (p->ps->closed) {
errno = EIO;
ret = -1;
spinlock_drop(&this->lock);
return ret;
}
if (description->flags & O_NONBLOCK) {
goto end;
}
spinlock_drop(&this->lock);
struct event *events[] = {&p->pm->res.event};
if (event_await(events, 1, true) < 0) {
errno = EINTR;
ret = -1;
return ret;
}
spinlock_acquire_or_wait(&this->lock);
}
if (p->in.used < count) {
count = p->in.used;
}
size_t before_wrap = 0, after_wrap = 0, new_ptr = 0;
if (p->in.read_ptr + count > p->in.data_length) {
before_wrap = p->in.data_length - p->in.read_ptr;
after_wrap = count - before_wrap;
new_ptr = after_wrap;
} else {
before_wrap = count;
after_wrap = 0;
new_ptr = p->in.read_ptr + count;
if (new_ptr == p->in.data_length) {
new_ptr = 0;
}
}
memcpy(buf, p->in.data + p->in.read_ptr, before_wrap);
if (after_wrap) {
memcpy(buf + before_wrap, p->in.data, after_wrap);
}
p->in.read_ptr = new_ptr;
p->in.used -= count;
if (p->in.used < p->in.data_length) {
p->ps->res.status |= POLLOUT;
}
if (p->in.used == 0) {
this->status &= ~POLLIN;
}
event_trigger(&p->ps->res.event, false);
ret = count;
end:
spinlock_drop(&this->lock);
return ret;
}
static ssize_t pty_master_write(struct resource *this,
struct f_description *description,
const void *buf, off_t offset, size_t count) {
(void)description;
(void)offset;
struct pty_master *pm = (struct pty_master *)this;
struct pty *p = pm->pty;
ssize_t ret = 0;
spinlock_acquire_or_wait(&p->ps->res.lock);
if (p->out.used == p->out.data_length) {
spinlock_drop(&p->ps->res.lock);
struct event *events[] = {&p->ps->res.event};
if (event_await(events, 1, true) < 0) {
errno = EINTR;
ret = -1;
return ret;
}
spinlock_acquire_or_wait(&p->ps->res.lock);
}
if (p->out.used + count > p->out.data_length) {
count = p->out.data_length - p->out.used;
}
size_t before_wrap = 0, after_wrap = 0, new_ptr = 0;
if (p->out.write_ptr + count > p->out.data_length) {
before_wrap = p->out.data_length - p->out.write_ptr;
after_wrap = count - before_wrap;
new_ptr = after_wrap;
} else {
before_wrap = count;
after_wrap = 0;
new_ptr = p->out.write_ptr + count;
if (new_ptr == p->out.data_length) {
new_ptr = 0;
}
}
memcpy(p->out.data + p->out.write_ptr, buf, before_wrap);
if (after_wrap) {
memcpy(p->out.data, buf + before_wrap, after_wrap);
}
p->out.write_ptr = new_ptr;
p->out.used += count;
if (p->out.used == p->out.data_length) {
this->status &= ~POLLOUT;
}
p->ps->res.status |= POLLIN;
event_trigger(&p->ps->res.event, false);
ret = count;
spinlock_drop(&p->ps->res.lock);
return ret;
}
static bool pty_slave_unref(struct resource *this,
struct f_description *description) {
(void)description;
struct pty_slave *ps = (struct pty_slave *)this;
struct pty *p = ps->pty;
this->refcount--;
if (!this->refcount) {
ps->closed = true;
p->pm->res.status |= POLLHUP;
p->pm->res.status &= ~POLLIN;
p->pm->res.status &= ~POLLOUT;
event_trigger(&ps->pty->pm->res.event, false);
}
return true;
}
static ssize_t pty_slave_read(struct resource *this,
struct f_description *description, void *buf,
off_t offset, size_t count) {
(void)description;
(void)offset;
spinlock_acquire_or_wait(&this->lock);
struct pty_slave *ps = (struct pty_slave *)this;
struct pty *p = ps->pty;
ssize_t ret = 0;
while (p->out.used == 0) {
if (description->flags & O_NONBLOCK) {
goto end;
}
spinlock_drop(&this->lock);
struct event *events[] = {&p->ps->res.event};
if (event_await(events, 1, true) < 0) {
errno = EINTR;
ret = -1;
return ret;
}
spinlock_acquire_or_wait(&this->lock);
}
if (p->out.used < count) {
count = p->out.used;
}
size_t before_wrap = 0, after_wrap = 0, new_ptr = 0;
if (p->out.read_ptr + count > p->out.data_length) {
before_wrap = p->out.data_length - p->out.read_ptr;
after_wrap = count - before_wrap;
new_ptr = after_wrap;
} else {
before_wrap = count;
after_wrap = 0;
new_ptr = p->out.read_ptr + count;
if (new_ptr == p->out.data_length) {
new_ptr = 0;
}
}
memcpy(buf, p->out.data + p->out.read_ptr, before_wrap);
if (after_wrap) {
memcpy(buf + before_wrap, p->out.data, after_wrap);
}
p->out.read_ptr = new_ptr;
p->out.used -= count;
if (p->out.used < p->out.data_length) {
p->pm->res.status |= POLLOUT;
}
if (p->out.used == 0) {
this->status &= ~POLLIN;
}
event_trigger(&p->pm->res.event, false);
ret = count;
end:
spinlock_drop(&this->lock);
return ret;
}
static ssize_t pty_slave_write(struct resource *this,
struct f_description *description,
const void *buf, off_t offset, size_t count) {
(void)description;
(void)offset;
struct pty_slave *ps = (struct pty_slave *)this;
struct pty *p = ps->pty;
ssize_t ret = 0;
spinlock_acquire_or_wait(&p->pm->res.lock);
if (p->in.used == p->in.data_length) {
spinlock_drop(&p->pm->res.lock);
struct event *events[] = {&p->pm->res.event};
if (event_await(events, 1, true) < 0) {
errno = EINTR;
ret = -1;
return ret;
}
spinlock_acquire_or_wait(&p->pm->res.lock);
}
char *buf_to_write_from = buf;
size_t newline_count = 0;
if ((p->term.c_oflag & ONLCR) && (p->term.c_oflag & OPOST)) {
char *buf_but_char = buf;
buf_to_write_from = kmalloc(count * 2);
if (!buf_to_write_from) {
spinlock_drop(&p->pm->res.lock);
errno = ENOMEM;
return -1;
}
memzero(buf_to_write_from, count * 2);
size_t k = 0;
for (size_t i = 0; i < count; i++) {
if (buf_but_char[i] == '\n') {
buf_to_write_from[k++] = '\r';
newline_count++;
}
buf_to_write_from[k++] = buf_but_char[i];
}
if (newline_count == 0) {
kfree(buf_to_write_from);
buf_to_write_from = buf;
}
count += newline_count;
}
if (p->in.used + count > p->in.data_length) {
count = p->in.data_length - p->in.used;
}
size_t before_wrap = 0, after_wrap = 0, new_ptr = 0;
if (p->in.write_ptr + count > p->in.data_length) {
before_wrap = p->in.data_length - p->in.write_ptr;
after_wrap = count - before_wrap;
new_ptr = after_wrap;
} else {
before_wrap = count;
after_wrap = 0;
new_ptr = p->in.write_ptr + count;
if (new_ptr == p->in.data_length) {
new_ptr = 0;
}
}
memcpy(p->in.data + p->in.write_ptr, buf_to_write_from, before_wrap);
if (after_wrap) {
memcpy(p->in.data, buf_to_write_from + before_wrap, after_wrap);
}
p->in.write_ptr = new_ptr;
p->in.used += count;
if (buf_to_write_from != buf) {
kfree(buf_to_write_from);
}
if (p->in.used == p->in.data_length) {
this->status &= ~POLLOUT;
}
count -= newline_count;
p->pm->res.status |= POLLIN;
event_trigger(&p->pm->res.event, false);
ret = count;
spinlock_drop(&p->pm->res.lock);
return ret;
}
void syscall_openpty(struct syscall_arguments *args) {
struct process *proc = sched_get_running_thread()->mother_proc;
int *fds = (int *)(args->args0);
if (fds == NULL) {
errno = EFAULT;
args->ret = -1;
return;
}
struct pty *p = kmalloc(sizeof(struct pty));
if (!p) {
errno = ENOMEM;
args->ret = -1;
return;
}
p->name = pty_number++;
p->in.data = kmalloc(PAGE_SIZE * 32);
memzero(p->in.data, PAGE_SIZE * 32);
p->in.data_length = PAGE_SIZE * 32;
p->in.used = 0;
p->in.read_ptr = 0;
p->in.write_ptr = 0;
p->out.data = kmalloc(PAGE_SIZE * 32);
memzero(p->out.data, PAGE_SIZE * 32);
p->out.data_length = PAGE_SIZE * 32;
p->out.used = 0;
p->out.read_ptr = 0;
p->out.write_ptr = 0;
p->term.c_iflag = IGNBRK | BRKINT | IGNPAR | ICRNL | IXON;
p->term.c_oflag = OPOST | ONLCR;
p->term.c_cflag = CS8 | CREAD | HUPCL;
p->term.c_lflag =
ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
p->term.c_cc[VINTR] = CTRL('C');
p->term.c_cc[VEOF] = CTRL('D');
p->term.c_cc[VSUSP] = CTRL('Z');
p->term.ibaud = 38400;
p->term.obaud = 38400;
p->ws.ws_row = 24;
p->ws.ws_col = 80;
struct pty_slave *ps = resource_create(sizeof(struct pty_slave));
struct pty_master *pm = resource_create(sizeof(struct pty_master));
if (!ps || !pm) {
errno = ENOMEM;
args->ret = -1;
return;
}
ps->pty = p;
ps->res.read = pty_slave_read;
ps->res.write = pty_slave_write;
pm->res.unref = pty_slave_unref;
ps->res.ioctl = pty_ioctl;
ps->res.stat.st_size = 0;
ps->res.stat.st_blocks = 0;
ps->res.stat.st_blksize = 4096;
ps->res.stat.st_rdev = resource_create_dev_id();
ps->res.stat.st_mode = 0644 | S_IFCHR;
ps->res.status = POLLOUT;
pm->pty = p;
pm->res.read = pty_master_read;
pm->res.write = pty_master_write;
pm->res.unref = pty_master_unref;
pm->res.ioctl = pty_ioctl;
pm->res.status = POLLOUT;
p->ps = ps;
p->pm = pm;
fds[0] = fdnum_create_from_resource(proc, (struct resource *)pm, O_RDWR, 0,
false);
fds[1] = fdnum_create_from_resource(proc, (struct resource *)ps, O_RDWR, 0,
false);
if (fds[0] == -1 || fds[1] == -1) {
args->ret = -1;
}
char name[5 + 3 + 1] = "pty";
char num[3 + 1] = {0};
ultoa(p->name, num, 10);
strcat(name, num);
devtmpfs_add_device((struct resource *)ps, name);
args->ret = 0;
}
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include "termios.h"
#include "sched/syscall.h"
#include "libk/resource.h"
struct ring_buffer {
uint8_t *data;
size_t data_length;
uintptr_t read_ptr;
uintptr_t write_ptr;
size_t used;
};
struct pty {
int name;
struct pty_slave *ps;
struct pty_master *pm;
struct termios term;
struct winsize ws;
struct ring_buffer in;
struct ring_buffer out;
};
struct pty_slave {
struct resource res;
struct pty *pty;
bool closed;
};
struct pty_master {
struct resource res;
struct pty *pty;
};
void syscall_openpty(struct syscall_arguments *args);
+182
View File
@@ -0,0 +1,182 @@
#pragma once
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
// indices for the c_cc array in struct termios
#define NCCS 32
#define VINTR 0
#define VQUIT 1
#define VERASE 2
#define VKILL 3
#define VEOF 4
#define VTIME 5
#define VMIN 6
#define VSWTC 7
#define VSTART 8
#define VSTOP 9
#define VSUSP 10
#define VEOL 11
#define VREPRINT 12
#define VDISCARD 13
#define VWERASE 14
#define VLNEXT 15
#define VEOL2 16
#define TTY_BUF_SIZE 1024
// 0x54 is just a magic number to make these relatively unique ('T')
#define TCGETS 0x5401
#define TCSETS 0x5402
#define TCSETSW 0x5403
#define TCSETSF 0x5404
#define TCGETA 0x5405
#define TCSETA 0x5406
#define TCSETAW 0x5407
#define TCSETAF 0x5408
#define TCSBRK 0x5409
#define TCXONC 0x540A
#define TCFLSH 0x540B
#define TIOCEXCL 0x540C
#define TIOCNXCL 0x540D
#define TIOCSCTTY 0x540E
#define TIOCGPGRP 0x540F
#define TIOCSPGRP 0x5410
#define TIOCOUTQ 0x5411
#define TIOCSTI 0x5412
#define TIOCGWINSZ 0x5413
#define TIOCSWINSZ 0x5414
#define TIOCMGET 0x5415
#define TIOCMBIS 0x5416
#define TIOCMBIC 0x5417
#define TIOCMSET 0x5418
#define TIOCGSOFTCAR 0x5419
#define TIOCSSOFTCAR 0x541A
// bitwise flags for c_iflag in struct termios
#define IGNBRK 0000001
#define BRKINT 0000002
#define IGNPAR 0000004
#define PARMRK 0000010
#define INPCK 0000020
#define ISTRIP 0000040
#define INLCR 0000100
#define IGNCR 0000200
#define ICRNL 0000400
#define IUCLC 0001000
#define IXON 0002000
#define IXANY 0004000
#define IXOFF 0010000
#define IMAXBEL 0020000
#define IUTF8 0040000
// bitwise flags for c_oflag in struct termios
#define OPOST 0000001
#define OLCUC 0000002
#define ONLCR 0000004
#define OCRNL 0000010
#define ONOCR 0000020
#define ONLRET 0000040
#define OFILL 0000100
#define OFDEL 0000200
#define NLDLY 0000400
#define NL0 0000000
#define NL1 0000400
#define CRDLY 0003000
#define CR0 0000000
#define CR1 0001000
#define CR2 0002000
#define CR3 0003000
#define TABDLY 0014000
#define TAB0 0000000
#define TAB1 0004000
#define TAB2 0010000
#define TAB3 0014000
#define BSDLY 0020000
#define BS0 0000000
#define BS1 0020000
#define FFDLY 0100000
#define FF0 0000000
#define FF1 0100000
#define VTDLY 0040000
#define VT0 0000000
#define VT1 0040000
// bitwise constants for c_cflag in struct termios
#define CSIZE 0000060
#define CS5 0000000
#define CS6 0000020
#define CS7 0000040
#define CS8 0000060
#define CSTOPB 0000100
#define CREAD 0000200
#define PARENB 0000400
#define PARODD 0001000
#define HUPCL 0002000
#define CLOCAL 0004000
// bitwise constants for c_lflag in struct termios
#define ISIG 0000001
#define ICANON 0000002
#define ECHO 0000010
#define ECHOE 0000020
#define ECHOK 0000040
#define ECHONL 0000100
#define NOFLSH 0000200
#define TOSTOP 0000400
#define IEXTEN 0100000
#define EXTA 0000016
#define EXTB 0000017
#define CBAUD 0010017
#define CBAUDEX 0010000
#define CIBAUD 002003600000
#define CMSPAR 010000000000
#define CRTSCTS 020000000000
#define XCASE 0000004
#define ECHOCTL 0001000
#define ECHOPRT 0002000
#define ECHOKE 0004000
#define FLUSHO 0010000
#define PENDIN 0040000
#define EXTPROC 0200000
#define XTABS 0014000
struct winsize {
unsigned short ws_row;
unsigned short ws_col;
unsigned short ws_xpixel;
unsigned short ws_ypixel;
};
#define NCC 8
struct termio {
unsigned short c_iflag; /* input mode flags */
unsigned short c_oflag; /* output mode flags */
unsigned short c_cflag; /* control mode flags */
unsigned short c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[NCC]; /* control characters */
};
struct termios {
tcflag_t c_iflag;
tcflag_t c_oflag;
tcflag_t c_cflag;
tcflag_t c_lflag;
cc_t c_line;
cc_t c_cc[NCCS];
speed_t ibaud;
speed_t obaud;
};
#define CTRL(x) ((x) & 037)
-457
View File
@@ -1,457 +0,0 @@
#pragma once
#include <stdint.h>
unsigned char zap_light16_psf[] = {
0x36, 0x04, 0x02, 0x10, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x5d, 0x7d, 0x7b,
0x77, 0x77, 0x7f, 0x77, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7e, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x22, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x7f, 0x04, 0x08, 0x10, 0x7f, 0x20,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x20, 0x40,
0x20, 0x10, 0x08, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10, 0x00, 0x3e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c,
0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
0x10, 0x11, 0x12, 0x04, 0x08, 0x12, 0x26, 0x4a, 0x0f, 0x02, 0x02, 0x00,
0x00, 0x00, 0x10, 0x30, 0x10, 0x11, 0x12, 0x04, 0x08, 0x10, 0x26, 0x49,
0x02, 0x04, 0x0f, 0x00, 0x00, 0x00, 0x70, 0x08, 0x30, 0x09, 0x72, 0x04,
0x08, 0x12, 0x26, 0x4a, 0x0f, 0x02, 0x02, 0x00, 0x00, 0x00, 0x08, 0x08,
0x08, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
0x00, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x30, 0x00, 0x00, 0x07, 0x08,
0x08, 0x08, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x70, 0x00, 0x00,
0x00, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x08, 0x08,
0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42,
0xa4, 0xa4, 0x48, 0x10, 0x10, 0x2a, 0x55, 0x55, 0x8a, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xf1, 0x5b, 0x55, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x49, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x08, 0x10, 0x20, 0x10, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x08, 0x10, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x24, 0x12, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x24,
0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24,
0x24, 0x24, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x24, 0x24, 0x24, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x00,
0x42, 0x3c, 0x00, 0x3c, 0x42, 0x42, 0x40, 0x40, 0x4e, 0x42, 0x42, 0x42,
0x3c, 0x00, 0x00, 0x00, 0x00, 0x42, 0x3c, 0x00, 0x00, 0x3a, 0x46, 0x42,
0x42, 0x42, 0x46, 0x3a, 0x02, 0x02, 0x42, 0x3c, 0x08, 0x08, 0x00, 0x3e,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x40, 0x30,
0x0c, 0x02, 0x42, 0x42, 0x3c, 0x08, 0x08, 0x30, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3c, 0x42, 0x40, 0x30, 0x0c, 0x02, 0x42, 0x3c, 0x08, 0x08, 0x30,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x24,
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x24, 0x24, 0x24, 0x7e, 0x24, 0x24, 0x7e, 0x24, 0x24,
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x49, 0x48, 0x48,
0x3e, 0x09, 0x09, 0x49, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x31,
0x4a, 0x4a, 0x34, 0x08, 0x08, 0x16, 0x29, 0x29, 0x46, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x24, 0x18, 0x28, 0x45, 0x42, 0x46,
0x39, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08,
0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x04, 0x00, 0x00,
0x00, 0x00, 0x20, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x10,
0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x49, 0x2a,
0x1c, 0x2a, 0x49, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x08, 0x08, 0x7f, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x20,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x4a,
0x52, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
0x18, 0x28, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x02, 0x1c,
0x02, 0x02, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
0x0c, 0x14, 0x24, 0x44, 0x44, 0x7e, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x02, 0x02, 0x02, 0x42,
0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x20, 0x40, 0x40, 0x7c,
0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
0x02, 0x02, 0x04, 0x04, 0x08, 0x08, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x3c, 0x42, 0x42, 0x42, 0x42,
0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42,
0x3e, 0x02, 0x02, 0x04, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x08,
0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20,
0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10,
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x02, 0x04,
0x08, 0x08, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
0x22, 0x4a, 0x56, 0x52, 0x52, 0x52, 0x4e, 0x20, 0x1e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42,
0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x7c,
0x42, 0x42, 0x42, 0x42, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
0x42, 0x42, 0x40, 0x40, 0x40, 0x40, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x44,
0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c,
0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e,
0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x40, 0x40, 0x4e, 0x42, 0x42, 0x42,
0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x7e,
0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1f, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x44,
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x44, 0x48, 0x50, 0x60,
0x60, 0x50, 0x48, 0x44, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x41, 0x63, 0x63, 0x55, 0x55, 0x49, 0x49, 0x41, 0x41,
0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x62, 0x62, 0x52, 0x52,
0x4a, 0x4a, 0x46, 0x46, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x40, 0x40, 0x40,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x5a, 0x66, 0x3c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
0x42, 0x42, 0x42, 0x7c, 0x48, 0x44, 0x44, 0x42, 0x42, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x40, 0x30, 0x0c, 0x02, 0x42, 0x42,
0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x22, 0x22, 0x22, 0x14, 0x14, 0x08,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x41, 0x49, 0x49,
0x55, 0x55, 0x63, 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42,
0x42, 0x24, 0x24, 0x18, 0x18, 0x24, 0x24, 0x42, 0x42, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x02, 0x02, 0x04, 0x08,
0x10, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x20, 0x20, 0x10, 0x10, 0x08, 0x08, 0x04, 0x04, 0x02,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x00, 0x08, 0x14, 0x22,
0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7f, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3c, 0x42, 0x02, 0x3e, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00,
0x00, 0x00, 0x40, 0x40, 0x40, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x62,
0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40,
0x40, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02,
0x02, 0x3a, 0x46, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x42,
0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x10, 0x10, 0x10, 0x7c, 0x10,
0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3a, 0x46, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x02, 0x02, 0x42, 0x3c,
0x00, 0x00, 0x40, 0x40, 0x40, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x18, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04,
0x00, 0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x44, 0x38,
0x00, 0x00, 0x40, 0x40, 0x40, 0x44, 0x48, 0x50, 0x60, 0x50, 0x48, 0x44,
0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x76, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x62, 0x5c, 0x40, 0x40, 0x40,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x46, 0x42, 0x42, 0x42, 0x42, 0x46,
0x3a, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x62, 0x40,
0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3c, 0x42, 0x40, 0x30, 0x0c, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x7c, 0x10, 0x10, 0x10, 0x10, 0x10,
0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x41, 0x41, 0x41, 0x22, 0x22, 0x14, 0x14, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x49, 0x49, 0x49, 0x49, 0x49,
0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x42, 0x24,
0x18, 0x18, 0x24, 0x42, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x02, 0x02, 0x42, 0x3c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x08, 0x08, 0x08, 0x08, 0x30,
0x08, 0x08, 0x08, 0x08, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
0x00, 0x00, 0x30, 0x08, 0x08, 0x08, 0x08, 0x06, 0x08, 0x08, 0x08, 0x08,
0x08, 0x30, 0x00, 0x00, 0x00, 0x31, 0x49, 0x46, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x30, 0x0c, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42,
0x42, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42,
0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00, 0x18,
0x24, 0x24, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00,
0x32, 0x4c, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42,
0x42, 0x00, 0x00, 0x00, 0x24, 0x24, 0x00, 0x18, 0x24, 0x24, 0x42, 0x42,
0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x18,
0x24, 0x24, 0x42, 0x42, 0x7e, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1f, 0x28, 0x48, 0x48, 0x7e, 0x48, 0x48, 0x48, 0x48,
0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x40, 0x40,
0x40, 0x40, 0x42, 0x42, 0x3c, 0x08, 0x08, 0x30, 0x30, 0x0c, 0x00, 0x7e,
0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00,
0x0c, 0x30, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40,
0x7e, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00, 0x7e, 0x40, 0x40, 0x40, 0x7c,
0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x24, 0x24, 0x00, 0x7e,
0x40, 0x40, 0x40, 0x7c, 0x40, 0x40, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00,
0x30, 0x0c, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x3e, 0x00, 0x00, 0x00, 0x06, 0x18, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00, 0x3e,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00,
0x22, 0x22, 0x00, 0x3e, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x44, 0x42, 0x42, 0xf2,
0x42, 0x42, 0x42, 0x44, 0x78, 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00, 0x42,
0x62, 0x62, 0x52, 0x52, 0x4a, 0x4a, 0x46, 0x46, 0x42, 0x00, 0x00, 0x00,
0x30, 0x0c, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x3c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00, 0x3c,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00,
0x32, 0x4c, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x3c, 0x00, 0x00, 0x00, 0x24, 0x24, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x3a, 0x44, 0x46, 0x4a, 0x4a, 0x52, 0x52, 0x62, 0x22,
0x5c, 0x40, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x00, 0x42,
0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00,
0x18, 0x24, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x3c, 0x00, 0x00, 0x00, 0x24, 0x24, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x06, 0x18, 0x00, 0x41,
0x41, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x40, 0x7c, 0x42, 0x42, 0x42, 0x42, 0x7c, 0x40,
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x4c, 0x50, 0x50,
0x4c, 0x42, 0x42, 0x52, 0x4c, 0x00, 0x00, 0x00, 0xaa, 0x55, 0xaa, 0x55,
0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55,
0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x49, 0x48,
0x48, 0x48, 0x48, 0x49, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x1c,
0x20, 0x20, 0x20, 0x78, 0x20, 0x20, 0x20, 0x22, 0x7e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0e, 0x11, 0x20, 0x7e, 0x20, 0x7c, 0x20, 0x11,
0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x41, 0x22, 0x14, 0x08,
0x3e, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0x00, 0x24, 0x18, 0x00, 0x3c,
0x42, 0x42, 0x40, 0x30, 0x0c, 0x02, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1c, 0x22, 0x20, 0x18, 0x24, 0x22, 0x22, 0x12, 0x0c, 0x02,
0x22, 0x1c, 0x00, 0x00, 0x00, 0x24, 0x18, 0x00, 0x00, 0x3c, 0x42, 0x40,
0x30, 0x0c, 0x02, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c,
0x42, 0x99, 0xa5, 0xa1, 0xa1, 0xa5, 0x99, 0x42, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x04, 0x3c, 0x44, 0x3c, 0x00, 0x7c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x24,
0x48, 0x24, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7e, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x1c, 0x22, 0x22, 0x22, 0x1c, 0x22,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0xb9, 0xa5, 0xa5,
0xb9, 0xa9, 0xa5, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x24, 0x24, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x7f, 0x08,
0x08, 0x08, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44,
0x04, 0x18, 0x20, 0x40, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x44, 0x04, 0x38, 0x04, 0x44, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x24, 0x18, 0x00, 0x7e, 0x02, 0x02, 0x04, 0x08,
0x10, 0x20, 0x40, 0x40, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x66, 0x5a, 0x40, 0x40, 0x40,
0x00, 0x00, 0x00, 0x3e, 0x7a, 0x7a, 0x7a, 0x7a, 0x3a, 0x0a, 0x0a, 0x0a,
0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x18, 0x00,
0x00, 0x7e, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x7e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x10, 0x30, 0x50, 0x10, 0x10, 0x10, 0x7c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 0x00,
0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x48, 0x24, 0x12, 0x24, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x37, 0x48, 0x48, 0x48, 0x4e, 0x48, 0x48, 0x48, 0x48,
0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x49, 0x49,
0x4f, 0x48, 0x48, 0x49, 0x36, 0x00, 0x00, 0x00, 0x22, 0x22, 0x00, 0x41,
0x41, 0x22, 0x22, 0x14, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x10, 0x10, 0x20, 0x40, 0x42, 0x42,
0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf8, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0xf8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0xf8, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22,
0x88, 0x22, 0x88, 0x22, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
0x10, 0x17, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfc, 0x04, 0xf4, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x17, 0x10, 0x1f, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xf4,
0x04, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0x14, 0x17, 0x10, 0x17, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xf4, 0x04, 0xf4, 0x14, 0x14,
0x14, 0x14, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x00, 0xf7, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14,
0x14, 0x14, 0x14, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0xf7, 0x00, 0xf7, 0x14, 0x14,
0x14, 0x14, 0x14, 0x14, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x1c, 0x2a, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x2a, 0x1c, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x20,
0x7f, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x08, 0x04, 0xfe, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x0c, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x3e, 0x42, 0x42, 0x46,
0x3a, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x3c, 0x42, 0x02,
0x3e, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00,
0x00, 0x3c, 0x42, 0x02, 0x3e, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00,
0x00, 0x32, 0x4c, 0x00, 0x00, 0x3c, 0x42, 0x02, 0x3e, 0x42, 0x42, 0x46,
0x3a, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x02,
0x3e, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x18, 0x24, 0x24, 0x18,
0x00, 0x3c, 0x42, 0x02, 0x3e, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x49, 0x09, 0x3f, 0x48, 0x48, 0x49,
0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x42, 0x40,
0x40, 0x40, 0x40, 0x42, 0x3c, 0x08, 0x08, 0x30, 0x00, 0x30, 0x0c, 0x00,
0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x0c, 0x30, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x42,
0x3c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x42,
0x7e, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x00,
0x00, 0x3c, 0x42, 0x42, 0x7e, 0x40, 0x40, 0x42, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x30, 0x0c, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x3e, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x18, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00,
0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x3e, 0x00, 0x00, 0x00,
0x00, 0x24, 0x24, 0x00, 0x00, 0x18, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x18, 0x64, 0x02, 0x3a, 0x46,
0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x32, 0x4c, 0x00,
0x00, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x00, 0x00, 0x00,
0x00, 0x30, 0x0c, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x3c, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x00, 0x00, 0x3c, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x18, 0x24, 0x00,
0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x32, 0x4c, 0x00, 0x00, 0x3c, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
0x3c, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x3c, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x10, 0x10, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x3c, 0x46, 0x4a, 0x4a, 0x52, 0x52, 0x62,
0x3c, 0x40, 0x00, 0x00, 0x00, 0x30, 0x0c, 0x00, 0x00, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x00,
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00,
0x00, 0x18, 0x24, 0x00, 0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x46,
0x3a, 0x00, 0x00, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x46, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x30, 0x00,
0x00, 0x42, 0x42, 0x42, 0x42, 0x42, 0x46, 0x3a, 0x02, 0x02, 0x42, 0x3c,
0x00, 0x00, 0x40, 0x40, 0x40, 0x5c, 0x62, 0x42, 0x42, 0x42, 0x42, 0x62,
0x5c, 0x40, 0x40, 0x40, 0x00, 0x24, 0x24, 0x00, 0x00, 0x42, 0x42, 0x42,
0x42, 0x42, 0x46, 0x3a, 0x02, 0x02, 0x42, 0x3c, 0xfd, 0xff, 0xff, 0xff,
0xc0, 0x03, 0xff, 0xff, 0x60, 0x22, 0xff, 0xff, 0x64, 0x22, 0xff, 0xff,
0x65, 0x22, 0xff, 0xff, 0xa0, 0x25, 0xac, 0x25, 0xae, 0x25, 0xfc, 0x25,
0xfe, 0x25, 0x1b, 0x2b, 0x0e, 0x22, 0xff, 0xff, 0xc6, 0x25, 0x66, 0x26,
0x25, 0x2b, 0x27, 0x2b, 0xff, 0xff, 0xbc, 0x00, 0xff, 0xff, 0xbd, 0x00,
0xff, 0xff, 0xbe, 0x00, 0xff, 0xff, 0xa6, 0x00, 0xff, 0xff, 0xa8, 0x00,
0xff, 0xff, 0xb8, 0x00, 0xff, 0xff, 0x92, 0x01, 0xff, 0xff, 0x20, 0x20,
0xff, 0xff, 0x21, 0x20, 0xff, 0xff, 0x30, 0x20, 0xff, 0xff, 0x22, 0x21,
0xff, 0xff, 0x26, 0x20, 0xff, 0xff, 0x39, 0x20, 0xff, 0xff, 0x3a, 0x20,
0xff, 0xff, 0x1c, 0x20, 0x1f, 0x20, 0x36, 0x20, 0xff, 0xff, 0x1d, 0x20,
0xba, 0x02, 0xdd, 0x02, 0xee, 0x02, 0x33, 0x20, 0xff, 0xff, 0x1e, 0x20,
0xff, 0xff, 0x42, 0x2e, 0xff, 0xff, 0x41, 0x2e, 0xce, 0x02, 0xff, 0xff,
0x1e, 0x01, 0xff, 0xff, 0x1f, 0x01, 0xff, 0xff, 0x30, 0x01, 0xff, 0xff,
0x31, 0x01, 0xff, 0xff, 0x5e, 0x01, 0xff, 0xff, 0x5f, 0x01, 0xff, 0xff,
0x20, 0x00, 0xa0, 0x00, 0x00, 0x20, 0x01, 0x20, 0x02, 0x20, 0x03, 0x20,
0x04, 0x20, 0x05, 0x20, 0x06, 0x20, 0x07, 0x20, 0x08, 0x20, 0x09, 0x20,
0x0a, 0x20, 0x2f, 0x20, 0x5f, 0x20, 0xff, 0xff, 0x21, 0x00, 0xff, 0xff,
0x22, 0x00, 0xff, 0xff, 0x23, 0x00, 0xff, 0xff, 0x24, 0x00, 0xff, 0xff,
0x25, 0x00, 0xff, 0xff, 0x26, 0x00, 0xff, 0xff, 0x27, 0x00, 0xb4, 0x00,
0xb9, 0x02, 0xbc, 0x02, 0xca, 0x02, 0x19, 0x20, 0x32, 0x20, 0xff, 0xff,
0x28, 0x00, 0xff, 0xff, 0x29, 0x00, 0xff, 0xff, 0x2a, 0x00, 0x4e, 0x20,
0x17, 0x22, 0xff, 0xff, 0x2b, 0x00, 0xff, 0xff, 0x2c, 0x00, 0xcf, 0x02,
0x1a, 0x20, 0xff, 0xff, 0x2d, 0x00, 0xad, 0x00, 0x10, 0x20, 0x11, 0x20,
0x12, 0x20, 0x13, 0x20, 0x43, 0x20, 0x12, 0x22, 0xff, 0xff, 0x2e, 0x00,
0x24, 0x20, 0xff, 0xff, 0x2f, 0x00, 0x44, 0x20, 0x15, 0x22, 0xff, 0xff,
0x30, 0x00, 0xff, 0xff, 0x31, 0x00, 0xff, 0xff, 0x32, 0x00, 0xff, 0xff,
0x33, 0x00, 0xff, 0xff, 0x34, 0x00, 0xff, 0xff, 0x35, 0x00, 0xff, 0xff,
0x36, 0x00, 0xff, 0xff, 0x37, 0x00, 0xff, 0xff, 0x38, 0x00, 0xff, 0xff,
0x39, 0x00, 0xff, 0xff, 0x3a, 0x00, 0x36, 0x22, 0xff, 0xff, 0x3b, 0x00,
0xff, 0xff, 0x3c, 0x00, 0xff, 0xff, 0x3d, 0x00, 0x40, 0x2e, 0xff, 0xff,
0x3e, 0x00, 0xff, 0xff, 0x3f, 0x00, 0xff, 0xff, 0x40, 0x00, 0xff, 0xff,
0x41, 0x00, 0xff, 0xff, 0x42, 0x00, 0xff, 0xff, 0x43, 0x00, 0xff, 0xff,
0x44, 0x00, 0xff, 0xff, 0x45, 0x00, 0xff, 0xff, 0x46, 0x00, 0xff, 0xff,
0x47, 0x00, 0xff, 0xff, 0x48, 0x00, 0xff, 0xff, 0x49, 0x00, 0xff, 0xff,
0x4a, 0x00, 0xff, 0xff, 0x4b, 0x00, 0x2a, 0x21, 0xff, 0xff, 0x4c, 0x00,
0xff, 0xff, 0x4d, 0x00, 0xff, 0xff, 0x4e, 0x00, 0xff, 0xff, 0x4f, 0x00,
0xff, 0xff, 0x50, 0x00, 0xff, 0xff, 0x51, 0x00, 0xff, 0xff, 0x52, 0x00,
0xff, 0xff, 0x53, 0x00, 0xff, 0xff, 0x54, 0x00, 0xff, 0xff, 0x55, 0x00,
0xff, 0xff, 0x56, 0x00, 0xff, 0xff, 0x57, 0x00, 0xff, 0xff, 0x58, 0x00,
0xff, 0xff, 0x59, 0x00, 0xff, 0xff, 0x5a, 0x00, 0xff, 0xff, 0x5b, 0x00,
0xff, 0xff, 0x5c, 0x00, 0xf5, 0x29, 0xff, 0xff, 0x5d, 0x00, 0xff, 0xff,
0x5e, 0x00, 0xc4, 0x02, 0xc6, 0x02, 0x03, 0x23, 0xff, 0xff, 0x5f, 0x00,
0xff, 0xff, 0x60, 0x00, 0xbb, 0x02, 0xbd, 0x02, 0xcb, 0x02, 0x18, 0x20,
0x1b, 0x20, 0x35, 0x20, 0xff, 0xff, 0x61, 0x00, 0xff, 0xff, 0x62, 0x00,
0xff, 0xff, 0x63, 0x00, 0xff, 0xff, 0x64, 0x00, 0xff, 0xff, 0x65, 0x00,
0xff, 0xff, 0x66, 0x00, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00,
0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x6b, 0x00,
0xff, 0xff, 0x6c, 0x00, 0xff, 0xff, 0x6d, 0x00, 0xff, 0xff, 0x6e, 0x00,
0xff, 0xff, 0x6f, 0x00, 0xff, 0xff, 0x70, 0x00, 0xff, 0xff, 0x71, 0x00,
0xff, 0xff, 0x72, 0x00, 0xff, 0xff, 0x73, 0x00, 0xff, 0xff, 0x74, 0x00,
0xff, 0xff, 0x75, 0x00, 0xff, 0xff, 0x76, 0x00, 0xff, 0xff, 0x77, 0x00,
0xff, 0xff, 0x78, 0x00, 0xff, 0xff, 0x79, 0x00, 0xff, 0xff, 0x7a, 0x00,
0xff, 0xff, 0x7b, 0x00, 0xff, 0xff, 0x7c, 0x00, 0x23, 0x22, 0xff, 0xff,
0x7d, 0x00, 0xff, 0xff, 0x7e, 0x00, 0xdc, 0x02, 0xff, 0xff, 0x22, 0x20,
0x19, 0x22, 0xcf, 0x25, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xc1, 0x00,
0xff, 0xff, 0xc2, 0x00, 0xff, 0xff, 0xc3, 0x00, 0xff, 0xff, 0xc4, 0x00,
0xff, 0xff, 0xc5, 0x00, 0x2b, 0x21, 0xff, 0xff, 0xc6, 0x00, 0xff, 0xff,
0xc7, 0x00, 0xff, 0xff, 0xc8, 0x00, 0xff, 0xff, 0xc9, 0x00, 0xff, 0xff,
0xca, 0x00, 0xff, 0xff, 0xcb, 0x00, 0xff, 0xff, 0xcc, 0x00, 0xff, 0xff,
0xcd, 0x00, 0xff, 0xff, 0xce, 0x00, 0xff, 0xff, 0xcf, 0x00, 0xff, 0xff,
0xd0, 0x00, 0x10, 0x01, 0xff, 0xff, 0xd1, 0x00, 0xff, 0xff, 0xd2, 0x00,
0xff, 0xff, 0xd3, 0x00, 0xff, 0xff, 0xd4, 0x00, 0xff, 0xff, 0xd5, 0x00,
0xff, 0xff, 0xd6, 0x00, 0xff, 0xff, 0xd7, 0x00, 0xff, 0xff, 0xd8, 0x00,
0xff, 0xff, 0xd9, 0x00, 0xff, 0xff, 0xda, 0x00, 0xff, 0xff, 0xdb, 0x00,
0xff, 0xff, 0xdc, 0x00, 0xff, 0xff, 0xdd, 0x00, 0xff, 0xff, 0xde, 0x00,
0xff, 0xff, 0xdf, 0x00, 0xff, 0xff, 0x92, 0x25, 0xff, 0xff, 0xa1, 0x00,
0xff, 0xff, 0xa2, 0x00, 0xff, 0xff, 0xa3, 0x00, 0xff, 0xff, 0xac, 0x20,
0xff, 0xff, 0xa5, 0x00, 0xff, 0xff, 0x60, 0x01, 0xff, 0xff, 0xa7, 0x00,
0xff, 0xff, 0x61, 0x01, 0xff, 0xff, 0xa9, 0x00, 0xff, 0xff, 0xaa, 0x00,
0xff, 0xff, 0xab, 0x00, 0xff, 0xff, 0xac, 0x00, 0xff, 0xff, 0xa4, 0x00,
0xff, 0xff, 0xae, 0x00, 0xff, 0xff, 0xaf, 0x00, 0xc9, 0x02, 0xff, 0xff,
0xb0, 0x00, 0xda, 0x02, 0xff, 0xff, 0xb1, 0x00, 0xff, 0xff, 0xb2, 0x00,
0xff, 0xff, 0xb3, 0x00, 0xff, 0xff, 0x7d, 0x01, 0xff, 0xff, 0xb5, 0x00,
0xbc, 0x03, 0xff, 0xff, 0xb6, 0x00, 0xff, 0xff, 0xb7, 0x00, 0x27, 0x20,
0xc5, 0x22, 0x31, 0x2e, 0xff, 0xff, 0x7e, 0x01, 0xff, 0xff, 0xb9, 0x00,
0xff, 0xff, 0xba, 0x00, 0xff, 0xff, 0xbb, 0x00, 0xff, 0xff, 0x52, 0x01,
0xff, 0xff, 0x53, 0x01, 0xff, 0xff, 0x78, 0x01, 0xff, 0xff, 0xbf, 0x00,
0xff, 0xff, 0x00, 0x25, 0x14, 0x20, 0x15, 0x20, 0xaf, 0x23, 0xff, 0xff,
0x02, 0x25, 0xff, 0xff, 0x0c, 0x25, 0x6d, 0x25, 0xff, 0xff, 0x10, 0x25,
0x6e, 0x25, 0xff, 0xff, 0x14, 0x25, 0x70, 0x25, 0xff, 0xff, 0x18, 0x25,
0x6f, 0x25, 0xff, 0xff, 0x1c, 0x25, 0xff, 0xff, 0x24, 0x25, 0xff, 0xff,
0x2c, 0x25, 0xff, 0xff, 0x34, 0x25, 0xff, 0xff, 0x3c, 0x25, 0xff, 0xff,
0x91, 0x25, 0xff, 0xff, 0xba, 0x23, 0x3e, 0x20, 0xff, 0xff, 0xbb, 0x23,
0xff, 0xff, 0xbc, 0x23, 0xff, 0xff, 0xbd, 0x23, 0xff, 0xff, 0x50, 0x25,
0x01, 0x25, 0xff, 0xff, 0x51, 0x25, 0x03, 0x25, 0xff, 0xff, 0x54, 0x25,
0x0f, 0x25, 0xff, 0xff, 0x57, 0x25, 0x13, 0x25, 0xff, 0xff, 0x5a, 0x25,
0x17, 0x25, 0xff, 0xff, 0x5d, 0x25, 0x1b, 0x25, 0xff, 0xff, 0x60, 0x25,
0x23, 0x25, 0xff, 0xff, 0x63, 0x25, 0x2b, 0x25, 0xff, 0xff, 0x66, 0x25,
0x33, 0x25, 0xff, 0xff, 0x69, 0x25, 0x3b, 0x25, 0xff, 0xff, 0x6c, 0x25,
0x4b, 0x25, 0xff, 0xff, 0x88, 0x25, 0xff, 0xff, 0x91, 0x21, 0xff, 0xff,
0x93, 0x21, 0xff, 0xff, 0x90, 0x21, 0xff, 0xff, 0x92, 0x21, 0xff, 0xff,
0xe0, 0x00, 0xff, 0xff, 0xe1, 0x00, 0xff, 0xff, 0xe2, 0x00, 0xff, 0xff,
0xe3, 0x00, 0xff, 0xff, 0xe4, 0x00, 0xff, 0xff, 0xe5, 0x00, 0xff, 0xff,
0xe6, 0x00, 0xff, 0xff, 0xe7, 0x00, 0xff, 0xff, 0xe8, 0x00, 0xff, 0xff,
0xe9, 0x00, 0xff, 0xff, 0xea, 0x00, 0xff, 0xff, 0xeb, 0x00, 0xff, 0xff,
0xec, 0x00, 0xff, 0xff, 0xed, 0x00, 0xff, 0xff, 0xee, 0x00, 0xff, 0xff,
0xef, 0x00, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xf1, 0x00, 0xff, 0xff,
0xf2, 0x00, 0xff, 0xff, 0xf3, 0x00, 0xff, 0xff, 0xf4, 0x00, 0xff, 0xff,
0xf5, 0x00, 0xff, 0xff, 0xf6, 0x00, 0xff, 0xff, 0xf7, 0x00, 0xff, 0xff,
0xf8, 0x00, 0xff, 0xff, 0xf9, 0x00, 0xff, 0xff, 0xfa, 0x00, 0xff, 0xff,
0xfb, 0x00, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0xfd, 0x00, 0xff, 0xff,
0xfe, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff
};
unsigned int zap_light16_psf_len = 5312;
typedef struct {
uint8_t magic[2]; // 0x36, 0x04
uint8_t mode;
uint8_t charsize; // bytes per glyph
} PSF1_Header;
-342
View File
@@ -1,342 +0,0 @@
#include <stdint.h>
#include "font.h"
#include <stdarg.h>
#include "render.h"
#include "mm/memory.h"
uint32_t *fb;
uint32_t fb_width;
uint32_t fb_height;
uint32_t fb_pitch;
static int cursor_x = 0;
static int cursor_y = 0;
void put_pixel(int x, int y, uint32_t color) {
fb[y * fb_pitch + x] = color;
}
static void scroll_up(void) {
uint32_t line_pixels = FONT_HEIGHT * fb_pitch;
uint32_t total_pixels = fb_height * fb_pitch;
// Shift everything up by one line
memmove(fb, fb + line_pixels, (total_pixels - line_pixels) * sizeof(uint32_t));
// Clear the last line
memset(fb + (total_pixels - line_pixels), 0, line_pixels * sizeof(uint32_t));
cursor_y -= FONT_HEIGHT;
}
void draw_char_colored(int x, int y, char c, uint32_t color) {
PSF1_Header *font = (PSF1_Header*)(uintptr_t)zap_light16_psf;
uint8_t *glyphs = zap_light16_psf + sizeof(PSF1_Header);
int charsize = font->charsize;
uint8_t *glyph = glyphs + ((unsigned char)c * charsize);
for (int row = 0; row < charsize; row++) {
for (int col = 0; col < 8; col++) {
if (glyph[row] & (0x80 >> col)) {
fb[(y + row) * fb_pitch + (x + col)] = color;
}
}
}
}
void putchar(char c) {
if (c == '\n') {
cursor_x = 0;
cursor_y += FONT_HEIGHT;
if (cursor_y + FONT_HEIGHT > fb_height) scroll_up();
return;
}
draw_char_colored(cursor_x, cursor_y, c, 0xFFFFFF);
cursor_x += FONT_WIDTH;
if (cursor_x >= (int)fb_width) {
cursor_x = 0;
cursor_y += FONT_HEIGHT;
if (cursor_y + FONT_HEIGHT > fb_height) scroll_up();
}
}
void putchar_colored(char c, uint32_t color) {
if (c == '\n') {
cursor_x = 0;
cursor_y += FONT_HEIGHT;
if (cursor_y + FONT_HEIGHT > fb_height) scroll_up();
return;
}
draw_char_colored(cursor_x, cursor_y, c, color);
cursor_x += FONT_WIDTH;
if (cursor_x >= (int)fb_width) {
cursor_x = 0;
cursor_y += FONT_HEIGHT;
if (cursor_y + FONT_HEIGHT > fb_height) scroll_up();
}
}
void print(const char *str) {
while (*str) {
putchar(*str++);
}
}
void itoa(int value, char *buf, int base) {
char *ptr = buf, *ptr1 = buf, tmp_char;
int tmp_value;
do {
tmp_value = value;
value /= base;
*ptr++ = "0123456789ABCDEF"[tmp_value - value * base];
} while (value);
*ptr-- = '\0';
while (ptr1 < ptr) {
tmp_char = *ptr;
*ptr-- = *ptr1;
*ptr1++ = tmp_char;
}
}
static inline uint32_t sample(uint32_t *src, int w, int h, int x, int y)
{
if (x < 0) x = 0;
if (y < 0) y = 0;
if (x >= w) x = w - 1;
if (y >= h) y = h - 1;
return src[y * w + x];
}
void clear_screen(uint32_t color)
{
uint32_t total = fb_width * fb_height;
for (uint32_t i = 0; i < total; i++)
{
fb[i] = color;
}
cursor_y = 0;
}
void draw_image_bilinear(uint32_t *img, int x0, int y0, int new_w, int new_h)
{
int src_w = img[0];
int src_h = img[1];
uint32_t *src = &img[2];
// fixed-point scale factors (16.16)
uint32_t x_scale = (src_w << 16) / new_w;
uint32_t y_scale = (src_h << 16) / new_h;
for (int y = 0; y < new_h; y++)
{
int sy_fp = y * y_scale;
int sy = sy_fp >> 16;
int fy = (sy_fp >> 8) & 0xFF;
for (int x = 0; x < new_w; x++)
{
int sx_fp = x * x_scale;
int sx = sx_fp >> 16;
int fx = (sx_fp >> 8) & 0xFF;
int x1 = sx + 1;
int y1 = sy + 1;
uint32_t c00 = sample(src, src_w, src_h, sx, sy);
uint32_t c10 = sample(src, src_w, src_h, x1, sy);
uint32_t c01 = sample(src, src_w, src_h, sx, y1);
uint32_t c11 = sample(src, src_w, src_h, x1, y1);
// unpack
uint32_t a00 = (c00 >> 24) & 0xFF;
uint32_t r00 = (c00 >> 16) & 0xFF;
uint32_t g00 = (c00 >> 8) & 0xFF;
uint32_t b00 = (c00) & 0xFF;
uint32_t a10 = (c10 >> 24) & 0xFF;
uint32_t r10 = (c10 >> 16) & 0xFF;
uint32_t g10 = (c10 >> 8) & 0xFF;
uint32_t b10 = (c10) & 0xFF;
uint32_t a01 = (c01 >> 24) & 0xFF;
uint32_t r01 = (c01 >> 16) & 0xFF;
uint32_t g01 = (c01 >> 8) & 0xFF;
uint32_t b01 = (c01) & 0xFF;
uint32_t a11 = (c11 >> 24) & 0xFF;
uint32_t r11 = (c11 >> 16) & 0xFF;
uint32_t g11 = (c11 >> 8) & 0xFF;
uint32_t b11 = (c11) & 0xFF;
// bilinear interpolation weights
uint32_t w00 = (256 - fx) * (256 - fy);
uint32_t w10 = fx * (256 - fy);
uint32_t w01 = (256 - fx) * fy;
uint32_t w11 = fx * fy;
uint32_t a = (a00*w00 + a10*w10 + a01*w01 + a11*w11) >> 16;
uint32_t r = (r00*w00 + r10*w10 + r01*w01 + r11*w11) >> 16;
uint32_t g = (g00*w00 + g10*w10 + g01*w01 + g11*w11) >> 16;
uint32_t b = (b00*w00 + b10*w10 + b01*w01 + b11*w11) >> 16;
int dst_x = x0 + x;
int dst_y = y0 + y;
if (dst_x < 0 || dst_y < 0 ||
dst_x >= (int)fb_width ||
dst_y >= (int)fb_height)
continue;
uint32_t color = (a << 24) | (r << 16) | (g << 8) | b;
// alpha blend with framebuffer
if (a < 255)
{
uint32_t dst = fb[dst_y * fb_pitch + dst_x];
uint32_t dr = (dst >> 16) & 0xFF;
uint32_t dg = (dst >> 8) & 0xFF;
uint32_t db = dst & 0xFF;
uint32_t inv = 255 - a;
r = (r * a + dr * inv) / 255;
g = (g * a + dg * inv) / 255;
b = (b * a + db * inv) / 255;
fb[dst_y * fb_pitch + dst_x] =
(0xFF << 24) | (r << 16) | (g << 8) | b;
}
else
{
fb[dst_y * fb_pitch + dst_x] =
(0xFF << 24) | (r << 16) | (g << 8) | b;
}
}
}
}
void backspace() {
if (cursor_x >= FONT_WIDTH) {
cursor_x -= FONT_WIDTH;
// clear the character cell
for (int y = 0; y < FONT_HEIGHT; y++) {
for (int x = 0; x < FONT_WIDTH; x++) {
fb[(cursor_y + y) * fb_pitch + (cursor_x + x)] = 0;
}
}
}
}
void draw_image(uint32_t *img, int x0, int y0)
{
uint32_t w = img[0];
uint32_t h = img[1];
uint32_t *pixels = &img[2];
for (uint32_t y = 0; y < h; y++) {
for (uint32_t x = 0; x < w; x++) {
int dst_x = x0 + x;
int dst_y = y0 + y;
// bounds check (VERY important in kernel)
if (dst_x < 0 || dst_y < 0 ||
dst_x >= (int)fb_width ||
dst_y >= (int)fb_height)
continue;
uint32_t color = pixels[y * w + x];
// alpha handling
uint8_t a = color >> 24;
// fully transparent → skip
if (a == 0)
continue;
// optional: simple alpha blend
if (a < 255) {
uint32_t dst = fb[dst_y * fb_pitch + dst_x];
uint8_t sr = (color >> 16) & 0xFF;
uint8_t sg = (color >> 8) & 0xFF;
uint8_t sb = (color) & 0xFF;
uint8_t dr = (dst >> 16) & 0xFF;
uint8_t dg = (dst >> 8) & 0xFF;
uint8_t db = (dst) & 0xFF;
uint8_t inv = 255 - a;
uint32_t out =
((sr * a + dr * inv) / 255) << 16 |
((sg * a + dg * inv) / 255) << 8 |
((sb * a + db * inv) / 255);
fb[dst_y * fb_pitch + dst_x] = out;
}
else {
// opaque fast path
fb[dst_y * fb_pitch + dst_x] = color;
}
}
}
}
/*void printf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
char buffer[32];
for (int i = 0; fmt[i] != 0; i++) {
if (fmt[i] == '%') {
i++;
switch (fmt[i]) {
case 'd': {
int val = va_arg(args, int);
itoa(val, buffer, 10);
print(buffer);
break;
}
case 'x': {
int val = va_arg(args, int);
itoa(val, buffer, 16);
print(buffer);
break;
}
case 's': {
char *str = va_arg(args, char*);
print(str);
break;
}
case 'c': {
char c = (char)va_arg(args, int);
putchar(c);
break;
}
}
} else {
putchar(fmt[i]);
}
}
va_end(args);
}*/
-18
View File
@@ -1,18 +0,0 @@
#pragma once
#include <stdint.h>
#define FONT_WIDTH 8
#define FONT_HEIGHT 16
extern uint32_t *fb;
extern uint32_t fb_width;
extern uint32_t fb_height;
extern uint32_t fb_pitch;
void putchar(char c);
void putchar_colored(char c, uint32_t color);
void draw_image(uint32_t *img, int x0, int y0);
void draw_image_bilinear(uint32_t *img, int x0, int y0, int new_w, int new_h);
void clear_screen(uint32_t color);
void backspace();
-253
View File
@@ -1,253 +0,0 @@
#include "mm/memory.h"
#include <stddef.h>
#include <stdint.h>
static inline int ok(int m, int need, int size)
{
return (m >= 0 && need >= 0 && m <= size && size - m >= need);
}
static inline uint32_t read_color(unsigned char *pal, int idx, int bpp)
{
// palette entry size = bpp/8
int step = bpp >> 3;
unsigned char b = pal[idx * step + 0];
unsigned char g = pal[idx * step + 1];
unsigned char r = pal[idx * step + 2];
unsigned char a = (step == 4) ? pal[idx * step + 3] : 0xFF;
return ((uint32_t)a << 24) |
((uint32_t)r << 16) |
((uint32_t)g << 8) |
(uint32_t)b;
}
unsigned int *tga_parse(unsigned char *ptr, int size)
{
if (!ptr || size < 18) return NULL;
int m = 0;
int id_len = ptr[0];
int cmap_type = ptr[1];
int img_type = ptr[2];
int cmap_start = ptr[3] | (ptr[4] << 8);
int cmap_len = ptr[5] | (ptr[6] << 8);
int cmap_bpp = ptr[7];
int w = ptr[12] | (ptr[13] << 8);
int h = ptr[14] | (ptr[15] << 8);
int bpp = ptr[16];
int desc = ptr[17];
if (w <= 0 || h <= 0 || w > 4096 || h > 4096)
return NULL;
if (!ok(18, id_len, size))
return NULL;
m = 18 + id_len;
if (m > size) return NULL;
int flip_y = !(desc & 0x20);
size_t pixels = (size_t)w * (size_t)h;
if (pixels == 0 || pixels > (SIZE_MAX / sizeof(unsigned int)))
return NULL;
unsigned int *out = (unsigned int *)kmalloc((pixels + 2) * sizeof(unsigned int));
if (!out) return NULL;
out[0] = w;
out[1] = h;
size_t i = 0;
unsigned char *palette = NULL;
if (cmap_type == 1)
{
// palette starts immediately after header+id
palette = ptr + m;
size_t pal_size = (size_t)cmap_len * (cmap_bpp >> 3);
if (!ok(m, pal_size, size)) {
kfree(out);
return NULL;
}
m += pal_size;
}
// =========================
// TYPE 2 (TRUECOLOR)
// =========================
if (img_type == 2)
{
int bytespp = bpp >> 3;
if (bytespp != 3 && bytespp != 4) goto fail;
for (int y = 0; y < h; y++)
{
int row = flip_y ? (h - 1 - y) : y;
for (int x = 0; x < w; x++)
{
if (!ok(m, bytespp, size)) goto fail;
unsigned char b = ptr[m + 0];
unsigned char g = ptr[m + 1];
unsigned char r = ptr[m + 2];
unsigned char a = (bytespp == 4) ? ptr[m + 3] : 0xFF;
m += bytespp;
out[2 + (size_t)row * w + x] =
((uint32_t)a << 24) |
((uint32_t)r << 16) |
((uint32_t)g << 8) |
(uint32_t)b;
}
}
}
// =========================
// TYPE 3 (GRAYSCALE)
// =========================
else if (img_type == 3)
{
for (size_t idx = 0; idx < pixels; idx++)
{
if (!ok(m, 1, size)) goto fail;
unsigned char v = ptr[m++];
out[2 + idx] =
0xFF000000 |
(v << 16) |
(v << 8) |
v;
}
}
// =========================
// TYPE 1 (PALETTED)
// =========================
else if (img_type == 1)
{
if (!palette) goto fail;
for (size_t idx = 0; idx < pixels; idx++)
{
if (!ok(m, 1, size)) goto fail;
unsigned char index = ptr[m++];
out[2 + idx] = read_color(palette, index, cmap_bpp);
}
}
// =========================
// TYPE 9/10/11 (RLE)
// =========================
else if (img_type == 9 || img_type == 10 || img_type == 11)
{
int bytespp = (img_type == 9) ? 1 : (bpp >> 3);
if (img_type != 9 && bytespp != 3 && bytespp != 4) goto fail;
while (i < pixels)
{
if (!ok(m, 1, size)) goto fail;
unsigned char packet = ptr[m++];
int count = (packet & 0x7F) + 1;
if (count > (int)(pixels - i))
count = (int)(pixels - i);
if (packet & 0x80)
{
// RLE
if (!ok(m, bytespp, size)) goto fail;
uint32_t color;
if (img_type == 9)
{
color = read_color(palette, ptr[m], cmap_bpp);
m += 1;
}
else if (img_type == 11)
{
unsigned char v = ptr[m++];
color = 0xFF000000 | (v << 16) | (v << 8) | v;
}
else
{
unsigned char b = ptr[m + 0];
unsigned char g = ptr[m + 1];
unsigned char r = ptr[m + 2];
unsigned char a = (bytespp == 4) ? ptr[m + 3] : 0xFF;
m += bytespp;
color =
((uint32_t)a << 24) |
((uint32_t)r << 16) |
((uint32_t)g << 8) |
(uint32_t)b;
}
for (int k = 0; k < count; k++)
out[2 + i++] = color;
}
else
{
// RAW
for (int k = 0; k < count; k++)
{
if (!ok(m, bytespp, size)) goto fail;
uint32_t color;
if (img_type == 9)
{
color = read_color(palette, ptr[m++], cmap_bpp);
}
else if (img_type == 11)
{
unsigned char v = ptr[m++];
color = 0xFF000000 | (v << 16) | (v << 8) | v;
}
else
{
unsigned char b = ptr[m + 0];
unsigned char g = ptr[m + 1];
unsigned char r = ptr[m + 2];
unsigned char a = (bytespp == 4) ? ptr[m + 3] : 0xFF;
m += bytespp;
color =
((uint32_t)a << 24) |
((uint32_t)r << 16) |
((uint32_t)g << 8) |
(uint32_t)b;
}
out[2 + i++] = color;
}
}
}
}
else
{
goto fail;
}
return out;
fail:
kfree(out);
return NULL;
}
-16
View File
@@ -1,16 +0,0 @@
#pragma once
typedef struct {
unsigned char magic1; // must be zero
unsigned char colormap; // must be zero
unsigned char encoding; // must be 2
unsigned short cmaporig, cmaplen; // must be zero
unsigned char cmapent; // must be zero
unsigned short x; // must be zero
unsigned short y; // image's height
unsigned short h; // image's height
unsigned short w; // image's width
unsigned char bpp; // must be 32
unsigned char pixeltype; // must be 40
} __attribute__((packed)) tga_header_t;
unsigned int *tga_parse(unsigned char *ptr, int size);
+227
View File
@@ -0,0 +1,227 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <limine.h>
#include "arch/x86_64/boot/gdt.h"
#include "arch/x86_64/boot/idt.h"
#include "arch/x86_64/boot/isr.h"
#include "mm/memory.h"
#include "mm/pmm.h"
#include "mm/vmm.h"
#include "arch/x86_64/bus/ata.h"
#include "string.h"
#include "arch/x86_64/cpu/io.h"
#include "arch/x86_64/sys/pit.h"
#include "arch/x86_64/bus/pci.h"
#include "arch/x86_64/sys/apic.h"
#include "mp/mp.h"
#include "drivers/fb/fb.h"
#include "libk/debug.h"
#include "fs/elf.h"
#include "sched/sched_types.h"
#include "arch/x86_64/sys/halt.h"
#include <cpuid.h>
#include "libk/random.h"
#include "libk/kargs.h"
#include "sched/sched_types.h"
#include "sched/sched.h"
#include "arch/x86_64/serial/serial.h"
#include "arch/x86_64/sys/tsc.h"
#include "arch/x86_64/fw/acpi.h"
extern bool print_now;
static volatile struct limine_framebuffer_request framebuffer_request = {
.id = LIMINE_FRAMEBUFFER_REQUEST,
.revision = 6
};
static volatile struct limine_kernel_file_request limine_kernel_file_request = {
.id = LIMINE_KERNEL_FILE_REQUEST, .revision = 0};
static volatile struct limine_memmap_request memmap_request = {
.id = LIMINE_MEMMAP_REQUEST,
.revision = 6
};
static volatile struct limine_rsdp_request rsdp_request = {
.id = LIMINE_RSDP_REQUEST,
.revision = 6
};
volatile struct limine_stack_size_request stack_size_request = {
.id = LIMINE_STACK_SIZE_REQUEST,
.revision = 0,
.stack_size = CPU_STACK_SIZE,
};
volatile struct limine_smp_request mp_request = {
.id = LIMINE_SMP_REQUEST,
.revision = 0
};
static volatile struct limine_module_request module_request = {
.id = LIMINE_MODULE_REQUEST, .revision = 0};
extern bool is_halting;
extern uint8_t is_pausing;
void nmi_vector(registers_t *reg) {
if (is_halting) {
for (;;) {
cli();
halt();
}
} else if (is_pausing) {
while (is_pausing & PAUSING) {
pause();
}
apic_eoi();
} else {
panic_((void *)(reg->rip), (void *)(reg->rbp), "Unexpected NMI\n");
}
}
void breakpoint_handler(registers_t *reg);
static uint64_t rdseed(void) {
uint64_t r = 0;
asm volatile("rdseed %0" : "=r"(r));
return r;
}
static uint64_t rdrand(void) {
uint64_t r = 0;
asm volatile("rdrand %0" : "=r"(r));
return r;
}
void random_setup_seed_source(void) {
uint32_t a = 0, b = 0, c = 0, d = 0;
__get_cpuid(7, &a, &b, &c, &d);
if (b & bit_RDSEED) {
kprintf("Using RDSEED as seed source\n");
random_get_seed = rdseed;
}
if (c & bit_RDRND) {
kprintf("Using RDRAND as seed source\n");
random_get_seed = rdrand;
}
}
uint64_t g_rsdp_phys = 0;
void _entry(void) {
cli();
struct limine_memmap_entry **memmap = memmap_request.response->entries;
size_t memmap_entries = memmap_request.response->entry_count;
struct limine_rsdp_response *rsdp_response = rsdp_request.response;
if (rsdp_response) {
g_rsdp_phys = (uint64_t)rsdp_response->address - MEM_PHYS_OFFSET;
}
pmm_init(memmap, memmap_entries);
slab_init();
vmm_init(memmap, memmap_entries);
struct limine_framebuffer *framebuffer = framebuffer_request.response->framebuffers[0];
struct framebuffer fb = {0};
fb.address = (uint32_t *)framebuffer->address;
fb.pitch = framebuffer->pitch;
fb.bpp = framebuffer->bpp;
fb.width = framebuffer->width;
fb.height = framebuffer->height;
fb.tex_color = 0x00eee8d5;
fb.tex_x = 0;
fb.tex_y = 0;
fb.bg_color = 0x00124560;
fb.color_masks[0].offset = framebuffer->red_mask_shift;
fb.color_masks[0].length = framebuffer->red_mask_size;
fb.color_masks[1].offset = framebuffer->green_mask_shift;
fb.color_masks[1].length = framebuffer->green_mask_size;
fb.color_masks[2].offset = framebuffer->blue_mask_shift;
fb.color_masks[2].length = framebuffer->blue_mask_size;
framebuffer_init(&fb);
print_now = true;
serial_init();
struct limine_file *kernel_file =
limine_kernel_file_request.response->kernel_file;
kargs_init(kernel_file->cmdline);
uint16_t kernel_args_num = kernel_arguments.kernel_args;
uint32_t cpu_count = kernel_arguments.cpu_count;
if ((kernel_args_num & KERNEL_ARGS_KPRINTF_LOGS)) {
put_to_fb = true;
}
kprintf("Hello x86_64!\n");
kprintf("Kernel base: %p Mem phys base: %p\n", KERNEL_BASE,
MEM_PHYS_OFFSET);
kprintf("KirkOS Ver. %s\n", KIRKOS_VERSION);
kprintf("Got kernel cmdline as \"%s\"\n", kernel_file->cmdline);
if ((kernel_args_num & KERNEL_ARGS_CPU_COUNT_GIVEN))
kprintf("CPU count is %u\n", cpu_count);
gdt_init();
isr_install();
isr_register_handler(2, nmi_vector);
isr_register_handler(3, breakpoint_handler);
isr_register_handler(48, resched);
elf_init_function_table(kernel_file->address);
acpi_init();
apic_init();
mp_init(mp_request.response);
// The NSA has also forced hardware manufacturers to backdoor their 'Random
// Number Generators' to allow them to break RSA encryption
if (!(kernel_arguments.kernel_args &
KERNEL_ARGS_DONT_TRUST_CPU_RANDOM_SEED)) {
random_setup_seed_source();
}
random_set_seed(random_get_seed());
size_t module_info[2] = {0};
if (module_request.response && module_request.response->module_count > 0) {
struct limine_file *module = module_request.response->modules[0];
module_info[0] = (size_t)module->address;
module_info[1] = (size_t)module->size;
}
//time_init(); on hold for the time being, heh get it?
sched_init((uint64_t)module_info);
timer_sched_oneshot(48, 20000);
sti();
for (;;) {
halt();
}
}
+341
View File
@@ -0,0 +1,341 @@
#include "libk/debug.h"
#include "libk/errno.h"
#include "devtmpfs.h"
#include "vfs.h"
#include "libk/misc.h"
#include "libk/types.h"
#include "libk/resource.h"
#include "libk/time.h"
#include "mp/spinlock.h"
#include "mm/mmap.h"
#include "mm/pmm.h"
#include "mm/slab.h"
#include "mm/vmm.h"
#include <stddef.h>
#include <stdint.h>
struct devtmpfs_resource {
struct resource res;
void *data;
size_t capacity;
};
struct devtmpfs {
struct vfs_filesystem fs;
uint64_t dev_id;
uint64_t inode_counter;
};
static struct vfs_filesystem *devtmpfs = NULL;
static struct vfs_node *devtmpfs_root = NULL;
static ssize_t devtmpfs_resource_read(struct resource *_this,
struct f_description *description,
void *buf, off_t offset, size_t count) {
(void)description;
struct devtmpfs_resource *this = (struct devtmpfs_resource *)_this;
spinlock_acquire_or_wait(&this->res.lock);
size_t actual_count = count;
if ((off_t)(offset + count) >= this->res.stat.st_size) {
actual_count = count - ((offset + count) - this->res.stat.st_size);
}
memcpy(buf, this->data + offset, actual_count);
spinlock_drop(&this->res.lock);
return actual_count;
}
static ssize_t devtmpfs_resource_write(struct resource *_this,
struct f_description *description,
const void *buf, off_t offset,
size_t count) {
(void)description;
ssize_t ret = -1;
struct devtmpfs_resource *this = (struct devtmpfs_resource *)_this;
spinlock_acquire_or_wait(&this->res.lock);
if (offset + count >= this->capacity) {
size_t new_capacity = this->capacity;
while (offset + count >= new_capacity) {
new_capacity *= 2;
}
void *new_data = kmalloc(new_capacity);
if (new_data == NULL) {
errno = ENOMEM;
goto fail;
}
memcpy(new_data, this->data, this->capacity);
kfree(this->data);
this->data = new_data;
this->capacity = new_capacity;
}
memcpy(this->data + offset, buf, count);
if ((off_t)(offset + count) >= this->res.stat.st_size) {
this->res.stat.st_size = (off_t)(offset + count);
this->res.stat.st_blocks =
DIV_ROUNDUP(this->res.stat.st_size, this->res.stat.st_blksize);
}
ret = count;
fail:
spinlock_drop(&this->res.lock);
return ret;
}
static void *devtmpfs_resource_mmap(struct resource *_this, size_t file_page,
int flags) {
struct devtmpfs_resource *this = (struct devtmpfs_resource *)_this;
spinlock_acquire_or_wait(&this->res.lock);
void *ret = NULL;
if ((flags & MAP_SHARED) != 0) {
ret = (this->data + file_page * PAGE_SIZE) - MEM_PHYS_OFFSET;
} else {
ret = pmm_alloc(1);
if (ret == NULL) {
goto cleanup;
}
memcpy(ret + MEM_PHYS_OFFSET, this->data + file_page * PAGE_SIZE,
PAGE_SIZE);
}
cleanup:
spinlock_drop(&this->res.lock);
return ret;
}
static bool devtmpfs_truncate(struct resource *this_,
struct f_description *description,
size_t length) {
(void)description;
struct devtmpfs_resource *this = (struct devtmpfs_resource *)this_;
if (length > this->capacity) {
size_t new_capacity = this->capacity;
while (new_capacity < length) {
new_capacity *= 2;
}
void *new_data = kmalloc(new_capacity);
if (new_data == NULL) {
errno = ENOMEM;
goto fail;
}
memcpy(new_data, this->data, this->capacity);
kfree(this->data);
this->data = new_data;
this->capacity = new_capacity;
}
this->res.stat.st_size = (off_t)length;
this->res.stat.st_blocks =
DIV_ROUNDUP(this->res.stat.st_size, this->res.stat.st_blksize);
return true;
fail:
return false;
}
static inline struct devtmpfs_resource *
create_devtmpfs_resource(struct devtmpfs *this, int mode) {
struct devtmpfs_resource *resource =
resource_create(sizeof(struct devtmpfs_resource));
if (resource == NULL) {
return resource;
}
if (S_ISREG(mode)) {
resource->capacity = 4096;
resource->data = kmalloc(resource->capacity);
resource->res.can_mmap = true;
}
resource->res.read = devtmpfs_resource_read;
resource->res.write = devtmpfs_resource_write;
resource->res.mmap = devtmpfs_resource_mmap;
resource->res.truncate = devtmpfs_truncate;
resource->res.stat.st_size = 0;
resource->res.stat.st_blocks = 0;
resource->res.stat.st_blksize = 512;
resource->res.stat.st_dev = this->dev_id;
resource->res.stat.st_ino = this->inode_counter++;
resource->res.stat.st_mode = mode;
resource->res.stat.st_nlink = 1;
resource->res.stat.st_atim = time_realtime;
resource->res.stat.st_ctim = time_realtime;
resource->res.stat.st_mtim = time_realtime;
return resource;
}
static inline struct vfs_filesystem *devtmpfs_instantiate(void);
static struct vfs_node *devtmpfs_mount(struct vfs_node *parent,
const char *name,
struct vfs_node *source) {
(void)parent;
(void)name;
(void)source;
return devtmpfs_root;
}
static struct vfs_node *devtmpfs_create(struct vfs_filesystem *_this,
struct vfs_node *parent,
const char *name, int mode) {
struct devtmpfs *this = (struct devtmpfs *)_this;
struct vfs_node *new_node = NULL;
struct devtmpfs_resource *resource = NULL;
new_node = vfs_create_node(_this, parent, name, S_ISDIR(mode));
if (new_node == NULL) {
goto fail;
}
resource = create_devtmpfs_resource(this, mode);
if (resource == NULL) {
goto fail;
}
new_node->resource = (struct resource *)resource;
return new_node;
fail:
if (new_node != NULL) {
kfree(new_node); // TODO: Use vfs_destroy_node
}
if (resource != NULL) {
kfree(resource);
}
return NULL;
}
static struct vfs_node *devtmpfs_symlink(struct vfs_filesystem *_this,
struct vfs_node *parent,
const char *name, const char *target) {
struct devtmpfs *this = (struct devtmpfs *)_this;
struct vfs_node *new_node = NULL;
struct devtmpfs_resource *resource = NULL;
new_node = vfs_create_node(_this, parent, name, false);
if (new_node == NULL) {
goto fail;
}
resource = create_devtmpfs_resource(this, 0777 | S_IFLNK);
if (resource == NULL) {
goto fail;
}
new_node->resource = (struct resource *)resource;
new_node->symlink_target = strdup(target);
return new_node;
fail:
if (new_node != NULL) {
kfree(new_node); // TODO: Use vfs_destroy_node
}
if (resource != NULL) {
kfree(resource);
}
return NULL;
}
static struct vfs_node *devtmpfs_link(struct vfs_filesystem *_this,
struct vfs_node *parent, const char *name,
struct vfs_node *node) {
if (S_ISDIR(node->resource->stat.st_mode)) {
errno = EISDIR;
return NULL;
}
struct vfs_node *new_node = vfs_create_node(_this, parent, name, false);
if (new_node == NULL) {
return NULL;
}
new_node->resource = node->resource;
return new_node;
}
static inline struct vfs_filesystem *devtmpfs_instantiate(void) {
struct devtmpfs *new_fs = kmalloc(sizeof(struct devtmpfs));
if (new_fs == NULL) {
return NULL;
}
new_fs->fs.create = devtmpfs_create;
new_fs->fs.symlink = devtmpfs_symlink;
new_fs->fs.link = devtmpfs_link;
return (struct vfs_filesystem *)new_fs;
}
void devtmpfs_init(void) {
devtmpfs = devtmpfs_instantiate();
if (devtmpfs == NULL) {
panic("Failed to instantiate devtmpfs\n");
}
devtmpfs_root = devtmpfs->create(devtmpfs, NULL, "", 0755 | S_IFDIR);
if (devtmpfs_root == NULL) {
panic("Failed to create root devtmpfs node\n");
}
vfs_add_filesystem(devtmpfs_mount, "devtmpfs");
}
bool devtmpfs_add_device(struct resource *device, const char *name) {
struct vfs_node *node = vfs_get_node(devtmpfs_root, name, false);
if (node != NULL) {
errno = EEXIST;
return false;
}
struct vfs_node *new_node =
vfs_create_node(devtmpfs, devtmpfs_root, name, false);
if (new_node == NULL) {
return false;
}
new_node->resource = device;
struct devtmpfs *fs = (struct devtmpfs *)devtmpfs;
device->stat.st_dev = fs->dev_id;
device->stat.st_ino = fs->inode_counter++;
device->stat.st_nlink = 1;
device->stat.st_atim = time_realtime;
device->stat.st_ctim = time_realtime;
device->stat.st_mtim = time_realtime;
spinlock_acquire_or_wait(&vfs_lock);
HASHMAP_SINSERT(&devtmpfs_root->children, name, new_node);
spinlock_drop(&vfs_lock);
return new_node;
}
+6
View File
@@ -0,0 +1,6 @@
#pragma once
#include "libk/resource.h"
#include <stdbool.h>
void devtmpfs_init(void);
bool devtmpfs_add_device(struct resource *device, const char *name);
+442 -184
View File
@@ -1,231 +1,489 @@
// elf.c (now extracts AT_PHDR / AT_PHENT / AT_PHNUM + minor cleanups)
#include "elf.h"
#include "libk/stdio.h"
#include "libk/string.h"
#include "mm/pmm.h"
#include "mm/vmm.h"
#include "mm/memory.h"
#include "fs/ext2.h"
#include "libk/debug.h"
#include "libk/module.h"
#include "fs/vfs.h"
#include "mm/mmap.h"
#include "libk/resource.h"
#include "libk/misc.h"
extern uintptr_t g_hhdm_offset;
// static struct function_symbol *name_to_function = NULL;
static struct function_symbol *function_to_name = NULL;
static size_t function_table_size = 0;
bool symbol_table_initialised = false;
bool ELF_Read(const char* path,
void** entryPoint,
struct pagemap *target_pagemap,
uint64_t *out_tls_fs_base,
uint64_t *out_phdr_va,
uint16_t *out_phent,
uint16_t *out_phnum)
{
*out_tls_fs_base = 0;
*out_phdr_va = 0;
*out_phent = 0;
*out_phnum = 0;
module_list_t modules_list = {0};
/*
static void simple_append_name(const char *string, uint64_t address) {
size_t index = hash(string, strlen(string)) % function_table_size;
name_to_function[index].address = address;
name_to_function[index].name = string;
}
*/
const char *elf_get_name_from_function(uint64_t address) {
if (!symbol_table_initialised)
return "";
uint32_t inum = ext2_resolve_path(path);
if (!inum) {
printf("ELF: file not found: %s\n", path);
return false;
}
address -= KERNEL_BASE;
address += 0xffffffff80000000;
ext2_inode_t inode;
if (!ext2_read_inode(inum, &inode)) {
printf("ELF: failed to read inode\n");
return false;
}
// I HATE HASH COLLISIONS
// I HATE HASH COLLISIONS
for (size_t i = 0; i < function_table_size; i++) {
if (function_to_name[i].address == address)
return function_to_name[i].name;
}
uint64_t file_size = inode.i_size;
if (file_size < sizeof(ELFHeader)) {
printf("ELF: file too small\n");
return false;
}
return "UNKNOWN";
}
uint64_t buf_pages = ALIGN_UP(file_size, PAGE_SIZE) / PAGE_SIZE;
void* buffer_phys = pmm_allocz(buf_pages);
if (!buffer_phys) {
printf("ELF: failed to allocate %lu pages for file buffer\n", buf_pages);
return false;
}
uint64_t elf_get_function_from_name(const char *string) {
if (!symbol_table_initialised || !string)
return (uint64_t)NULL;
uint8_t* elf_buffer = (uint8_t*)((uintptr_t)buffer_phys + MEM_PHYS_OFFSET);
// size_t index = hash(string, strlen(string)) % function_table_size;
// uint64_t address = name_to_function[index].address;
if (!ext2_read_file(&inode, elf_buffer)) {
pmm_free(buffer_phys, buf_pages);
return false;
}
// I HATE HASH COLLISIONS
// I HATE HASH COLLISIONS
uint64_t address = 0;
for (size_t i = 0; i < function_table_size; i++) {
if (!strcmp(function_to_name[i].name, string)) {
address = function_to_name[i].address;
break;
}
}
ELFHeader* header = (ELFHeader*)elf_buffer;
if (address) {
address -= 0xffffffff80000000;
address += KERNEL_BASE;
}
printf("=== ELF DEBUG ===\n"
"Entry=0x%lx PHDR@0x%lx count=%u type=0x%x arch=0x%x\n"
"=== END ===\n",
header->ProgramEntryPosition,
header->ProgramHeaderTablePosition,
header->ProgramHeaderTableEntryCount,
header->Type,
header->InstructionSet);
return address;
}
if (memcmp(header->Magic, ELF_MAGIC, 4) != 0 ||
header->Bitness != ELF_BITNESS_64BIT ||
header->Endianness != ELF_ENDIANNESS_LITTLE ||
(header->Type != ELF_TYPE_EXECUTABLE && header->Type != ELF_TYPE_SHARED) ||
header->InstructionSet != ELF_INSTRUCTION_SET_X64) {
void elf_init_function_table(uint8_t *binary) {
vec_init(&modules_list);
printf("ELF: unsupported/invalid header\n");
goto cleanup;
}
Elf64_Ehdr *ehdr = (Elf64_Ehdr *)binary;
*entryPoint = (void*)header->ProgramEntryPosition;
Elf64_Shdr *elf_section_headers = (Elf64_Shdr *)(binary + ehdr->e_shoff);
// ------------------------------------------------------------------
// Parse program headers LOAD, TLS, and PHDR
// ------------------------------------------------------------------
uint64_t tls_vaddr = 0, tls_filesz = 0, tls_memsz = 0, tls_align = 8;
uint8_t* tls_src = NULL;
uint64_t phdr_vaddr = 0;
Elf64_Shdr *symtab = NULL;
char *strtab = NULL;
uint8_t* ph_table = elf_buffer + header->ProgramHeaderTablePosition;
uint64_t phdr_table_end = header->ProgramHeaderTablePosition +
(uint64_t)header->ProgramHeaderTableEntryCount *
header->ProgramHeaderTableEntrySize;
for (int i = 0; i < ehdr->e_shnum; i++) {
if (elf_section_headers[i].sh_type == SHT_SYMTAB) {
symtab = &elf_section_headers[i];
strtab = (char *)((uintptr_t)binary +
elf_section_headers[symtab->sh_link].sh_offset);
break;
}
}
if (phdr_table_end > file_size) {
printf("ELF: program header table extends beyond file\n");
goto cleanup;
}
if (symtab != NULL) {
Elf64_Sym *sym_entries = (Elf64_Sym *)(binary + symtab->sh_offset);
size_t num_symbols = symtab->sh_size / symtab->sh_entsize;
for (uint32_t i = 0; i < header->ProgramHeaderTableEntryCount; i++) {
ELFProgramHeader* ph = (ELFProgramHeader*)(ph_table + i * header->ProgramHeaderTableEntrySize);
function_table_size = 0;
// name_to_function =
// kmalloc(sizeof(struct function_symbol) * num_symbols);
function_to_name =
kmalloc(sizeof(struct function_symbol) * num_symbols);
// PT_PHDR
if (ph->Type == ELF_PROGRAM_TYPE_PHDR) {
phdr_vaddr = ph->VirtualAddress;
printf("ELF: Found PT_PHDR VA=0x%lx\n", phdr_vaddr);
// fall through
}
for (size_t i = 0; i < num_symbols; i++) {
if ((ELF64_ST_TYPE(sym_entries[i].st_info) == STT_OBJECT) &&
ELF64_ST_BIND(sym_entries[i].st_info) == STB_GLOBAL) {
if (((uint64_t)strtab + sym_entries[i].st_name)) {
char *dupped = strdup(
(char *)((uint64_t)strtab + sym_entries[i].st_name));
// PT_TLS
if (ph->Type == ELF_PROGRAM_TYPE_TLS) {
tls_vaddr = ph->VirtualAddress;
tls_filesz = ph->FileSize;
tls_memsz = ph->MemorySize;
tls_align = ph->Align ? ph->Align : 8;
tls_src = elf_buffer + ph->Offset;
function_to_name[function_table_size].address =
sym_entries[i].st_value;
function_to_name[function_table_size++].name = dupped;
}
}
if ((ELF64_ST_TYPE(sym_entries[i].st_info) == STT_FUNC) &&
ELF64_ST_BIND(sym_entries[i].st_info) == STB_GLOBAL) {
if (ph->Offset + ph->FileSize > file_size) {
printf("ELF: PT_TLS segment data out of file bounds\n");
goto cleanup;
}
// We need a better hash function for the addresses since there
// are hash collisions. For now we are using this slow way.
if (((uint64_t)strtab + sym_entries[i].st_name)) {
char *dupped = strdup(
(char *)((uint64_t)strtab + sym_entries[i].st_name));
printf("ELF: Found PT_TLS VA=0x%lx FileSz=0x%lx MemSz=0x%lx Align=0x%lx\n",
tls_vaddr, tls_filesz, tls_memsz, tls_align);
continue;
}
function_to_name[function_table_size].address =
sym_entries[i].st_value;
function_to_name[function_table_size++].name = dupped;
if (ph->Type != ELF_PROGRAM_TYPE_LOAD || ph->MemorySize == 0)
continue;
// simple_append_name(dupped, sym_entries[i].st_value);
}
}
}
symbol_table_initialised = true;
}
}
if (ph->Offset + ph->FileSize > file_size) {
printf("ELF: PT_LOAD segment data out of file bounds\n");
goto cleanup;
}
uint64_t module_load(const char *path) {
struct vfs_node *node = vfs_get_node(vfs_root, path, true);
if (!node) {
kprintf("Module not found\n");
return 1;
}
// Map with exact permissions
uint64_t map_flags = PAGE_USER;
if (ph->Flags & PF_R) map_flags |= PAGE_READ;
if (ph->Flags & PF_W) map_flags |= PAGE_WRITE;
if (!(ph->Flags & PF_X)) map_flags |= PAGE_NO_EXECUTE;
struct resource *res = node->resource;
uint64_t virt = ph->VirtualAddress;
uint64_t aligned_virt = ALIGN_DOWN(virt, PAGE_SIZE);
uint64_t page_offset = virt & (PAGE_SIZE - 1);
uint64_t aligned_memsz = ALIGN_UP(ph->MemorySize + page_offset, PAGE_SIZE);
uint64_t pages = aligned_memsz / PAGE_SIZE;
struct module *m = kmalloc(sizeof(struct module));
memzero(m, sizeof(struct module));
strncpy(m->name, path, sizeof(m->name));
void* seg_phys = pmm_allocz(pages);
if (!seg_phys) {
printf("ELF: failed to allocate physical pages for LOAD segment\n");
goto cleanup;
}
Elf64_Ehdr *ehdr = kmalloc(sizeof(Elf64_Ehdr));
for (uint64_t p = 0; p < pages; p++) {
if (!vmm_map_page(target_pagemap,
aligned_virt + p * PAGE_SIZE,
(uintptr_t)seg_phys + p * PAGE_SIZE,
map_flags,
Size4KiB)) {
pmm_free(seg_phys, pages);
goto cleanup;
}
}
res->read(res, NULL, ehdr, 0, sizeof(Elf64_Ehdr));
uint8_t* dst = (uint8_t*)((uintptr_t)seg_phys + MEM_PHYS_OFFSET);
memcpy(dst + page_offset, elf_buffer + ph->Offset, ph->FileSize);
if (ph->MemorySize > ph->FileSize) {
memset(dst + page_offset + ph->FileSize, 0,
ph->MemorySize - ph->FileSize);
}
}
if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG)) {
kprintf("ELF header check fail\n");
return 1;
}
if (ehdr->e_ident[EI_CLASS] != ELFCLASS64 ||
ehdr->e_ident[EI_DATA] != ELFDATA2LSB || ehdr->e_ident[EI_OSABI] != 0 ||
ehdr->e_machine != EM_X86_64) {
kprintf("This ELF isn't for us\n");
return 1;
}
uint64_t tls_size = tls_memsz ? ALIGN_UP(tls_memsz, tls_align) : 0ULL;
if (ehdr->e_type != 1) {
kprintf("This ELF isn't executable\n");
return 1;
}
uint64_t tcb_va = TLS_BASE_VA + PAGE_SIZE;
uint64_t tls_va = tcb_va - tls_size;
if (ehdr->e_shentsize != sizeof(Elf64_Shdr)) {
kprintf("Malformed ELF?\n");
return 1;
}
uint64_t page_va = ALIGN_DOWN(tls_va, PAGE_SIZE);
uint64_t tcb_size = sizeof(TCB);
uint64_t block_end_va = tcb_va + tcb_size;
uint64_t block_end_page = ALIGN_UP(block_end_va, PAGE_SIZE);
uint64_t map_pages = ((block_end_page - page_va) / PAGE_SIZE) + 8;
if (map_pages == 0) map_pages = 1;
// Setup variable for the section headers
size_t section_count = ehdr->e_shnum;
size_t section_header_size = sizeof(Elf64_Shdr);
Elf64_Shdr *elf_section_headers =
kmalloc(section_header_size * section_count);
res->read(res, NULL, elf_section_headers, ehdr->e_shoff,
section_header_size * section_count);
void* tls_phys = pmm_allocz(map_pages);
if (!tls_phys) {
printf("ELF: failed to allocate TLS/TCB pages\n");
goto cleanup;
}
for (size_t index = 0; index < section_count; index++) {
Elf64_Shdr *section = (elf_section_headers + index);
uint64_t tls_map_flags = PAGE_USER | PAGE_READ | PAGE_WRITE;
for (uint64_t p = 0; p < map_pages; p++) {
if (!vmm_map_page(target_pagemap,
page_va + p * PAGE_SIZE,
(uintptr_t)tls_phys + p * PAGE_SIZE,
tls_map_flags,
Size4KiB)) {
pmm_free(tls_phys, map_pages);
goto cleanup;
}
}
// If this section should allocate memory and is bigger than 0
if ((section->sh_flags & SHF_ALLOC) && section->sh_size > 0) {
// Allocate memory, currenty RW so we can write to it
char *mem = (char *)((uint64_t)pmm_allocz(
1 + (section->sh_size / PAGE_SIZE)) +
MEM_PHYS_OFFSET);
uint8_t* base_hhdm = (uint8_t*)((uintptr_t)tls_phys + MEM_PHYS_OFFSET);
m->mappings[m->mappings_count].addr = (uint64_t)(size_t)mem;
m->mappings[m->mappings_count++].size = section->sh_size;
if (tls_size > 0) {
uint8_t* tls_dst = base_hhdm + (tls_va - page_va);
if (tls_filesz) memcpy(tls_dst, tls_src, tls_filesz);
if (tls_memsz > tls_filesz)
memset(tls_dst + tls_filesz, 0, tls_memsz - tls_filesz);
}
if (section->sh_type == SHT_PROGBITS) {
// Read data from the file
res->read(res, NULL, mem, section->sh_offset, section->sh_size);
} else if (section->sh_type == SHT_NOBITS) {
// Section is empty, so fill with zeros
memzero(mem, section->sh_size);
}
section->sh_addr = (uintptr_t)mem;
}
TCB* tcb = (TCB*)(base_hhdm + (tcb_va - page_va));
memset(tcb, 0, sizeof(TCB));
tcb->self = (void*)tcb_va;
tcb->tid = 1;
// Load symbol and string tables from the file
if (section->sh_type == SHT_SYMTAB || section->sh_type == SHT_STRTAB) {
Elf64_Sym *table = kmalloc(section->sh_size);
*out_tls_fs_base = tcb_va;
res->read(res, NULL, table, section->sh_offset, section->sh_size);
*out_phdr_va = tls_vaddr ? tls_vaddr : phdr_vaddr;
*out_phent = header->ProgramHeaderTableEntrySize;
*out_phnum = header->ProgramHeaderTableEntryCount;
section->sh_addr = (uintptr_t)table;
}
}
printf("ELF: TLS/TCB setup complete TCB@0x%lx TLS@0x%lx FS=0x%lx\n"
" PHDR@0x%lx PHENT=0x%x PHNUM=%u\n",
tcb_va, tls_va, tcb_va, *out_phdr_va, *out_phent, *out_phnum);
for (size_t index = 0; index < section_count; index++) {
Elf64_Shdr *section = (elf_section_headers + index);
pmm_free(buffer_phys, buf_pages);
return true;
if (section->sh_type == SHT_RELA) {
size_t entry_count = section->sh_size / section->sh_entsize;
if (section->sh_entsize != sizeof(Elf64_Rela)) {
return 1;
}
cleanup:
pmm_free(buffer_phys, buf_pages);
return false;
}
// Load relocation entries from the file
Elf64_Rela *entries = kmalloc(section->sh_size);
res->read(res, NULL, entries, section->sh_offset, section->sh_size);
section->sh_addr = (uintptr_t)entries;
// Locate the section we are relocating
Elf64_Shdr *relocation_section =
(Elf64_Shdr *)(elf_section_headers + section->sh_info);
char *relocation_section_data = (char *)relocation_section->sh_addr;
// Locate the symbol table for this relocation table
Elf64_Shdr *section_symbol_table =
(elf_section_headers + section->sh_link);
Elf64_Sym *symbol_table =
(Elf64_Sym *)(section_symbol_table->sh_addr);
// Locate the string table for the symbol table
Elf64_Shdr *section_string_table =
(elf_section_headers + section_symbol_table->sh_link);
char *string_table = (char *)(section_string_table->sh_addr);
// Relocate all the entries
for (size_t entry_ind = 0; entry_ind < entry_count; entry_ind++) {
Elf64_Rela *entry = (entries + entry_ind);
// Find the symbol for this entry
Elf64_Sym *symbol = (symbol_table + ELF64_R_SYM(entry->r_info));
char *symbol_name = (string_table + symbol->st_name);
if (ELF64_R_TYPE(entry->r_info) == 1) {
// Determine the offset in the section
uint64_t *location =
(uint64_t *)((uint64_t)relocation_section_data +
entry->r_offset);
// Check that the symbol is defined in this file
if (symbol->st_shndx > 0) {
// Calculate the location of the symbol
Elf64_Shdr *symbol_section =
(elf_section_headers + symbol->st_shndx);
uint64_t symbol_value = symbol_section->sh_addr +
symbol->st_value +
entry->r_addend;
// Store the location
*location = symbol_value;
} else {
// The symbol is not defined inside the object file
// resolve using other rules
// kprintffos(0, "%s %p %s\n", symbol_name,
// elf_get_function_from_name(symbol_name),
// elf_get_name_from_function(elf_get_function_from_name(symbol_name)));
*location = elf_get_function_from_name(symbol_name);
if (*location == 0) {
// We need to add some exemptions
kprintf("Failed to find symbol %s\n", symbol_name);
return 1;
}
}
} else {
kprintf("What the fuck?\n");
return 1;
}
}
}
}
for (size_t index = 0; index < section_count; index++) {
Elf64_Shdr *section = (elf_section_headers + index);
if ((section->sh_flags & SHF_ALLOC) && section->sh_size > 0) {
// Calculate the correct permissions
int prot = PAGE_READ;
if (section->sh_flags & SHF_WRITE)
prot |= PAGE_WRITE;
m->mappings[index].prot = prot;
for (size_t i = 0; i < section->sh_size; i += PAGE_SIZE) {
vmm_map_page(kernel_pagemap, section->sh_addr,
section->sh_addr - MEM_PHYS_OFFSET, prot,
Size4KiB);
}
}
}
module_entry_t run_func = NULL;
for (size_t index = 0; index < section_count; index++) {
Elf64_Shdr *section = (elf_section_headers + index);
// Look in all symbol tables for the run function
if (section->sh_type == SHT_SYMTAB) {
Elf64_Sym *symbol_table = (Elf64_Sym *)section->sh_addr;
// Find the string table for this symbol table
Elf64_Shdr *section_string_table =
(elf_section_headers + section->sh_link);
char *string_table = (char *)(section_string_table->sh_addr);
size_t symbol_count = section->sh_size / section->sh_entsize;
for (size_t i = 0; i < symbol_count; i++) {
// Get the symbol from the table
Elf64_Sym *symbol = (symbol_table + i);
char *symbol_name = (string_table + symbol->st_name);
Elf64_Shdr *run_section =
(elf_section_headers + symbol->st_shndx);
// Check if it is the run symbol
if (strcmp("driver_entry", symbol_name) == 0 &&
((symbol->st_info >> 4) & 0xf) == 1 &&
(run_section->sh_flags & 4)) {
// Calculate the symbol location
run_func = (module_entry_t)(run_section->sh_addr +
symbol->st_value);
break;
}
}
}
if (run_func)
break;
}
kfree(ehdr);
kfree(elf_section_headers);
if (run_func != NULL) {
m->entry_point = run_func;
vec_push(&modules_list, m);
return run_func(m);
} else {
kprintf("Failed to find driver_entry\n");
return 1;
}
}
bool module_unload(const char *name) {
for (int i = 0; i < modules_list.length; i++) {
if (!strncmp(name, modules_list.data[i]->name, 128)) {
struct module *m = modules_list.data[i];
if (!m->exit)
return false;
m->exit();
for (size_t j = 0; j < m->mappings_count; j++) {
pmm_free((void *)(m->mappings[j].addr - MEM_PHYS_OFFSET),
(m->mappings[j].size / PAGE_SIZE) + 1);
for (size_t k = 0; k < m->mappings[j].size; k += PAGE_SIZE) {
vmm_unmap_page(kernel_pagemap, m->mappings[j].addr, false);
}
}
vec_remove(&modules_list, m);
kfree(m);
return true;
}
}
return false;
}
void module_dump(void) {
kprintf("Loaded drivers\n");
for (int i = 0; i < modules_list.length; i++) {
struct module *mod = modules_list.data[i];
kprintf("\t%s with entry point at %p\n", mod->name, mod->entry_point);
for (size_t j = 0; j < mod->mappings_count; j++) {
kprintf("\t\t%p - %p with protections 0b%b\n",
mod->mappings[j].addr,
mod->mappings[j].addr + mod->mappings[j].size,
mod->mappings[j].prot);
}
}
}
bool elf_load(struct pagemap *pagemap, struct resource *res, uint64_t load_base,
struct auxval *auxv, const char **ld_path) {
Elf64_Ehdr header;
if (res->read(res, NULL, &header, 0, sizeof(header)) < 0) {
return false;
}
if (memcmp(header.e_ident, ELFMAG, SELFMAG)) {
return false;
}
if (header.e_ident[EI_CLASS] != ELFCLASS64 ||
header.e_ident[EI_DATA] != ELFDATA2LSB ||
header.e_ident[EI_OSABI] != 0 || header.e_machine != EM_X86_64) {
return false;
}
for (size_t i = 0; i < header.e_phnum; i++) {
Elf64_Phdr phdr;
if (res->read(res, NULL, &phdr, header.e_phoff + i * header.e_phentsize,
sizeof(phdr)) < 0) {
goto fail;
}
switch (phdr.p_type) {
case PT_LOAD: {
int prot = PROT_READ;
if (phdr.p_flags & PF_W) {
prot |= PROT_WRITE;
}
if (phdr.p_flags & PF_X) {
prot |= PROT_EXEC;
}
size_t misalign = phdr.p_vaddr & (PAGE_SIZE - 1);
size_t page_count =
DIV_ROUNDUP(phdr.p_memsz + misalign, PAGE_SIZE);
void *phys = pmm_allocz(page_count);
if (phys == NULL) {
goto fail;
}
if (!mmap_range(pagemap, phdr.p_vaddr + load_base,
(uintptr_t)phys, page_count * PAGE_SIZE, prot,
MAP_ANONYMOUS)) {
pmm_free(phys, page_count);
goto fail;
}
if (res->read(
res, NULL,
(void *)((uintptr_t)phys + misalign + MEM_PHYS_OFFSET),
phdr.p_offset, phdr.p_filesz) < 0) {
goto fail;
}
break;
}
case PT_PHDR:
auxv->at_phdr = phdr.p_vaddr + load_base;
break;
case PT_INTERP: {
void *path = kmalloc(phdr.p_filesz + 1);
if (path == NULL) {
goto fail;
}
if (res->read(res, NULL, path, phdr.p_offset, phdr.p_filesz) <
0) {
kfree(path);
goto fail;
}
if (ld_path != NULL) {
*ld_path = path;
} else {
kfree(path);
path = NULL;
}
break;
}
}
}
auxv->at_entry = header.e_entry + load_base;
auxv->at_phent = header.e_phentsize;
auxv->at_phnum = header.e_phnum;
return true;
fail:
if (ld_path != NULL && *ld_path != NULL) {
kfree((void *)*ld_path);
}
return false;
}
+428 -113
View File
@@ -1,130 +1,445 @@
// elf.h
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h> // size_t for TCB
#include "mm/vmm.h"
#include "libk/resource.h"
// ELF magic and basic constants
#define ELF_MAGIC ("\x7F" "ELF")
// Standard ELF program header flags (bitfield)
#define PF_X 0x00000001 // Execute
#define PF_W 0x00000002 // Write
#define PF_R 0x00000004 // Read
// Fixed canonical address for the initial thread's TLS + TCB block.
// This lives in the upper half of the 47-bit user address space and
// will never overlap with normal LOAD segments (which are usually low).
#define TLS_BASE_VA 0x00007FFF00000000ULL
typedef struct
{
uint8_t Magic[4];
uint8_t Bitness; // 1 = 32-bit, 2 = 64-bit
uint8_t Endianness; // 1 = little, 2 = big
uint8_t ELFHeaderVersion;
uint8_t ABI;
uint8_t ABIVersion;
uint8_t _Padding[7];
uint16_t Type; // relocatable, executable, shared, core
uint16_t InstructionSet; // architecture
uint32_t ELFVersion;
uint64_t ProgramEntryPosition;
uint64_t ProgramHeaderTablePosition;
uint64_t SectionHeaderTablePosition;
uint32_t Flags;
uint16_t HeaderSize;
uint16_t ProgramHeaderTableEntrySize;
uint16_t ProgramHeaderTableEntryCount;
uint16_t SectionHeaderTableEntrySize;
uint16_t SectionHeaderTableEntryCount;
uint16_t SectionNamesIndex;
} __attribute__((packed)) ELFHeader;
enum ELFBitness
{
ELF_BITNESS_32BIT = 1,
ELF_BITNESS_64BIT = 2,
struct auxval {
uint64_t at_entry;
uint64_t at_phdr;
uint64_t at_phent;
uint64_t at_phnum;
};
enum ELFEndianness
{
ELF_ENDIANNESS_LITTLE = 1,
ELF_ENDIANNESS_BIG = 2,
};
/* These constants define the various ELF target machines */
#define EM_NONE 0
#define EM_M32 1
#define EM_SPARC 2
#define EM_386 3
#define EM_68K 4
#define EM_88K 5
#define EM_486 6 /* Perhaps disused */
#define EM_860 7
#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */
#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */
enum ELFInstructionSet
{
ELF_INSTRUCTION_SET_NONE = 0,
ELF_INSTRUCTION_SET_X86 = 3,
ELF_INSTRUCTION_SET_ARM = 0x28,
ELF_INSTRUCTION_SET_X64 = 0x3E,
ELF_INSTRUCTION_SET_ARM64 = 0xB7,
ELF_INSTRUCTION_SET_RISCV = 0xF3,
};
#define EM_PARISC 15 /* HPPA */
#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
#define EM_PPC 20 /* PowerPC */
#define EM_PPC64 21 /* PowerPC64 */
#define EM_SPU 23 /* Cell BE SPU */
#define EM_ARM 40 /* ARM 32 bit */
#define EM_SH 42 /* SuperH */
#define EM_SPARCV9 43 /* SPARC v9 64-bit */
#define EM_H8_300 46 /* Renesas H8/300 */
#define EM_IA_64 50 /* HP/Intel IA-64 */
#define EM_X86_64 62 /* AMD x86-64 */
#define EM_S390 22 /* IBM S/390 */
#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */
#define EM_M32R 88 /* Renesas M32R */
#define EM_MN10300 89 /* Panasonic/MEI MN10300, AM33 */
#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */
#define EM_ARCOMPACT 93 /* ARCompact processor */
#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */
#define EM_BLACKFIN 106 /* ADI Blackfin Processor */
#define EM_UNICORE 110 /* UniCore-32 */
#define EM_ALTERA_NIOS2 113 /* Altera Nios II soft-core processor */
#define EM_TI_C6000 140 /* TI C6X DSPs */
#define EM_HEXAGON 164 /* QUALCOMM Hexagon */
#define EM_NDS32 \
167 /* Andes Technology compact code size \
embedded RISC processor family */
#define EM_AARCH64 183 /* ARM 64 bit */
#define EM_TILEPRO 188 /* Tilera TILEPro */
#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */
#define EM_TILEGX 191 /* Tilera TILE-Gx */
#define EM_ARCV2 195 /* ARCv2 Cores */
#define EM_RISCV 243 /* RISC-V */
#define EM_BPF 247 /* Linux BPF - in-kernel virtual machine */
#define EM_CSKY 252 /* C-SKY */
#define EM_LOONGARCH 258 /* LoongArch */
#define EM_FRV 0x5441 /* Fujitsu FR-V */
enum ELFType
{
ELF_TYPE_RELOCATABLE = 1,
ELF_TYPE_EXECUTABLE = 2,
ELF_TYPE_SHARED = 3,
ELF_TYPE_CORE = 4,
};
/*
* This is an interim value that we will use until the committee comes
* up with a final number.
*/
#define EM_ALPHA 0x9026
typedef struct
{
uint32_t Type;
uint32_t Flags;
uint64_t Offset;
uint64_t VirtualAddress;
uint64_t PhysicalAddress;
uint64_t FileSize;
uint64_t MemorySize;
uint64_t Align;
/* Bogus old m32r magic number, used by old tools. */
#define EM_CYGNUS_M32R 0x9041
/* This is the old interim value for S/390 architecture */
#define EM_S390_OLD 0xA390
/* Also Panasonic/MEI MN10300, AM33 */
#define EM_CYGNUS_MN10300 0xbeef
} __attribute__((packed)) ELFProgramHeader;
/* 32-bit ELF base types. */
typedef uint32_t Elf32_Addr;
typedef uint16_t Elf32_Half;
typedef uint32_t Elf32_Off;
typedef int32_t Elf32_Sword;
typedef uint32_t Elf32_Word;
enum ELFProgramType {
ELF_PROGRAM_TYPE_NULL = 0,
ELF_PROGRAM_TYPE_LOAD = 1,
ELF_PROGRAM_TYPE_DYNAMIC = 2,
ELF_PROGRAM_TYPE_INTERP = 3,
ELF_PROGRAM_TYPE_NOTE = 4,
ELF_PROGRAM_TYPE_SHLIB = 5,
ELF_PROGRAM_TYPE_PHDR = 6,
ELF_PROGRAM_TYPE_TLS = 7,
/* 64-bit ELF base types. */
typedef uint64_t Elf64_Addr;
typedef uint16_t Elf64_Half;
typedef int16_t Elf64_SHalf;
typedef uint64_t Elf64_Off;
typedef int32_t Elf64_Sword;
typedef uint32_t Elf64_Word;
typedef uint64_t Elf64_Xword;
typedef int64_t Elf64_Sxword;
// OS/processor reserved ranges (we ignore them)
ELF_PROGRAM_TYPE_LOOS = 0x60000000,
ELF_PROGRAM_TYPE_HIOS = 0x6FFFFFFF,
ELF_PROGRAM_TYPE_LOPROC = 0x70000000,
ELF_PROGRAM_TYPE_HIPROC = 0x7FFFFFFF,
};
/* These constants are for the segment types stored in the image headers */
#define PT_NULL 0
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
#define PT_TLS 7 /* Thread local storage segment */
#define PT_LOOS 0x60000000 /* OS-specific */
#define PT_HIOS 0x6fffffff /* OS-specific */
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7fffffff
#define PT_GNU_EH_FRAME 0x6474e550
#define PT_GNU_STACK (PT_LOOS + 0x474e551)
/* These constants define the different elf file types */
#define ET_NONE 0
#define ET_REL 1
#define ET_EXEC 2
#define ET_DYN 3
#define ET_CORE 4
#define ET_LOPROC 0xff00
#define ET_HIPROC 0xffff
/* This is the info that is needed to parse the dynamic section of the file */
#define DT_NULL 0
#define DT_NEEDED 1
#define DT_PLTRELSZ 2
#define DT_PLTGOT 3
#define DT_HASH 4
#define DT_STRTAB 5
#define DT_SYMTAB 6
#define DT_RELA 7
#define DT_RELASZ 8
#define DT_RELAENT 9
#define DT_STRSZ 10
#define DT_SYMENT 11
#define DT_INIT 12
#define DT_FINI 13
#define DT_SONAME 14
#define DT_RPATH 15
#define DT_SYMBOLIC 16
#define DT_REL 17
#define DT_RELSZ 18
#define DT_RELENT 19
#define DT_PLTREL 20
#define DT_DEBUG 21
#define DT_TEXTREL 22
#define DT_JMPREL 23
#define DT_ENCODING 32
#define OLD_DT_LOOS 0x60000000
#define DT_LOOS 0x6000000d
#define DT_HIOS 0x6ffff000
#define DT_VALRNGLO 0x6ffffd00
#define DT_VALRNGHI 0x6ffffdff
#define DT_ADDRRNGLO 0x6ffffe00
#define DT_ADDRRNGHI 0x6ffffeff
#define DT_VERSYM 0x6ffffff0
#define DT_RELACOUNT 0x6ffffff9
#define DT_RELCOUNT 0x6ffffffa
#define DT_FLAGS_1 0x6ffffffb
#define DT_VERDEF 0x6ffffffc
#define DT_VERDEFNUM 0x6ffffffd
#define DT_VERNEED 0x6ffffffe
#define DT_VERNEEDNUM 0x6fffffff
#define OLD_DT_HIOS 0x6fffffff
#define DT_LOPROC 0x70000000
#define DT_HIPROC 0x7fffffff
/* This info is needed when parsing the symbol table */
#define STB_LOCAL 0
#define STB_GLOBAL 1
#define STB_WEAK 2
#define STT_NOTYPE 0
#define STT_OBJECT 1
#define STT_FUNC 2
#define STT_SECTION 3
#define STT_FILE 4
#define STT_COMMON 5
#define STT_TLS 6
#define ELF_ST_BIND(x) ((x) >> 4)
#define ELF_ST_TYPE(x) (((unsigned int)x) & 0xf)
#define ELF32_ST_BIND(x) ELF_ST_BIND(x)
#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x)
#define ELF64_ST_BIND(x) ELF_ST_BIND(x)
#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x)
typedef struct dynamic {
Elf32_Sword d_tag;
union {
Elf32_Sword d_val;
Elf32_Addr d_ptr;
} d_un;
} Elf32_Dyn;
// Thread Control Block layout expected by mlibc.
// Only the fields mlibc actually reads are populated; the rest stay zero.
typedef struct {
void* self; // 0x00 fs:0 (TCB self-pointer)
size_t dtvSize; // 0x08
void** dtvPointers; // 0x10
int tid; // 0x18
int didExit; // 0x1C
uint8_t padding[8]; // 0x20
uintptr_t stackCanary; // 0x28
int cancelBits; // 0x30
} TCB;
Elf64_Sxword d_tag; /* entry tag value */
union {
Elf64_Xword d_val;
Elf64_Addr d_ptr;
} d_un;
} Elf64_Dyn;
bool ELF_Read(const char* path,
void** entryPoint,
struct pagemap *target_pagemap,
uint64_t *out_tls_fs_base,
uint64_t *out_phdr_va, // AT_PHDR
uint16_t *out_phent, // AT_PHENT
uint16_t *out_phnum); // AT_PHNUM
/* The following are used with relocations */
#define ELF32_R_SYM(x) ((x) >> 8)
#define ELF32_R_TYPE(x) ((x) & 0xff)
#define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
typedef struct elf32_rel {
Elf32_Addr r_offset;
Elf32_Word r_info;
} Elf32_Rel;
typedef struct elf64_rel {
Elf64_Addr r_offset; /* Location at which to apply the action */
Elf64_Xword r_info; /* index and type of relocation */
} Elf64_Rel;
typedef struct elf32_rela {
Elf32_Addr r_offset;
Elf32_Word r_info;
Elf32_Sword r_addend;
} Elf32_Rela;
typedef struct elf64_rela {
Elf64_Addr r_offset; /* Location at which to apply the action */
Elf64_Xword r_info; /* index and type of relocation */
Elf64_Sxword r_addend; /* Constant addend used to compute value */
} Elf64_Rela;
typedef struct elf32_sym {
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
} Elf32_Sym;
typedef struct elf64_sym {
Elf64_Word st_name; /* Symbol name, index in string tbl */
unsigned char st_info; /* Type and binding attributes */
unsigned char st_other; /* No defined meaning, 0 */
Elf64_Half st_shndx; /* Associated section index */
Elf64_Addr st_value; /* Value of the symbol */
Elf64_Xword st_size; /* Associated symbol size */
} Elf64_Sym;
#define EI_NIDENT 16
typedef struct elf32_hdr {
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry; /* Entry point */
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} Elf32_Ehdr;
typedef struct elf64_hdr {
unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
Elf64_Half e_type;
Elf64_Half e_machine;
Elf64_Word e_version;
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags;
Elf64_Half e_ehsize;
Elf64_Half e_phentsize;
Elf64_Half e_phnum;
Elf64_Half e_shentsize;
Elf64_Half e_shnum;
Elf64_Half e_shstrndx;
} Elf64_Ehdr;
/* These constants define the permissions on sections in the program
header, p_flags. */
#define PF_R 0x4
#define PF_W 0x2
#define PF_X 0x1
typedef struct elf32_phdr {
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
} Elf32_Phdr;
typedef struct elf64_phdr {
Elf64_Word p_type;
Elf64_Word p_flags;
Elf64_Off p_offset; /* Segment file offset */
Elf64_Addr p_vaddr; /* Segment virtual address */
Elf64_Addr p_paddr; /* Segment physical address */
Elf64_Xword p_filesz; /* Segment size in file */
Elf64_Xword p_memsz; /* Segment size in memory */
Elf64_Xword p_align; /* Segment alignment, file & memory */
} Elf64_Phdr;
/* sh_type */
#define SHT_NULL 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_HASH 5
#define SHT_DYNAMIC 6
#define SHT_NOTE 7
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_SHLIB 10
#define SHT_DYNSYM 11
#define SHT_NUM 12
#define SHT_LOPROC 0x70000000
#define SHT_HIPROC 0x7fffffff
#define SHT_LOUSER 0x80000000
#define SHT_HIUSER 0xffffffff
/* sh_flags */
#define SHF_WRITE 0x1
#define SHF_ALLOC 0x2
#define SHF_EXECINSTR 0x4
#define SHF_MASKPROC 0xf0000000
/* special section indexes */
#define SHN_UNDEF 0
#define SHN_LORESERVE 0xff00
#define SHN_LOPROC 0xff00
#define SHN_HIPROC 0xff1f
#define SHN_ABS 0xfff1
#define SHN_COMMON 0xfff2
#define SHN_HIRESERVE 0xffff
typedef struct {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} Elf32_Shdr;
typedef struct elf64_shdr {
Elf64_Word sh_name; /* Section name, index in string tbl */
Elf64_Word sh_type; /* Type of section */
Elf64_Xword sh_flags; /* Miscellaneous section attributes */
Elf64_Addr sh_addr; /* Section virtual addr at execution */
Elf64_Off sh_offset; /* Section file offset */
Elf64_Xword sh_size; /* Size of section in bytes */
Elf64_Word sh_link; /* Index of another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */
Elf64_Xword sh_entsize; /* Entry size if section holds table */
} Elf64_Shdr;
#define EI_MAG0 0 /* e_ident[] indexes */
#define EI_MAG1 1
#define EI_MAG2 2
#define EI_MAG3 3
#define EI_CLASS 4
#define EI_DATA 5
#define EI_VERSION 6
#define EI_OSABI 7
#define EI_PAD 8
#define ELFMAG0 0x7f /* EI_MAG */
#define ELFMAG1 'E'
#define ELFMAG2 'L'
#define ELFMAG3 'F'
#define ELFMAG "\177ELF"
#define SELFMAG 4
#define ELFCLASSNONE 0 /* EI_CLASS */
#define ELFCLASS32 1
#define ELFCLASS64 2
#define ELFCLASSNUM 3
#define ELFDATANONE 0 /* e_ident[EI_DATA] */
#define ELFDATA2LSB 1
#define ELFDATA2MSB 2
#define EV_NONE 0 /* e_version, EI_VERSION */
#define EV_CURRENT 1
#define EV_NUM 2
#define ELFOSABI_NONE 0
#define ELFOSABI_LINUX 3
#ifndef ELF_OSABI
#define ELF_OSABI ELFOSABI_NONE
#endif
/* Notes used in ET_CORE */
#define NT_PRSTATUS 1
#define NT_PRFPREG 2
#define NT_PRPSINFO 3
#define NT_TASKSTRUCT 4
#define NT_AUXV 6
#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */
#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */
#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */
#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
#define NT_PRXSTATUS 0x300 /* s390 upper register halves */
/* Note header in a PT_NOTE section */
typedef struct elf32_note {
Elf32_Word n_namesz; /* Name size */
Elf32_Word n_descsz; /* Content size */
Elf32_Word n_type; /* Content type */
} Elf32_Nhdr;
/* Note header in a PT_NOTE section */
typedef struct elf64_note {
Elf64_Word n_namesz; /* Name size */
Elf64_Word n_descsz; /* Content size */
Elf64_Word n_type; /* Content type */
} Elf64_Nhdr;
bool elf_load(struct pagemap *pagemap, struct resource *res, uint64_t load_base,
struct auxval *auxv, const char **ld_path);
void elf_init_function_table(uint8_t *binary);
const char *elf_get_name_from_function(uint64_t address);
uint64_t elf_get_function_from_name(const char *string);
-1400
View File
File diff suppressed because it is too large Load Diff
-220
View File
@@ -1,220 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#define EXT2_SUPERBLOCK_OFFSET 1024
#define EXT2_SUPERBLOCK_SIZE 1024
#define EXT2_MAGIC 0xEF53
#define EXT2_NAME_LEN 255
typedef struct ext2_superblock {
unsigned int s_inodes_count; /* Inodes count */
unsigned int s_blocks_count; /* Blocks count */
unsigned int s_r_blocks_count; /* Reserved blocks count */
unsigned int s_free_blocks_count; /* Free blocks count */
unsigned int s_free_inodes_count; /* Free inodes count */
unsigned int s_first_data_block; /* First Data Block */
unsigned int s_log_block_size; /* Block size */
unsigned int s_log_frag_size; /* Fragment size */
unsigned int s_blocks_per_group; /* # Blocks per group */
unsigned int s_frags_per_group; /* # Fragments per group */
unsigned int s_inodes_per_group; /* # Inodes per group */
unsigned int s_mtime; /* Mount time */
unsigned int s_wtime; /* Write time */
unsigned short s_mnt_count; /* Mount count */
unsigned short s_max_mnt_count; /* Maximal mount count */
unsigned short s_magic; /* Magic signature */
unsigned short s_state; /* File system state */
unsigned short s_errors; /* Behaviour when detecting errors */
unsigned short s_minor_rev_level; /* minor revision level */
unsigned int s_lastcheck; /* time of last check */
unsigned int s_checkinterval; /* max. time between checks */
unsigned int s_creator_os; /* OS */
unsigned int s_rev_level; /* Revision level */
unsigned short s_def_resuid; /* Default uid for reserved blocks */
unsigned short s_def_resgid; /* Default gid for reserved blocks */
/*
* These fields are for EXT2_DYNAMIC_REV superblocks only.
*
* Note: the difference between the compatible feature set and
* the incompatible feature set is that if there is a bit set
* in the incompatible feature set that the kernel doesn't
* know about, it should refuse to mount the filesystem.
*
* e2fsck's requirements are more strict; if it doesn't know
* about a feature in either the compatible or incompatible
* feature set, it must abort and not try to meddle with
* things it doesn't understand...
*/
unsigned int s_first_ino; /* First non-reserved inode */
unsigned short s_inode_size; /* size of inode structure */
unsigned short s_block_group_nr; /* block group # of this superblock */
unsigned int s_feature_compat; /* compatible feature set */
unsigned int s_feature_incompat; /* incompatible feature set */
unsigned int s_feature_ro_compat; /* readonly-compatible feature set */
unsigned char s_uuid[16]; /* 128-bit uuid for volume */
char s_volume_name[16]; /* volume name */
char s_last_mounted[64]; /* directory where last mounted */
unsigned int s_algorithm_usage_bitmap; /* For compression */
/*
* Performance hints. Directory preallocation should only
* happen if the EXT2_COMPAT_PREALLOC flag is on.
*/
unsigned char s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
unsigned char s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
unsigned short s_padding1;
/*
* Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
*/
unsigned char s_journal_uuid[16]; /* uuid of journal superblock */
unsigned int s_journal_inum; /* inode number of journal file */
unsigned int s_journal_dev; /* device number of journal file */
unsigned int s_last_orphan; /* start of list of inodes to delete */
unsigned int s_hash_seed[4]; /* HTREE hash seed */
unsigned char s_def_hash_version; /* Default hash version to use */
unsigned char s_reserved_char_pad;
unsigned short s_reserved_word_pad;
unsigned int s_default_mount_opts;
unsigned int s_first_meta_bg; /* First metablock block group */
unsigned int s_reserved[190]; /* Padding to the end of the block */
} __attribute__((packed)) ext2_superblock_t;
typedef struct ext2_group_desc {
unsigned int bg_block_bitmap; /* Blocks bitmap block */
unsigned int bg_inode_bitmap; /* Inodes bitmap block */
unsigned int bg_inode_table; /* Inodes table block */
unsigned short bg_free_blocks_count; /* Free blocks count */
unsigned short bg_free_inodes_count; /* Free inodes count */
unsigned short bg_used_dirs_count; /* Directories count */
unsigned short bg_pad;
unsigned int bg_reserved[3];
} __attribute__((packed)) ext2_group_desc_t;
typedef struct ext2_inode {
unsigned short i_mode; /* File mode */
unsigned short i_uid; /* Low 16 bits of Owner Uid */
unsigned int i_size; /* Size in bytes */
unsigned int i_atime; /* Access time */
unsigned int i_ctime; /* Creation time */
unsigned int i_mtime; /* Modification time */
unsigned int i_dtime; /* Deletion Time */
unsigned short i_gid; /* Low 16 bits of Group Id */
unsigned short i_links_count; /* Links count */
unsigned int i_blocks; /* Blocks count IN DISK SECTORS*/
unsigned int i_flags; /* File flags */
unsigned int osd1; /* OS dependent 1 */
unsigned int i_block[15]; /* Pointers to blocks */
unsigned int i_generation; /* File version (for NFS) */
unsigned int i_file_acl; /* File ACL */
unsigned int i_dir_acl; /* Directory ACL */
unsigned int i_faddr; /* Fragment address */
unsigned int extra[3];
} __attribute__((packed)) ext2_inode_t;
typedef struct ext2_dir_entry {
unsigned int inode; /* Inode number */
unsigned short rec_len; /* Directory entry length */
unsigned char name_len; /* Name length */
unsigned char file_type;
char name[]; /* File name, up to EXT2_NAME_LEN */
} __attribute__((packed)) ext2_dir_entry_t;
typedef struct {
uint32_t ino;
uint16_t mode;
uint16_t uid;
uint16_t gid;
uint32_t size;
uint32_t atime;
uint32_t mtime;
uint32_t ctime;
uint32_t nlink;
uint32_t blocks;
} ext2_stat_t;
typedef enum {
EXT2_WRITE_OVERWRITE,
EXT2_WRITE_APPEND,
} ext2_write_mode_t;
// Inode type and permissions
#define EXT2_S_IFIFO 0x1000
#define EXT2_S_IFCHR 0x2000
#define EXT2_S_IFDIR 0x4000
#define EXT2_S_IFBLK 0x6000
#define EXT2_S_IFREG 0x8000
#define EXT2_S_IFLNK 0xA000
#define EXT2_S_IFSOCK 0xC000
#define EXT2_S_IRUSR 0x0100
#define EXT2_S_IWUSR 0x0080
#define EXT2_S_IXUSR 0x0040
#define EXT2_S_IRGRP 0x0020
#define EXT2_S_IWGRP 0x0010
#define EXT2_S_IXGRP 0x0008
#define EXT2_S_IROTH 0x0004
#define EXT2_S_IWOTH 0x0002
#define EXT2_S_IXOTH 0x0001
// File types for directory entries
#define EXT2_FT_UNKNOWN 0
#define EXT2_FT_REG_FILE 1
#define EXT2_FT_DIR 2
#define EXT2_FT_CHRDEV 3
#define EXT2_FT_BLKDEV 4
#define EXT2_FT_FIFO 5
#define EXT2_FT_SOCK 6
#define EXT2_FT_SYMLINK 7
// ── init ──────────────────────────────────────────────────────────────────────
bool ext2_read_superblock(void);
bool ext2_read_group_desc_table(void);
// ── low-level ────────────────────────────────────────────────────────────────
bool ext2_read_block(uint32_t block_num, void* buf);
bool ext2_write_block(uint32_t block_num, const void* buf);
bool ext2_read_inode(uint32_t inode_num, ext2_inode_t* out);
bool ext2_write_inode(uint32_t inode_num, ext2_inode_t* inode);
// ── path / directory ─────────────────────────────────────────────────────────
uint32_t ext2_resolve_path(const char* path); // returns inode num, 0 = not found
bool ext2_find_in_dir(ext2_inode_t* dir, const char* name, uint32_t* out_inum);
bool ext2_read_dir(ext2_inode_t* dir);
bool ext2_read_root_dir(void);
// ── file I/O ─────────────────────────────────────────────────────────────────
bool ext2_read_file(ext2_inode_t* inode, uint8_t* buf);
bool ext2_write_file(ext2_inode_t* inode, uint32_t inode_num,
const uint8_t* data, uint32_t size, ext2_write_mode_t mode);
bool ext2_truncate(ext2_inode_t* inode, uint32_t inode_num, uint32_t new_size);
// ── high-level (operate from a path string) ───────────────────────────────────
bool ext2_read_file_from_root(const char* name, uint8_t* buf, uint32_t* size);
bool ext2_write_file_from_root(const char* name, const uint8_t* data,
uint32_t size, ext2_write_mode_t mode);
// ── create / delete ───────────────────────────────────────────────────────────
bool ext2_create_file(ext2_inode_t* dir, uint32_t dir_inum,
const char* name, uint16_t mode, uint32_t* out_inum);
bool ext2_mkdir(ext2_inode_t* parent, uint32_t parent_inum,
const char* name, uint32_t* out_inum);
bool ext2_unlink(ext2_inode_t* dir, uint32_t dir_inum, const char* name);
bool ext2_rmdir(ext2_inode_t* parent, uint32_t parent_inum, const char* name);
bool ext2_rename(ext2_inode_t* src_dir, uint32_t src_inum,
ext2_inode_t* dst_dir, uint32_t dst_inum,
const char* old_name, const char* new_name);
// ── symlinks ──────────────────────────────────────────────────────────────────
bool ext2_symlink(ext2_inode_t* dir, uint32_t dir_inum,
const char* name, const char* target);
bool ext2_readlink(uint32_t inode_num, char* buf, uint32_t buf_size);
// ── metadata ─────────────────────────────────────────────────────────────────
bool ext2_stat(uint32_t inode_num, ext2_stat_t* st);
bool ext2_chmod(uint32_t inode_num, uint16_t mode);
bool ext2_chown(uint32_t inode_num, uint16_t uid, uint16_t gid);
const char* ext2_file_type_string(uint8_t type);

Some files were not shown because too many files have changed in this diff Show More