Yangbo's Blog

MIT 6.828 Lab2 - Memory Management

The first PCs, which were based on the 16-bit Intel 8088 processor, were only capable of addressing 1MB of physical memory. The physical address space of an early PC would therefore start at 0x00000000 but end at 0x000FFFFF instead of 0xFFFFFFFF. The 640KB area marked “Low/Base Memory” was the only random-access memory (RAM) that an early PC could use.

PC’s Physical Address Space

A PC’s physical address space is hard-wired to have the following general layout:

The 384KB area from 0x000A0000 through 0x000FFFFF was reserved by the hardware for special uses such as video display buffers and firmware held in non-volatile memory. The most important part of this reserved area is the Basic Input/Output System (BIOS), which occupies the 64KB region from 0x000F0000 through 0x000FFFFF. In early PCs the BIOS was held in true read-only memory (ROM), but current PCs store the BIOS in updateable flash memory. The BIOS is responsible for performing basic system initialization such as activating the video card and checking the amount of memory installed. After performing this initialization, the BIOS loads the operating system from some appropriate location such as floppy disk, hard disk, CD-ROM, or the network, and passes control of the machine to the operating system.

When Intel finally “broke the one megabyte barrier” with the 80286 and 80386 processors, which supported 16MB and 4GB physical address spaces respectively, the PC architects nevertheless preserved the original layout for the low 1MB of physical address space in order to ensure backward compatibility with existing software. Modern PCs therefore have a “hole” in physical memory from 0x000A0000 to 0x00100000, dividing RAM into “low” or “conventional memory” (the first 640KB) and “extended memory” (everything else). In addition, some space at the very top of the PC’s 32-bit physical address space, above all physical RAM, is now commonly reserved by the BIOS for use by 32-bit PCI devices. Recent x86 processors can support more than 4GB of physical RAM, so RAM can extend further above 0xFFFFFFFF. In this case the BIOS must arrange to leave a second hole in the system’s RAM at the top of the 32-bit addressable region, to leave room for these 32-bit devices to be mapped.

Memory Management

For 32-bit architecture PCs, there are two stages of memory management:

1
2
3
4
5
6
1. Segment-based memory management:
Allocate => segments
Arbitrate => segment registers
2. Page-based memory management:
Allocate => pages -> page frames
Arbitrate => page tables

The calculation of the single-level/flat page table size:

1
2
3
4
- Page table entry (PTE) => 4 bytes, including PFN (physical page frame number) and flags
- Virtual page number (VPN) => 2^32 / page_size
- Page size => 4KB
page_table_size = (2^32 / 2^12) * 4B = 4MB per process, consumes lots of memory

Adding levels to the address translation process (hierarchical page tables) will reduce the size of the page tables. But it will add some overheads to the address translation process.

1
2
3
4
5
6
Flat page table:
- x1 accesses to page table entries
- x1 access to memory
2-level page table:
- x2 accesses to page table entries
- x1 access to memory

The image below summarizes both phases of the transformation from a logical address to a physical address when paging is enabled. The page translation mechanism uses 2-level page tables to converts the Dir, Table, and Offset fields of a linear address into the physical address:

The addressing mechanism uses the Dir field as an index into a page directory, uses the Table field as an index into the page table determined by the page directory, and uses the Offset field to address a byte within the page determined by the page table. The physical page number (PPN) specifies the physical starting address of a page. Because pages are located on 4K boundaries, the low-order 12 bits (from bit 12 to bit 23) are always zero. In a page directory, the PPN is the address of a page table. In a second-level page table, the PPN is the address of the physical page frame that contains the desired memory operand.

Exercises

The solution code for the exercises of Lab 2 can be found here.

Exercise 1

When implementing the page_init function, it’s worth mentioning that the page tables were not allocated to physical memory address UTEMP (defined in inc/memlayout.h); instead, because in function mem_init the page directories and page tables were allocated using function boot_alloc, therefore, simply using boot_alloc(0) can point to the first free page after the memory chunk that stores page tables.

Exercise 2

For details about the segmentation mechanism, read the 10th and 11th chapters of book x86 Assembly Language - from Real Mode to Protected Mode. The paging machanism can be learnt from the lesson P3L2: Memory Management of the online Udacity course Introduction to Operating System, as well as the Intel 30386 Reference Manual.

Exercise 3

Inspect memory at corresponding physical (in QEMU monitor) and virtual addresses (in GDB):

1
2
3
4
5
6
7
8
9
10
11
(qemu) x/16x 0x100000
00100000: 0x1badb002 0x00000000 0xe4524ffe 0x7205c766
00100010: 0x34000004 0x2000b812 0x220f0011 0xc0200fd8
00100020: 0x0100010d 0xc0220f80 0x10002fb8 0xbde0fff0
00100030: 0x00000000 0x112000bc 0x0002e8f0 0xfeeb0000
(gdb) x/16x 0xf0100000
0xf0100000 <_start+4026531828>: 0x1badb002 0x00000000 0xe4524ffe 0x7205c766
0xf0100010 <entry+4>: 0x34000004 0x2000b812 0x220f0011 0xc0200fd8
0xf0100020 <entry+20>: 0x0100010d 0xc0220f80 0x10002fb8 0xbde0fff0
0xf0100030 <relocated+1>: 0x00000000 0x112000bc 0x0002e8f0 0xfeeb0000

Inspect detailed representation of the current page tables in QEMU monitor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(qemu) info pg
VPN range Entry Flags Physical page
[00000-003ff] PDE[000] ----A----P
[00000-00000] PTE[000] --------WP 00000
[00001-0009f] PTE[001-09f] ---DA---WP 00001-0009f
[000a0-000b7] PTE[0a0-0b7] --------WP 000a0-000b7
[000b8-000b8] PTE[0b8] ---DA---WP 000b8
[000b9-000ff] PTE[0b9-0ff] --------WP 000b9-000ff
[00100-00102] PTE[100-102] ----A---WP 00100-00102
[00103-00110] PTE[103-110] --------WP 00103-00110
[00111-00111] PTE[111] ---DA---WP 00111
[00112-00113] PTE[112-113] --------WP 00112-00113
[00114-003ff] PTE[114-3ff] ---DA---WP 00114-003ff
[f0000-f03ff] PDE[3c0] ----A---WP
[f0000-f0000] PTE[000] --------WP 00000
[f0001-f009f] PTE[001-09f] ---DA---WP 00001-0009f
[f00a0-f00b7] PTE[0a0-0b7] --------WP 000a0-000b7
[f00b8-f00b8] PTE[0b8] ---DA---WP 000b8
[f00b9-f00ff] PTE[0b9-0ff] --------WP 000b9-000ff
[f0100-f0102] PTE[100-102] ----A---WP 00100-00102
[f0103-f0110] PTE[103-110] --------WP 00103-00110
[f0111-f0111] PTE[111] ---DA---WP 00111
[f0112-f0113] PTE[112-113] --------WP 00112-00113
[f0114-f03ff] PTE[114-3ff] ---DA---WP 00114-003ff

Show ranges of virtual memory that are mapped and their permissions in QEMU monitor:

1
2
3
(qemu) info mem
0000000000000000-0000000000400000 0000000000400000 -r-
00000000f0000000-00000000f0400000 0000000000400000 -rw

Ctrl-a c is used to switch beween the QEMU serial console and monitor.
Ctrl-a x is used to exit QEMU.

Exercise 4

It’s important to understand that the page_alloc in pgdir_walk allocates a page, in other words, it creates a page table, so page2pa(pp) in pgdir_walk returns the page table’s address. However, the function argument pp in page_insert represents a physical page frame, therefore the page2pa(pp) in function page_insert returns the page frame’s address.

Questions

Q: What entries (rows) in the page directory have been filled in at this point? What addresses do they map and where do they point?
A: See the table below:

1
2
3
4
5
6
Entry Base Virtual Address Points to (logically):
960 0xf0000000 mapped physical memory
959 0xefff8000 kernel stack
957 0xef400000 page table
956 0xef000000 page structures
0 0x00000000 start of memory (see entrypgdir.c)

Q: We have placed the kernel and user environment in the same address space. Why will user programs not be able to read or write the kernel’s memory? What specific mechanisms protect the kernel memory?
A: The permission bits/flags of PDE/PTE are used to protect the kernel memory.

Q: What is the maximum amount of physical memory that this operating system can support? Why?
A: The operating system uses a 4MB space at UPAGES to store the PageInfo structures. It can store 512 structures (a.k.a., 512 physical page frames) because each structure occupies 8B. The total amount of physical memory it can support is thus 512 x 4KB = 2GB. The maximum memory that can be used by the kernel is 256MB. Base address of mapped physical memory starts from virtual address 0xf0000000, which allows up to 256MB only.

Q: How much space overhead is there for managing memory, if we actually had the maximum amount of physical memory? How is this overhead broken down?
A: Up to 6MB + 4KB space overhead. page directory: 2^10 x 4B = 4KB; per PTE refers to 4KB physical memory, then per PT refers to 2^10 x 4KB = 4MB physical memory, needs 2GB/4MB = 512 page tables which takes 512 x 4KB = 2MB; PageInfo structures: 4MB.

Q: Revisit the page table setup in kern/entry.S and kern/entrypgdir.c. Immediately after we turn on paging, EIP is still a low number (a little over 1MB). At what point do we transition to running at an EIP above KERNBASE? What makes it possible for us to continue executing at a low EIP between when we enable paging and when we begin running at an EIP above KERNBASE? Why is this transition necessary?
A: After the instruction “jmp *%eax” we transition to running at virtual kernel address. The low 4MB of virtual address was mapped to the low 4MB physical address. The transition allows user programs to use the low address space.