MIT 6.828 JOS Lab 4 Report
MIT 6.828: JOS Lab
Lab 4: Preemptive Multitasking
Part A: Multiprocessor Support and Cooperative Multitasking
Questions
Answer the following questions:
- Compare
kern/mpentry.S
side by side withboot/boot.S
. Bearing in mind thatkern/mpentry.S
is compiled and linked to run aboveKERNBASE
just like everything else in the kernel, what is the purpose of macroMPBOOTPHYS
? Why is it necessary inkern/mpentry.S
but not inboot/boot.S
? In other words, what could go wrong if it were omitted inkern/mpentry.S
?
Hint: recall the differences between the link address and the load address that we have discussed in Lab 1.
- The
MPBOOTPHYS
macro is needed becausempentry.S
is linked at high addresses but gets loaded byboot_aps()
at the low addressMPENTRY_ADDR
. The bootloader doesn't need a macro like this because it is linked and loaded at the same low address (0x00007c00
).
Questions
- It seems that using the big kernel lock guarantees that only one CPU can run the kernel code at a time. Why do we still need separate kernel stacks for each CPU? Describe a scenario in which using a shared kernel stack will go wrong, even with the protection of the big kernel lock.
- During a trap/interrupt, the trapframe is pushed onto the stack without holding the kernel lock. Say CPU 1 enters the kernel on a system call and while it is in the kernel, CPU 2 attempts to enter the kernel on a timer interrupt. CPU 2 can't enter the kernel, it will be spinning at the lock in
trap()
. However, it will have pushed its trap frame on top of the trap frame already pushed by CPU 1. This of course means that when CPU 1 returns to user mode, it will pop off CPU 2's frame and return in that environment instead of its own.
Questions
- In your implementation of
env_run()
you should have calledlcr3()
. Before and after the call tolcr3()
, your code makes references (at least it should) to the variablee
, the argument toenv_run
. Upon loading the%cr3
register, the addressing context used by the MMU is instantly changed. But a virtual address (namelye
) has meaning relative to a given address context--the address context specifies the physical address to which the virtual address maps. Why can the pointere
be dereferenced both before and after the addressing switch?- Whenever the kernel switches from one environment to another, it must ensure the old environment's registers are saved so they can be restored properly later. Why? Where does this happen?
- Because all environment page directories share certain mappings. The
envs
array is allocated and mapped toUENVS
inmem_init()
and those mappings are then copied to all new page directories inenv_setup_vm()
. - It's a like the caller/callee save calling convention except here it is for interrupting the whole process. Processes keep temporary data and variables in registers and the process assumes that when it returns, all those values will still be there. The registers are saved on the user environment's stack as part of the trapframe constructed by the
int
instruction and the code inalltraps
. To restore the state of a new process, JOS uses theenv_pop_tf()
function, which switches first to the new process' stack and the pops all the registers in place.