I have now meditated about the pmm and, using great part of the Bona Fide tutorial 'Implementing Basic Paging', I expanded it to what I think could be a first attempt of a physical memory manager. Please have a look at my code:
This is file paging.c
Code: Select all
#include "system.h"
unsigned long *page_directory;
// CR access functions, doc found in cr_access.asm
extern unsigned long read_cr0(void);
extern void write_cr0(unsigned long cr0);
extern unsigned long read_cr3(void);
extern void write_cr3(unsigned long *cr3);
/** Enables paging.
* Maps only 4MB of memory.
*/
void enable_paging()
{
page_directory = (unsigned long *)0x9C000; // TODO: Find out where kernel ends
unsigned long *page_table = (unsigned long *)0x9D000;
unsigned long address = 0;
unsigned int i;
//Map first 4MB of memory
for (i = 0; i < 1024; i++)
{
page_table[i] = address | 3;
address = address + 4096;
};
// fill the first entry of the page directory (the only one we actually set up)
page_directory[0] = (unsigned long)page_table;
page_directory[0] = page_directory[0] | 3; // supervisor level, read/write, present
// Fill in the other 1023 entries (the ones we haven't done yet)
for (i = 1; i < 1024; i++)
{
page_directory[i] = 0 | 2; // supervisor level, read/write, not present
};
write_cr3(page_directory); // page directory address into CR3
write_cr0(read_cr0() | 0x80000000); // set paging bit in CRO to 1
}
/** Enables paging.
* The bitmap is automatic, as this first version will use the avail bytes of the page table entries.
* Must be called first thing.
*/
void paging_init()
{
enable_paging();
}
/** Allocates the first single page found.
* In order to achieve this, it sets all avail bits.
* Returns 0 if it doesn't find any page available.
*/
void *page_alloc()
{
unsigned long pde;
// Loop variables
unsigned int i;
unsigned int j;
for (i = 0; i < 1024; i++)
{
pde = page_directory[i]; // TODO: Better read cr3 in order to be more efficient
if ((pde & 1) == 1) // Check bit 0 (present)
{
unsigned long *pt = (unsigned long *)(pde >> 12); // Is this correct?
unsigned long pe;
for (j = 0; j < 1024; j++)
{
pe = pt[i];
if ((pe & 0xE01) == 1) // check present & 3 avail bits (avail bits MUST NOT be set)
{
pe = pe | 0xE00; // Set bits 11,10 and 9 (made available by Intel, I think)
return (void *)(pe >> 12);
}
}
}
}
return 0;
}
/** Frees a given page.
* Unmarks bytes 11,10 and 9
*/
void page_free(void *ptr)
{
// TODO
}
Code: Select all
; In CR0, we must set bit 31 to 1 to tell the processor that paging is enabled.
; But first, we must put the address of our page directory into CR3.
; Other bits?
[global _read_cr0]
_read_cr0:
mov eax, cr0
retn
[global _write_cr0]
_write_cr0:
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov cr0, eax
pop ebp
retn
; In CR3, we store the pointer to our page directory.
; Aftwerwards, we set bit 31 of CR0 to 1 in order to enable paging.
[global _read_cr3]
_read_cr3:
mov eax, cr3
retn
[global _write_cr3]
_write_cr3:
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov cr3, eax
pop ebp
retn
Thanks
Candamir