OSDev.org

The Place to Start for Operating System Developers
It is currently Fri Mar 29, 2024 6:27 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: Switch Directory Paging causing QEMU error
PostPosted: Sat Sep 07, 2019 7:21 am 
Offline

Joined: Mon Jul 01, 2019 10:46 am
Posts: 24
I've always confused. I've always tried paging, but always got trouble in function "switch_page_directory" like this:
Code:
void switch_directory(page_directory_t *dir) {
    current_directory = dir;
   asm volatile ("mov %0, %%cr3":: "r"(dir->physical_address));
   uint32_t cr0;
   asm volatile ("mov %%cr0, %0": "=r"(cr0));
   cr0 |= 0x80000000;
   asm volatile ("mov %0, %%cr0":: "r"(cr0));
}

I've debugged all, using gdb but still can't find the solution to solve this. Now I want to show paging code

Code:
#include <system.h>
#include <stdiok.h>
#define HEAP_END 0x02000000

extern void *end;
uintptr_t placement_address = (uintptr_t)&end;
uintptr_t heap_end = NULL;

uintptr_t kmalloc_real(size_t size,int align,uintptr_t *phys) {
    if ((align == 1) && (placement_address & 0xFFFFF000)) {
        placement_address &= 0xFFFFF000;
        placement_address += 0x1000;
    }
    if (phys)
        *phys = placement_address;
    uintptr_t address = placement_address;
    address += size;
    return address;
}

/*Only using size*/
uintptr_t kmalloc(size_t size) {
    return kmalloc_real(size,0,NULL);
}

/*Return with physical address*/
uintptr_t kmalloc_p(size_t size,uintptr_t *phys) {
    return kmalloc_real(size,0,phys);
}

/*Aligned Page with physical address*/
uintptr_t kmalloc_ap(size_t size,uintptr_t *phys) {
    return kmalloc_real(size,1,phys);
}

/*Aligned Page*/
uintptr_t kmalloc_a(size_t size) {
    return kmalloc_real(size,1,NULL);
}

uint32_t nframes;
uint32_t *frames;

#define INDEX_FROM_BIT(b) (b / 0x20)
#define OFFSET_FROM_BIT(b) (b % 0x20)

void set_frame(uint32_t frame_address) {
    uint32_t frame = frame_address / 0x1000;
    uint32_t index = INDEX_FROM_BIT(frame);
    uint32_t offset = OFFSET_FROM_BIT(frame);
    frames[index] |= (1 << offset);
}

void clear_frame(uint32_t frame_address) {
    uint32_t frame = frame_address / 0x1000;
    uint32_t index = INDEX_FROM_BIT(frame);
    uint32_t offset = OFFSET_FROM_BIT(frame);
    frames[index] &= ~(1 << offset);
}

bool isset(uint32_t frame_address) {
    uint32_t frame = frame_address / 0x1000;
    uint32_t index = INDEX_FROM_BIT(frame);
    uint32_t offset = OFFSET_FROM_BIT(frame);
    return frames[index] & (1 << offset);
}

bool notset(uint32_t frame_address) {
    return !isset(frame_address);
}

uintptr_t first_frame() {
    uint32_t i, j;
    uint32_t index = INDEX_FROM_BIT(nframes);
    for (i = 0; i < index; ++i) {
        if (frames[i] != 0xFFFFFFFF) {
            for (j = 0; j < 32; j++) {
                uint32_t test_frame = 1 << j;
                if (!(frames[i] & test_frame))
                    return i * 32 + j;
            }
        }
    }
    return -1;
}

page_directory_t *kernel_directory = 0;
page_directory_t *current_directory = 0;

void alloc_frame(page_t *page,int is_kernel,int is_writeable) {
    if (page->frame != 0) {
        page->present = 1;
        page->rw = is_writeable ? 1 : 0;
        page->user = is_kernel ? 0 : 1;
        return;
    } else {
        uint32_t index = first_frame();
        if ((uint32_t)index == -1) {
            asm("cli");
            printk("No Free Frames\n");
            for(;;);
        }
        page->present = 1;
        page->rw = is_writeable ? 1 : 0;
        page->user = is_kernel ? 0 : 1;

    }
}

void free_frame(page_t *page) {
    uint32_t frame;
    if (!(frame = page->frame)) {
        return;
    } else {
        clear_frame(frame);
        page->frame = 0x0;
    }
}

page_t *get_page(uint32_t address,int make,page_directory_t *dir) {
    address /= 0x1000;
    uint32_t table_index = address / 1024;
    if (dir->tables[table_index]) {
        return &dir->tables[table_index]->pages[address % 1024];
    } else if (make) {
        uint32_t temp;
        dir->tables[table_index] = (page_table_t*)kmalloc_ap(sizeof(page_table_t),(uintptr_t*)&temp);
        memset(dir->tables[table_index],0,sizeof(page_table_t));
        dir->physical_tables[table_index] = temp | 0x7;
        return &dir->tables[table_index]->pages[address % 1024];
    } else {
        return 0;
    }
}

void switch_directory(page_directory_t *dir) {
    current_directory = dir;
   asm volatile (
         "mov %0, %%cr3\n"
         "mov %%cr0, %%eax\n"
         "orl $0x80000000, %%eax\n"
         "mov %%eax, %%cr0\n"
         :: "r"(dir->physical_address)
         : "%eax");
}

void page_fault(register_t *r) {
    uint32_t fault_address;
    asm volatile("mov %0, %%cr2" : "=r"(fault_address));
    int present = !(r->err_code & 0x1) ? 1 : 0;
    int rw = (r->err_code & 0x2) ? 1 : 0;
    int us = (r->err_code & 0x4) ? 1 : 0;
    int reserved = (r->err_code & 0x8) ? 1 : 0;
    int id = (r->err_code & 0x10) ? 1 : 0;
    printk("Segmentation Fault [rw : %d, us : %d, reserved : %d, id : %d]\n",
    present,rw,us,reserved,id);
}

void paging_install() {
    uint32_t mem_end_page = 0x1000000;
    nframes = mem_end_page / 0x1000;
    frames = (uint32_t*)kmalloc(INDEX_FROM_BIT(nframes));
    memset(frames,0,INDEX_FROM_BIT(nframes));

    kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t));
    // memset(kernel_directory,0,sizeof(page_directory_t));
    current_directory = kernel_directory;

    uint32_t i = 0;
    while (i < placement_address) {
        alloc_frame(get_page(i,1,kernel_directory),0,0);
        i += 0x1000;
    }

    isr_install_handler(14,page_fault);
    switch_directory(kernel_directory);
}


Top
 Profile  
 
 Post subject: Re: Switch Directory Paging causing QEMU error
PostPosted: Sat Sep 07, 2019 12:23 pm 
Offline
Member
Member
User avatar

Joined: Fri Aug 07, 2015 6:13 am
Posts: 1134
Maybe instead of copying a tutorial you should try to understand it first.
We've seen this code countless times and it's bad.

For starters that switch directory is just ugly.
I do it this way:
Code:
extern "C" void Switch_Page_Directory(uint32_t page_directory_address);

global Switch_Page_Directory
Switch_Page_Directory:
   mov eax, [esp + 4]
   mov cr3, eax
   ret


Also you should make a clear distinction between your physical and virtual (paging) memory managers, not bunch it up together like the tutorial guy did.

Trying to understand paging on your own and writing your own code will definitely take longer, but will save you all the hassle later.
Trust me I've been trough all this and something as important as paging shouldn't be left to a tutorial.

_________________
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader


Top
 Profile  
 
 Post subject: Re: Switch Directory Paging causing QEMU error
PostPosted: Sun Sep 08, 2019 7:02 am 
Offline
Member
Member
User avatar

Joined: Thu Oct 13, 2016 4:55 pm
Posts: 1584
Hi,

Everything Octacone said, plus: you can't debug virtual memory mappings with gdb. You should either
1. start qemu with a monitor, and on the monitor tab use "show mem"
2. for a more precise output, use bochs, and on the debug console when the page fault happens, enter "page (address)" to see the full mapping tree for that address. You can get the faulty address from CR2.

Cheers,
bzt


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], Google [Bot], Majestic-12 [Bot] and 155 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group