Paul Torrez, Tim Hallner, Kiran Mathrani
12 November 2006
modified by Anu Bhaskar
10 December 2006
Topics
Single Level Page Table
Calling the pmap function with a virtual page number as an argument will return the physical page number associated with it:
pmap(vpn) {
return PTABLE[vpn];
}
2-Level Page Table
There is now a hierarchy of two different levels of tables, the first encountered being Level 1 and the second Level 0.
pmap(vpn) {
uvpn = vpn / 2^10;
lvpn = vpn % 2^10;
l0pt = PTABLE[uvpn];
if (l0pt == FAULT)
return FAULT;
return l0pt[lvpn];
}
Level 1 Level 0
For example, if the virtual address = 0x00002003 = 0 * 2^22 + 2 * 2^12 + 3, then
offset = 3
uvpn = 0
lvpn = 2
Assuming we only have a small program running that only uses one physical page number (49):
To implement this scenario with a 2-level page table we would need only one Level 1 page table and one Level 0 page table. Because each table takes 4 KB to store, our entire page table takes only 8 KB to store versus 4 MB in the Single Level case. 2-Level page tables save space in a sparse address space. x86 machines use a 2-Level page table.
On a context switch, the kernel loads a new pmap function:
pmap(va) can give different results depending on:Either return physical address or FAULT
<code> if (access_type == write) return fault; else return pa; </code> * Kernel-only mapping <code> if (cpl == user) //Remember Kernel must handle the context switch to preserve isolation return fault; else return pa; </code>
On a fault, the processor causes a trap, the kernel gets control, and the kernel runs the pfault function.
pfault(va, cpl, atype) { // page fault handler
- either: install a mapping and restart process at faulting instruction
- or: kill the process (segmentation fault)
}
Problems solved by virtual memory
swapmap(proc, va) {
- either: return disk address
- or: return FAIL
}
pfault(va, cpl, atype) {
if (swapmap(current, va) != FAIL) {
<process, va'> = removal_policy(); // process = process to steal page from, va' = which page to steal
pa = process->pmap(va');
write page pa to disk @ swapmap(process, va');
set process->pmap(va') to FAULT;
read disk @ swapmap(current, va) into page pa);
set current->pmap(va) to pa;
return;
}
else
kill;
}
Let's see how this process works.
If we didn't, than we would be infinitely creating more and more pages as more applications are run...
What would this result in?
Goal: Remove a page that won't be used and avoid "thrashing" - a high portion of accesses require a swap (because it's slow)
Note: If all memory accesses are uniformly random there is no good answer to the removal policy. We rely on Locality of Reference
| FIFO | 1 | 2 | 3 | 4 | 1 | 2 | 5 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| P1 | 1 | 1 | 1 | 4 | 4 | 4 | 5 | 5 | 5 | 5 | 5 | 5 |
| P2 | 2 | 2 | 2 | 1 | 1 | 1 | 1 | 1 | 3 | 3 | 3 | |
| P3 | 3 | 3 | 3 | 2 | 2 | 2 | 2 | 2 | 4 | 4 |
| Belady's | 1 | 2 | 3 | 4 | 1 | 2 | 5 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| P1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 3 | 3 | 3 |
| P2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 4 | 4 | |
| P3 | 3 | 4 | 4 | 4 | 5 | 5 | 5 | 5 | 5 | 5 |
| LRU | 1 | 2 | 3 | 4 | 1 | 2 | 5 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| P1 | 1 | 1 | 1 | 4 | 4 | 4 | 5 | 5 | 5 | 3 | 3 | 3 |
| P2 | 2 | 2 | 2 | 1 | 1 | 1 | 1 | 1 | 1 | 4 | 4 | |
| P3 | 3 | 3 | 3 | 2 | 2 | 2 | 2 | 2 | 5 | 5 |
| FIFO | 1 | 2 | 3 | 4 | 1 | 2 | 5 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| P1 | 1 | 1 | 1 | 1 | 1 | 1 | 5 | 5 | 5 | 5 | 4 | 4 |
| P2 | 2 | 2 | 2 | 2 | 2 | 2 | 1 | 1 | 1 | 1 | 5 | |
| P3 | 3 | 3 | 3 | 3 | 3 | 3 | 2 | 2 | 2 | 2 | ||
| P4 | 4 | 4 | 4 | 4 | 4 | 4 | 3 | 3 | 3 |
LRU and Belady's Optimal don't suffer from Belady's Annomally Stack Algorithms never suffer from Belady's annomally
Optimizations Page hasn't changed so there is no need to swap and Demand Paging