Abstract: When the operating system loads the user program, it not only needs to allocate physical memory to store the content of the program; but also needs to allocate physical memory to store the page directory and page table of the program.
This article is shared from the HUAWEI CLOUD community " Linux from scratch 15: [Page Table of Contents and Page Tables] ", author: Brother Dao.
In the x86 system, in order to be able to use the physical memory more fully and flexibly, the physical memory is paged in units of 4KB.
Then through the middle mapping table, the continuous virtual memory space is mapped to the discrete physical memory space. Each entry in the mapping table points to the start address of a physical page.
However, such a mapping table has an obvious disadvantage: the mapping table itself also needs to be stored in physical memory.
In a 32-bit system, it uses up to 4MB of physical memory space (4 bytes per entry, a total of 4G/4K entries).
To solve this problem, the x86 processor uses two levels of conversion: page directory and page table.
In this article, we will start from the most basic low-level computing process, and get the most important memory management mechanism. It will be easier to understand when we learn more in-depth knowledge points in the future.
1. The splitting process of the page table
In a 32-bit system, the maximum representable space of physical memory is 0xFFFF_FFFF, which is 4GB.
Although the actual installed physical memory may not be so large, when designing the memory management mechanism, it is still necessary to design according to the largest addressable range.
Divided according to the unit of a physical page 4KB, 4GB space can be divided into 1024 * 1024 physical pages:
In the previous article, a single mapping table was used to point to these physical pages, which caused the mapping table itself to occupy too much physical memory space.
Several segments defined in a user program may actually use only a small amount of space, not 4 GB at all.
But it still needs to allocate up to 4GB of physical memory space to save this mapping table, which is wasteful.
In order to solve this problem, this single mapping table can be split into 1024 smaller mapping tables:
- In each mapping table, there are only 1024 entries, and each entry still points to the starting address of a physical page;
- A total of 1024 such mapping tables are used;
In this way, 1024 (the number of entries in each table) * 1024 (the number of tables) can still cover 4GB of physical memory space.
Each table here is called a page table, so there are 1024 page tables in total.
There are a total of 1024 entries in a page table, and each page table entry occupies 4 bytes, so a page table occupies 4KB of physical memory space, which is exactly the size of a physical page.
Maybe some friends have started to settle accounts: a page table itself occupies 4KB, then 1024 page tables occupies a total of 4MB of physical memory space, still a lot?
Yes, it looks like this in terms of total number, but: it is impossible for an application to fully use all 4GB of space, maybe only dozens of page tables are enough.
For example, the code segment, data segment, and stack segment of a user program need a total of 10 MB of space, so using 3 page tables is sufficient, plus the page directory, a total of 16 KB of space is required.
calculation process:
Each page table entry points to a 4KB physical page, so 1024 page table entries in a page table can cover a total of 4MB of physical memory;
Then for a 10MB program, after aligning and rounding up (a multiple of 4MB, which is 12 MB), 3 page tables are enough.
Remember the sentence in the above figure: A page table can cover 4MB of physical memory space (1024 * 4 KB).
In the page table, the format of each table entry is as follows:
Pay attention to the following attributes:
P(Present): Presence bit. 1-physical page exists; 0-physical page does not exist;
RW (Read/Write): Read/write bit. 1-This physical page is readable and writable; 0-This physical page is only readable;
D(Dirty): Dirty bit. Indicates whether the data in this physical page has been written;
2. Page directory structure
Now, every physical page is pointed to by an entry in a page table, so how should the addresses of these 1024 page tables be managed?
The answer is: page directory table!
As the name implies: in the page directory, each entry points to the start address (physical address) of a page table.
When the operating system loads the user program, it not only needs to allocate physical memory to store the contents of the program;
And also need to allocate physical memory, used to save the page directory and page table of the program.
Let's settle the accounts again:
As mentioned earlier: each page table covers 4MB of memory space, then there are 1024 entries in the page directory, pointing to the physical addresses of 1024 page tables.
Then the memory space that the page directory can cover is 1024 * 4MB, which is 4GB, which is exactly the maximum addressing range of a 32-bit address.
In the page directory, the format of each entry is as follows:
The attribute field is similar to the attribute in the page table, except that its description object is the page table.
One more thing: every user program has its own page directory and page table! There are detailed instructions below.
3. Several related registers
Now that the physical addresses of all page tables are pointed to by page directory entries, how does the processor know the physical address of the page directory?
The answer is: CR3 register, also called: PDBR (Page Table Base Register).
In this register, the page directory address of the task currently being executed is saved.
Each task (program) has its own page directory and page table, and the address of the page directory table is recorded in the TSS segment of the task.
When the operating system schedules a task, the processor will find the TSS segment information of the new task to be executed, and then update the start address of the page directory of the new task to the CR3 register.
When the instructions of the new task start to be executed, the processor is operating linear addresses when fetching instructions and operating data.
The page processing unit will start from the page directory table stored in the CR3 register, and finally convert this linear address into a physical address.
Of course, there is also a fast table in the processor to speed up the conversion process from linear addresses to physical addresses.
The format of the CR3 register is as follows:
By the way, post several other control registers on the official website:
Among them, the highest bit PG of the CR0 register is the switch to turn on the page processing unit.
In other words:
After the system is powered on, the initial address addressing mode is always [segment: offset address].
After the startup code has prepared the page directory and page table, CR0.PG = 1 can be set.
At this point, the page processing unit in the processor starts to work: facing any linear address, it must pass through the page processing unit before obtaining a physical address.
4. When loading the user program: page directory, page table allocation and filling process
In the previous article, I introduced the entire process of a user program being loaded by the operating system, which is briefly described as follows:
- Read the program header information, analyze the total length of the program, and allocate a sufficient continuous space from the task's own virtual memory;
- Allocate a free physical page to be used as the page directory of the program. The address of the page directory will be recorded in the TSS segment created later;
- Use the linear address in the virtual memory to allocate a physical page (4 KB) and register it in the page directory and page table;
- Read 8 sectors of data (512 bytes per sector) from the hard disk and store them in the physical page just allocated;
- Check whether the program content has been read: Yes-go to step 6; No-return to step 3;
- Create some necessary kernel data structures for user programs, such as: TSS, TCB/PCB, etc.;
- Create LDT for the user program, and create each segment descriptor in it;
- Copy the table entries in the high-end address part of the page directory of the operating system to the page directory table of the user program.
In this case, the high-end address entries in the page directories of all user programs all point to the same page table address, achieving the purpose of sharing the "operating system space".
Here we mainly talk about the third step, assuming that the length of the user program file on the hard disk is 20 MB, and the physical memory actually installed in the computer is 1 GB.
You can calculate it first: in the page directory, the space covered by each entry is 4 MB, so 20 MB of data requires 5 entries.
In the initial state, all entries in the page directory are empty, and the P bit is 0, indicating that the page table does not exist.
The operating system first allocates a 20 MB space from the virtual memory, assuming that it starts from the address of 1 GB (0x4000_0000), this address is a linear address.
That is to say, read the file of the application program into the memory, store it from the address 0x4000_0000, and grow to the higher address.
Note: In the "flat" segmented model, the linear address is equal to the virtual address.
0x4000_0000 = 0100_0000_0000_0000___0000_0000_0000_0000
The first 10 bits represent the index of the linear address in the page directory, the middle 10 bits represent the index in the page table, and the last 12 bits represent the offset address in the physical page.
Therefore, the first 10 bits are 0100_0000_00, indicating that this linear address is located at the 256th entry in the page directory:
The operating system found that this entry was empty and did not point to any page table.
Therefore, a free physical page is found from the physical memory and used as the page table pointed to by the 256th entry in the page directory.
Note: This physical page is used as a page table, not for storing user program files.
Suppose that a free physical page is found at an address of 128 MB (0x0800_0000) on the physical memory and used as this page table.
Clear all 1024 entries in the page table, and register the physical address of the page table, 0x0800_0000, in the 256th entry in the page directory: 0x08000 (the yellow part in the figure above).
Why not 0x0800_0000?
Because the address of a physical page must be 4KB aligned (the last 12 bits are all 0), only the upper 20 bits of the page table address need to be recorded in the entry of the page directory.
Now, the page table is also there, and the following is to allocate a physical page to store the contents of the program.
Suppose that on the top of the physical page (the one used as the page table), another free physical page is found, the address is: 0x0800_1000.
At this time, the address of the physical page used to store the program content needs to be recorded in an entry in the page table.
So where should it be recorded in the page table? That is, in which entry should it be registered?
It needs to be determined according to the middle 10 bits of the linear address:
0x4000_0000 = 0100_0000_0000_0000___0000_0000_0000_0000
The middle 10 bits are all 0s, indicating that the index value is 0, which means that the 0th entry in the page table saves the address of this physical page, as shown in the following figure:
The address of a physical page must be 4KB aligned (the last 12 bits are all 0), so only the upper 20 bits of the physical page address need to be recorded.
The physical page used to store the content of the program file is allocated, and then the content of the program file will be read from the hard disk.
The size of a physical page is 4 KB, and the size of a sector on the hard disk is 512 B. Then the data of 8 sectors can be read continuously from the hard disk to fill a physical page.
It has been assumed that the length of the user program file on the hard disk is 20 MB.
After reading the content of a physical page, it is found through calculation that the user program content has not been read, so the above process continues to be repeated.
- Linear address increases by 4KB: 0x4000_1000 = 0100_0000_0000_0000___0001_0000_0000_0000;
- The first 10 bits have not changed, and it is still the 256th entry in the page directory. It is found that the page table pointed to by this entry already exists, so there is no need to allocate physical pages as the page table;
- Allocate a free physical page for storing program content. Assuming that one is found at 0x0100_4000, register this address in the page table;
At this time, the index value of the middle 10 bits of the linear address is 1, so it is registered in the first entry in the page table.
- Read 8 sectors of data from the hard disk and write to this physical page;
Because the range covered by an entry in the page directory is 4 MB (that is, the sum of the physical page space pointed to by 1024 entries in a page table).
So when the 4 MB program content is read, all the entries in this page table are filled.
At this time, the [linear address] space occupied by the read program content is: 0x4000_0000 ~ 0x403F_FFFF.
When the new content continues to be read below, it is stored from the linear address 0x4040_0000, and the reading process is the same as above:
- Determine the page directory table entry:
0x4040_0000 = 0100_0000_0100_0000___0000_0000_0000_0000, the index value of the first 10 bits is 257;
- Found that 257 this entry is empty, so a free physical page is allocated for use as a page table;
- Allocate a physical page to store the contents of the program file, and record the address of this physical page in the page table;
The index value of the middle 10 bits of the linear address 0x4040_0000 is 0, so it is registered in the first entry of the page table;
The rest of the process will no longer be nagging, it's the same~~
The layout of the final page directory and page table is similar to the following picture:
5. Search and calculation examples from linear address to physical address
If you understand the content of the previous topic, you should not need to read the part again, because the two are opposite processes, and the search process is simpler.
Continue our assumptions:
- The length of the user program is 20 MB, stored in the space of virtual memory 0x4000_0000 ~ 0x4140_0000 (linear address);
- The length of the code segment is 8 MB, and it is stored from 0x40C0_0000 in the virtual memory;
That is, as shown in the following figure:
Now, the contents of the user program have all been read into the memory, and the page directory and page table have all been arranged.
In the page directory table, there are a total of 5 entries, which exactly represent the 20MB address space.
Among them, the physical page address stored by the 8 MB code is registered in the two entries 259 and 260 in the page directory table (the green entry on the right side of the above figure).
Goal: When the processor is executing code, it encounters a linear address 0x4100_8800, and the page processing unit needs to convert it to a physical address.
0x4100_8800 = 0100_0001_0000_0000___1000_1000_0000_0000
First, according to the first 10 bits of the linear address (0100_0001_00), the index value in the page directory is 260.
The page table address recorded in this entry is 0x08040, because the lower 12 bits of the page table address must be bit0, so the address of this page table is 0x0804_0000.
The start address of the page directory table must be obtained from the CR3 register;
Then, according to the middle 10 bits of the linear address (00_0000___1000), the index value in the page table is 8.
The physical page address recorded in this entry is 0x02004, add the lower 12 bit0s, and the starting address of the physical page is 0x0200_4000.
Finally, according to the last 12 bits of the linear address (1000_0000_0000), get its offset 2048 in the physical page.
That is to say: from the start address of the physical page (0x0200_4000), offset by 2048 bytes, is the physical address (0x0200_4800) corresponding to this linear address (0x4100_8080).
That's it!
Click to follow and learn about Huawei Cloud's fresh technology for the first time~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。