xv6, line by line
test yourself

Test yourself · category 13 of 20

Page tables and address spaces

Sv39 page tables in this kernel, from PTE bits and walk() to the kernel’s direct map, the trampoline mapped twice, satp and the TLB on each hart, and what a user address space really contains.

1warm-upChoose one

In kvminithart, line 80 turns paging on with csrw satp. Nothing jumps to a new address afterwards: the program counter simply moves on to the next instruction. Why does that next instruction (the second sfence.vma) still get fetched correctly?

kernel/vm.c
72// Switch the current CPU's h/w page table register to
73// the kernel's page table, and enable paging.
74void
77 // wait for any previous writes to the page table memory to finish.
82 // flush stale entries from the TLB.
2warm-upType a number

A page-table page in Sv39 is one 4096-byte page. How many page-table entries (PTEs) does it hold?

kernel/vm.c
86// Return the address of the PTE in page table pagetable
87// that corresponds to virtual address va. If alloc!=0,
88// create any required page-table pages.
89//
90// The risc-v Sv39 scheme has three levels of page-table
91// pages. A page-table page contains 512 64-bit PTEs.
92// A 64-bit virtual address is split into five fields:
93// 39..63 -- must be zero.
94// 30..38 -- 9 bits of level-2 index.
95// 21..29 -- 9 bits of level-1 index.
96// 12..20 -- 9 bits of level-0 index.
97// 0..11 -- 12 bits of byte offset within the page.
decimal, 0x hex or 0b binary
3solidDecode the bits

Right after exec, the level-0 PTE for sh’s data page (virtual 0x2000) read 0x21fce817 in our run. Decode it using the macros in kernel/riscv.h.

kernel/riscv.h
395#define PTE_V (1L << 0) // valid
396#define PTE_R (1L << 1)
397#define PTE_W (1L << 2)
398#define PTE_X (1L << 3)
399#define PTE_U (1L << 4) // user can access
401// shift a physical address to the right place for a PTE.
402#define PA2PTE(pa) ((((uint64)pa) >> 12) << 10)
404#define PTE2PA(pte) (((pte) >> 10) << 12)
406#define PTE_FLAGS(pte) ((pte) & 0x3FF)

Value: 0x21fce817

4solidType a number

TRAMPOLINE is 0x3ffffff000. What is its index in the root (level-2) page-table page, PX(2, TRAMPOLINE)?

kernel/riscv.h
408// extract the three 9-bit page table indices from a virtual address.
409#define PXMASK 0x1FF // 9 bits
410#define PXSHIFT(level) (PGSHIFT + (9 * (level)))
411#define PX(level, va) ((((uint64)(va)) >> PXSHIFT(level)) & PXMASK)
413// one beyond the highest possible virtual address.
414// MAXVA is actually one bit less than the max allowed by
415// Sv39, to avoid having to sign-extend virtual addresses
416// that have the high bit set.
417#define MAXVA (1L << (9 + 9 + 9 + 12 - 1))
decimal, 0x hex or 0b binary
5solidChoose one

Sv39 can translate 39-bit virtual addresses, 512 GiB. Why does xv6 set MAXVA to 1 << 38 (256 GiB) instead?

kernel/riscv.h
413// one beyond the highest possible virtual address.
414// MAXVA is actually one bit less than the max allowed by
415// Sv39, to avoid having to sign-extend virtual addresses
416// that have the high bit set.
417#define MAXVA (1L << (9 + 9 + 9 + 12 - 1))
6warm-upTrue or false, and why

True or false: every xv6 user page table maps the whole kernel, protected from the program only by leaving PTE_U clear.

Why?

7solidClick the line

Click the line in walk without which a freshly allocated page-table page would be full of entries that look valid, so that walk would follow garbage pointers or mappages would panic with “remap”.

kernel/vm.c
101 if (va >= MAXVA)
102 panic("walk");
104 for (int level = 2; level > 0; level--) {
106 if (*pte & PTE_V) {
108 } else {
109 if (!alloc || (pagetable = (pde_t *)kalloc()) == 0)
110 return 0;
113 }
114 }
115 return &pagetable[PX(0, va)];

Your pick: none yet (click a line in the code)

8warm-upChoose all that apply

sh’s address space has these pages. Which of them have PTE_U set, so that sh itself, in user mode, may touch them?

9solidChoose one

Line 47 of kvmmake maps the trampoline page at TRAMPOLINE, although the direct map (line 39) already covers its physical page 0x80006000. Why is this second mapping necessary?

kernel/vm.c
38 // map kernel text executable and read-only.
41 // map kernel data and the physical RAM we'll make use of.
45 // map the trampoline for trap entry/exit to
46 // the highest virtual address in the kernel.
10deepChoose one

A buggy program passes its trapframe’s address, 0x3fffffe000, as a buffer to a system call, and the kernel calls copyout(p->pagetable, p->sz, 0x3fffffe000, src, 8). The page is mapped in the user table (R W, no U). What happens?

kernel/vm.c
344int
350 while (len > 0) {
352 if (va0 >= MAXVA)
353 return -1;
356 if (pa0 == 0) {
357 if ((pa0 = vmfault(pagetable, psz, va0, 0)) == 0) {
358 return -1;
359 }
360 }
363 // forbid copyout over read-only user text pages.
364 if ((*pte & PTE_W) == 0)
365 return -1;
367 n = PGSIZE - (dstva - va0);
368 if (n > len)
369 n = len;
370 memmove((void *)(pa0 + (dstva - va0)), src, n);
372 len -= n;
373 src += n;
375 }
376 return 0;
11solidPut in order

sh runs lb a5, 0(a0) with a0 = 0x2020 in user mode, and the translation is not in the TLB. Put the hardware’s steps in order.

  1. Read the level-2 PTE at index bits 38…30 (0); it has V and no R/W/X, so follow it
  2. Take the root page-table page’s physical address from satp’s PPN field
  3. Add the offset 0x020 to the leaf’s page address and load the byte
  4. Read the level-1 PTE at index bits 29…21 (0) and follow it
  5. Look up virtual page 0x2 in this hart’s TLB, and miss
  6. Read the level-0 PTE at index bits 20…12 (2) and check V, U and R
12warm-upMatch the pairs

Match each macro from kernel/riscv.h with what it computes.

13warm-upChoose one

Hart 0 runs sh and hart 2 runs ls. At the same instant both execute a load from virtual address 0x0. Why don’t they interfere?

14solidType a number

Line 36 of kvmmake maps the PLIC: 64 MiB (0x4000000) starting at 0x0c000000. The level-2 and level-1 tables for the first GiB already exist. How many level-0 page-table pages does walk allocate for this one call?

kernel/vm.c
29 // uart registers
32 // virtio mmio disk interface
35 // PLIC
36 kvmmap(kpgtbl, PLIC, PLIC, 0x4000000, PTE_R | PTE_W);
decimal, 0x hex or 0b binary
15solidDecode the bits

gdb shows satp = 0x8000000000087f41 on a hart. In this build the kernel’s root page is at 0x87fff000. Decode it.

Value: 0x8000000000087f41

16deepFill in the machine state

Hart 1 has left its spin loop in main, printed hart 1 starting, and has just executed the csrw satp on line 80 of kvminithart (called from main line 39). What is hart 1’s state?

kernel/vm.c
72// Switch the current CPU's h/w page table register to
73// the kernel's page table, and enable paging.
74void
77 // wait for any previous writes to the page table memory to finish.
82 // flush stale entries from the TLB.
17warm-upChoose one

Hart 0 executed sfence.vma around its csrw satp at boot. Why must harts 1 and 2 run kvminithart, with its own two sfence.vma, for themselves?

kernel/vm.c
72// Switch the current CPU's h/w page table register to
73// the kernel's page table, and enable paging.
74void
77 // wait for any previous writes to the page table memory to finish.
82 // flush stale entries from the TLB.
18solidTrue or false, and why

True or false: because three harts translate through kernel_pagetable at the same time, xv6 must protect it with a lock.

Why?

19deepChoose one

Suppose a buggy kernel function, handling sh’s read(0, buf, 100), did *(char *)0x2020 = 'l' with the user’s address (buf is at 0x2020). What would happen?

20solidChoose one

With KSTACK(p) = TRAMPOLINE - (p+1) × 2 × PGSIZE, what is mapped at virtual address 0x3fffffc000 in the kernel page table?

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.
52#define KSTACK(p) (TRAMPOLINE - ((p) + 1) * 2 * PGSIZE)
21deepChoose one

Why does proc_freepagetable unmap TRAMPOLINE and TRAPFRAME (with do_free = 0) before calling uvmfree?

kernel/proc.c
207// Free a process's page table, and free the
208// physical memory it refers to.
209void
22solidChoose all that apply

Which of these mappings in the kernel page table have PTE_X (executable) set?

kernel/vm.c
29 // uart registers
32 // virtio mmio disk interface
35 // PLIC
36 kvmmap(kpgtbl, PLIC, PLIC, 0x4000000, PTE_R | PTE_W);
38 // map kernel text executable and read-only.
41 // map kernel data and the physical RAM we'll make use of.
45 // map the trampoline for trap entry/exit to
46 // the highest virtual address in the kernel.
49 // allocate and map a kernel stack for each process.
23deepChoose all that apply

sh’s layout: code 0x0–0x1fff (R X U), data 0x2000 (R W U), guard 0x3000 (R W), stack 0x4000 (R W U), sz = 0x5000, trapframe at 0x3fffffe000 (R W). Which of these, executed by sh in user mode, raise a page fault?

24warm-upChoose one

What does the satp register give the hardware?

kernel/riscv.h
245// use riscv's sv39 page table scheme.
246#define SATP_SV39 (8L << 60)
248#define MAKE_SATP(pagetable) (SATP_SV39 | (((uint64)pagetable) >> 12))
25deepType a number

sh’s page table uses 5 page-table pages (root; a level-1 and a level-0 page for the bottom; a level-1 and a level-0 page for the top). If its heap grew eagerly from 0x5000 by 4 MiB (to sz = 0x405000), how many page-table pages would the table use in total?

decimal, 0x hex or 0b binary