Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * Execution Context
- *
- * Copyright (C) 2009-2011 Udo Steinberg <[email protected]>
- * Economic rights: Technische Universitaet Dresden (Germany)
- *
- * This file is part of the NOVA microhypervisor.
- *
- * NOVA is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * NOVA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License version 2 for more details.
- */
- #include "bits.h"
- #include "ec.h"
- #include "assert.h"
- #include "cpu.h"
- #include "ptab.h"
- #include "multiboot.h"
- #include "elf.h"
- Ec * Ec::current;
- // used for idle() and root_invoke()
- Ec::Ec (void (*f)(), mword mbi) : cont (f)
- {
- regs.eax = mbi;
- regs.cs = SEL_USER_CODE;
- regs.ds = SEL_USER_DATA;
- regs.es = SEL_USER_DATA;
- regs.ss = SEL_USER_DATA;
- regs.efl = 0x200; // IF = 1
- }
- // only used by syscall create thread (EC+SC)
- Ec::Ec (mword eip)
- {
- cont = ret_user_iret;
- regs.cs = SEL_USER_CODE;
- regs.ds = SEL_USER_DATA;
- regs.es = SEL_USER_DATA;
- regs.ss = SEL_USER_DATA;
- regs.efl = 0x200; // IF = 1
- regs.eip = eip;
- }
- void Ec::ret_user_sysexit()
- {
- asm volatile ("lea %0, %%esp;"
- "popa;"
- "sti;"
- "sysexit"
- : : "m" (current->regs) : "memory");
- UNREACHED;
- }
- void Ec::ret_user_iret()
- {
- asm volatile ("lea %0, %%esp;"
- "popa;"
- "pop %%gs;"
- "pop %%fs;"
- "pop %%es;"
- "pop %%ds;"
- "add $8, %%esp;"
- "iret"
- : : "m" (current->regs) : "memory");
- UNREACHED;
- }
- void Ec::idle()
- {
- for (;;)
- UNREACHED;
- }
- void Ec::root_invoke()
- {
- //panic ("root_invoke\n");
- printf("Running 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 sys_user_iret()
- // find multi boot info
- Multiboot * multiboot = static_cast<Multiboot *>(Ptab::remap (current->regs.eax));
- if (!(multiboot->flags & 8) || (multiboot->mods_count != 1)){
- panic ("Panika, horii\n");
- }
- Multiboot_module module = *static_cast<Multiboot_module *>(Ptab::remap (multiboot->mods_addr));
- printf("module.mod_start is %x and module.mod_end is %x\n", module.mod_start, module.mod_end);
- char *cmd_line = static_cast<char *>(Ptab::remap (module.cmdline));
- printf ("cmd_line is %s\n",cmd_line);
- Eh *elf = static_cast<Eh *>(Ptab::remap (module.mod_start));
- int headers = elf->ph_count; //number of program headers
- current->regs.eip = elf->entry; //set regs.eip to correct entry point
- int offset1 = elf->ph_offset;
- //program header
- Ph *ph = static_cast<Ph *>(Ptab::remap (module.mod_start + offset1)); //first header
- int i;
- printf("# of Headers %d\n", headers);
- for(i = 0; i < headers; i++){
- if (ph->type == Ph::PT_LOAD) { //from slides page 13.
- printf("---------\n");
- printf("HEADER %d\n", i);
- unsigned attr;
- if(Ph::PF_W & ph->flags){
- attr=7;
- } else{
- attr=5;
- }
- //if file size is different from memory size
- if (ph->f_size != ph->m_size){panic ("file size is different from memory size\n");}
- //if virtual address remainder is different from offset remainder
- if(ph->v_addr % PAGE_SIZE != ph->f_offs % PAGE_SIZE){panic ("virtual address remainder is different from offset remainder\n");}
- printf("ph: v_addr %d, p_addr %d, f_size %d, m_size %d, f_offs %d\n", ph->v_addr, ph->p_addr, ph->f_size, ph->m_size, ph->f_offs);
- int offset2 = ph->f_offs;
- mword phys = align_dn (offset2 + module.mod_start, PAGE_SIZE);
- mword virt = align_dn (ph->v_addr, PAGE_SIZE); //where to map
- mword size = align_up (ph->f_size, PAGE_SIZE);
- int j;
- int pages = (size%PAGE_SIZE == 0) ? (size/PAGE_SIZE) : (size/PAGE_SIZE + 1);
- for(j = 0; j < pages; j++) {
- Ptab::insert_mapping (virt, phys, attr);
- virt += PAGE_SIZE;
- phys += PAGE_SIZE;
- }
- //printf("After alligning: v_addr %d, p_addr %d, f_size %d, m_size %d, f_offs %d\n", ph->v_addr, ph->p_addr, ph->f_size, ph->m_size, ph->f_offs);
- }
- ph++;
- }
- printf("ret_user_iret()\n");
- ret_user_iret();
- FAIL;
- }
- void Ec::handle_tss()
- {
- panic ("Task gate invoked\n");
- }
- void Ec::syscall_handler (uint8 number)
- {
- Sys_regs * r = current->sys_regs();
- switch (number) {
- case 0: // nop
- printf ("syscall %d - nop\n", number);
- break;
- case 1: // add
- printf ("syscall %d - add : %lu + %lu\n", number, r->esi, r->edi);
- r->esi += r->edi;
- break;
- case 2: // ptab
- printf ("syscall %d - ptab : to be implemented\n", number);
- // TODO
- // - implement functionality in ptab.h and ptab.cc
- // - make Ptab::dump() available though syscall
- // Ptab::dump();
- break;
- default:
- printf ("syscall %d - unknown\n", number);
- break;
- };
- ret_user_sysexit();
- UNREACHED;
- }
- bool Ec::handle_exc_ts (Exc_regs *r)
- {
- if (r->user())
- return false;
- // SYSENTER with EFLAGS.NT=1 and IRET faulted
- r->efl &= ~0x4000; // nested task eflag
- return true;
- }
- void Ec::handle_exc (Exc_regs *r)
- {
- if (r->vec == Cpu::EXC_TS && handle_exc_ts (r))
- return;
- if (r->vec == Cpu::EXC_GP)
- panic ("%s GP (EIP=%#lx CR2=%#lx)\n", r->eip < LINK_ADDR ? "User" : "Kernel", r->eip, r->cr2);
- if (r->vec == Cpu::EXC_PF)
- panic ("%s PF (EIP=%#lx CR2=%#lx)\n", r->eip < LINK_ADDR ? "User" : "Kernel", r->eip, r->cr2);
- panic ("%s EXC %#lx (EIP=%#lx CR2=%#lx)\n", r->eip < LINK_ADDR ? "User" : "Kernel", r->vec, r->eip, r->cr2);
- UNREACHED;
- }
Advertisement
Add Comment
Please, Sign In to add comment