Test yourself · category 4 of 20
Trampoline and trapframe The border between user and kernel - one trampoline page mapped at the same address in every page table, one trapframe page per process, and the stackless assembly in uservec and userret that crosses it in both directions.
All Not yet answered Got wrong Reset this category
proc_pagetable maps the trampoline page at TRAMPOLINE in every user page table,
and kvmmake maps the same page at the same address in the kernel page table. Why must
the address be the same in both?
kernel/proc.c
185 // map the trampoline code (for system call return)
186 // at the highest user virtual address.
187 // only the supervisor uses it, on the way
188 // to/from user space, so not PTE_U.
Check Try again
The first instruction of uservec is csrw sscratch, a0. Why does it start there?
kernel/trampoline.S
24 # trap.c sets stvec to point here, so
25 # traps from user space start here,
26 # in supervisor mode, but with a
30 # save user a0 in sscratch so
31 # a0 can be used to get at TRAPFRAME.
34 # each process has a separate p->trapframe memory area,
35 # but it's mapped to the same virtual address
36 # (TRAPFRAME) in every process's user page table.
Check Try again
What is the virtual address TRAPFRAME in this kernel? (Answer in hex.)
kernel/memlayout.h
46 // map the trampoline page to the highest address,
47 // in both user and kernel space.
50 // map kernel stacks beneath the trampoline,
51 // each surrounded by invalid guard pages.
57 // original data and bss
61 // TRAPFRAME (p->trapframe, used by the trampoline)
62 // TRAMPOLINE (the same page as in the kernel)
Check Try again
4 warm-up True or false, and why True or false: every process has its own trampoline page.
Check Try again
How many general-purpose registers does uservec save into the trapframe?
kernel/trampoline.S
39 # save the user registers in TRAPFRAME
71 # save the user a0 in p->trapframe->a0
Check Try again
In userret , one register must be restored last. Click the line that restores it.
kernel/trampoline.S
116 # restore all but a0 from TRAPFRAME
151 # return to user mode and user pc.
152 # prepare_return() sets up sstatus and sepc.
Your pick: none yet (click a line in the code)
Check Try again
Put the steps of userret in the order it executes them.
kernel/trampoline.S
102 # usertrap() returns here, with user satp in a0.
103 # return from kernel to user.
105 # flush icache, in case this is the first time
106 # we're running this proc on this hart.
109 # switch to the user page table.
110 sfence.vma zero , zero
112 sfence.vma zero , zero
116 # restore all but a0 from TRAPFRAME
151 # return to user mode and user pc.
152 # prepare_return() sets up sstatus and sepc.
fence.i: make this hart’s instruction fetches see what is now in memory↑ ↓ sret: drop to user mode at sepc↑ ↓ li a0, TRAPFRAME↑ ↓ load sp and the other user registers, except a0 ↑ ↓ ld a0, 112(a0): the user’s a0↑ ↓ csrw satp, a0 between two sfence.vma: install the user page table↑ ↓ Check Try again
Neither the TRAMPOLINE nor the TRAPFRAME mapping has PTE_U. What does that achieve?
kernel/proc.c
185 // map the trampoline code (for system call return)
186 // at the highest user virtual address.
187 // only the supervisor uses it, on the way
188 // to/from user space, so not PTE_U.
195 // map the trapframe page just below the trampoline page, for
Check Try again
Match each load in the trampoline with what it fetches from the trapframe.
kernel/trampoline.S
75 # initialize kernel stack pointer, from p->trapframe->kernel_sp
78 # make tp hold the current hartid, from p->trapframe->kernel_hartid
81 # load the address of usertrap(), from p->trapframe->kernel_trap
84 # fetch the kernel page table address, from p->trapframe->kernel_satp.
ld sp, 8(a0) in uservecchoose… the top of this process’s kernel stack the satp value of the kernel page table the user’s stack pointer the ID of this hart the address of usertrap ld tp, 32(a0) in uservecchoose… the top of this process’s kernel stack the satp value of the kernel page table the user’s stack pointer the ID of this hart the address of usertrap ld t0, 16(a0) in uservecchoose… the top of this process’s kernel stack the satp value of the kernel page table the user’s stack pointer the ID of this hart the address of usertrap ld t1, 0(a0) in uservecchoose… the top of this process’s kernel stack the satp value of the kernel page table the user’s stack pointer the ID of this hart the address of usertrap ld sp, 48(a0) in userretchoose… the top of this process’s kernel stack the satp value of the kernel page table the user’s stack pointer the ID of this hart the address of usertrap
Check Try again
Line 76 puts the kernel-stack address into sp, but at that moment the address is not
mapped. Click the line that installs the page table in which it maps the kernel stack.
kernel/trampoline.S
75 # initialize kernel stack pointer, from p->trapframe->kernel_sp
78 # make tp hold the current hartid, from p->trapframe->kernel_hartid
81 # load the address of usertrap(), from p->trapframe->kernel_trap
84 # fetch the kernel page table address, from p->trapframe->kernel_satp.
87 # wait for any previous memory operations to complete, so that
88 # they use the user page table.
91 # install the kernel page table.
94 # flush now-stale user entries from the TLB.
Your pick: none yet (click a line in the code)
Check Try again
11 solid Fill in the machine state A process has just made a system call. Hart 0 has executed line 76 of uservec ,
ld sp, 8(a0), and nothing after it. What is its state? (For stack, give the stack the
hart could safely push to right now; see The stacks of xv6 .)
kernel/trampoline.S
75 # initialize kernel stack pointer, from p->trapframe->kernel_sp
78 # make tp hold the current hartid, from p->trapframe->kernel_hartid
81 # load the address of usertrap(), from p->trapframe->kernel_trap
84 # fetch the kernel page table address, from p->trapframe->kernel_satp.
87 # wait for any previous memory operations to complete, so that
88 # they use the user page table.
91 # install the kernel page table.
94 # flush now-stale user entries from the TLB.
Privilege mode choose… M (machine) S (supervisor) U (user) Active stack choose… user stack the process's kernel stack scheduler stack (stack0) boot stack (stack0) no usable stack Page table (satp) choose… paging off kernel page table user page table Interrupts (sstatus.SIE) choose… on off
Check Try again
gdb shows sstatus = 0x8000000200006020 on hart 0 at the sret in userret . Decode
the bits xv6 cares about.
Value: 0x8000000200006020
SIE (bit 1), now choose… 0 (interrupts off) 1 (interrupts on) SPIE (bit 5) choose… 1 0 SPP (bit 8): the mode sret returns to choose… user mode supervisor mode SIE right after sret choose… 1 0
Check Try again
forkret computes MAKE_SATP(p->pagetable) for init and gets 0x8000000000087f52.
Decode it.
Value: 0x8000000000087f52
MODE (bits 63-60) choose… 8: Sv39 paging 0: paging off 9: Sv48 paging PPN (low 44 bits) choose… 0x87f52 0x87f52000 0x8000000000087f52 Physical address of the root page table choose… 0x87f52000 0x87f52 0x3ffffff000 Does writing this value into satp also flush the TLB? choose… no: that takes sfence.vma yes
Check Try again
prepare_return calls intr_off() (line 108) before it points stvec at
uservec (line 112). What would go wrong if an interrupt could arrive after line 112?
kernel/trap.c
105 // we're about to switch the destination of traps from
106 // kerneltrap() to usertrap(). because a trap from kernel
107 // code to usertrap would be a disaster, turn off interrupts.
110 // send syscalls, interrupts, and exceptions to uservec in trampoline.S
Check Try again
15 solid Choose all that apply kernel/trap.c
105 // we're about to switch the destination of traps from
106 // kerneltrap() to usertrap(). because a trap from kernel
107 // code to usertrap would be a disaster, turn off interrupts.
110 // send syscalls, interrupts, and exceptions to uservec in trampoline.S
114 // set up trapframe values that uservec will need when
115 // the process next traps into the kernel.
121 // set up the registers that trampoline.S's sret will use
122 // to get to user space.
124 // set S Previous Privilege mode to User.
130 // set S Exception Program Counter to the saved user pc.
Check Try again
16 solid Choose all that apply Which of these are sret’s own doing, done by the hardware when userret executes it?
kernel/trampoline.S
151 # return to user mode and user pc.
152 # prepare_return() sets up sstatus and sepc.
Check Try again
17 deep Choose all that apply Which of these are the same for every process in this kernel?
Check Try again
Hart 0 (running cat) and hart 1 (running grep) both execute sd ra, 40(a0) in
uservec at the same instant, both with a0 = 0x3fffffe000. Why does neither
overwrite the other’s saved ra?
kernel/trampoline.S
39 # save the user registers in TRAPFRAME
Check Try again
In this tree, what does sscratch hold while a process runs in user mode?
Check Try again
usertrap computes the user satp at the very end and hands it to userret in a0.
Why not reuse the satp value that was installed when the trap arrived?
kernel/trap.c
84 // give up the CPU if this is a timer interrupt.
90 // the user page table to switch to, for trampoline.S
93 // return to trampoline.S; satp value in a0.
Check Try again
A process lives in proc[2]. What value does prepare_return store in its
trapframe->kernel_sp? (Answer in hex.)
kernel/memlayout.h
46 // map the trampoline page to the highest address,
47 // in both user and kernel space.
50 // map kernel stacks beneath the trampoline,
51 // each surrounded by invalid guard pages.
Check Try again
uservec reaches usertrap with ld t0, 16(a0) … jalr t0 instead of simply
call usertrap. Why?
kernel/trampoline.S
75 # initialize kernel stack pointer, from p->trapframe->kernel_sp
78 # make tp hold the current hartid, from p->trapframe->kernel_hartid
81 # load the address of usertrap(), from p->trapframe->kernel_trap
84 # fetch the kernel page table address, from p->trapframe->kernel_satp.
87 # wait for any previous memory operations to complete, so that
88 # they use the user page table.
91 # install the kernel page table.
94 # flush now-stale user entries from the TLB.
Check Try again
Imagine a bug that leaves the TRAPFRAME mapping out of a process’s page table. What
happens the first time that process traps into the kernel?
kernel/trampoline.S
30 # save user a0 in sscratch so
31 # a0 can be used to get at TRAPFRAME.
34 # each process has a separate p->trapframe memory area,
35 # but it's mapped to the same virtual address
36 # (TRAPFRAME) in every process's user page table.
39 # save the user registers in TRAPFRAME
Check Try again
24 deep True or false, and why True or false: in this kernel, the twelve loads ld s0 … ld s11 in userret are
redundant on every return to user mode, because the s registers already hold the user’s
values when usertrap returns.
kernel/trampoline.S
116 # restore all but a0 from TRAPFRAME
Check Try again
uservec sets tp from trapframe->kernel_hartid, a value written by
prepare_return the last time this process left the kernel. Why is it guaranteed to be
the ID of the hart now executing uservec?
kernel/trap.c
114 // set up trapframe values that uservec will need when
115 // the process next traps into the kernel.
Check Try again
← Traps and system calls All categories Interrupts, the PLIC and the timer →