Self-referencing page-directory
Posted: Fri Jul 24, 2015 5:54 am
Hello,
since the usual bitshifting and calculating with magic numbers can get really ugly and confusing like in this example: i've created a little struct, which helps me with those problems:
This will only work, if the last entry in the page-directory is mapped to itself!
After a single line of initialisation:
It can be used fairly easy:
Might be worth to put it in the wiki, might not.
since the usual bitshifting and calculating with magic numbers can get really ugly and confusing like in this example:
Code: Select all
void * get_physaddr(void * virtualaddr)
{
unsigned long pdindex = (unsigned long)virtualaddr >> 22;
unsigned long ptindex = (unsigned long)virtualaddr >> 12 & 0x03FF;
unsigned long * pd = (unsigned long *)0xFFFFF000;
// Here you need to check whether the PD entry is present.
unsigned long * pt = ((unsigned long *)0xFFC00000) + (0x400 * pdindex);
// Here you need to check whether the PT entry is present.
return (void *)((pt[ptindex] & ~0xFFF) + ((unsigned long)virtualaddr & 0xFFF));
}
Code: Select all
typedef struct {
union {
struct {
uint32_t present : 1; // 1
uint32_t write : 1; // 2
uint32_t user : 1; // 3
uint32_t writethrough : 1; // 4
uint32_t cache_disabled : 1; // 5
uint32_t accessed : 1; // 6
uint32_t dirty : 1; // 7
uint32_t ignore0 : 1; // 8
uint32_t global : 1; // 9
uint32_t avail : 3; // 12
uint32_t frame : 20; // 32
};
uint32_t val;
};
} page_table_entry_t;
typedef struct {
union {
struct {
uint32_t present : 1; // 1
uint32_t write : 1; // 2
uint32_t user : 1; // 3
uint32_t writethrough : 1; // 4
uint32_t cache_disabled : 1; // 5
uint32_t accessed : 1; // 6
uint32_t ignore0 : 1; // 7
uint32_t big_pages : 1; // 8
uint32_t ignore1 : 1; // 9
uint32_t avail : 3; // 12
uint32_t frame : 20; // 32
};
uint32_t val;
};
} page_directory_entry_t;
typedef struct {
page_table_entry_t page[1024];
} page_table_t;
typedef struct {
union {
page_table_t table[1023];
page_table_entry_t page[1024 * 1023];
};
page_directory_entry_t directory[1023];
uint32_t ignore;
} page_directory_t;
After a single line of initialisation:
Code: Select all
page_directory_t* CURRENT_DIR = (page_directory_t*)0xFFC00000;
Code: Select all
uint32_t virtual = 0xC0000000; //our 'demo' virtual address
uint32_t page_id = virtual / 4096; // or rightshift by 12, this is the 'id' of the page
uint32_t table_id = page_id / 1024; // Or rightshift by 10, the table in which the page is
uint32_t table_offset = page_id%1024; // Or &0x3FF, the offset our page in the table
CURRENT_DIR->directory[table_id].present; //Not doing anything, only showing how to access the directory
CURRENT_DIR->directory[table_id].frame; //and so on
//To access a table:
CURRENT_DIR->table[table_id]->page[table_offset].present;
//or even easier with the full page id
CURRENT_DIR->page[page_id].present;