Setting Up Paging: Difference between revisions

no edit summary
[unchecked revision][unchecked revision]
mNo edit summary
No edit summary
Line 22:
The first step is to create a blank page directory. The page directory is blank because we have not yet created any page tables where the entries in the page directory can point.
 
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, but you should write the page frame allocator as soon as possible. Another temporary solution (used in this tutorial) is to simply declare global objects with __attribute__((align(4096))). Note that this is a GCC extension. It allows you to declare data aligned with some mark, such as 4KiB here. We can use this because we are only using one page directory and one page table. Please note that on the real world, dynamic allocation is too basic to be missing, and paging structures are constantly being added, deleted, and modified. For now, just use static objects;
First we need a piece of free memory where we can keep the page directory.
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>
__end__ = .;
</source>
 
Now your linker will provide you with a symbol named __end__, which marks the end of your kernel. Now, its time to use it in actual code
<source lang="c">
uint32_t page_directory[1024] __attribute__((align(4096)));
extern const unsigned int __end__;
unsigned int *page_aligned_end = (unsigned int*)((((unsigned int)&__end__) & 0xFFFFF000) + 0x1000);
unsigned int *page_directory = page_aligned_end; // Where else?
</source>
 
Now that we have a piece of free memory for the page directory, we need to blank it. The page directory should havehas exactly 1024 entries. We will set each entry to not present so that if the MMU looks for that page table, it will see that it is not there (...yet. We will add the first page table in a moment).
 
<source lang="c">
Line 59 ⟶ 48:
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 create a new page table.
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">
uint32_t first_page_table[1024];
//our first page table comes right after the page directory
unsigned int *first_page_table = (unsigned int*)((unsigned int)page_directory + 0x1000);
</source>
 
Anonymous user