major refactorings
Signed-off-by: kaguya3311 <kaguya3311@national.shitposting.agency>
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -1,6 +0,0 @@
|
||||
.intel_syntax noprefix
|
||||
.global x86_64_IDT_Load
|
||||
|
||||
x86_64_IDT_Load:
|
||||
lidt [rdi] # descriptor in RDI
|
||||
ret
|
||||
+348
-110
@@ -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
@@ -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);
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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; \
|
||||
})
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
void start_userspace(void);
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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,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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
@@ -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,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);
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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");
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
*.d
|
||||
*.o
|
||||
@@ -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.
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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 (0x00–0x58 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);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
|
||||
void ps2_kbd_init(void);
|
||||
|
||||
uint8_t ps2_kbd_read_scancode(void);
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
void console_init(void);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}*/
|
||||
@@ -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();
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
-220
@@ -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
Reference in New Issue
Block a user