176 lines
4.7 KiB
C
176 lines
4.7 KiB
C
#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 <lib/print.h>
|
|
#include <lib/stream.h>
|
|
#include <lib/memory.h>
|
|
|
|
#include <memory/mm.h>
|
|
|
|
#include <drivers/iso/iso.h>
|
|
#include <drivers/ide/ide.h>
|
|
#include <drivers/pic/pic.h>
|
|
#include <drivers/ps2/ps2.h>
|
|
#include <drivers/pit/pit.h>
|
|
#include <drivers/vga/vga.h>
|
|
#include <drivers/cpio/cpio.h>
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
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) {
|
|
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
|
|
|
|
create_task(e_hdr->e_entry, (uint32_t)cr3, 1, (uint32_t)u_esp);
|
|
|
|
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();
|
|
load_root_program("/origin.elf");
|
|
kprintf("done loading origin program\n");
|
|
enable_interrupts();
|
|
}
|