From 30d6e8f850d2fe26fffdeef0c38fc627ef8bab9a Mon Sep 17 00:00:00 2001 From: "Anna (navi) Figueiredo Gomes" Date: Wed, 13 Dec 2023 13:24:48 +0100 Subject: initial commit currently with: booted via multiboot 1 protected mode to long mode boostrap code vga used for outputting gdt and idt set up identity paging for the whole memory reported by multiboot pic and ps/2 set up acpi code exists but is broken --- src/memory.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 src/memory.c (limited to 'src/memory.c') diff --git a/src/memory.c b/src/memory.c new file mode 100644 index 0000000..eac0718 --- /dev/null +++ b/src/memory.c @@ -0,0 +1,185 @@ +#include +#include +#include + +#include +#include +#include +#include + +extern uint64_t multiboot_magic; +extern struct multiboot_info *multiboot_header; +extern void *kernel_end; + +extern uint64_t pml4[512]; + +struct memory { + struct memory *prev, *next; + bool free; + size_t size; + uint8_t block[]; +} *blocklist; + +void print_blocks() { + struct memory *block = NULL; + for (block = blocklist; block; block = block->next) { + vga_puts("block at: "); + vga_putx((size_t)block); + vga_puts(", size: "); + vga_putx(block->size); + if (block->free) + vga_puts(", free"); + vga_putc('\n'); + } +} + +void *kmalloc_a(size_t size, size_t alignment) { + struct memory *block = NULL; + for (block = blocklist; block; block = block->next) { + if (!block->free || block->size < size + sizeof(struct memory)) + continue; + size_t offset = (uintptr_t)block->block % alignment; + if (offset) { + if (block->size < (2 * sizeof(struct memory)) + size + (alignment - offset)) { + continue; + } + + struct memory *new_block = (void *)block + (alignment - offset); + *new_block = (struct memory) { + .size = block->size - (alignment - offset), + .free = true, + .prev = block, + .next = block->next, + }; + block->next = new_block; + block->size = alignment - offset; + + block = new_block; + break; + } + } + if (!block) { + print_blocks(); + vga_puts("\n\noom"); + while(1); + } + + struct memory *nextblock = (void *)block->block + size; + *nextblock = (struct memory) { + .size = block->size - size, + .free = true, + .prev = block, + .next = block->next + }; + block->next = nextblock; + block->size = size; + block->free = false; + return block->block; +} + +void *kmalloc(size_t size) { + struct memory *block = NULL; + for (block = blocklist; block && (!block->free || block->size < size + sizeof(struct memory)); block = block->next); + if (!block) { + print_blocks(); + vga_puts("\n\noom"); + while(1); + } + + struct memory *nextblock = (void *)block->block + size; + *nextblock = (struct memory) { + .size = block->size - size, + .free = true, + .prev = block, + .next = block->next + }; + block->next = nextblock; + block->size = size; + block->free = false; + + return block->block; +} + +void kfree(void *ptr) { + struct memory *header = ptr - sizeof(struct memory); + if (header->next && header->next == (void*)header->block + header->size && header->next->free) { + header->size += header->next->size + sizeof(struct memory); + header->next = header->next->next; + if (header->next) + header->next->prev = header; + } + if (header->prev && header == (void*)header->prev->block + header->prev->size && header->prev->free) { + header->prev->size += header->size + sizeof(struct memory); + header->prev->next = header->next; + if (header->next) + header->next->prev = header->prev; + header = header->prev; + } + + header->free = true; +} + +uint64_t alloc_page() { + uint64_t *page = kmalloc_a(sizeof(uint64_t) * 512, 0x1000); + memset(page, 0, sizeof(uint64_t) * 512); + return (uint64_t)page | 0x3; +} + +uint64_t *addr_to_page(uint64_t addr) { + size_t index = (addr >> 39) & 0x1ff; + if (!(pml4[index] & 0x1)) + pml4[index] = alloc_page(); + + uint64_t *pdpr = (uint64_t*)(pml4[index] & ~0xfff); + index = (addr >> 30) & 0x1ff; + if (!(pdpr[index] & 0x1)) + pdpr[index] = alloc_page(); + + uint64_t *pd = (uint64_t*)(pdpr[index] & ~0xfff); + index = (addr >> 21) & 0x1ff; + if (!(pd[index] & 0x1)) + pd[index] = alloc_page(); + + uint64_t *pt = (uint64_t*)(pd[index] & ~0xfff); + index = (addr >> 12) & 0x1ff; + return &pt[index]; +}; + +bool paging_init() { + blocklist = (void *)0x7e00; + *blocklist = (struct memory) { + .size = 0x7ffff - 0x7e00, + .free = true + }; + + if (multiboot_magic != 0x2badb002) + return false; + + for (size_t i = 0; i < multiboot_header->mmap_length / sizeof(struct multiboot_mmap_entry); i++) { + struct multiboot_mmap_entry *mmap = &((struct multiboot_mmap_entry *) (uintptr_t) multiboot_header->mmap_addr)[i]; + + if (mmap->type == MULTIBOOT_MEMORY_AVAILABLE && mmap->addr > 0x1000) { + struct memory *header = mmap->addr > (uint64_t)&kernel_end ? (void*) mmap->addr : (void *)&kernel_end; + + // map the first header, in case we need to use this region for paging itself + uint64_t *page = addr_to_page((uintptr_t) header); + *page = ((uintptr_t)header & ~0xfff) | 0x3; + + *header = (struct memory) { + .size = mmap->len, + .free = true + }; + struct memory *last; + for (last = blocklist; last->next; last = last->next); + last->next = header; + header->prev = last; + } + + size_t end = mmap->addr + mmap->len; + for (size_t addr = mmap->addr & ~0xfff; addr < end; addr += 0x1000) { + uint64_t *page = addr_to_page(addr); + *page = addr | 0x3; + } + } + return true; +} -- cgit v1.2.3