ArvernOS
|
Data Structures | |
struct | page_table_t |
Functions | |
void | paging_init () |
Initializes paging to separate virtual and physical memory. | |
page_number_t | page_containing_address (uint64_t virtual_address) |
uint64_t | page_start_address (page_number_t page_number) |
opt_uint64_t | translate_page (page_number_t page_number) |
opt_uint64_t | translate (uint64_t virtual_address) |
void | map (page_number_t page_number, uint64_t flags) |
void | map_multiple (page_number_t start_page_number, uint32_t number_of_pages, uint64_t flags) |
void | unmap (page_number_t page_number) |
void | unmap_multiple (page_number_t start_page_number, uint32_t number_of_pages) |
uint32_t | paging_amount_for_byte_size (uint64_t start_address, uint64_t byte_size) |
void | identity_map (uint64_t address, uint64_t flags) |
void identity_map | ( | uint64_t | address, |
uint64_t | flags ) |
Maps a page (virtual address) to the equivalent frame (physical address).
address | the address to map |
flags | paging flags |
void map | ( | page_number_t | page_number, |
uint64_t | flags ) |
Convenient function to map a page (number) without providing a frame. The frame is automatically allocated.
page_number | a page number (not an address) |
flags | paging flags |
void map_multiple | ( | page_number_t | start_page_number, |
uint32_t | number_of_pages, | ||
uint64_t | flags ) |
Maps multiple pages in a row if possible.
start_page_number | the first page of the sequence |
number_of_pages | the amount of pages to map |
flags | the paging flags |
page_number_t page_containing_address | ( | uint64_t | virtual_address | ) |
Returns a page number given a virtual address.
virtual_address | a virtual address (page) |
uint64_t page_start_address | ( | page_number_t | page_number | ) |
Returns the virtual start address of a page.
page_number | a page number |
uint32_t paging_amount_for_byte_size | ( | uint64_t | start_address, |
uint64_t | byte_size ) |
Calculates how many pages are needed for a range of addresses.
start_address | the starting virtual address |
byte_size | the amount of bytes |
void paging_init | ( | ) |
Initializes paging to separate virtual and physical memory.
The bootloader (assembly code) already set up a 4-level paging hierarchy that maps every page of our kernel to a physical frame. It does this because paging is mandatory in 64-bit mode on x86_64.
This means that every memory address that we used in our kernel was a virtual address. Accessing the VGA buffer at address 0xb8000
only worked because the bootloader identity mapped that memory page, which means that it mapped the virtual page 0xb8000
to the physical frame 0xb8000
.
In addition, this improves safety since illegal memory accesses cause page fault exceptions instead of modifying arbitrary physical memory. That being said, identity mapping clutters the virtual address space and makes it more difficult to find continuous memory regions of larger sizes (like 1000 KiB).
We remap the kernel and other useful sections/addresses in this function, then we enable write protection, the NXE bit and we switch to our own table. This allows us to make everything safer. Memory is still identity mapped, which isn't great but it works for now.
opt_uint64_t translate | ( | uint64_t | virtual_address | ) |
Translates a virtual address to the corresponding physical address.
virtual_address | a virtual address |
opt_uint64_t translate_page | ( | page_number_t | page_number | ) |
Translates a page number to a frame number.
page_number | a page number (not an address) |
void unmap | ( | page_number_t | page_number | ) |
Unmaps (free) a page.
page_number | a page number (not an address) |
void unmap_multiple | ( | page_number_t | start_page_number, |
uint32_t | number_of_pages ) |
Unmaps multiple consecutive pages.
start_page_number | the first page of the sequence |
number_of_pages | the amount of pages to unmap |