Setting Up Paging: Difference between revisions

Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content deleted Content added
Wording change in heading
added source tags
Line 27: Line 27:
Note that all of your paging structures need to be at page aligned addresses. 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.
Note that all of your paging structures need to be at page aligned addresses. 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.


<source lang="c">
<pre>
//the page directory comes right after the kernel - NOTE: make sure the address is page aligned!
//the page directory comes right after the kernel - NOTE: make sure the address is page aligned!
unsigned int page_aligned_end = (((unsigned int*)end) & 0xFFFFF000) + 0x1000;
unsigned int page_aligned_end = (((unsigned int*)end) & 0xFFFFF000) + 0x1000;
unsigned int *page_directory = (unsigned int*)page_aligned_end;
unsigned int *page_directory = (unsigned int*)page_aligned_end;
</pre>
</source>


If you don't know where the end of your kernel is, then you need to edit your linker script to tell you where the end of your kernel is. In the meantime, use something like this.
If you don't know where the end of your kernel is, then you need to edit your linker script to tell you where the end of your kernel is. In the meantime, use something like this.


<source lang="c">
<pre>
//this is only a temporary solution. Find out where your kernel ends!
//this is only a temporary solution. Find out where your kernel ends!
unsigned int *page_directory = (unsigned int*) 0x9C000;//Make sure that this address is properly page aligned
unsigned int *page_directory = (unsigned int*) 0x9C000;//Make sure that this address is properly page aligned
</pre>
</source>


Now that we have a piece of free memory for the page directory, we need to blank it. The page directory should have 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).
Now that we have a piece of free memory for the page directory, we need to blank it. The page directory should have 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">
<pre>
//set each entry to not present
//set each entry to not present
int i = 0;
int i = 0;
Line 50: Line 50:
page_directory[i] = 0 | 2;
page_directory[i] = 0 | 2;
}
}
</pre>
</source>


===Creating Your First Page Table===
===Creating Your First Page Table===
Line 56: Line 56:


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 past the page directory. If we properly page-aligned the page directory, then the page table should also be properly page aligned.
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 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">
<pre>
//our first page table comes right after the page directory
//our first page table comes right after the page directory
unsigned int *first_page_table = page_directory + 0x1000;
unsigned int *first_page_table = page_directory + 0x1000;
</pre>
</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 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 1024'th page.
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 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 1024'th page.


<source lang="c">
<pre>
// holds the physical address where we want to start mapping these pages to.
// 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.
// in this case, we want to map these pages to the very beginning of memory.
Line 75: Line 75:
address = address + 4096; //advance the address to the next page boundary
address = address + 4096; //advance the address to the next page boundary
}
}
</pre>
</source>


===Put the Page Table in the Page Directory===
===Put the Page Table in the Page Directory===
The third step is to put the newly created page table into our blank page directory. We do this by setting the first entry in the page directory to the address of our page table.
The third step is to put the newly created page table into our blank page directory. We do this by setting the first entry in the page directory to the address of our page table.


<source lang="c">
<pre>
page_directory[0] = first_page_table;
page_directory[0] = first_page_table;
page_directory[0] |= 3;// attributes: supervisor level, read/write, present
page_directory[0] |= 3;// attributes: supervisor level, read/write, present
</pre>
</source>


===Enable Paging===
===Enable Paging===
The final step is to actually enable paging. First we tell the processor where to find our page table 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 GCC. If you use a different compiler then you will need to translate between this assembly format and the format supported by your compiler.
The final step is to actually enable paging. First we tell the processor where to find our page table 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 GCC. If you use a different compiler then you will need to translate between this assembly format and the format supported by your compiler.


<source lang="c">
<pre>
//moves page_directory (which is a pointer) into the cr3 register.
//moves page_directory (which is a pointer) into the cr3 register.
asm volatile("mov %0, %%cr3":: "b"(page_directory));
asm volatile("mov %0, %%cr3":: "b"(page_directory));
</pre>
</source>


Finally we switch the paging bit on the cr0 register. This operation also requires inline assembly code.
Finally we switch the paging bit on the cr0 register. This operation also requires inline assembly code.
<source lang="c">
<pre>
//reads cr0, switches the "paging enable" bit, and writes it back.
//reads cr0, switches the "paging enable" bit, and writes it back.
unsigned int cr0;
unsigned int cr0;
Line 100: Line 100:
cr0 |= 0x80000000;
cr0 |= 0x80000000;
asm volatile("mov %0, %%cr0":: "b"(cr0));
asm volatile("mov %0, %%cr0":: "b"(cr0));
</pre>
</source>


Paging should now be enabled.
Paging should now be enabled.