如何设置 x86 分页?出现三重故障错误

发布于 2024-12-01 12:44:52 字数 1960 浏览 2 评论 0原文

我有一个玩具内核,正在 bochs 上的 x86 下运行。当我启用分页时,bochs 会重置并出现三重故障错误。似乎每次内存访问都会触发错误。因此,我假设我在设置分页时出错,并且问题不在于我的中断处理程序。这是代码。

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

I have a toy kernel that I'm working with running under x86 on bochs. When I enable paging, bochs resets with a triple fault error. It seems that it is every and any memory access which triggers the error. So, I'm assuming that I have an error with setting up paging, and the issue is not with my interrupt handler. Here is the code.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

鹿港小镇 2024-12-08 12:44:52

“frame”和“phys_page_addr”字段是物理地址的第 32 位到第 12 位(在此分页模式中)。

分页不会对偏移量 (0 - 4K) 执行任何操作。

至少,您需要:

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

并且

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

由于“addr”和“page_table”都与 4096 对齐,因此这只是删除了多余的零。

The "frame" and "phys_page_addr" fields are bits 32 through 12 (in this paging mode) of the physical address.

Paging doesn't do anything with the offset (0 - 4K).

At the least, you need:

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

and

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

Since both 'addr' and 'page_table' are aligned to 4096, this just removes the extra zeros.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文