Page fault after enabling paging? OSDEV

1

I am trying to make my own Operating System. I got interrupts working, some keyboard and mouse drivers, basic video and printing functions. Now I want to get into memory management and tasks and the first thing I realized is that I need paging which I have yet to set up properly.

I followed some guides and tutorials on it, the most primary one being the setting up paging tutorial in osdev wiki (https://wiki.osdev.org/Setting_Up_Paging). I "wrote" (copied and pasted basically) the following code in order to initialize paging.

void initPaging()
{
    
    unsigned int i;
    for(i = 0; i < 1024; i++)
    {
        // This sets the following flags to the pages:
        //   Supervisor: Only kernel-mode can access them
        //   Write Enabled: It can be both read from and written to
        //   Not Present: The page table is not present
        page_directory[i] = 0x00000002;
    }       
    
    //we will fill all 1024 entries in the table, mapping 4 megabytes
    for(i = 0; i < 1024; i++)
    {
        // As the address is page aligned, it will always leave 12 bits zeroed.
        // Those bits are used by the attributes ;)
        first_page_table[i] = (i * 0x1000) | 3; // attributes: supervisor level, read/write, present.
    }
    
    page_directory[0] = ((unsigned int)first_page_table) | 3;
    
    enablePaging(page_directory);
    
}

The enablePaging function loads the page directory to cr3 and then enables paging by setting the PG bit in cr0.

The problem is after calling this if I call anything else like a printk it causes a page fault. I think that is because I don't identity page the kernel or something. In my page fault handler, I move the error code to eax and check the registers in qemu monitor. The error code is 0x00000020 which is

0 1 0 - Supervisory process tried to write to a non-present page entry

TL;DR

I cannot call anything else after enabling paging, do I need to map my kernel? How do I do that? What else is wrong?

This is my code on github: https://github.com/Danyy427/PagingOsdev

Edit: Registers after the exception enter image description here

My exception handler:

void isr14_handler(interrupt_frame_t *frame)
{
    //panic("Page Fault");
    
    unsigned int err = frame->err_code;
    
    //asm(".intel_syntax noprefix");
    asm("mov %0, %%eax "::"r"(err));
    
    while(1);
}

I commented out panic as it causes a double fault which causes triple fault. I put error code into eax and code hangs which is intended.

c
x86
paging
osdev
asked on Stack Overflow Apr 8, 2021 by Özgür Güzeldereli • edited Apr 8, 2021 by Özgür Güzeldereli

1 Answer

2

I finally got it. My kernel had the following code:


    initPaging();
    
    printk("Hello %d", 15) ;
    

After enabling paging I was trying to print something and realized printk threw a page fault error. I went to printk code and realized that I was accessing 0xFD000000 which is the framebuffer address for QEMU. But I didn't map it so the program was trying to access a unmapped location. I wrote the following code which maps 0xFD000000 to 0x400000 in my initPaging function:

int from = 0x00000000, size = 0x400000,  zz = 0;
    for(; size>0; from += 4096, size -= 4096, zz++){
       first_page_table[zz] = from | 1;     // mark page present.
    }
    
    from = 0xFD000000;
    size = 0x400000;
    zz = 0;
    for(; size>0; from += 4096, size -= 4096, zz++){
       second_page_table[zz] = from | 1;     // mark page present.
    }
    
    vbemode.framebuffer = 0x400000;
    
    page_directory[0] = ((unsigned int)first_page_table) | 3;
    page_directory[1] = ((unsigned int)second_page_table) | 3;
    
    enablePaging(page_directory);

The code maps 4 MB worth of memory starting from 0x400000 to 0x800000 (hopefully) of the physcial address 0xFD000000 which enables access to video memory.

Feel free to point out my mistakes in the code.


User contributions licensed under CC BY-SA 3.0