Как настроить пейджинг x86? Получение тройной ошибки

У меня есть игрушечное ядро, с которым я работаю, работая под х86 на боксах. Когда я включаю пейджинг, 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

person Maz    schedule 24.08.2011    source источник
comment
Вы поставили свой стек после ядра? Если это так, любой доступ к стеку вызовет это (тройная ошибка, поскольку вы не можете обработать прерывание без стека). Если на вашем компьютере включен отладчик, используйте show dbg-all, чтобы получить дополнительную информацию о причине. Кроме того, чтобы округлить next_addr без цикла: next_addr = (next_addr + 0xFFF) & 0xFFFFF000   -  person ughoavgfhw    schedule 25.08.2011
comment
Когда я запускаю его, next_addr=0x250A8000 и esp=0x7FE2C, так что это не проблема.   -  person Maz    schedule 25.08.2011
comment
Пример минимального рабочего пейджинга: github.com/cirosantilli/x86 -голые-металлические-примеры/blob/   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 27.10.2015


Ответы (1)


Поля «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, это просто удаляет лишние нули.

person Michael Rho    schedule 04.09.2011