From 0a817a5a74c328229f8a732fc3ec22d8fd7dc20d Mon Sep 17 00:00:00 2001 From: Peter Mikkelsen Date: Tue, 29 Jul 2025 21:40:45 +0200 Subject: Some work on keeping track of memory, and providing more info in panics --- src/aplos.h | 39 ++++++++++++- src/main.c | 57 +----------------- src/nasty.S | 41 +++++++++++++ src/paging.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/panic.c | 11 ++++ src/screen.c | 3 + 6 files changed, 280 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/src/aplos.h b/src/aplos.h index 7d3fce0..ad9109b 100644 --- a/src/aplos.h +++ b/src/aplos.h @@ -29,6 +29,40 @@ struct boot_info uint64_t physbase; }; +struct cpu_regs +{ + /* Keep this in sync with dump_regs in nasty.S */ + uint64_t rax; + uint64_t rbx; + uint64_t rcx; + uint64_t rdx; + uint64_t rsi; + uint64_t rdi; + uint64_t rsp; + uint64_t rbp; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rip; + uint64_t rflags; + uint64_t cr0; + uint64_t cr2; + uint64_t cr3; + uint64_t cr4; + uint64_t cr8; + uint16_t cs; + uint16_t ds; + uint16_t ss; + uint16_t es; + uint16_t fs; + uint16_t gs; +}; + /* boot.c */ uint64_t cpu_count(void); @@ -47,7 +81,7 @@ void main(struct boot_info *); /* nasty.S */ struct table_reg; -void halt(void); +[[noreturn]] void halt(void); void disable_interrupts(void); void enable_interrupts(void); void set_gdt(struct table_reg *, uint64_t, uint64_t, uint64_t); @@ -55,13 +89,14 @@ void set_idt(struct table_reg *); uint64_t get_cr2(void); uint64_t get_cr3(void); extern void (*isr_stubs[32])(void); +void dump_regs(struct cpu_regs *); /* paging.c */ void setup_paging(struct boot_info *); bool page_fault_handler(uint32_t); /* panic.c */ -void panic(void); +[[noreturn]] void panic(void); /* screen.c */ void screen_init(struct framebuffer *); diff --git a/src/main.c b/src/main.c index 03ad3fd..a3b7719 100644 --- a/src/main.c +++ b/src/main.c @@ -1,66 +1,15 @@ #include "aplos.h" -static void welcome(void); -static void print_memmap(struct boot_info *); -static void print_size(uint64_t); - void main(struct boot_info *info) { screen_init(&info->framebuffer); - welcome(); + print(u8"Starting ☺☻☺☻☺☻☺☻☺☻\n"); print(u8"CPU count: %u64\n", cpu_count()); - print_memmap(info); setup_descriptors(); setup_paging(info); -} - -static void -welcome(void) -{ - print(u8"Starting ☺☻☺☻☺☻☺☻☺☻\n"); -} - -static void -print_memmap(struct boot_info *info) -{ - print(u8"Usable memory: "); - uint64_t total = 0; - for(uint64_t i = 0; i < info->memmap_count; i++) - total += info->memmaps[i].size; - print_size(total); - print(u8"\n"); - - for(uint64_t i = 0; i < info->memmap_count; i++){ - struct memmap *m = &info->memmaps[i]; - print(u8"%p - %p (", m->start, m->start + m->size); - print_size(m->size); - print(u8")\n"); - } -} - -static void -print_size(uint64_t size) -{ - uint64_t gb, mb, kb, b; - gb = size >> 30; size -= gb << 30; - mb = size >> 20; size -= mb << 20; - kb = size >> 10; size -= kb << 10; - b = size; - - int printed = 0; - -#define P(what, spec, force) \ - if(what || (force && !printed)){ \ - if(printed) \ - print(u8" + "); \ - printed = 1; \ - print(u8"%u64 " spec, what); \ - } - P(gb, "GB", 0); - P(mb, "MB", 0); - P(kb, "KB", 0); - P(b, "B", 1); + int *x = (int*)0xBEEF; + *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 9fdab5f..f3d958e 100644 --- a/src/nasty.S +++ b/src/nasty.S @@ -106,3 +106,44 @@ DEFINE_ISRS isr_stubs: DEFINE_ISRS #undef ISR + +.section .text +.global dump_regs +dump_regs: + mov [rdi+0], rax + mov [rdi+8], rbx + mov [rdi+16], rcx + mov [rdi+24], rdx + mov [rdi+32], rsi + mov [rdi+40], rdi + mov [rdi+48], rsp + mov [rdi+56], rbp + mov [rdi+64], r8 + mov [rdi+72], r9 + mov [rdi+80], r10 + mov [rdi+88], r11 + mov [rdi+96], r12 + mov [rdi+104], r13 + mov [rdi+112], r14 + mov [rdi+120], r15 + lea rax, [rip] + mov [rdi+128], rax + pushf + pop [rdi+136] + mov rax, cr0 + mov [rdi+144], rax + mov rax, cr2 + mov [rdi+152], rax + mov rax, cr3 + mov [rdi+160], rax + mov rax, cr4 + mov [rdi+168], rax + mov rax, cr8 + mov [rdi+176], rax + mov [rdi+184], cs + mov [rdi+186], ds + mov [rdi+188], ss + mov [rdi+190], es + mov [rdi+192], fs + mov [rdi+194], gs + ret diff --git a/src/paging.c b/src/paging.c index 0728178..ecbd647 100644 --- a/src/paging.c +++ b/src/paging.c @@ -1,9 +1,50 @@ #include "aplos.h" +#define MAX_REGIONS 1024 +#define INVALID_PTR UINT64_MAX + +struct region +{ + uint64_t start; + uint64_t size; + uint64_t next; + int available : 1; +}; + +struct region_map +{ + uint64_t used; /* Chain of used indices in the regions table */ + uint64_t unused; /* Chain of unused indices in the regions table */ + struct region regions[MAX_REGIONS]; +}; + +static struct region_map physical; +static struct region_map virtual; + +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); +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); + void setup_paging(struct boot_info *info) { print(u8"Setting up paging. All usable physical memory is mapped starting at %p\n", info->physbase); + + init_map(&physical, false); + init_map(&virtual, true); + + for(uint64_t i = 0; i < info->memmap_count; i++) + mark_region(&physical, info->memmaps[i].start, info->memmaps[i].size, true); + debug_region_map(&physical); + + /* 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); } @@ -18,3 +59,147 @@ page_fault_handler(uint32_t code) return false; /* We didn't actually handle it */ } + +static void +init_map(struct region_map *map, bool available) +{ + map->used = INVALID_PTR; + map->unused = 0; + + for(uint64_t p = 0; p < MAX_REGIONS-1; p++) + map->regions[p].next = p+1; + map->regions[MAX_REGIONS-1].next = INVALID_PTR; + + add_node(map, 0, UINT64_MAX, available); +} + +static void +mark_region(struct region_map *map, uint64_t addr, uint64_t size, bool available) +{ + uint64_t p = lookup(map, addr); + struct region *r = &map->regions[p]; + + if((r->start <= addr) && (r->start+r->size >= addr+size) && (r->available != available)){ + /* Entirely within a current region. Split the current one up. */ + uint64_t oldstart = r->start; + uint64_t oldend = r->start+r->size; + delete_node(map, p); + add_node(map, oldstart, addr - r->start, !available); + add_node(map, addr, size, available); + add_node(map, addr+size, oldend-(addr+size), !available); + }else + panic(); /* I don't want to think about this right now */ +} + +static uint64_t +lookup(struct region_map *map, uint64_t addr) +{ + uint64_t p; + struct region *r; + + for(p = map->used; p != INVALID_PTR; p = r->next){ + r = &map->regions[p]; + if((r->start <= addr) && (r->start+r->size > addr)) + return p; + } + panic(); +} + +static void +delete_node(struct region_map *map, uint64_t p) +{ + uint64_t x; + uint64_t prev = INVALID_PTR; + for(x = map->used; x != INVALID_PTR; prev = x, x = map->regions[x].next){ + if(x == p){ + if(prev != INVALID_PTR) + map->regions[prev].next = map->regions[x].next; + else + map->used = INVALID_PTR; + map->regions[x].next = map->unused; + map->unused = x; + return; + } + } + panic(); +} + +static uint64_t +add_node(struct region_map *map, uint64_t start, uint64_t size, bool available) +{ + struct region *r; + uint64_t p; + uint64_t prev = INVALID_PTR; + for(p = map->used; p != INVALID_PTR; prev = p, p = map->regions[p].next){ + if(map->regions[p].start > start) + break; + } + + uint64_t new = map->unused; + + if(prev == INVALID_PTR){ + r = &map->regions[map->unused]; + uint64_t tmp = map->used; + map->used = map->unused; + map->unused = r->next; + r->next = tmp; + }else{ + r = &map->regions[map->unused]; + map->unused = r->next; + r->next = map->regions[prev].next; + map->regions[prev].next = new; + } + + r->start = start; + r->size = size; + r->available = available; + return new; +} + +static void +debug_region_map(struct region_map *map) +{ + uint64_t available = 0; + for(uint64_t p = map->used; p != INVALID_PTR; p = map->regions[p].next){ + struct region *r = &map->regions[p]; + if(r->available) + available += r->size; + } + print(u8"Total available memory: "); + print_size(available); + print(u8"\n"); + + for(uint64_t p = map->used; p != INVALID_PTR; p = map->regions[p].next){ + struct region *r = &map->regions[p]; + if(r->available){ + print(u8"[%p - %p] (", r->start, r->start+r->size); + print_size(r->size); + print(u8")\n"); + } + } +} + +static void +print_size(uint64_t size) +{ + uint64_t gb, mb, kb, b; + gb = size >> 30; size -= gb << 30; + mb = size >> 20; size -= mb << 20; + kb = size >> 10; size -= kb << 10; + b = size; + + int printed = 0; + +#define P(what, spec, force) \ + if(what || (force && !printed)){ \ + if(printed) \ + print(u8" + "); \ + printed = 1; \ + print(u8"%u64 " spec, what); \ + } + + P(gb, "GB", 0); + P(mb, "MB", 0); + P(kb, "KB", 0); + P(b, "B", 1); +} diff --git a/src/panic.c b/src/panic.c index 5b17b04..3b39aeb 100644 --- a/src/panic.c +++ b/src/panic.c @@ -3,6 +3,17 @@ void panic(void) { + struct cpu_regs r; + dump_regs(&r); + print(u8"--- PANIC ---\n"); + print(u8"rax: %p rbx: %p rcx: %p rdx: %p\n", r.rax, r.rbx, r.rcx, r.rdx); + print(u8"rsi: %p rdi: %p rsp: %p rbp: %p\n", r.rsi, r.rdi, r.rsp, r.rbp); + print(u8"r8: %p r9: %p r10: %p r11: %p\n", r.r9, r.r9, r.r10, r.r11); + print(u8"r12: %p r13: %p r14: %p r15: %p\n", r.r12, r.r13, r.r14, r.r15); + print(u8"rip: %p cr0: %p cr2: %p cr3: %p\n", r.rip, r.cr0, r.cr2, r.cr3); + print(u8"cr4: %p cr8: %p cs: %p ds: %p\n", r.cr4, r.cr8, r.cs, r.ds); + print(u8"ss: %p es: %p fs: %p gs: %p\n", r.ss, r.es, r.fs, r.gs); + print(u8"rflags: %p\n", r.rflags); halt(); } diff --git a/src/screen.c b/src/screen.c index 903ce9c..46f1231 100644 --- a/src/screen.c +++ b/src/screen.c @@ -48,6 +48,9 @@ print_char: row++; col = 0; break; + case '\t': + col = (col+8) & ~7; + break; case '%': n = print_fmt(p, args); if(n == 0) -- cgit v1.2.3