Virtual Addresses
A 32-bit virtual address can be divided into a 20-bit page number and a 12-bit page offset (or just offset), like this:
31 12 11 0
+-------------------+-----------+
| Page Number | Offset |
+-------------------+-----------+
Virtual Address
Macros and Functions
Work with Virtual Addresses
Header threads/vaddr.h defines these functions and macros for working with virtual addresses:
- Macro: PGSHIFT
- Macro: PGBITS
- The bit index (0) and number of bits (12) of the offset part of a virtual address, respectively.
- Macro: PGMASK
- A bit mask with the bits in the page offset set to 1, the rest set to 0 (0xfff).
- Macro: PGSIZE
- The page size in bytes (4,096).
- Function: unsigned pg_ofs (const void *va)
- Extracts and returns the page offset in virtual address va.
- Function: uintptr_t pg_no (const void *va)
- Extracts and returns the page number in virtual address va.
- Function: void *pg_round_down (const void *va)
- Returns the start of the virtual page that va points within, that is, va with the page offset set to 0.
- Function: void *pg_round_up (const void *va)
- Returns va rounded up to the nearest page boundary.
Work with User/Kernel Virtual Memory Boundary
Virtual memory in Pintos is divided into two regions: user virtual memory and kernel virtual memory. The boundary between them is PHYS_BASE:
- Macro: PHYS_BASE
- Base address of kernel virtual memory.
- It defaults to 0xc0000000 (3 GB), but it may be changed to any multiple of 0x10000000 from 0x80000000 to 0xf0000000.
- User virtual memory ranges from virtual address 0 up to
PHYS_BASE. Kernel virtual memory occupies the rest of the virtual address space, fromPHYS_BASEup to 4 GB.
- Function: bool is_user_vaddr (const void *va)
- Function: bool is_kernel_vaddr (const void *va)
- Returns true if va is a user or kernel virtual address, respectively, false otherwise.
Work with Mapping Kernel VM One-to-One to PM
The 80x86 doesn’t provide any way to directly access memory given a physical address. This ability is often necessary in an operating system kernel, so Pintos works around it by mapping kernel virtual memory one-to-one to physical memory.
- That is, virtual address
PHYS_BASEaccesses physical address 0, virtual addressPHYS_BASE+ 0x1234 accesses physical address 0x1234, and so on up to the size of the machine’s physical memory. - Thus, adding**
PHYS_BASEto a physical address obtains a kernel virtual address that accesses that address; conversely, subtractingPHYS_BASE**from a kernel virtual address obtains the corresponding physical address.
Header threads/vaddr.h provides a pair of functions to do these translations:
- Function: void *ptov (uintptr_t pa)
- Returns the kernel virtual address corresponding to physical address pa, which should be between 0 and the number of bytes of physical memory.
- Function: uintptr_t vtop (void *va)
- Returns the physical address corresponding to va, which must be a kernel virtual address.