answers.txt: 6.828 Lab 3 Dan R. K. Ports 2004/10/07 PART A ---------- Exercise 1: Each exception has its own handler procedure called from the IDT in order to push the exception/interrupt number onto the stack. If this was not done, then it would not be possible to determine which type of exception or interrupt led to the common handler being called. Exercise 2: The INT 14 exception causes a GPF, not a page fault. This is the correct behavior, since the DPL of IDT vector 14 is 0, and the user process's CPL is 3. The user thus cannot trigger interrupt 14, and a GPF is caused by the protection violation. If the kernel allowed the INT 14 to trigger the page fault handler, the interrupt handler would not correctly generate the Trapframe since the INT call would not push an error code onto the stack, which is expected from a real page fault. This would cause the trap handler to behave incorrectly, probably causing a real page fault in the kernel. Challenge: I changed the IDTFNC and IDTFNC_NOEC macros in trapentry.S so that in addition to defining a trap procedure that calls _alltraps, it also writes the exception number and the address of the trap into a "pseudo-IDT" array. The addresses in this array can be relocated correctly by the linker at link time. At runtime, the idt_init function reads the entries from the pseudo-IDT and puts them into a correctly formatted IDT. Another (old) challenge: I finally got around to implementing the backtrace with symbol table support, using a technique provided by Austin Clements for placing the symbol table in the kernel image itself. The source code defines an array symtable that is initialized empty; after the kernel binary is created, a "splicer" program parses the kernel symbol table and ELF headers, identifies the location of the symtable array in the binary, and replaces it with an encoded form of the symbol table. At runtime, the kernel can then identify a symbolic name for an address by searching through the symtable. PART B ---------- Exercise 6: 1. The breakpoint test will generate a GPF if the breakpoint entry in the IDT has DPL < 3, and a breakpoint interrupt if the DPL is 3, because the test case operates in protection ring 3. So the breakpoint IDT entry's DPL should be set to 3. 2. These mechanism prevent user programs from triggering interrupts that should only be caused by hardware exceptions. This prevents the user from causing the kernel to execute interrupt handlers that will, e.g. cause a panic. Exercise 8: 1. The printf function in lib/printf.c uses the putchar() function to write the formatted output to the console. When linked into the kernel, this will be the kern/console.c function that actually prints to the console. When linked into a user program, which cannot access the console directly, it uses lib/console.c's putchar(), which uses a sys_cputs syscall to have the kernel call its console output functions.