#include #include .data // Define the global symbols 'envs', 'pages', 'vpt', and 'vpd' // so that they can be used in C as if they were ordinary global arrays. .globl envs .set envs, UENVS .globl pages .set pages, UPAGES .globl vpt .set vpt, UVPT .globl vpd .set vpd, (UVPT+(UVPT>>12)*4) // Entrypoint - this is where the kernel (or our parent environment) // starts us running when we are initially loaded into a new environment. .text .globl _start _start: // See if we were started with arguments on the stack cmpl $USTACKTOP, %esp jne args_exist // If not, push dummy argc/argv arguments. // This happens when we are loaded by the kernel, // because the kernel does not know about passing arguments. pushl $0 pushl $0 args_exist: call libmain 1: jmp 1b .data .globl _pgfault_handler _pgfault_handler: .long 0 // Page fault handler entrypoint - // this is where we ask the kernel // (by calling sys_set_pgfault_handler) // to redirect us to whenever we cause a page fault in user space. // // When a page fault actually occurs, // the kernel switches our ESP to point to the user exception stack // if we're not already on the user exception stack, // and then it pushes the following minimal trap frame // onto our user exception stack: // // [ 5 spare words ] // trap-time eip // trap-time eflags // trap-time esp // trap-time errcode // trap-time va <-- %esp // // We then have to save additional callee-saved registers // and call up to the appropriate page fault handler in C code, // pointed to by the global variable '_pgfault_handler' declared above. .text .globl _asm_pgfault_handler _asm_pgfault_handler: // save the caller-save registers // (your code here) // call the C page fault handler movl _pgfault_handler, %eax call *%eax // push trap-time eip, eflags onto trap-time stack // (your code here) // restore the caller-save registers // (your code here) // switch to the trap-time stack // (your code here) // restore eflags and eip from the stack // (your code here)