3.2 Kernel address space
When it starts, xv6 creates a single page table describing the kernel’s address space. The kernel configures the layout of its address space to give itself access to physical memory and various hardware resources at predictable virtual addresses. Figure 3.3 shows how this layout maps kernel virtual addresses to physical addresses. The file (0200) declares the constants for xv6’s kernel memory layout.
QEMU simulates a computer that includes RAM (physical memory) starting at physical address 0x80000000 and continuing through at least 0x88000000, which xv6 calls PHYSTOP. The QEMU simulation also includes I/O devices such as a disk interface. QEMU exposes the device interfaces to software as memory-mapped control registers that sit below 0x80000000 in the physical address space. The kernel can interact with the devices by reading/writing these special physical addresses; such reads and writes communicate with the device hardware rather than with RAM. Chapter 4 explains how xv6 interacts with devices.
The kernel maps all physical RAM and device
registers at virtual addresses equal to the
physical addresses.
This is called “direct mapping,” and allows the kernel
to read or write physical address simply by loading
or storing to virtual address .
The kernel code itself is located at KERNBASE=0x80000000 in both
the virtual address space and in physical memory.
When kfork
(2373)
allocates user memory for the child process,
the allocator returns the physical address of that memory;
kfork uses that address directly as a virtual
address when it is copying the parent’s user memory to the child.
There are a couple of kernel virtual addresses that aren’t direct-mapped:
-
•
The trampoline page. It is mapped at the top of the virtual address space; user page tables have this same mapping. Chapter 4 discusses the role of the trampoline page, but we see here an interesting use case of page tables; a physical page (holding the trampoline code) is mapped twice in the virtual address space of the kernel: once at the top of the virtual address space and once with a direct mapping.
-
•
The kernel stack pages. Each process has its own kernel stack, which is mapped at a high kernel virtual address so that below it xv6 can leave an unmapped guard page. The guard page’s PTE is invalid (i.e.,
PTE_Vis not set), so that if the kernel overflows a kernel stack, it will likely cause a page fault and the kernel will panic. Without a guard page an overflowing stack would overwrite other kernel memory, resulting in incorrect operation. A panic crash is preferable.
While the kernel uses its stacks via the high-memory mappings, each is also accessible to the kernel through a direct-mapped address. An alternate design might have just the direct mapping, and use the stacks at the direct-mapped address. In that arrangement, however, providing guard pages would involve unmapping virtual addresses that would otherwise refer to physical memory, which would then be hard to use.
The kernel maps the pages for the trampoline and the kernel text with
the permissions
PTE_R
and
PTE_X, but not PTE_W.
The kernel maps other pages with the permissions
PTE_R
and
PTE_W,
but not PTE_X.
The mappings for the guard pages are invalid.
The purpose of these restricted permissions is to help
catch kernel bugs that access pages in unexpected
ways, for example if kernel code accidentally tried
to write over kernel instructions.
The kernel creates a single kernel page table, used by all CPUs when they execute in the kernel. xv6 does not modify the kernel page table after initially creating it.