diff --git a/src/boot/main.c b/src/boot/main.c index 91ba514..f303e6e 100644 --- a/src/boot/main.c +++ b/src/boot/main.c @@ -1,55 +1,8 @@ #include "console.h" -#include "multiboot2.h" - -#include -#include "console.h" -#include "multiboot2.h" -#include "panic.h" -#include "util.h" - -#define MAX_REGIONS 64 - -typedef struct { - u64 base_addr; - u64 length; -} memory_region; - -extern uptr kernel_start; -extern uptr kernel_end; - -static memory_region memory_regions[MAX_REGIONS] = {0}; -static size_t memory_region_count = 0; - -static void find_memory_regions() { - multiboot_tag_mmap *tag = multiboot_get_mmap(); - if (tag == NULL) { - boot_panic("Multiboot did not provide mmap tag"); - } - - u32 entry_count = (tag->size - 16) / tag->entry_size; - u8 *entry_ptr = (u8*)tag->entries; - - for (u32 i = 0; i < entry_count; ++i) { - multiboot_mmap_entry *entry = (multiboot_mmap_entry*)entry_ptr; - - if (entry->type == MULTIBOOT_MEMORY_AVAILABLE) { - if (memory_region_count >= MAX_REGIONS) { - boot_panic("Too many memory regions"); - } - - memory_regions[memory_region_count++] = (memory_region){ entry->base_addr, entry->length }; - } - - entry_ptr += tag->entry_size; - } -} +#include "pmm.h" // We are now in long mode with kernel pages and vga buffer identity mapped void x86_64_main() { console_clear(); - find_memory_regions(); - - for (u32 i = 0; i < memory_region_count; ++i) { - kprintf("region: base_addr=0x%X, length=0x%X\n", memory_regions[i].base_addr, memory_regions[i].length); - } + pmm_init(); } \ No newline at end of file diff --git a/src/boot/multiboot2.c b/src/boot/multiboot2.c index 7c75416..321c7fe 100644 --- a/src/boot/multiboot2.c +++ b/src/boot/multiboot2.c @@ -1,4 +1,5 @@ #include "multiboot2.h" +#include "symbols.h" // [size:4][reserved:4][data:N] #define INFO_DATA_OFFSET 8 @@ -6,10 +7,8 @@ #define TAG_TYPE_OFFSET 0 #define TAG_SIZE_OFFSET 4 -extern u8 multiboot_info[]; - void *multiboot_get_tag(u32 type) { - uptr current = (uptr)&multiboot_info + INFO_DATA_OFFSET; + uptr current = get_multiboot_info() + INFO_DATA_OFFSET; while (true) { u32 tag_type = *(u32*)(current + TAG_TYPE_OFFSET); @@ -24,7 +23,7 @@ void *multiboot_get_tag(u32 type) { } // note(nub31): Each tag is aligned to 8 bytes - current = align_up(current + tag_size, 8); + current = ALIGN_UP(current + tag_size, 8); } return NULL; diff --git a/src/boot/multiboot2.h b/src/boot/multiboot2.h index d71027e..03ef7ff 100644 --- a/src/boot/multiboot2.h +++ b/src/boot/multiboot2.h @@ -265,6 +265,10 @@ static inline multiboot_tag_mmap *multiboot_get_mmap() { return multiboot_get_tag(MULTIBOOT_TAG_TYPE_MMAP); } +static inline size_t get_mmap_entry_count(multiboot_tag_mmap *mmap) { + return (mmap->size - 16) / mmap->entry_size; +} + static inline multiboot_tag_vbe *multiboot_get_vbe() { return multiboot_get_tag(MULTIBOOT_TAG_TYPE_VBE); } diff --git a/src/boot/pmm.c b/src/boot/pmm.c new file mode 100644 index 0000000..6eefed8 --- /dev/null +++ b/src/boot/pmm.c @@ -0,0 +1,116 @@ +#include "pmm.h" +#include "util.h" +#include "panic.h" +#include "multiboot2.h" +#include "symbols.h" +#include + +#define PAGE_SIZE 4096 +#define MAX_PHYS_MEM GiB(128) +#define MAX_PAGES (MAX_PHYS_MEM / PAGE_SIZE) +#define BITMAP_SIZE ((MAX_PAGES + 63) / 64) + +static u64 pmm_bitmap[BITMAP_SIZE]; + +static inline void bitmap_set(size_t bit) { + pmm_bitmap[bit / 64] |= (U64_C(1) << (bit % 64)); +} + +static inline void bitmap_clear(size_t bit) { + pmm_bitmap[bit / 64] &= ~(U64_C(1) << (bit % 64)); +} + +static inline int bitmap_test(size_t bit) { + return pmm_bitmap[bit / 64] & (U64_C(1) << (bit % 64)); +} + +static inline size_t to_page(uptr addr) { + if (addr % PAGE_SIZE != 0) { + boot_panic("Address is not page aligned"); + } + + return addr / PAGE_SIZE; +} + +static inline uptr to_addr(size_t page) { + return page * PAGE_SIZE; +} + +static void clear_range(size_t start_page, size_t end_page) { + if (start_page >= MAX_PAGES) { + return; + } + + if (end_page > MAX_PAGES) { + end_page = MAX_PAGES; + } + + for (size_t j = start_page; j < end_page; ++j) { + bitmap_clear(j); + } +} + +static void set_range(size_t start_page, size_t end_page) { + if (start_page >= MAX_PAGES) { + return; + } + + if (end_page > MAX_PAGES) { + end_page = MAX_PAGES; + } + + for (size_t j = start_page; j < end_page; ++j) { + bitmap_set(j); + } +} + +void pmm_init() { + for (size_t i = 0; i < BITMAP_SIZE; i++) { + pmm_bitmap[i] = U64_MAX; + } + + multiboot_tag_mmap *mmap = multiboot_get_mmap(); + if (mmap == NULL) { + boot_panic("No memory map found"); + } + + for (size_t i = 0; i < get_mmap_entry_count(mmap); ++i) { + multiboot_mmap_entry entry = mmap->entries[i]; + if (entry.type == MULTIBOOT_MEMORY_AVAILABLE) { + size_t start_page = to_page(ALIGN_DOWN(entry.base_addr, PAGE_SIZE)); + size_t end_page = to_page(ALIGN_UP(entry.base_addr + entry.length, PAGE_SIZE)); + + clear_range(start_page, end_page); + } + } + + size_t start_page = to_page(ALIGN_DOWN(get_kernel_start(), PAGE_SIZE)); + size_t end_page = to_page(ALIGN_UP(get_kernel_end(), PAGE_SIZE)); + + set_range(start_page, end_page); +} + +void *pmm_alloc_page() { + for (size_t i = 0; i < MAX_PAGES; ++i) { + if (!bitmap_test(i)) { + bitmap_set(i); + return (void*)to_addr(i); + } + } + + boot_panic("Out of physical memory"); +} + +void pmm_free_page(void *addr) { + size_t page = to_page((uptr)addr); + + if (page >= MAX_PAGES) { + boot_panic("Trying to free page beyond physical memory limit"); + } + + if (!bitmap_test(page)) { + boot_panic("Page is already free"); + } + + bitmap_clear(page); +} \ No newline at end of file diff --git a/src/boot/pmm.h b/src/boot/pmm.h new file mode 100644 index 0000000..74594e9 --- /dev/null +++ b/src/boot/pmm.h @@ -0,0 +1,3 @@ +#pragma once + +void pmm_init(); \ No newline at end of file diff --git a/src/boot/symbols.c b/src/boot/symbols.c new file mode 100644 index 0000000..1fcd4ac --- /dev/null +++ b/src/boot/symbols.c @@ -0,0 +1,19 @@ +#include "symbols.h" + +extern u8 kernel_start[]; + +uptr get_kernel_start() { + return (uptr)&kernel_start; +} + +extern u8 kernel_end[]; + +uptr get_kernel_end() { + return (uptr)&kernel_end; +} + +extern u8 multiboot_info[]; + +uptr get_multiboot_info() { + return (uptr)&multiboot_info; +} \ No newline at end of file diff --git a/src/boot/symbols.h b/src/boot/symbols.h new file mode 100644 index 0000000..9948cf0 --- /dev/null +++ b/src/boot/symbols.h @@ -0,0 +1,7 @@ +#pragma once + +#include + +uptr get_kernel_start(); +uptr get_kernel_end(); +uptr get_multiboot_info(); \ No newline at end of file diff --git a/src/boot/util.h b/src/boot/util.h index e9e756c..bc1ed63 100644 --- a/src/boot/util.h +++ b/src/boot/util.h @@ -1,12 +1,9 @@ #pragma once -static inline uptr align_up(uptr value, size_t alignment) { - return (value + alignment - 1) / alignment * alignment; -} +#include -static inline uptr align_down(uptr value, size_t alignment) { - return value - (value % alignment); -} +#define ALIGN_UP(value, alignment) ((value + alignment - 1) / alignment * alignment) +#define ALIGN_DOWN(value, alignment) (value - (value % alignment)) static inline void hlt() { asm("hlt");