Paging: Difference between revisions

193 bytes added ,  26 days ago
m
Bot: Replace deprecated source tag with syntaxhighlight
[unchecked revision][unchecked revision]
(→‎Example: je + jmp -> jne)
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(4 intermediate revisions by 3 users not shown)
Line 52:
Say the kernel is loaded to 0x100000. However, it needed to be remapped to 0xC0000000. After loading the kernel, it'll initiate paging, and set up the appropriate tables. (See [[Higher Half Kernel]]) After [[Identity Paging]] the first megabyte, it'll need to create a second table (ie. at entry #768 in the paging directory.) to map 0x100000 to 0xC0000000. The code may be like:
 
<sourcesyntaxhighlight lang="ASM">
mov eax, 0x0
mov ebx, 0x100000
Line 63:
cmp eax, 1024
jne .fill_table
</syntaxhighlight>
</source>
 
== 64-Bit Paging ==
Line 94:
Enabling paging is actually very simple. All that is needed is to load CR3 with the address of the page directory and to set the paging (PG) and protection (PE) bits of CR0.
 
<sourcesyntaxhighlight lang="ASM">
mov eax, page_directory
mov cr3, eax
Line 101:
or eax, 0x80000001
mov cr0, eax
</syntaxhighlight>
</source>
 
Note: setting the paging flag when the protection flag is clear causes a [[Exceptions#General_Protection_Fault|general protection exception]]. Also, once paging has been enabled, any attempt to enable long mode by setting LME (bit 8) of the [[CPU_Registers_x86-64#IA32_EFER|EFER register]] will trigger a [[Exceptions#General_Protection_Fault|GPF]]. The CR0.PG must first be cleared before EFER.LME can be set.
Line 109:
To enable PSE (4 MiB pages) the following code is required.
 
<sourcesyntaxhighlight lang="ASM">
mov eax, cr4
or eax, 0x00000010
mov cr4, eax
</syntaxhighlight>
</source>
 
=== 64-bit Paging ===
Enabling paging in long mode requires a few more additional steps. Since it is not possible to enter long mode without paging with PAE active, the order in which one enables the bits are important. Firstly, paging must not be active (i.e. CR0.PG must be cleared.) Then, CR4.PAE (bit 5) and EFER.LME (bit 8 of MSR 0xC0000080) are set. If 57-bit virtual addresses are to be enabled, then CR4.LA57 (bit 12) is set. Finally, CR0.PG is set to enable paging.
 
<sourcesyntaxhighlight lang="ASM">
; Skip these 3 lines if paging is already disabled
mov ebx, cr0
Line 159:
hlt ; Done. Replace these lines with your own code
jmp reloadCS
</syntaxhighlight>
</source>
 
Once paging has been enabled, you cannot switch from 4-level paging to 5-level paging (and vice-versa) directly. The same is true for switching to legacy 32-bit paging. You must first disable paging by clearing CR0.PG before making changes. Failure to do so will result in a [[Exceptions#General_Protection_Fault|general protection fault]].
Line 190:
Many prefer to map the last PDE to itself. The page directory will look like a page table to the system. To get the physical address of any virtual address in the range 0x00000000-0xFFFFF000 is then just a matter of:
 
<sourcesyntaxhighlight lang="C">
void *get_physaddr(void *virtualaddr) {
unsigned long pdindex = (unsigned long)virtualaddr >> 22;
Line 203:
return (void *)((pt[ptindex] & ~0xFFF) + ((unsigned long)virtualaddr & 0xFFF));
}
</syntaxhighlight>
</source>
 
To map a virtual address to a physical address can be done as follows:
 
<sourcesyntaxhighlight lang="C">
void map_page(void *physaddr, void *virtualaddr, unsigned int flags) {
// Make sure that both addresses are page-aligned.
Line 228:
// or you might not notice the change.
}
</syntaxhighlight>
</source>
 
Unmapping an entry is essentially the same as above, but instead of assigning the <code>pt[ptindex]</code> a value, you set it to 0x00000000 (i.e. not present). When the entire page table is empty, you may want to remove it and mark the page directory entry 'not present'. Of course you don't need the 'flags' or 'physaddr' for unmapping.
Line 261:
== INVLPG ==
 
INVLPG is an instruction available since the i486 that invalidates a single page in the TLB. Intel notes that this instruction may be implemented differently on future processesprocessors, but that this alternate behavior must be explicitly enabled. INVLPG modifies no flags.
 
NASM example:
 
<sourcesyntaxhighlight lang="ASM">
invlpg [0]
</syntaxhighlight>
</source>
 
Inline assembly for GCC (from Linux kernel source):
 
<sourcesyntaxhighlight lang="C">
static inline void __native_flush_tlb_single(unsigned long addr) {
asm volatile("invlpg (%0)" ::"r" (addr) : "memory");
}
</syntaxhighlight>
</source>
 
This only invalidates the page on the current processor. If you're using SMP, you'll need to send an IPI to the other processors so that they can also invalidate the page (this is called a TLB shootdown; it's very slow), making sure to avoid any nasty race conditions. You may only want to do this when removing a mapping, and just make your page fault handler invalidate a page if it you didn't invalidate a mapping addition on that processor by looking through the page directory, again avoiding race conditions.
Line 368:
 
[[Category:Memory management]]
[[Category:Paging]]
[[Category:Virtual Memory]]
[[Category:Security]]
[[de:Paging]]