Setting Up Paging: Difference between revisions

Jump to navigation Jump to search
no edit summary
[unchecked revision][unchecked revision]
m (Removed underscores from link to Page Frame Allocation)
No edit summary
Line 2:
This is a guide to setting up paging. It will teach you the basic concepts behind paging and how it can help you with your OS. This example will concentrate on Legacy Non-PSE Non-PAE paging (See also [[Setting Up Paging With PAE]]).
 
Paging is a term that refers to the management of the computer's ''virtual'' memory''. If you have not yet created a ''physical'' memory manager'', please read and follow [[Page Frame Allocation]] before continuing with this article.
 
==Basic Paging==
Line 25:
If you know where the end of your kernel is, then you can put the page directory right after it.
 
Note that all of your paging structures need to be at page -aligned addresses (i.e. being a multiple of 4096). If you have already written a page frame allocator then you can use it to allocate the first free page after your kernel for the page directory. If you have not created a proper page allocator, simply finding the first free page-aligned address after the kernel will be fine.
 
To get the first page after your kernel, you must modify your Linker Script. Add this to the end of your "SECTIONS" block (*inside* it):
<source lang="c">
<source>
//the page directory comes right after the kernel - NOTE: make sure the address is page aligned!
__end__ = .;
unsigned int page_aligned_end = (((unsigned int*)end) & 0xFFFFF000) + 0x1000;
unsigned int *page_directory = (unsigned int*)page_aligned_end;
</source>
 
If you don't know where the end ofNow your kernellinker is,will thenprovide you needwith toa editsymbol yournamed linker__end__, scriptwhich to tell you wheremarks the end of your kernel is. InNow, theits meantime,time to use somethingit likein this.actual code
 
<source lang="c">
extern const unsigned int __end__;
//this is only a temporary solution. Find out where your kernel ends!
unsigned int *page_directorypage_aligned_end = (unsigned int*)((((unsigned 0x9C000;//Makeint)&__end__) sure& that0xFFFFF000) this+ address is properly page aligned0x1000);
unsigned int *page_directory = (unsigned int*)page_aligned_end; // Where else?
</source>
 
Line 44 ⟶ 43:
<source lang="c">
//set each entry to not present
int i = 0;
for(i = 0; i < 1024; i++)
{
// This sets the following flags to the pages:
//attribute: supervisor level, read/write, not present.
// Supervisor: Only kernel-mode can access them
page_directory[i] = 0 | 2;
// Write Enabled: It can be both read from and written to
// Not Present: The page table is not present
page_directory[i] = 0 | 20x00000002;
}
</source>
 
A page is "not present" is one which is not (intented to be) used. If the MMU finds one, it will Page Fault. Non-present pages are useful for technics such as Lazy Loading. It's also used when a page has been swapped to disk, so the Page Fault is not interpreted as an error by the OS. To the OS, it means someone needs a page it swapped to disk, so it is restored. A page fault over a page that was never swapped is a error by which the OS has a reason to kill the process.
 
===Creating Your First Page Table===
The second step is to create a basic page table. In this example we choose to fill up the whole first page table with addresses for the MMU. Because each page is 4 kilobytes large, and because each page table has exactly 1024 entries, filling up the whole table causes us to map 4 megabytes of memory. Also, the page directory is 1024 entries long, so everything can map up to 4GiB, the full 32-bit address space. Remembered the non-present page trick? Without it, we would use 16MiB per each paging structure. A single page directory needs 4KiB, but it can map some tables as non-present, effectively removing their space needs.
 
Now, its time to put a new page table in the directory! We start like we did with the page directory, by finding a piece of free memory where we can keep our page table. Again, use your page allocator for this if you have written one. If not, then put the page table one page (i.e. +4KiB) past the page directory. If we properly page-aligned the page directory, then the page table should also be properly page aligned.
<source lang="c">
//our first page table comes right after the page directory
unsigned int *first_page_table = (unsigned int*)((unsigned int)page_directory + 10240x1000);
</source>
 
We now need to fill each index in the table with an address to which the MMU will map that page. Index 0 (zero) holds the address from where the first page will be mapped. Likewise, index 1 (one) holds the address for the second page and index 1023 holds the address of the 1024th page. That's for the first table. So, to get the page at which a certain index is mapped is as simple as (PageDirIndexOfTable * 1024) + PageTabIndexOfPage. If you multiply that by 4, you'thll get the address (in KiB) at which the page will be loaded. For example, page index 123 in table index 456 will be mapped to (456 * 1024) + 123 = 467067. 467067 * 4 = 1868268 KiB = 1824.48046875 MiB = 1.781719207763671875 GiB. It's easy, right?
 
<source lang="c">
// holds the physical address where we want to start mapping these pages to.
// in this case, we want to map these pages to the very beginning of memory.
unsigned int address = 0;
unsigned int i;
 
//we will fill all 1024 entries in the table, mapping 4 megabytes
for(i = 0; i < 1024; i++)
{
first_page_table[i]// =As the address |is 3;page //aligned, attributes:it supervisorwill level,always read/write,leave 12 bits presentzeroed.
// Those bits are used by the attributes ;)
address = address + 4096; //advance the address to the next page boundary
first_page_table[i] = (i * 0x1000) | 3; // attributes: supervisor level, read/write, present.
}
</source>
Line 81 ⟶ 85:
 
<source lang="c">
//attribute attributes: supervisor level, read/write, not present.
page_directory[0] = first_page_table;
page_directory[0] |= 3;//((unsigned attributes:int)first_page_table) supervisor| level, read/write, present3;
</source>
 
===Enable Paging===
The final step is to actually enable paging. First we tell the processor where to find our page directory by putting it's address into the cr3 register. Because C code can not directly access the computer's registers, we will need to use inline assembly to set cr3. The following inline assembly is written for GCCGAS. If you use a different compilerassembler then you will need to translate between this assembly format and the format supported by your compilerassembler.
 
<source lang="casm">
.text
//moves page_directory (which is a pointer) into the cr3 register.
.globl loadPageDirectory
asm volatile("mov %0, %%cr3":: "b"(page_directory));
loadPageDirectory:
push %ebp
mov %esp, %ebp
mov 8(%esp), %eax
mov %eax, %cr3
mov %ebp, %esp
pop %ebp
ret
</source>
 
This small assembly function takes one parameter: the address of the page directory. It then loads the address onto the CR3 register, where the MMU will find it. But wait! Paging is not still enabled. That's what we will do next. We must set the 32th bit in the CR0 register, the paging bit. This operation also requires assembly code. Once done, paging will be enabled.
<source lang="casm">
.text
.globl enablePaging
enablePaging:
push %ebp
mov %esp, %ebp
mov %cr0, %eax
or $0x80000000, %eax
mov %eax, %cr0
mov %ebp, %esp
pop %ebp
ret
</source>
 
Now lets call the functions!
Finally we switch the paging bit on the cr0 register. This operation also requires inline assembly code.
<source lang="c">
// This should go outside any function..
//reads cr0, switches the "paging enable" bit, and writes it back.
extern void loadPageDirectory(unsigned int cr0*);
extern void enablePaging();
asm volatile("mov %%cr0, %0": "=b"(cr0));
// And this inside a function
cr0 |= 0x80000000;
loadPageDirectory(page_directory);
asm volatile("mov %0, %%cr0":: "b"(cr0));
enablePaging();
</source>
 
Paging should now be enabled. Try printing something to screen like "Hello, paging world!". If all goes well, congratulations! You've just learned the basics of paging. But there are lots of other things to do with it. You won't be able to almost all of them for now. Just remember that you have a little friend in the CR3 register that will help you one day.
Paging should now be enabled.
 
==More Advanced Paging Example==
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.

Navigation menu