Machine, supervisor and user mode, the control and status registers xv6 uses, what the hardware does on a trap, mret and sret, and why every CSR belongs to one hart.
1warm-upChoose one
start runs in machine mode and wants main to run in supervisor
mode. Why does it write mstatus.MPP and mepc and then execute mret, instead of
switching modes directly?
Just before mret, start copies the hart ID into the ordinary register tp.
From then on cpuid returns tp. Why not just read mhartid whenever the ID is
needed?
kernel/start.c
46// keep each CPU's hartid in its tp register, for cpuid().
After kvminithart, gdb reads satp = 0x8000000000087fff on every hart. Decode it
as an Sv39 satp (MODE in bits 63–60, ASID in bits 59–44, PPN in bits 43–0).
A user program has just executed ecall. The hart is about to run the first instruction
of uservec, line 32. Fill in its state. (For the stack, count it only if the code
running here may push onto it; see The stacks of xv6.)
How many places in the kernel’s source write satp (count each w_satp(...) call and
each csrw satp instruction, not the helper’s definition in riscv.h)?
decimal, 0x hex or 0b binary
15solidChoose all that apply
Hart 0 executes each of these. Which ones can affect what hart 1 sees or does?
Choose all that apply.
16solidChoose one
usertrap panics on line 43 if the trap did not come from user mode. How does it know
where the trap came from?
Put the steps of a return to user mode in order, from prepare_return to the sret.
stvec = uservec in the trampoline
intr_off(): clear sstatus.SIE
fill the trapframe’s kernel_satp, kernel_sp, kernel_trap, kernel_hartid
write sstatus with SPP = 0 and SPIE = 1
sepc = p->trapframe->epc
ld sp, 48(a0): the user’s sp
sret
csrw satp, a0: user page table
18solidChoose one
timerinit asks for the first timer interrupt 0.1 s after boot. Hart 0 spends about
1.5 s in main building the kernel. When is hart 0’s first timer interrupt
actually taken?
xv6 has no machine-mode trap handler. timerinit therefore enables the Sstc extension
(menvcfg.STCE) and uses stimecmp. Why couldn’t xv6 just use the classic machine
timer (mtimecmp) and rely on mideleg = 0xffff?
In a scratch copy of xv6, line 62 (w_mcounteren(r_mcounteren() | 2)) is deleted. The
kernel finishes main on hart 0 and enters the scheduler. What happens next?
xv6’s PTEs never set the A (accessed) and D (dirty) bits. Line 41 sets menvcfg.ADUE
(QEMU happens to set it already at reset). On a machine where it starts at 0, what would
happen if line 41 were missing?
kernel/start.c
40// enable hardware updates of page table A and D bits
True or false: if prepare_return left sstatus.SPIE at 0 (so that sret sets
SIE to 0), a user program spinning in an infinite loop could never be preempted by the
timer.
A trap from user mode always sets sstatus.SPP to 0. Yet prepare_return clears
SPP explicitly on line 126 before every return to user mode. Why is that necessary?
kernel/trap.c
121// set up the registers that trampoline.S's sret will use
A kernel thread is preempted by a timer interrupt (it calls yield from
kerneltrap) and is later resumed by a scheduler, possibly on another hart. When it
runs again, which of these may hold a different value from the moment before it yielded?
Choose all that apply.