In the chapter related to the GDT, we saw that using segmentation a physical memory address is calculated using a segment selector and an offset.
In this chapter, we are going to implement paging, paging will translate a linear address from segmentation into a physical address.
Paging will allow our kernel to:
In a paged system, each process may execute in its own 4gb area of memory, without any chance of effecting any other process's memory, or the kernel's. It simplifies multitasking.
The translation of a linear address to a physical address is done in multiple steps:
CR3
to know the physical address of the pages directory.The two types of entries (table and directory) look like the same. Only the field in gray will be used in our OS.
P
: indicate if the page or table is in physical memoryR/W
: indicate if the page or table is accessible in writting (equals 1)U/S
: equals 1 to allow access to non-preferred tasksA
: indicate if the page or table was accessedD
: (only for pages table) indicate if the page was writtenPS
(only for pages directory) indicate the size of pages:
Note: Physical addresses in the pages diretcory or pages table are written using 20 bits because these addresses are aligned on 4kb, so the last 12bits should be equal to 0.
To enable pagination, we just need to set bit 31 of the CR0
registry to 1:
asm(" mov %%cr0, %%eax; \
or %1, %%eax; \
mov %%eax, %%cr0" \
:: "i"(0x80000000));
But before, we need to initialize our pages directory with at least one pages table.
With the identity mapping model, the page will apply only to the kernel as the first 4 MB of virtual memory coincide with the first 4 MB of physical memory:
This model is simple: the first virtual memory page coincide to the first page in physical memory, the second page coincide to the second page on physical memory and so on ...