diff --git a/kern/src/ec.cc b/kern/src/ec.cc index d68c9f2..12f1cb9 100644 --- a/kern/src/ec.cc +++ b/kern/src/ec.cc @@ -21,6 +21,8 @@ #include "assert.h" #include "cpu.h" #include "ptab.h" +#include "multiboot.h" +#include "elf.h" Ec * Ec::current = 0; @@ -76,16 +78,53 @@ void Ec::ret_user_iret() void Ec::root_invoke() { - printf ("root_invoke\n"); - - // TODO - // - current->regs.eax holds pointer to Multiboot info (see multiboot.h) - // - get mbi remapped, find single Multiboot_module - // - get module descriptor mapped, print physical addr and size, check - // if its size is correct (should be equal to filesize of user.nova) - // - get module remapped (its an elf binary, see elf.h for details) - // - sanity check and decode elf binary - // - finally start user module via ret_user_iret() + // find multi boot info + Multiboot * mbi = static_cast(Ptab::remap (current->regs.eax)); + + if (!(mbi->flags & 8) || (mbi->mods_count != 1)) + panic ("exactly ONE multi boot module is required.\n"); + + // load module desciptor + Multiboot_module mod = *static_cast(Ptab::remap (mbi->mods_addr)); + + printf ("load module from %x - %x (%u bytes) : ", mod.mod_start, mod.mod_end, mod.mod_end - mod.mod_start); + char * cmd = static_cast(Ptab::remap (mod.cmdline)); + printf ("%s\n",cmd); + + // remap elf header + Eh * e = static_cast(Ptab::remap (mod.mod_start)); + if (e->ei_magic != 0x464c457f || e->ei_data != 1 || e->type != 2) + panic ("No ELF\n"); + + unsigned count = e->ph_count; + current->regs.eip = e->entry; + + // remap program headers + Ph * p = static_cast(Ptab::remap (mod.mod_start + e->ph_offset)); + + for (; count--; p++) { + + if (p->type == Ph::PT_LOAD) { + + unsigned attr = p->flags & Ph::PF_W ? 7 : 5; + + if (p->f_size != p->m_size || p->v_addr % PAGE_SIZE != p->f_offs % PAGE_SIZE) + panic ("Bad ELF\n"); + + mword phys = align_dn (p->f_offs + mod.mod_start, PAGE_SIZE); + mword virt = align_dn (p->v_addr, PAGE_SIZE); + mword size = align_up (p->f_size, PAGE_SIZE); + + while (size) { + Ptab::insert_mapping (virt, phys, attr); + virt += PAGE_SIZE; + phys += PAGE_SIZE; + size -= PAGE_SIZE; + } + } + } + + ret_user_iret(); FAIL; }