Setting Up Paging With PAE: Difference between revisions
[unchecked revision] | [unchecked revision] |
No edit summary |
m (Bot: Replace deprecated source tag with syntaxhighlight) |
||
(10 intermediate revisions by 8 users not shown) | |||
Line 1: | Line 1: | ||
{{Rating|1}} |
{{Rating|1}} |
||
{{In_Progress}} |
|||
This is a guide to setting up paging with PAE enabled. You should read [[Setting Up Paging]] first. |
This is a guide to setting up paging with [[PAE]] enabled. You should read [[Setting Up Paging]] first. |
||
===Differences between PAE-Paging and Legacy-Paging=== |
===Differences between PAE-Paging and Legacy-Paging=== |
||
*PAE allows you to access more physical memory, which is usually 64GiB (in fact, this is implementation specific). |
*PAE allows you to access more physical memory, which is usually 64GiB (in fact, this is implementation specific). |
||
*A new data structure is added, the so called 'Page-Directory-Pointer-Table' |
*A new data structure is added, the so called 'Page-Directory-Pointer-Table' |
||
* |
*An entry is now 8-byte-wide (Legacy: 4-byte), so the number of entries is halved to 512 (Legacy: 1024) |
||
*If the CPU supports it you can use the NoExecute-bit |
*If the CPU supports it you can use the NoExecute-bit |
||
===Setting Up The Data Structures=== |
===Setting Up The Data Structures=== |
||
As mentioned above the 'Page-Directory-Pointer-Table' is added, which contains 4 Page-Directory-Entries |
As mentioned above the 'Page-Directory-Pointer-Table' is added, which contains 4 Page-Directory-Entries |
||
<syntaxhighlight lang="c"> |
|||
<pre> |
|||
uint64_t page_dir_ptr_tab[4] __attribute__((aligned(0x20))); // must be aligned to (at least)0x20, ... |
uint64_t page_dir_ptr_tab[4] __attribute__((aligned(0x20))); // must be aligned to (at least)0x20, ... |
||
// ... turning out that you can put more of them into one page, saving memory |
// ... turning out that you can put more of them into one page, saving memory |
||
</syntaxhighlight> |
|||
</pre> |
|||
Keep in mind that the size of the CR3 register remains at 4byte, meaning that a PDPT must be located below 4GiB in physical memory. |
Keep in mind that the size of the CR3 register remains at 4byte, meaning that a PDPT must be located below 4GiB in physical memory. |
||
Now we need our Page-Directory |
Now we need our Page-Directory. For the sake of easiness, we'll use PSE. (2 MIB pages mapped in page directory) |
||
<syntaxhighlight lang="c"> |
|||
<pre> |
|||
// 512 entries |
// 512 entries |
||
uint64_t page_dir[512] __attribute__((aligned(0x1000))); // must be aligned to page boundary |
uint64_t page_dir[512] __attribute__((aligned(0x1000))); // must be aligned to page boundary |
||
</syntaxhighlight> |
|||
uint64_t page_tab[512] __attribute__((aligned(0x1000))); |
|||
</pre> |
|||
===Making it run=== |
===Making it run=== |
||
Ok, now we have our structures. |
Ok, now we have our structures. Let's map the first 2 MIB. |
||
<syntaxhighlight lang="c"> |
|||
<pre> |
|||
page_dir_ptr_tab[0] = (uint64_t)&page_dir | 1; // set the page directory into the PDPT and mark it present |
page_dir_ptr_tab[0] = (uint64_t)&page_dir | 1; // set the page directory into the PDPT and mark it present |
||
page_dir[0] = |
page_dir[0] = 0b10000011; //Address=0, 2MIB, RW and present |
||
</syntaxhighlight> |
|||
</pre> |
|||
⚫ | |||
Ok, let's map the first 2MiB. |
|||
<syntaxhighlight lang="c"> |
|||
<pre> |
|||
⚫ | |||
unsigned int i, address = 0; |
|||
⚫ | |||
for(i = 0; i < 512; i++) |
|||
</syntaxhighlight> |
|||
{ |
|||
page_tab[i] = address | 3; // map address and mark it present/writable |
|||
address = address + 0x1000; |
|||
} |
|||
</pre> |
|||
⚫ | |||
<pre> |
|||
⚫ | |||
⚫ | |||
</pre> |
|||
Finally, we'll enable paging. |
|||
Simply done: |
Simply done: |
||
<syntaxhighlight lang="c"> |
|||
<pre> |
|||
asm volatile ("movl %cr0, %eax; orl $0x80000000, %eax; movl %eax, %cr0;"); |
asm volatile ("movl %%cr0, %%eax; orl $0x80000000, %%eax; movl %%eax, %%cr0;" ::: "eax"); |
||
</syntaxhighlight> |
|||
</pre> |
|||
PAE |
PAE paging should now be enabled. |
||
==FAQ== |
|||
===Mapping the PD to itself=== |
|||
Q: Why is it causing triple fault/page fault? |
|||
In Legacy-Paging this is quite easy. Just map the PD to the last entry of itself. |
|||
A: You're kernel is probably not inside the first 2 MiB of the memory. You'll need to identity map your kernel. |
|||
In PAE-Paging we have 4 entries and the PDPT, so how does it work? |
|||
Depending on where you want to set it you just map all 4 directories into one of those! |
|||
Example (PD's at end of virtual memory) |
|||
<pre> |
|||
uint64_t * page_dir = (uint64_t*)page_dir_ptr_tab[3]; // get the page directory (you should 'and' the flags away) |
|||
page_dir[511] = (uint64_t)page_dir; // map pd to itself |
|||
page_dir[510] = page_dir_ptr_tab[2]; // map pd3 to it |
|||
page_dir[509] = page_dir_ptr_tab[1]; // map pd2 to it |
|||
page_dir[508] = page_dir_ptr_tab[0]; // map pd1 to it |
|||
page_dir[507] = (uint64_t)&page_dir_ptr_tab; /* map the PDPT to the directory |
|||
</pre> |
|||
Now you can access all structures in virtual memory. Mapping the PDPT into the directory wastes quite much virtual memory as only 32 bytes are used, but if you allocate most/all PDPT's into one page then you can access ALL of them, which can be quite useful. |
|||
Q: How do I map pages? |
|||
You can also statically allocate the PDPT at boot time, put the 4 page directory addresses in your process struct, and then just write the same PDPT address to CR3 on a context switch after you've |
|||
patched the PDPT. |
|||
A: Firstly, align your desired virtual memory address to 1 GiB, and divide it by 1 GiB to obtain the PDPT index. Then, find the index of the page directory by aligning your desired virtual address to 2 MiB and divide it by 2 MiB. Finally, lookup the page directory entry by the index obtained in the previous step, and set the entry's address to your desired physical address that's aligned to 2 MiB. |
|||
[[Category:Paging]] |
|||
[[Category:Virtual Memory]] |
|||
[[Category:X86 CPU]] |
[[Category:X86 CPU]] |
||
[[Category:Tutorials]] |
[[Category:Tutorials]] |
Latest revision as of 04:48, 9 June 2024
Difficulty level |
---|
![]() Beginner |
This is a guide to setting up paging with PAE enabled. You should read Setting Up Paging first.
Differences between PAE-Paging and Legacy-Paging
- PAE allows you to access more physical memory, which is usually 64GiB (in fact, this is implementation specific).
- A new data structure is added, the so called 'Page-Directory-Pointer-Table'
- An entry is now 8-byte-wide (Legacy: 4-byte), so the number of entries is halved to 512 (Legacy: 1024)
- If the CPU supports it you can use the NoExecute-bit
Setting Up The Data Structures
As mentioned above the 'Page-Directory-Pointer-Table' is added, which contains 4 Page-Directory-Entries
uint64_t page_dir_ptr_tab[4] __attribute__((aligned(0x20))); // must be aligned to (at least)0x20, ...
// ... turning out that you can put more of them into one page, saving memory
Keep in mind that the size of the CR3 register remains at 4byte, meaning that a PDPT must be located below 4GiB in physical memory.
Now we need our Page-Directory. For the sake of easiness, we'll use PSE. (2 MIB pages mapped in page directory)
// 512 entries
uint64_t page_dir[512] __attribute__((aligned(0x1000))); // must be aligned to page boundary
Making it run
Ok, now we have our structures. Let's map the first 2 MIB.
page_dir_ptr_tab[0] = (uint64_t)&page_dir | 1; // set the page directory into the PDPT and mark it present
page_dir[0] = 0b10000011; //Address=0, 2MIB, RW and present
Pages are mapped. Now we have to set the PAE-bit in CR4 and load the PDPT into CR3
asm volatile ("movl %%cr4, %%eax; bts $5, %%eax; movl %%eax, %%cr4" ::: "eax"); // set bit5 in CR4 to enable PAE
asm volatile ("movl %0, %%cr3" :: "r" (&page_dir_ptr_tab)); // load PDPT into CR3
Finally, we'll enable paging. Simply done:
asm volatile ("movl %%cr0, %%eax; orl $0x80000000, %%eax; movl %%eax, %%cr0;" ::: "eax");
PAE paging should now be enabled.
FAQ
Q: Why is it causing triple fault/page fault?
A: You're kernel is probably not inside the first 2 MiB of the memory. You'll need to identity map your kernel.
Q: How do I map pages?
A: Firstly, align your desired virtual memory address to 1 GiB, and divide it by 1 GiB to obtain the PDPT index. Then, find the index of the page directory by aligning your desired virtual address to 2 MiB and divide it by 2 MiB. Finally, lookup the page directory entry by the index obtained in the previous step, and set the entry's address to your desired physical address that's aligned to 2 MiB.