////////////////////////////////////////////////////////////////////// // Make 'envs' point to an array of size 'NENV' of 'struct Env'. // LAB 3: Your code here. envs = (struct Env *) boot_alloc(NENV * sizeof(struct Env)); memset(envs, 0, NENV * sizeof(struct Env));
1 2 3 4 5 6 7 8
////////////////////////////////////////////////////////////////////// // Map the 'envs' array read-only by the user at linear address UENVS // (ie. perm = PTE_U | PTE_P). // Permissions: // - the new image at UENVS -- kernel R, user R // - envs itself -- kernel RW, user NONE // LAB 3: Your code here. boot_map_region(kern_pgdir, UENVS, PTSIZE, PADDR(envs), PTE_U);
for (size_t i = PDX(UTOP); i < NPDENTRIES; ++i) e->env_pgdir[i] = kern_pgdir[i]; // UVPT maps the env's own page table read-only. // Permissions: kernel R, user R e->env_pgdir[PDX(UVPT)] = PADDR(e->env_pgdir) | PTE_P | PTE_U; return0; }
region_alloc
按要求为进程的虚拟页分配对应的物理页即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
staticvoid region_alloc(struct Env *e, void *va, size_t len) { // LAB 3: Your code here. // (But only if you need it for load_icode.) uintptr_t vstart, vend; structPageInfo *pp; int err;
vstart = ROUNDDOWN((uintptr_t)va, PGSIZE); vend = ROUNDUP((uintptr_t)va + len, PGSIZE);
for (; vstart < vend; vstart += PGSIZE) { if (!(pp = page_alloc(ALLOC_ZERO))) panic("region_alloc(1)"); if ((err = page_insert(e->env_pgdir, pp, (void*)vstart, PTE_W | PTE_U)) < 0) panic("region_alloc(2): %e", err); } }
void env_run(struct Env *e) { // Step 1: If this is a context switch (a new environment is running): // 1. Set the current environment (if any) back to // ENV_RUNNABLE if it is ENV_RUNNING (think about // what other states it can be in), // 2. Set 'curenv' to the new environment, // 3. Set its status to ENV_RUNNING, // 4. Update its 'env_runs' counter, // 5. Use lcr3() to switch to its address space. // Step 2: Use env_pop_tf() to restore the environment's // registers and drop into user mode in the // environment.
// LAB 3: Your code here. for (int i = 0; i < 32; ++i) SETGATE(idt[i], 0, GD_KT, handlers[i], 0); SETGATE(idt[T_BRKPT], 0, GD_KT, handlers[T_BRKPT], 3); SETGATE(idt[T_SYSCALL], 0, GD_KT, handlers[T_SYSCALL], 3); // Per-CPU setup trap_init_percpu(); }
Questions
1.
What is the purpose of having an individual handler function for each exception/interrupt? (i.e., if all exceptions/interrupts were delivered to the same handler, what feature that exists in the current implementation could not be provided?)
Did you have to do anything to make the user/softint program behave correctly? The grade script expects it to produce a general protection fault (trap 13), but softint’s code says int 14 instruction to invoke the kernel’s page fault handler (which is interrupt vector 14)?
IF software interrupt (* Generated by INT n, INT3, or INTO; does not apply to INT1 *) THEN IF gate DPL < CPL (* PE = 1, DPL < CPL, software interrupt *) THEN #GP(error_code(vector_number,1,0)); FI; (* idt operand to error_code set because vector is used *) (* ext operand to error_code is 0 because INT n, INT3, or INTO*)
The break point test case will either generate a break point exception or a general protection fault depending on how you initialized the break point entry in the IDT (i.e., your call to SETGATE from trap_init). Why? How do you need to set it up in order to get the breakpoint exception to work as specified above and what incorrect setup would cause it to trigger a general protection fault?
// Make sure this memory is valid. // Return -1 if it is not. Hint: Call user_mem_check. // LAB 3: Your code here. if (curenv && user_mem_check(curenv, (void*)usd, sizeof(struct UserStabData), PTE_U) < 0) return-1;
1 2 3 4 5 6 7 8
// Make sure the STABS and string table memory is valid. // LAB 3: Your code here. if (curenv && ( user_mem_check(curenv, (void*)stabs, (uintptr_t)stab_end - (uintptr_t)stabs, PTE_U) < 0 || user_mem_check(curenv, (void*)stabstr, (uintptr_t)stabstr_end - (uintptr_t)stabstr, PTE_U) < 0)) return-1;
This completes this lab
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
divzero: OK (3.4s) softint: OK (1.0s) badsegment: OK (0.9s) Part A score: 30/30
faultread: OK (1.7s) faultreadkernel: OK (1.2s) faultwrite: OK (1.8s) faultwritekernel: OK (1.2s) breakpoint: OK (1.7s) testbss: OK (2.1s) hello: OK (2.1s) buggyhello: OK (1.8s) buggyhello2: OK (1.2s) evilhello: OK (1.8s) Part B score: 50/50
[00000000] new env 00001000 Incoming TRAP frame at 0xefffffbc Incoming TRAP frame at 0xefffffbc Welcome to the JOS kernel monitor! Type 'help' for a list of commands. TRAP frame at 0xf01c7000 edi 0x00000000 esi 0x00000000 ebp 0xeebfdfc0 oesp 0xefffffdc ebx 0x00802000 edx 0x0080202c ecx 0x00000000 eax 0xeec00000 es 0x----0023 ds 0x----0023 trap 0x00000003 Breakpoint err 0x00000000 eip 0x00800037 cs 0x----001b flag 0x00000082 esp 0xeebfdfc0 ss 0x----0023 K> step Incoming TRAP frame at 0xefffffbc Welcome to the JOS kernel monitor! Type 'help' for a list of commands. TRAP frame at 0xf01c7000 edi 0x00000000 esi 0x00000000 ebp 0xeebfdff0 oesp 0xefffffdc ebx 0x00802000 edx 0x0080202c ecx 0x00000000 eax 0xeec00000 es 0x----0023 ds 0x----0023 trap 0x00000001 Debug err 0x00000000 eip 0x00800038 cs 0x----001b flag 0x00000182 esp 0xeebfdfc4 ss 0x----0023 K> continue Incoming TRAP frame at 0xefffffbc [00001000] exiting gracefully [00001000] free env 00001000 Destroyed the only environment - nothing more to do! Welcome to the JOS kernel monitor! Type 'help' for a list of commands. K>