首页 > 解决方案 > 在 cr0 上设置标志后,启用分页会立即导致 PAGE_FAULT

问题描述

我在自己的操作系统上工作,这很有趣,但我被分页卡住了,我写了简单(非常简单)的分页代码,但是当我打开分页时,出现页面错误。一些细节: 我使用 C 作为内核 我使用 qemu 作为 VM 我有自己的交叉编译器 我不使用任何外部库加载并跳转到内核代码后我设置中断并重新映射 PIC,它正在工作,我认为它不是问题,之后我尝试启用分页 这是 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

我正在使用一些教程中的 page_t 结构,因为我认为它非常方便,其他部分,我自己写了两次,在这两种情况下都是使用 PageFault 的代码结果。这是page.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));

}

这是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);
}

我的内核低于 0x10000,它大约有 16kb,所以 0x10000 是映射空间的安全开始,并且该地址的内存肯定没有被使用,我只设置了一个页表,因为我想制作分页准系统,然后注意分配和释放,所以我现在唯一的目标是找出我犯了什么错误。

===========
_

//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;
        }
}

我认为这绝对可能是问题的根源,但我不知道为什么当我调用另一个函数时placement_addr 会发生变化,以及为什么它会更改为 0x11000

标签: coperating-systempaging

解决方案


推荐阅读