Setting Up Paging: Difference between revisions

no edit summary
[unchecked revision][unchecked revision]
No edit summary
Line 122:
 
==More Advanced Paging Example==
Add sections on how to dynamically get and free pages...
 
Here we are going to make it it little bit more complicated. The code you have now enables paging, but we want to be able to allocate and free pages dynamically. For this, we need to find 4KB aligned addresses using alloc (WARNING, this version of the alloc functions needs to be disabled as soon as you have working heap, otherwise you will destroy your heap).
 
===Temporary Malloc===
 
First, we need to find the end of our kernel, to make sure we don't overwrite our data. For this, we need a symbol at the end of our linker script.
<pre>
/* Read-write data (uninitialized) and stack */
.bss BLOCK(4K) : ALIGN(4K)
{
*(COMMON)
*(.bss)
*(.bootstrap_stack)
}
/* a symbol without a value to be able to find the last address of our kernel */
end_kernel = .;
/* The compiler may produce other sections, put them in the proper place in
in this file, if you'd like to include them in the final kernel. */
}
</pre>
We can now reference this symbol by using
<source lang="c">
extern uint32_t end_kernel;
uint32_t end_pointer = &end_kernel;
</source>
Congratulations, we can now find the end of our kernel. Now we can start writing a temporary malloc function.
<source lang="c">
uint32_t malloc_temp(uint32_t size, uint32_t paging, uint32_t* phys){
if (align == 1 && (placement_address & 0xFFFFF000)) // If the address is not already page-aligned
{
// Align it.
end_pointer &= 0xFFFFF000;
end_pointer += 0x1000;
}
if(phys){
*phys = end_pointer;
}
uint32_t temp = end_pointer;
end_pointer += size;
return temp;
}
</source>
===Allocating and Freeing Pages===
Now that we have a malloc function we can start with our page_alloc and page_free.
<source lang="c">
void page_alloc(uint32_t virtual_address, uint32_t flags){
virtual_address/=0x1000;
uint32_t table_index = virtual_address/1024;
uint32_t page_index = virtual_address%1024;
uint32_t *table;
// if the table doesn't exist
if(page_directory[table_index]==0){
//create it
uint32_t *phys;
table = malloc_temp(0x1000, 1, phys);
memset(table, 0, 0x1000); // I do hope you have this?
page_directory[table_index] = phys | 0x1 | 0x2 | 0x4 // the numbers are flags we need to set.
// 0x1 = present, 0x2 = read_write (just to be sure),
// 0x4 = user (tables where user isn't set cannot be accessed by a usermode program even if the page has this flag)
}else{
// setting the table if we didn't need to create it
table = page_directory[table_index];
table &= 0xFFFFF000;
}
// adding the page to the table, while making sure the present flag is set
table[page_index] = frame_alloc() | 0x1 | flags;
}
void page_free(uint32_t virtual_address){
virtual_address/=0x1000;
uint32_t table_index = virtual_address/1024;
uint32_t page_index = virtual_address%1024;
uint32_t *table;
// if the table doesn't exist we don't need to do anything
if(page_directory[table_index]==0){
return;
}
table = page_directory[table_index];
table &= 0xFFFFF000;
table[page_index] = 0; //setting the page entry to zero
frame_free(virtual_address);
}
</source>
This gives you a function to allocate a page and one to free a page. For the flags you can check [[Paging]] but because I'm nice I will give you the defines for them.
===flags===
<source lang="c">
#define PAGE_PRESENT 0x1
#define PAGE_READ_WRITE 0x2
#define PAGE_USER 0x4
#define PAGE_WRITE_THROUGH 0x8
#define PAGE_CACHE 0x10
#define PAGE_ACCESSED 0x20
#define PAGE_DIRTY 0x40
#define PAGE_GLOBAL 0x100
</source>
Note:
This tutorial requires that you have a working page frame allocator ([[Writing_A_Page_Frame_Allocator]]) and a memset implementation.
[[Category:X86 CPU]]
[[Category:Tutorials]]
Anonymous user