MIT 6.828: JOS Lab
Lab 4: Preemptive Multitasking
Part A: Multiprocessor Support and Cooperative Multitasking
Answer the following questions:
kern/mpentry.Sside by side with
boot/boot.S. Bearing in mind that
kern/mpentry.Sis compiled and linked to run above
KERNBASEjust like everything else in the kernel, what is the purpose of macro
MPBOOTPHYS? Why is it necessary in
kern/mpentry.Sbut not in
boot/boot.S? In other words, what could go wrong if it were omitted in
Hint: recall the differences between the link address and the load address that we have discussed in Lab 1.
MPBOOTPHYSmacro is needed because
mpentry.Sis linked at high addresses but gets loaded by
boot_aps()at the low address
MPENTRY_ADDR. The bootloader doesn't need a macro like this because it is linked and loaded at the same low address (
- 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.
- In your implementation of
env_run()you should have called
lcr3(). Before and after the call to
lcr3(), your code makes references (at least it should) to the variable
e, the argument to
env_run. Upon loading the
%cr3register, the addressing context used by the MMU is instantly changed. But a virtual address (namely
e) has meaning relative to a given address context--the address context specifies the physical address to which the virtual address maps. Why can the pointer
ebe 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
envsarray is allocated and mapped to
mem_init()and those mappings are then copied to all new page directories in
- 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
intinstruction and the code in
alltraps. To restore the state of a new process, JOS uses the
env_pop_tf()function, which switches first to the new process' stack and the pops all the registers in place.