Writing A Page Frame Allocator: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content deleted Content added
No edit summary
m Bot: Replace deprecated source tag with syntaxhighlight
 
(5 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{Rating|2}}
{{Rating|2}}
{{In_Progress}}


==Introduction==
==Introduction==
Line 51: Line 52:
The variable endkernel will be declared in the kernel as:
The variable endkernel will be declared in the kernel as:


<source lang="c">
<syntaxhighlight lang="c">
extern u32int endkernel;
extern uint32_t endkernel;
</syntaxhighlight>
</source>


The variable itself has no value, it is the address of the variable that we are using. endkernel will be used to calculate the address of the first page frame
The variable itself has no value, it is the address of the variable that we are using. endkernel will be used to calculate the address of the first page frame
after the kernel. The code for searching through the array is also very simple:
after the kernel. The code for searching through the array is also very simple:


<source lang="c">
<syntaxhighlight lang="c">
static pageframe_t kalloc_frame_int()
static pageframe_t kalloc_frame_int()
{
{
u32int i = 0;
uint32_t i = 0;
while(frame_map[i] != FREE)
while(frame_map[i] != FREE)
{
{
Line 74: Line 75:
//in the array
//in the array
}
}
</source>
</syntaxhighlight>




Line 80: Line 81:




<source lang="c">
<syntaxhighlight lang="c">


pageframe_t kalloc_frame()
pageframe_t kalloc_frame()
{
{
static u8int allocate = 1;//whether or not we are going to allocate a new set of preframes
static uint8_t allocate = 1;//whether or not we are going to allocate a new set of preframes
static u8int pframe = 0;
static uint8_t pframe = 0;
pageframe_t ret;
pageframe_t ret;
Line 106: Line 107:
return(ret);
return(ret);
}
}
</syntaxhighlight>
</source>


Freeing the page frame is simply a matter of reversing the process used to get the page frame.
Freeing the page frame is simply a matter of reversing the process used to get the page frame.


<source lang="c">
<syntaxhighlight lang="c">
void kfree_frame(pageframe_t a)
void kfree_frame(pageframe_t a)
{
{
Line 116: Line 117:
if(a == 0)//in case it is the first frame we are freeing
if(a == 0)//in case it is the first frame we are freeing
{
{
u32int index = (u32int)a;
uint32_t index = (uint32_t)a;
frame_map[index] = FREE;
frame_map[index] = FREE;
}
}
else{
else{
a = a;//divide by 4kb to get the index to declare free
a = a;//divide by 4kb to get the index to declare free
u32int index = ((u32int)a)/0x1000;
uint32_t index = ((uint32_t)a)/0x1000;
frame_map[index] = FREE;
frame_map[index] = FREE;
}
}
}
}
</syntaxhighlight>
</source>

== See Also ==
* [[Page Frame Allocation]]


[[Category:Tutorials]]
[[Category:Tutorials]]
[[Category:Memory management]]

Latest revision as of 05:49, 9 June 2024

Difficulty level

Medium
This page is a work in progress.
This page may thus be incomplete. Its content may be changed in the near future.

Introduction

This tutorial will attempt to show you how to write a simple page frame allocator for the x86 CPU. The language used is C and we are using standard paging with 4 KiB pages. The page frame allocator will allocate frames with the first frame starting right after the end of the kernel.

The Method

Each frame shall be managed with a byte map (for the sake of simplicity): a value of 0x01 for used pages and a value of 0x00 for unused pages. To allocate a page, all that is needed is to search through the array for a free page and then mark it as used. You may have noticed that this would be very inefficient, having to search through a possible number of 1048319 pages. To speed up the allocation process the allocator will allocate 20 page frames at a time, so most of the time all that will have been done before hand. Alocatting a new page is simply a matter of getting a page frame off an array of preallocated frames.

The Implementation

First of all, we will need something in the linker script to tell us where the end of our kernel is.

ENTRY (loader)

SECTIONS{
    . = 0x00100000;

    .text :{
	text_start = .;
        *(.text)
    }

    .rodata ALIGN (0x1000) : {
        *(.rodata)
    }

.data ALIGN (0x1000) : {

   *(.data)
   end_data = .;
}


    .bss : {
        sbss = .;
        *(COMMON)
        *(.bss)
        ebss = .;
	endkernel = .;
    }


}

The variable endkernel will be declared in the kernel as:

extern uint32_t endkernel;

The variable itself has no value, it is the address of the variable that we are using. endkernel will be used to calculate the address of the first page frame after the kernel. The code for searching through the array is also very simple:

static pageframe_t kalloc_frame_int()
{
        uint32_t i = 0;
        while(frame_map[i] != FREE)
        {
                i++;
                if(i == npages)
                {
                        return(ERROR);
                }
        }
        frame_map[i] = USED;
        return(startframe + (i*0x1000));//return the address of the page frame based on the location declared free
        //in the array
}


The last function used calls kalloc_frame_int every 20 page frame allocations:


pageframe_t kalloc_frame()
{
        static uint8_t allocate = 1;//whether or not we are going to allocate a new set of preframes
        static uint8_t pframe = 0;
        pageframe_t ret;
        
        if(pframe == 20)
        {
                allocate = 1;
        }

        if(allocate == 1)
        {
                for(int i = 0; i<20; i++)
                {
                        pre_frames[i] = kalloc_frame_int();
                }
                pframe = 0;
                allocate = 0;
        }
        ret = pre_frames[pframe];
        pframe++;
        return(ret);
}

Freeing the page frame is simply a matter of reversing the process used to get the page frame.

void kfree_frame(pageframe_t a)
{
                a = a - startframe;//get the offset from the first frame
                if(a == 0)//in case it is the first frame we are freeing
                {
                       uint32_t index = (uint32_t)a;
                       frame_map[index] = FREE;    
                }
                else{ 
                       a = a;//divide by 4kb to get the index to declare free
                       uint32_t index = ((uint32_t)a)/0x1000;
                       frame_map[index] = FREE;
                    }
}

See Also