Triple fault on enabling paging
Posted: Thu Jun 30, 2022 8:38 am
Hi, I'm writing a code for paging and now it triple faults as soon as I enable paging. Qemu shows nothing when I type info mem or info tlb, so my paging structures are empty so that's the problem, but I checked it on debug that the address that I pass to cpu contains address of my page_directory structure. The page_table entries are also filled with correct values.
Code: Select all
#include <kernel/page_table_entry.h>
#include <stdint.h>
#include <stdbool.h>
#include <kernel/physical_memory_manager.h>
#include <string.h>
#include <kernel/math.h>
page_directory* current_directory=0;
extern void loadPageDirectory(unsigned int*);
extern void enablePaging();
void set_bit(uint32_t* pte, uint8_t bit_number){
uint32_t pte_value = *pte;
pte_value |= (1 << bit_number);
*pte = pte_value;
}
void unset_bit (uint32_t* pte, int bit_number){
uint32_t pte_value = *pte;
pte_value &= ~(1 << bit_number);
*pte = pte_value;
}
bool is_bit_set (uint32_t* pte, int bit_number) {
uint32_t pte_value = *pte;
return pte_value & (1 << bit_number);
}
void set_frame (uint32_t* pte, physical_address physical_address){
uint32_t pte_value = *pte;
pte_value |= (physical_address << 12);
*pte = pte_value;
}
uint32_t get_frame (uint32_t pte){
return pte >> 12;
}
bool allocate_page (pt_entry* e) {
void* block = allocate_block ();
if (!block)
return false;
set_frame (e, (physical_address)block);
set_bit (e, IS_PRESENT);
return true;
}
void vmmngr_free_page (pt_entry* e) {
void* p = (void*)get_frame (*e);
if (p)
free_block (p);
unset_bit (e, IS_PRESENT);
}
inline pt_entry* get_page_table_entry_from_address (page_table* page_table,virtual_address address) {
if (page_table)
return &page_table->entries[ PAGE_TABLE_INDEX (address) ];
return 0;
}
inline pd_entry* get_page_directory_entry_from_address (page_directory* p, virtual_address addr) {
if (p)
return &p->entries[ PAGE_DIRECTORY_INDEX (addr) ];
return 0;
}
bool switch_pdirectory (page_directory* directory) {
if (!directory)
return false;
current_directory = directory;
loadPageDirectory (¤t_directory[0].entries);
return true;
}
page_directory* get_directory () {
return current_directory;
}
void flush_tlb_entry (virtual_address addr) {
#ifdef _MSC_VER
_asm {
cli
invlpg addr
sti
}
#endif
}
void map_page (void* physical_addr, void* virtual_address) {
page_directory* page_directory = get_directory ();
pd_entry* e = &page_directory->entries [PAGE_DIRECTORY_INDEX ((uint32_t) virtual_address) ];
if ( !is_bit_set(e, IS_PRESENT)) {
page_table* table = (page_table*) allocate_block();
if (!table){
return;
}
memset (table, 0, sizeof(page_table));
set_bit(e, IS_PRESENT);
set_bit(e, IS_WRITABLE);
set_frame(e, (physical_address) table);
}
page_table* table = (page_table*) get_frame ( *e );
pt_entry* page = &table->entries [ PAGE_TABLE_INDEX ( (uint32_t) virtual_address) ];
set_frame(page, (physical_address)physical_addr);
set_bit(page, IS_PRESENT);
}
void set_up_paging () {
page_table* default_page_table = (page_table*) allocate_block ();
if (!default_page_table)
return;
page_table* kernel_page_table = (page_table*) allocate_block ();
if (!kernel_page_table)
return;
memset(default_page_table, 0, sizeof(page_table));
memset(kernel_page_table, 0, sizeof(page_table));
for (int i=0, frame=0x0, virtual=0x00000000; i<1024; i++, frame+=4096, virtual+=4096) {
pt_entry page=0;
set_bit (&page, IS_PRESENT);
set_frame (&page, frame);
default_page_table->entries [PAGE_TABLE_INDEX (virtual) ] = page;
}
for (int i=0, frame=0x100000, virtual=0xc0000000; i<1024; i++, frame+=4096, virtual+=4096) {
pt_entry page=0;
set_bit (&page, IS_PRESENT);
set_frame (&page, frame);
kernel_page_table->entries [PAGE_TABLE_INDEX (virtual) ] = page;
}
page_directory* page_dir = (page_directory*) allocate_blocks(divide_round_up(sizeof(page_directory), BLOCKS_SIZE));
if (!page_dir){
return;
}
memset(page_dir, 0, sizeof(page_dir));
pd_entry* entry = &page_dir->entries [PAGE_DIRECTORY_INDEX (0xc0000000) ];
set_bit (entry, IS_PRESENT);
set_bit (entry, IS_WRITABLE);
set_frame (entry, (physical_address)kernel_page_table);
pd_entry* entry2 = &page_dir->entries [PAGE_DIRECTORY_INDEX (0x00000000) ];
set_bit (entry2, IS_PRESENT);
set_bit (entry2, IS_WRITABLE);
set_frame (entry2, (physical_address)default_page_table);
switch_pdirectory (page_dir);
enablePaging ();
}
Code: Select all
#ifndef PAGE_TABLE_ENTRY
#define PAGE_TABLE_ENTRY
#include <stdint.h>
#include <stdbool.h>
#define PAGES_PER_TABLE 1024
#define PAGE_TABLES_PER_DIRECTORY 1024
#define PAGE_DIRECTORY_INDEX(x) (((x) >> 22) & 0x3ff)
#define PAGE_TABLE_INDEX(x) (((x) >> 12) & 0x3ff)
#define PAGE_TABLE_ADDRESS_SPACE_SIZE 0x400000
#define DIRECTORY_TABLE_ADDRESS_SPACE_SIZE 0x100000000
#define PAGE_SIZE 4096
typedef uint32_t pt_entry;
typedef uint32_t pd_entry;
typedef uint32_t virtual_address;
typedef uint32_t physical_address;
typedef struct page_table {
pt_entry entries[PAGES_PER_TABLE];
} page_table;
//! page directory
typedef struct pdirectory {
pd_entry entries[PAGE_TABLES_PER_DIRECTORY];
} page_directory;
enum PTE_BIT_NUMBERS {
IS_PRESENT = 0,
IS_WRITABLE = 1,
USER_MODE = 2,
WRITETHOUGH = 3,
NOT_CACHEABLE = 4,
IS_ACCESSED = 5,
IS_DIRTY = 6,
PAT = 7,
CPU_GLOBAL = 8,
LV4_GLOBAL = 9,
};
void set_frame (uint32_t* pte, uint32_t physical_address);
uint32_t get_frame (uint32_t pte);
void set_up_paging ();
#endif
Code: Select all
.text
.globl loadPageDirectory
loadPageDirectory:
push %ebp
mov %esp, %ebp
mov 8(%esp), %eax
mov %eax, %cr3
mov %ebp, %esp
pop %ebp
ret
.text
.globl enablePaging
enablePaging:
push %ebp
mov %esp, %ebp
mov %cr0, %eax
or $0x80000001, %eax
mov %eax, %cr0
mov %ebp, %esp
pop %ebp
ret