Me and paging don't go togheter :(
Posted: Sat Aug 12, 2006 4:05 pm
Ok I'm at the point of writing a memory manager from scratch, yes for the sixth time now But again as always I have problems with paging
The problem lies in the pde's and pte's. When I try to load my pagetable to cr3 my kernel somehow crashes. As a guide I used the following tutorial, looks easy on the eye, but it turns out otherwise. (http://www.osdever.net/tutorials/paging.php?the_id=43) After reading this tutorial and implementing some functions in the assembly part of my kernel I decided to map all physical memory 1:1 into kernel space. But when I get to the point of loading the pagetable it fails. I made sure my pagetable is page aligned (see code)
functions:
- void clear_bit(unsigned long* field, unsigned long index)
- void set_bit(unsigned long* field, unsigned long index)
- unsigned long is_bit_set(unsigned long field, unsigned long index)
- addr_t AllocPage()
- void FreePage(addr_t address)
are OK and have no bugs; all tested through and through, not yet optimized.
function: void mm_install(unsigned long mem)
is NOT ok has only one bug and that is setting up the paging.
types:
addr_t - > typedef unsigned long addr_t
Troubling piece of code:
Entire file:
P.S sorry for my longest post ever :p
The problem lies in the pde's and pte's. When I try to load my pagetable to cr3 my kernel somehow crashes. As a guide I used the following tutorial, looks easy on the eye, but it turns out otherwise. (http://www.osdever.net/tutorials/paging.php?the_id=43) After reading this tutorial and implementing some functions in the assembly part of my kernel I decided to map all physical memory 1:1 into kernel space. But when I get to the point of loading the pagetable it fails. I made sure my pagetable is page aligned (see code)
This I read in the tutorial Beneath here I posted my code. Don't pay attention to my bit setting functions they work but they are not optimal, I know, but this is just for the time being, first implement basic stuff ie enabling paging, then optimizeSetting up the page directory is rather easy. We just need to find some free memory that is 4k aligned(if the address can be devided by 4096 and not have a remainder, the address is 4kb aligned). In the case, I have choosen 0x9C000 for the address(this may not work though depending on where your kernel is located at). Now we need to set up a pointer so that we can access that memory
functions:
- void clear_bit(unsigned long* field, unsigned long index)
- void set_bit(unsigned long* field, unsigned long index)
- unsigned long is_bit_set(unsigned long field, unsigned long index)
- addr_t AllocPage()
- void FreePage(addr_t address)
are OK and have no bugs; all tested through and through, not yet optimized.
function: void mm_install(unsigned long mem)
is NOT ok has only one bug and that is setting up the paging.
types:
addr_t - > typedef unsigned long addr_t
Troubling piece of code:
Code: Select all
asm("movl %0,%%eax\n"
"movl %%eax,%%cr3\n"
"movl %%cr0,%%eax\n"
"orl $0x80000000,%%eax\n"
"movl %%eax,%%cr0\n"
"jmp 1f\n"
"1:\n"
"movl $1f,%%eax\n"
"jmp *%%eax\n"
"1:":: "m" (page_directory));
Code: Select all
#include <libc\stdlib.h>
#include <libc\stdio.h>
#include <libc\string.h>
#include <mm.h>
#include <kernel.h>
extern size_t end;
/* lookup table */
unsigned long bit_pattern[] =
{
0x00000008, 0x00000004, 0x00000002, 0x00000001,
0x00000080, 0x00000040, 0x00000020, 0x00000010,
0x00000800, 0x00000400, 0x00000200, 0x00000100,
0x00008000, 0x00004000, 0x00002000, 0x00001000,
0x00080000, 0x00040000, 0x00020000, 0x00010000,
0x00800000, 0x00400000, 0x00200000, 0x00100000,
0x08000000, 0x04000000, 0x02000000, 0x01000000,
0x80000000, 0x40000000, 0x20000000, 0x10000000,
};
/* bit setting functions */
void clear_bit(unsigned long* field, unsigned long index)
{
*field = ((*field) & (~bit_pattern[index]));
}
void set_bit(unsigned long* field, unsigned long index)
{
*field = ((*field) | (bit_pattern[index]));
}
unsigned long is_bit_set(unsigned long field, unsigned long index)
{
if((field | (~bit_pattern[index])) == ~bit_pattern[index])
{
return 0;
}
return 1;
}
/* some global data, info about paging memory */
addr_t* page_directory;
size_t num_pte = 0;
size_t num_pde = 0;
static addr_t MemoryStart = (addr_t)&end;
addr_t MemoryEnd = 0;
size_t MemorySize = 0;
size_t Pages = 0;
size_t PagesInUse = 0;
addr_t* Bitmap;
size_t BitmapSize;
size_t ref_ptr_one = 0;
size_t ref_ptr_two = 0;
/* some lookup values */
#define LOOKUP_VALUE_L2 131072
size_t lk1;
addr_t AllocPage()
{
while(ref_ptr_one < lk1)
{
while(ref_ptr_two < 32)
{
if(!is_bit_set(Bitmap[ref_ptr_one], ref_ptr_two))
{
set_bit((unsigned long*)&Bitmap[ref_ptr_one], ref_ptr_two);
PagesInUse++;
return MemoryStart + (ref_ptr_one * LOOKUP_VALUE_L2) + (ref_ptr_two * PAGE_SIZE);
}
ref_ptr_two++;
}
ref_ptr_two = 0;
ref_ptr_one++;
}
// try going to begin of bitmap
// first chek if we have any pages left
if(!(Pages - PagesInUse))
{
// out of memory
return 0;
}
/* reset parameters */
ref_ptr_two = 0;
ref_ptr_one = 0;
/* retry */
return AllocPage();
}
void FreePage(addr_t address)
{
// just clear a bit ;)
unsigned long page = ((address - MemoryStart) / 4096);
unsigned long entry = (page / 32);
unsigned long index = (page % 32);
clear_bit((unsigned long*)&Bitmap[entry], index);
PagesInUse--;
}
void mm_install(unsigned long mem)
{
puts("creating paging bitmap... ");
MemoryStart = MemoryStart + (4096 - (MemoryStart % 4096)); // align
MemoryEnd = mem * 1024;
MemorySize = MemoryEnd - MemoryStart;
Pages = MemorySize / PAGE_SIZE;
Bitmap = (addr_t*)MemoryStart;
BitmapSize = (Pages / 32) * 4; // in Bytes
memset(Bitmap, 0, ((BitmapSize / 4096) + 1) * 4096); /* zero bitmap */
while(PagesInUse < (BitmapSize / 4096) + 1)
{
set_bit((unsigned long*)Bitmap, PagesInUse);
PagesInUse++;
}
lk1 = (BitmapSize / 4) + 1;
puts("OK\n");
puts("testing memory... "); // just 1 chek, slows boot, but better to prevent crashes ;)
// the more the memory the more time it takes to boot ;)
addr_t* i = (addr_t*)Bitmap + (PagesInUse * 4096);
// first loop
for(; i < (addr_t*)MemoryEnd; i = i + 4)
{
*i = (addr_t)i;
if(*i != (addr_t)i)
{
printf("error @ 0x%x loop 1", (addr_t)i);
asm("hlt");
}
}
addr_t* j = (addr_t*)Bitmap + (PagesInUse * 4096);
i = (addr_t*)Bitmap + (PagesInUse * 4096);
// second loop
for(; j < (addr_t*)MemoryEnd; j = j + 4, i = i + 4)
{
*i = ~*i;
if(*i != ~(addr_t)j) // chek with real answer
{
printf("error @ 0x%x loop 2", (addr_t)i);
asm("hlt");
}
}
puts("OK\nfilling with 0... ");
i = (addr_t*)Bitmap + (PagesInUse * 4096);
// zero memory
for(; i < (addr_t*)MemoryEnd; i = i + 4)
{
*i = 0x00000000;
}
puts("OK\nloading page tables... ");
/* **************************************************** */
/* PROBLEMS START HERE!!!!!!!!!!!!!!!!!!!!!! */
/* **************************************************** */
/* we map all physical memory into kernel virutal memory */
/* 1:1 mapping */
/* calculate number of pte's and pde's we need */
num_pte = (mem * 1024) / PAGE_SIZE;
num_pde = (num_pte / 1024) + 1; // round up
size_t iterator_a = 0;
size_t iterator_b = 0;
addr_t base = 0x00000000;
// allocate memory for pd
page_directory = (addr_t*)AllocPage();
if((addr_t)page_directory % 4096) // error if not aligned (debug function)
{
printf("Error: %d 0x%08x", (addr_t)page_directory % 4096, (addr_t)page_directory);
asm("hlt");
}
memset(page_directory, 0, PAGE_SIZE); /* force empty table */
addr_t* pde; // page table entry
// fill pd with pde's and pte's
while(iterator_a < num_pde && num_pte)
{
pde = (addr_t*)AllocPage();
// fill it with pte's
while(iterator_b < 1024 && num_pte)
{
pde[iterator_b] = base | 3; // attribute set to: supervisor level, read/write, present(011 in binary)
base += PAGE_SIZE; // 4096 = 4kb
iterator_b++;
num_pte--;
}
iterator_a++;
iterator_b = 0;
page_directory[iterator_a] = (addr_t)pde;
page_directory[iterator_a] = page_directory[iterator_a] | 3;
}
num_pte = (mem * 1024) / PAGE_SIZE; // restore
/* don't work commented out */
// write_cr3, read_cr3, write_cr0, and read_cr0 all come from the assembly functions
//write_cr3((addr_t)page_directory); // put that page directory address into CR3
//write_cr0(read_cr0() | 0x80000000); // set the paging bit in CR0 to 1
/* above doesn't work let's try something else */
asm("movl %0,%%eax\n"
"movl %%eax,%%cr3\n"
"movl %%cr0,%%eax\n"
"orl $0x80000000,%%eax\n"
"movl %%eax,%%cr0\n"
"jmp 1f\n"
"1:\n"
"movl $1f,%%eax\n"
"jmp *%%eax\n"
"1:":: "m" (page_directory));
/* reboot here -_- doesn't work either */
puts("OK\n");
}