diff options
Diffstat (limited to 'kernel/entry.cpp')
-rw-r--r-- | kernel/entry.cpp | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/kernel/entry.cpp b/kernel/entry.cpp new file mode 100644 index 0000000..c8f74c8 --- /dev/null +++ b/kernel/entry.cpp @@ -0,0 +1,212 @@ +#include <mercury/kernel/framebuffer.hpp> +#include <mercury/kernel/terminal.hpp> +#include <mercury/kernel/limine.hpp> +#include <mercury/kernel/paging.hpp> + +using namespace mercury::kernel; + +LIMINE_BASE_REVISION(1) + +static volatile limine_memmap_request memmap_request { + .id = LIMINE_MEMMAP_REQUEST, + .revision = 0, + .response = 0 +}; + +static volatile limine_kernel_address_request kernel_address_request { + .id = LIMINE_KERNEL_ADDRESS_REQUEST, + .revision = 0, + .response = 0 +}; + +static volatile limine_framebuffer_request framebuffer_request { + .id = LIMINE_FRAMEBUFFER_REQUEST, + .revision = 0, + .response = 0 +}; + +static volatile limine_hhdm_request hhdm_request { + .id = LIMINE_HHDM_REQUEST, + .revision = 0, + .response = 0 +}; + +static limine_internal_module initfs_module = { + .path = "initfs.tgz", + .cmdline = "initfs", + .flags = LIMINE_INTERNAL_MODULE_REQUIRED | LIMINE_INTERNAL_MODULE_COMPRESSED +}; + +static limine_internal_module termfont_module = { + .path = "termfont.psf", + .cmdline = "termfont", + .flags = LIMINE_INTERNAL_MODULE_REQUIRED +}; + +static limine_internal_module *internal_modules[] = { + &initfs_module, &termfont_module +}; + +static volatile limine_module_request module_request = { + .id = LIMINE_MODULE_REQUEST, + .revision = 2, + .response = 0, + .internal_module_count = 2, + .internal_modules = internal_modules +}; + +bool try_map_module_by_cmdline( + const char *cmdline, void *&vaddr_out, uint64_t &len_out +) { + auto response = module_request.response; + for (uint64_t i = 0; i < response->module_count; ++i) { + limine_file *file = response->modules[i]; + for (uint64_t j = 0; cmdline[j] == file->cmdline[j]; ++j) + if (!cmdline[j]) { + + //module start is guaranteed to be page-aligned, end is not. + uint64_t start_paddr = + (uint64_t)file->address - hhdm_request.response->offset; + uint64_t end_paddr = + ((start_paddr + file->size - 1) / 4096 + 1) * 4096; + + uint64_t start_vaddr = + paging::find_unmapped_vram_region((end_paddr - start_paddr) / 4096); + for (uint64_t i = 0; i < end_paddr - start_paddr; i += 4096) + paging::map_kernel_page( + start_paddr + i, start_vaddr + i, true, false); + + vaddr_out = (void *)start_vaddr; + len_out = file->size; + + return true; + } + } + return false; +} + +//defined in linker script, page-aligned: +extern uint8_t __kernel_start; +extern uint8_t __kernel_end; +extern uint8_t __kernel_rx_start; +extern uint8_t __kernel_rx_end; +extern uint8_t __kernel_ro_start; +extern uint8_t __kernel_ro_end; +extern uint8_t __kernel_rw_start; +extern uint8_t __kernel_rw_end; + +uint8_t *initfs; +uint64_t initfs_len; + +[[noreturn]] static void with_kernel_p4(); + +extern "C" [[noreturn]] void entry() { + + //TODO?: maybe we should check if the limine requests were + // fulfilled and display some error message if not + + //set up the physical memory usage bitmap: + + paging::mark_all_pram_used(); + auto memmap = memmap_request.response; + for (uint64_t i = 0; i < memmap->entry_count; ++i) { + //we don't start allocating physical pages until after we are done using + //limine structures (specifically at the call to paging::map_kernel_stack), + //so we consider bootloader reclaimable to be free. usable and bootloader + //reclaimable are guaranteed by limine spec to be page-aligned. + auto entry = memmap->entries[i]; + if (entry->type == LIMINE_MEMMAP_USABLE || + entry->type == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE) + paging::mark_pram_region_free(entry->base, entry->base + entry->length); + } + + //set up page mappings: + + auto kernel_address = kernel_address_request.response; + uint64_t kernel_offset = kernel_address->virtual_base + - kernel_address->physical_base; + + uint64_t hhdm = hhdm_request.response->offset; + + //framebuffer might not be page-aligned + auto framebuffer = framebuffer_request.response->framebuffers[0]; + uint64_t fb_start = ((uint64_t)framebuffer->address / 4096) * 4096 - hhdm; + uint64_t fb_end = (uint64_t)framebuffer->address + + framebuffer->pitch * framebuffer->height - hhdm; + fb_end = ((fb_end - 1) / 4096 + 1) * 4096; + + paging::init_kernel_page_tables(kernel_offset); + + //kernel image rx + for (uint64_t vaddr = (uint64_t)&__kernel_rx_start; + vaddr < (uint64_t)&__kernel_rx_end; vaddr += 4096) + paging::map_kernel_page(vaddr - kernel_offset, vaddr, false, true); + + //kernel image ro + for (uint64_t vaddr = (uint64_t)&__kernel_ro_start; + vaddr < (uint64_t)&__kernel_ro_end; vaddr += 4096) + paging::map_kernel_page(vaddr - kernel_offset, vaddr, false, false); + + //kernel image rw + for (uint64_t vaddr = (uint64_t)&__kernel_rw_start; + vaddr < (uint64_t)&__kernel_rw_end; vaddr += 4096) + paging::map_kernel_page(vaddr - kernel_offset, vaddr, true, false); + + //framebuffer + uint64_t fb_vaddr = + paging::find_unmapped_vram_region((fb_end - fb_start) / 4096); + for (uint64_t i = 0; i < fb_end - fb_start; i += 4096) + paging::map_kernel_page(fb_start + i, fb_vaddr + i, true, false); + + //initfs and termfont - these are required modules + //so there is no worry about them not being present. + try_map_module_by_cmdline("initfs", (void *&)initfs, initfs_len); + try_map_module_by_cmdline( + "termfont", (void *&)terminal::termfont, terminal::termfont_len); + + //set up framebuffer and terminal: + //TODO: assumes framebuffer is 32-bpp rgb + + framebuffer::init_framebuffer( + fb_vaddr, framebuffer->width, framebuffer->height, framebuffer->pitch); + + //switch to kernel p4 + + paging::map_kernel_stack(); + switch_to_kernel_p4(&with_kernel_p4); + +} + +[[noreturn]] static void with_kernel_p4() { + + terminal::init_terminal(); + terminal::put_string_sz("kernel initialization complete.\n"); + + int used_vram_kib = paging::get_used_vram_page_count() * 4; + int free_pram_kib = paging::get_free_pram_page_count() * 4; + + terminal::put_int_decimal(used_vram_kib); + terminal::put_string_sz(" kiB kernel memory mapped.\n"); + terminal::put_int_decimal(free_pram_kib); + terminal::put_string_sz(" kiB physical memory free.\n"); + + terminal::put_string_sz("initfs first sector:"); + for (int y = 0; y < 8; ++y) { + terminal::put_string_sz("\n "); + for (int x = 0; x < 64; ++x) + terminal::put_char((char)initfs[y * 64 + x]); + } + + terminal::put_string_sz("\ninitfs second sector:"); + for (int y = 0; y < 8; ++y) { + terminal::put_string_sz("\n "); + for (int x = 0; x < 64; ++x) + terminal::put_char((char)initfs[512 + y * 64 + x]); + } + + while (1) + ; + + //TODO + +} |