Setting Up Paging With PAE: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
No edit summary
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(18 intermediate revisions by 11 users not shown)
Line 1: Line 1:
{{Rating|1}}
This is a guide to setting up paging with PAE enabled. You should read [[Setting Up Paging]] first.
{{In_Progress}}
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'
*A entry is now 8-byte-wide (Legacy: 4-byte), so the number of entries is halved to 512 (Legacy: 1024)
*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===
===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(0x1000))); // must be aligned to page boundary
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
</pre>
</syntaxhighlight>
Now we need our Page-Directory/-Table
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.
<pre>

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">
// 512 entries
// 512 entries
uint64_t page_dir[512] __attribute__((aligned(0x1000)));
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. Now we have to make it run.
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] = (uint64_t)&p_tab | 3; //set the page table into the PD and mark it present/writable
page_dir[0] = 0b10000011; //Address=0, 2MIB, RW and present
</syntaxhighlight>
</pre>


Pages are mapped. Now we have to set the PAE-bit in CR4 and load the PDPT into CR3
Ok, let's map the first 2MiB.
<syntaxhighlight lang="c">
<pre>
asm volatile ("movl %%cr4, %%eax; bts $5, %%eax; movl %%eax, %%cr4" ::: "eax"); // set bit5 in CR4 to enable PAE
unsigned int i, address = 0;
asm volatile ("movl %0, %%cr3" :: "r" (&page_dir_ptr_tab)); // load PDPT into CR3
for(i = 0; i < 512; i++)
</syntaxhighlight>
{
page_tab[i] = address | 3; // map address and mark it present/writable
address = address + 0x1000;
}
</pre>
Ok, pages are mapped. Now we have to set the PAE-bit and load the PDPT into CR3
<pre>
asm volatile("movl %cr4, %eax; bts $5, %eax; movl %eax, %cr4"); // set bit5 in CR4 to enable PAE
asm volatile ("movl %%eax, %%cr3" :: "a" (&page_dir_ptr_tab)); // load PDPT into CR3
</pre>


The last thing we need to do is activating paging.
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 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.
PAE-Paging should be now enabled.


[[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 page is a work in progress.
This page may thus be incomplete. Its content may be changed in the near future.

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.