diff options
author | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2025-07-31 22:33:56 +0200 |
---|---|---|
committer | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2025-07-31 22:33:56 +0200 |
commit | 5e12467c860372dfa10323365fb0df9db79c8f9b (patch) | |
tree | 13e81afa3accb633fdb0ab0d655244ea752814a5 /src | |
parent | 0a817a5a74c328229f8a732fc3ec22d8fd7dc20d (diff) |
APIC/ACPI/keyboard stuff. I now get interrupts when a key is pressed
Diffstat (limited to 'src')
-rw-r--r-- | src/aplos.h | 47 | ||||
-rw-r--r-- | src/boot.c | 15 | ||||
-rw-r--r-- | src/interrupt.c | 11 | ||||
-rw-r--r-- | src/main.c | 9 | ||||
-rw-r--r-- | src/nasty.S | 19 | ||||
-rw-r--r-- | src/paging.c | 108 | ||||
-rw-r--r-- | src/util.c | 10 |
7 files changed, 208 insertions, 11 deletions
diff --git a/src/aplos.h b/src/aplos.h index ad9109b..bed0d7a 100644 --- a/src/aplos.h +++ b/src/aplos.h @@ -3,6 +3,8 @@ #include <stdarg.h> #include <uchar.h> +#define PAGE_SIZE 4096 + #define nelem(arr) (sizeof(arr)/sizeof(*(arr))) struct framebuffer @@ -19,14 +21,20 @@ struct memmap uint64_t size; }; +struct ioapic_info +{ + uint32_t base; + uint32_t interrupt_base; +}; + struct boot_info { struct framebuffer framebuffer; - + struct ioapic_info ioapic; uint64_t memmap_count; struct memmap *memmaps; - uint64_t physbase; + uint64_t rsdp; }; struct cpu_regs @@ -63,8 +71,33 @@ struct cpu_regs uint16_t gs; }; +struct ioapic_redirection +{ + uint8_t vector; + uint8_t delivery_mode; + uint8_t destination_mode; + uint8_t delivery_status; + uint8_t pin_polarity; + uint8_t remote_irr; + uint8_t trigger_mode; + uint8_t mask; + uint8_t destination; + + uint64_t reserved; +}; + +/* acpi.c */ +void setup_acpi(uint64_t, struct ioapic_info *); + +/* apic.c */ +void setup_apic(struct ioapic_info *); +void apic_end_of_interrupt(void); +struct ioapic_redirection read_redirection(uint8_t); +void write_redirection(uint8_t, struct ioapic_redirection); + /* boot.c */ uint64_t cpu_count(void); +uint8_t boot_apic_id(void); /* descriptors */ void setup_descriptors(void); @@ -76,6 +109,10 @@ void assert(bool); void font_init(void); void font_draw(char8_t *, uint32_t, uint32_t, uint32_t, uint32_t); +/* keyboard.c */ +void setup_keyboard(void); +bool keyboard_interrupt_handler(uint32_t); + /* main.c */ void main(struct boot_info *); @@ -88,12 +125,15 @@ void set_gdt(struct table_reg *, uint64_t, uint64_t, uint64_t); void set_idt(struct table_reg *); uint64_t get_cr2(void); uint64_t get_cr3(void); -extern void (*isr_stubs[32])(void); +extern void (*isr_stubs[33])(void); void dump_regs(struct cpu_regs *); +uint64_t get_msr(uint32_t); +uint8_t in_uint8(uint8_t); /* paging.c */ void setup_paging(struct boot_info *); bool page_fault_handler(uint32_t); +uint64_t map_page(uint64_t, uint64_t, bool); /* panic.c */ [[noreturn]] void panic(void); @@ -117,3 +157,4 @@ void write_uint32_le(uint8_t *, uint32_t); void write_uint64_le(uint8_t *, uint64_t); int memcmp(const void *, const void *, size_t); void memset(void *, uint8_t, size_t); +void memcpy(void *, void *, size_t); @@ -41,11 +41,16 @@ REQUEST struct limine_entry_point_request entry_point_request = { .entry = bootmain }; -REQUEST struct limine_hhdm_request hhdm_request = { +REQUEST struct limine_hhdm_request hhdm_request = { .id = LIMINE_HHDM_REQUEST, .revision = 0 }; +REQUEST struct limine_rsdp_request rsdp_request = { + .id = LIMINE_RSDP_REQUEST, + .revision = 0 +}; + LIMINE(".limine_requests_start") LIMINE_REQUESTS_START_MARKER LIMINE(".limine_requests_end") LIMINE_REQUESTS_END_MARKER @@ -55,6 +60,12 @@ cpu_count(void) return mp_request.response->cpu_count; } +uint8_t +boot_apic_id(void) +{ + return mp_request.response->bsp_lapic_id; +} + static void bootmain(void) { @@ -66,6 +77,7 @@ bootmain(void) assert(paging_request.response); assert(mp_request.response); assert(hhdm_request.response); + assert(rsdp_request.response); assert(framebuffer_request.response->framebuffer_count >= 1); @@ -92,6 +104,7 @@ bootmain(void) } info.memmaps = memmaps; info.physbase = hhdm_request.response->offset; + info.rsdp = rsdp_request.response->address; main(&info); halt(); diff --git a/src/interrupt.c b/src/interrupt.c index 54f9947..6406fc0 100644 --- a/src/interrupt.c +++ b/src/interrupt.c @@ -3,6 +3,7 @@ struct handler { char8_t *description; bool (*fn)(uint32_t code); + bool apic; } handlers[256] = { [0] = { .description = u8"divide-by-zero-error" @@ -73,7 +74,12 @@ struct handler { }, [30] = { .description = u8"security exception" - } + }, + [32] = { + .description = u8"keyboard interrupt", + .fn = keyboard_interrupt_handler, + .apic = true, + }, }; void @@ -87,6 +93,9 @@ interrupt_handler(uint8_t n, uint32_t code) print(u8"Unhandled interrupt: %u8 (%s) with error code %x32\n", n, h->description ? h->description : u8"???", code); panic(); } + + if(h->apic) + apic_end_of_interrupt(); } @@ -9,7 +9,12 @@ main(struct boot_info *info) setup_descriptors(); setup_paging(info); + setup_acpi(info->rsdp, &info->ioapic); + setup_apic(&info->ioapic); + setup_keyboard(); - int *x = (int*)0xBEEF; - *x = 4; /* This should give us a page fault, and trigger the panic function */ + halt(); + +// int *x = (int*)0x0001; +// *x = 4; /* This should give us a page fault, and trigger the panic function */ } diff --git a/src/nasty.S b/src/nasty.S index f3d958e..997fb6c 100644 --- a/src/nasty.S +++ b/src/nasty.S @@ -79,7 +79,8 @@ get_cr3: ISR(28) \ ISR(29) \ ISR(30) \ - ISR(31) + ISR(31) \ + ISR(32) .extern interrupt_handler #define ISR(n) \ @@ -147,3 +148,19 @@ dump_regs: mov [rdi+192], fs mov [rdi+194], gs ret + +.global get_msr +get_msr: + mov ecx, edi + mov rax, 0 /* Not sure if this and the next line are needed. My assembly skills are lacking. */ + mov rdx, 0 + rdmsr + shl rdx, 32 + or rax, rdx + ret + +.global in_uint8 +in_uint8: + mov dx, di + in ax, dx + ret diff --git a/src/paging.c b/src/paging.c index ecbd647..9fdf6ea 100644 --- a/src/paging.c +++ b/src/paging.c @@ -2,6 +2,7 @@ #define MAX_REGIONS 1024 #define INVALID_PTR UINT64_MAX +#define PADDR_MASK 0x000FFFFFFFFFF000 struct region { @@ -21,6 +22,8 @@ struct region_map static struct region_map physical; static struct region_map virtual; +static uint64_t physbase; + static void init_map(struct region_map *, bool); static void mark_region(struct region_map *, uint64_t, uint64_t, bool); static uint64_t lookup(struct region_map *, uint64_t); @@ -28,11 +31,17 @@ static void delete_node(struct region_map *, uint64_t); static uint64_t add_node(struct region_map *, uint64_t, uint64_t, bool); static void debug_region_map(struct region_map *); static void print_size(uint64_t); +static uint64_t allocate_virtual(uint64_t); +static void update_pagetables(uint64_t, uint64_t, uint64_t, bool); +static uint64_t *table_ptr(uint64_t *, uint16_t); +static uint64_t encode_entry(uint64_t, bool); +static uint64_t get_physical_page(void); void setup_paging(struct boot_info *info) { print(u8"Setting up paging. All usable physical memory is mapped starting at %p\n", info->physbase); + physbase = info->physbase; init_map(&physical, false); init_map(&virtual, true); @@ -44,9 +53,7 @@ setup_paging(struct boot_info *info) /* TODO fill in the used regions of virtual memory, by inspection the page tables that was setup for us * by the bootloader. */ - - uint64_t cr3 = get_cr3(); - print(u8"CR3: %p\n", cr3); + mark_region(&virtual, 0, PAGE_SIZE, false); /* don't use the first page of virtual memory */ } bool @@ -60,6 +67,21 @@ page_fault_handler(uint32_t code) return false; /* We didn't actually handle it */ } +uint64_t +map_page(uint64_t paddr, uint64_t pagecount, bool cacheable) +{ + /* Find a region of virtual memory which isn't in use yet, and which is large enough */ + uint64_t offset = paddr % PAGE_SIZE; + if(offset != 0){ + pagecount++; + paddr -= offset; + } + + uint64_t vaddr = allocate_virtual(pagecount); + update_pagetables(paddr, vaddr, pagecount, cacheable); + return vaddr + offset; +} + static void init_map(struct region_map *map, bool available) { @@ -203,3 +225,83 @@ print_size(uint64_t size) P(kb, "KB", 0); P(b, "B", 1); } + +static uint64_t +allocate_virtual(uint64_t pagecount) +{ + uint64_t size = PAGE_SIZE * pagecount; + + for(uint64_t p = virtual.used; p != INVALID_PTR; p = virtual.regions[p].next){ + struct region *r = &virtual.regions[p]; + if(r->available && r->size >= size){ + uint64_t vaddr = r->start; + mark_region(&virtual, vaddr, size, false); + return vaddr; + } + } + panic(); +} + +static void +update_pagetables(uint64_t paddr, uint64_t vaddr, uint64_t pagecount, bool cacheable) +{ + uint64_t cr3 = get_cr3(); + uint64_t *pml4 = table_ptr(&cr3, 0); + + for(uint64_t i = 0; i < pagecount; i++){ + uint16_t pml4o = (vaddr >> 39) & 0x1F; + uint16_t pdpo = (vaddr >> 30) & 0x1F; + uint16_t pdeo = (vaddr >> 21) & 0x1F; + uint16_t pteo = (vaddr >> 12) & 0x1F; + + uint64_t *pdp = table_ptr(pml4, pml4o); + uint64_t *pde = table_ptr(pdp, pdpo); + uint64_t *pte = table_ptr(pde, pdeo); + + pte[pteo] = encode_entry(paddr, cacheable); + + paddr += PAGE_SIZE; + vaddr += PAGE_SIZE; + } +} + +static uint64_t * +table_ptr(uint64_t *table, uint16_t index) +{ + uint64_t v = table[index]; + if(v == 0){ + v = get_physical_page(); + memset((void*)(v + physbase), 0, PAGE_SIZE); + table[index] = encode_entry(v, true); + }else + v &= PADDR_MASK; + + return (uint64_t *)(v + physbase); +} + +static uint64_t +encode_entry(uint64_t paddr, bool cacheable) +{ + uint64_t v = 0; + v |= (paddr & PADDR_MASK); + v |= 0x3; /* Present + RW */ + if(!cacheable) + v |= 0x10; /* Cache disable */ + return v; +} + +static uint64_t +get_physical_page(void) +{ + /* Almost identical to allocate_virtual. merge them. */ + + for(uint64_t p = physical.used; p != INVALID_PTR; p = physical.regions[p].next){ + struct region *r = &physical.regions[p]; + if(r->available && r->size >= PAGE_SIZE){ + uint64_t paddr = r->start; + mark_region(&physical, paddr, PAGE_SIZE, false); + return paddr; + } + } + panic(); +} @@ -65,3 +65,13 @@ memset(void *v, uint8_t b, size_t n) for(size_t i = 0; i < n; i++) p[i] = b; } + +void +memcpy(void *dstp, void *srcp, size_t n) +{ + uint8_t *dst = dstp; + uint8_t *src = srcp; + + for(size_t i = 0; i < n; i++) + dst[i] = src[i]; +} |