2011-08-24 38 views
4

我有一個玩具內核,我正在x86上運行bochs。當我啓用分頁時,bochs會重置三重錯誤。它似乎是觸發錯誤的每一個和任何內存訪問。所以,我假設我在設置分頁時出錯,而這個問題與我的中斷處理程序無關。這是代碼。如何設置x86分頁?獲取三重故障錯誤

paging.c

#include "paging.h" 
#include "lib.h" 
#include "screen.h" 
#include "descriptor_tables.h" 

typedef struct page_dir_entry_s{ 
    bool present:1; 
    bool writeable:1; 
    bool user_access:1; 
    bool write_through:1; 
    bool cache_disabled:1; 
    bool accessed:1; 
    bool unused0:1; 
    bool use_mb:1;//makes pages 4MB not 4KB 
    bool unused1:4; 
    u32 frame:20; 
} page_dir_entry_t; 

typedef struct page_table_entry_s{ 
    bool present:1; 
    bool writeable:1; 
    bool user_access:1; 
    bool write_through:1; 
    bool cache_disabled:1; 
    bool accessed:1; 
    bool dirty:1; 
    bool unused0:1; 
    bool global:1; 
    bool unused1:3; 
    u32 phys_page_addr:20; 
} page_table_entry_t; 

extern u32 end;//as declared in the linker script 

static u32 next_addr=0; 
static page_dir_entry_t* page_dir=NULL; 
static page_table_entry_t* page_table=NULL; 

extern void enable_paging(u32); 

void InitPaging(){ 
    next_addr=end; 
    while((next_addr%4096)!=0) 
     ++next_addr; 
    page_dir=(void*)next_addr; 
    next_addr+=4*1024; 
    memset(page_dir,0,4*1024); 
    page_table=(void*)next_addr; 
    next_addr+=4; 
    u32 addr=0; 
    u32 i=0; 
    *(((u32*)page_table)+i)=0;//zero it out 
    while(addr<next_addr){ 
     page_table[i].present=true; 
     page_table[i].writeable=true; 
     page_table[i].phys_page_addr=addr; 
     ++i; 
     *(((u32*)page_table)+i)=0;//zero it out 
     addr+=(1024*4);//4KB 
     next_addr+=4; 
    } 

    page_dir[0].writeable=true; 
    page_dir[0].present=true; 
    page_dir[0].frame=(u32)page_table; 

    enable_paging((u32)page_dir); 
} 

paging_asm.s

[global enable_paging] 
enable_paging: 
    mov eax,[esp+4] 
    mov cr3,eax 
    mov eax,cr0 
    or eax,0x80000000 
    mov cr0,eax 
    ret 
+1

你把你的堆棧放在內核之後嗎?如果是這樣,任何堆棧訪問都會導致此錯誤(三重錯誤,因爲如果沒有堆棧,則無法處理中斷)。如果您的bochs已啓用調試器,請使用show dbg-all來獲取有關原因的更多信息。另外,爲了循環next_addr而沒有循環:next_addr =(next_addr + 0xFFF)&0xFFFFF000' – ughoavgfhw

+0

當我運行它時,next_addr = 0x250A8000和esp = 0x7FE2C,所以這不是問題。 – Maz

+0

最小工作分頁示例:https://github.com/cirosantilli/x86-bare-metal-examples/blob/24988411adf10cf9f6afd1566e35472eb8ae771a/paging.S –

回答

1

「幀」 和 「phys_page_addr」 字段的位32至12(在這個尋呼模式)實際地址。

尋呼不會對偏移量(0 - 4K)做任何事情。

至少,你需要:

page_table[i].phys_page_addr=addr >> 12; 

page_dir[0].frame=((u32)page_table) >> 12; 

因爲這兩個 '地址' 和 'page_table' 對齊到4096,這只是刪除了多餘的零。