#include "multiboot.h" #include "interrupts.h" #include "gdt.h" #include "common.h" #include "scheduler.h" #include "vfs.h" #include "elf.h" #include "gdt.h" #include #include #include #include #include #include #include #include #include #include #include #include #include extern char __kernel_start; extern char __kernel_end; extern uint32_t page_directory[1024]; void* kernel_cr3 = page_directory; void parse_multiboot_modules(uint32_t mbi_vaddr) { // find where grub put the boot module containing initrd multiboot_info* mbi = (multiboot_info*)mbi_vaddr; uint32_t mod_count = mbi->mods_count; multiboot_module_t* mod = (multiboot_module_t*)((uint32_t)mbi->mods_addr + 0xC0000000); kprintf("found %d mods starting @ [v]0x%x\n", mod_count, (uint32_t)mod); for (uint32_t i = 0; i < mod_count; i++) { uint32_t start = mod[i].mod_start; uint32_t end = mod[i].mod_end; uint32_t cmdline = mod[i].cmdline; multiboot_module_info_table[i].mod_start = start + 0xC0000000; multiboot_module_info_table[i].mod_end = end + 0xC0000000; multiboot_module_info_table[i].cmdline = cmdline + 0xC0000000; } } vfs_node_t* load_initrd() { multiboot_module_t* initrd_module = &multiboot_module_info_table[0]; kprintf("initrd found @ [v] 0x%x\n", initrd_module->mod_start); return cpio_read_fs(initrd_module->mod_start); } void load_root_program(const char* path) { lock_scheduler(); uint32_t kernel_cr3 = fetch_cr3(); void* cr3 = create_task_pd(); load_pd(cr3); flush_tlb(); int fd = open(path, 0); if (fd == -1) { kprintf("failed to open program: %s\n", path); return;; } elf_header_t* e_hdr = kalloc(sizeof(elf_header_t)); memset((void*)e_hdr, 0, sizeof(elf_header_t)); uint32_t bytes_rd = read(fd, e_hdr, sizeof(elf_header_t)); if (bytes_rd <= 0) { kprintf("failed to read program data for %s\n", path); return; } uint32_t ph_table_ptr = e_hdr->e_phoff; elf_program_header_t* ph = kalloc(sizeof(elf_program_header_t)); uint32_t heap_start = 0; for (uint32_t i = 0; i < e_hdr->e_phnum; i++) { fseek(fd, ph_table_ptr); memset((void*)ph, 0, sizeof(elf_program_header_t)); read(fd, ph, sizeof(elf_program_header_t)); if (ph->p_type == PT_LOAD) { uint32_t vstart = ph->p_vaddr; uint32_t vend = vstart + ph->p_memsz; if (vend > heap_start) { heap_start = vend; } uint32_t page_start = vstart & ~(PAGE_SIZE - 1); uint32_t page_end = (vend + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); for (uint32_t v = page_start; v < page_end; v += PAGE_SIZE) { void* phys_frame = p_alloc_frame(); map_page(v, (uint32_t)phys_frame, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER); } uint32_t data_ptr = ph->p_offset; fseek(fd, data_ptr); read(fd, (void*)vstart, ph->p_filesz); // 0 out bss if (ph->p_memsz > ph->p_filesz) { size_t bss_size = ph->p_memsz - ph->p_filesz; memset((void*)(vstart + ph->p_filesz), 0, bss_size); } } ph_table_ptr += sizeof(elf_program_header_t); } uint32_t stack_sz = PAGE_SIZE * 16; uint32_t stack_top = 0xBFFF0000; uint32_t stack_bottom = stack_top - stack_sz; for (uint32_t vaddr = stack_bottom; vaddr < stack_top; vaddr += PAGE_SIZE) { void* phys_frame = p_alloc_frame(); map_page(vaddr, (uint32_t)phys_frame, PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER); } uint32_t* u_esp = (uint32_t*)stack_top; *(--u_esp) = 0; // envp = NULL *(--u_esp) = 0; // argv = NULL *(--u_esp) = 0; // argc = 0 process_t* process = kalloc(sizeof(process_t)); init_task(process, e_hdr->e_entry, (uint32_t)cr3, 1, (uint32_t)u_esp); add_task(process); unlock_scheduler(); load_pd((void*)kernel_cr3); flush_tlb(); } void kmain(uint32_t magic, multiboot_info* mbi) { disable_interrupts(); if (!(mbi->flags & (1 << 6))) { return; } vga_init(); uint32_t mmap_virtual_addr = mbi->mmap_addr + 0xC0000000; init_pmm((void*)mmap_virtual_addr, mbi->mmap_length); kprintf("memory detection complete. total free memory: %dMB\n", total_free_memory() / 1024 / 1024); init_gdt(); init_idt(); init_pic(); init_pit(); init_page_tables(); parse_multiboot_modules((uint32_t)mbi); kprintf("basic initializations complete\n"); vfs_node_t* vfs_root = vfs_create_root(); vfs_node_t* initrd_root = load_initrd(); if (!initrd_root) { kprintf("failed to load initrd\n"); } mount(vfs_root, initrd_root); kprintf("initrd read, mounted @ /\n"); disable_interrupts(); init_scheduler(); enable_interrupts(); kprintf("loading test program\n"); load_root_program("/test.elf"); kprintf("kernel going to sleep...\n"); }