I'm trying to implement a function that creates a new page table (its number is taken as an argument).
Here is a list of actions it does:
- Request a free physical page.
- Calculate an address of the first page that is covered by the page table.
- Fill in the page table.
- Calculate a 4KB-aligned address of the current page .
- OR that address with 3 (011b).
- Write the result into the page table at offset "i" (0-1023).
- Calculate an address of the entry in the page directory for the page table.
- OR the address of the page table with 3 (011b).
- Write the result to the calculated address.
The code I have:
Code: Select all
// Create a page table.
int create_page_table (int num)
{
// `num` is the number of a new page table (counting from 1).
// Get the physical address of the current page directory.
int page_dir = read_cr3 ();
if (num < 1)
{
return CPT_ZERONUM;
}
if (num > 1024)
{
// The maximum value of page tables in one page directory is 1024.
return CPT_BIGNUM;
}
// Request a free physical page.
u32 *ppage = (u32 *) pop_physical_page ();
// The new page table will be located in this physical page.
/*
puts ("ppage = 0x");
char str[32];
puts (itoa ((int) ppage, str, 16));
puts ("\n");
*/
// Convert `num` to the address of the first page that will be pushed into
// the first entry of the new page table.
int first = (num - 1) * 4194304;
/*
puts ("first = 0x");
puts (itoa (first, str, 16));
puts ("\n");
*/
// Fill in the page table.
int i;
for (i = 0; i < 1024; ++i)
{
int page = first + (i * 4096);
// Fill in the entry "i".
ppage[i] = page | 3; // End with 011 (supervisor level, read and write
// access, the page is present).
}
// Update the page directory entry.
int page_dir_entry_num = num - 1;
u32 *page_dir_entry_addr = (u32 *) (page_dir + page_dir_entry_num * 32);
*page_dir_entry_addr = (u32) ppage | 3; // End with 011 (supervisor level,
// read and write access, the page table is present).
for (i = 0; i < 1024; ++i)
{
int page = first + (i * 4096);
invlpg ((void *) ppage[i]);
}
return CPT_SUCCESS;
}