Enabling paging causes PAGE_FAULT immeditially after setting flag on cr0

1

I'm working on own OS, it's a lot of fun but i'm stucked with paging, I had wrote simple(very simple) pagination code, but when I turn pagination on, there is page fault. Some details: I'm using C for kernel I'm using qemu as VM I had own crosscompiler I don't use any external libs After loading and jumping into kernel code I setup interrupts and remap PIC, It's working and i reckon it's not the issue, after that I'm trying to enable paging Here is paging.h

#ifndef PAGING_H
#define PAGING_H

#include "../cpu/types.h"
#include "../cpu/isr.h"

#define PAGE_SIZE 4096

typedef struct page{
        u32 present             :1;
        u32 rw                      :1;
        u32 kernel_space    :1;
        u32 accessed            :1;
        u32 dirty                   :1;
        u32 unused              :7;
        u32 frame                   :20;
} page_t;

typedef struct page_table{
        page_t pages[1024];
} page_table_t;
typedef struct page_directory{
        u32 page_tables[1024];
} page_dir_t;
typedef struct page_directory_interface{
        page_dir_t dir;
        page_table_t* page_tables;
        u32 page_dir_ph_address;
} page_dir_interface_t;
void init_paging();


void switch_page_dir(page_dir_t* new_dir);

page_t* get_page(u32 addres, page_dir_t* dir, u8 make);

void page_fault(registers_t regs);
#endif

I'm using page_t struct from some tutorial, because I reckon it's quite convinent, other parts, I've writed on my own twice, on both cases code results with PageFault. Here's paging.c:

#include "./paging.h"
#include "../util/panic.h"
#include "./memory.h"
#include "../drivers/screen.h"

page_dir_t* kernel_dir, cur_dir;

//helper function for convinient printing
void pint(u32 a){
        char * tmp;
        itoa(a, tmp);
        kprint(tmp);
        kprint("\n");
}

void init_paging(){
        kernel_dir = kmalloc(sizeof(page_dir_t));
        memset(kernel_dir, 0, 4096);
        pint(sizeof(page_dir_t));
        pint(&kernel_dir->page_tables[0]);
        pint(kernel_dir);
        int i;
        for(i=0; i<1024; i++){ //setting up page directories for kernel
                // read and write and kernel_mode and not present
                kernel_dir->page_tables[i] = (u32)kmalloc(sizeof(page_table_t)) | 0x2;
        }
        map_page_table(kernel_dir->page_tables[0], 1, 1); //map ram to pages;
        kernel_dir->page_tables[0] |= 0x3; //set as present
        enable_paging();
}
void map_page_table(page_table_t* p_table, int kernel, int rw){
        int i;
        page_t tmp_page;
        tmp_page.present = 1; 
        tmp_page.rw = (rw) ? 1 : 0;
        tmp_page.kernel_space = (kernel) ? 1: 0;

        for(i=0; i<1024; i++){
                tmp_page.frame |= kmalloc(PAGE_SIZE);
                p_table->pages[i] = tmp_page;       
        }
}
void enable_paging(){
        u32 cr0_temp_value;
        __asm__ __volatile__("mov %0, %%cr3":: "r"(&kernel_dir->page_tables));
        __asm__ ("mov %%cr0, %0": "=r"(cr0_temp_value));
        cr0_temp_value |= 0x80000000;
        __asm__ __volatile__("mov %0, %%cr0":: "r"(cr0_temp_value));

}

And here is memory.c:

#include "./memory.h"
#include "../cpu/types.h"
#include "../../cathesimc/def.h"
u32 placement_addr = 0x10000;


void memcpy(char* src, char* dst, unsigned int bytes){
        int i=0;
        for (i=0; i< bytes; i++){
                dst[i] = src[i];

        }
}

void memset(u8* dest, u8 val, u32 len){
        u8* tmp = (u8*)dest;
        for(;len != 0; len--) *tmp++ = val;
}

//@TODO poprawic tego biedackiego malloca
u32 kmalloc_intrnl(size_t size, short int align, u32 *phys_addr){
        if(align != 0 && (placement_addr & 0xFFFFF000)){
                placement_addr &= 0xFFFFF000;
                placement_addr += 0x1000;
        }
        if(phys_addr) *phys_addr = placement_addr;
        u32 ret = placement_addr;
        placement_addr += size;
        return ret;
}

u32 kmalloc(size_t size){
        return kmalloc_intrnl(size, 0, NULL);
}
u32 kmalloc_a(size_t size){
        return kmalloc_intrnl(size, 1, NULL);
}
u32 kmalloc_p(size_t size, u32* phys_addr){
        return kmalloc_intrnl(size, 0, phys_addr);
}
u32 kmalloc_ap(size_t size, u32* phys_addr){
        return kmalloc_intrnl(size, 1, phys_addr);
}

My kernel is below 0x10000, it has about 16kb so 0x10000 is safe start of mapped space and memory from that address is definetely not used, I only set up one page table because I want to make paging barebones, and then take care about allocation and freeing, so my only goal for now is to find out what mistake I has making.

============EDIT==============
I have made intensive investigation, and I found that malloc has strange bahaviour, below are snippets of code with explaination

//as we can se from kmalloc() code above, kmalloc starts with 
//placement_addr == 0x10000 when kernel starts
void init_paging(){
        kernel_dir = kmalloc(sizeof(page_dir_t)); //page_dir_t has size 4096 and that is first malloc in kernel code
        memset(kernel_dir, 0, 4096);
        pint(sizeof(page_dir_t));
        phex(sizeof(page_dir_t));
        pint(&kernel_dir->page_tables[0]);
        phex(&kernel_dir->page_tables[0]); //prints 0x10000 as expected
        int i;
        for(i=0; i<1024; i++){ //setting up page directories for kernel
                // read and write and kernel_mode and not present
                kernel_dir->page_tables[i] = (u32)kmalloc(sizeof(page_table_t)) | 0x2;
        }
        phex(kernel_dir->page_tables[0]); //0x11002 as expected
        phex(kernel_dir->page_tables[1023]); //0x410002 as expected
        kprint("pages\n");
        map_page_table(kernel_dir->page_tables[0], 1, 1); //map ram to pages;
        kernel_dir->page_tables[0] |= 0x3; //set as present
        kprint("lol");
        enable_paging();
}
void map_page_table(page_table_t* p_table, int kernel, int rw){
        int i;
        page_t tmp_page;
        tmp_page.present = 1; 
        tmp_page.rw = (rw) ? 1 : 0;
        tmp_page.kernel_space = (kernel) ? 1: 0;
        //since now troubles starts this forloop below prints adresses:
        // iteration0 0x11000
        // iteration1 0x12000
        // iteration2 0x13000
        // iteration3 0x14000
        // iteration4 0x15000
        // iteration5 0x16000
        // iteration6 0x17000
        // iteration7 0x18000
        for(i=0; i<8; i++){
                tmp_page.frame = kmalloc(PAGE_SIZE);
                phex(tmp_page.frame);
                p_table->pages[i] = tmp_page;
        }
}

I think that's definetly might be source of problems but I have no idea why placement_addr changes when i call another function, and why then it changes to 0x11000

c
operating-system
paging
asked on Stack Overflow Jan 17, 2020 by Rafal Wegrzyniak • edited Jan 17, 2020 by Rafal Wegrzyniak

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0