2016-11-20 43 views
1

我試圖在Qemu上的x86架構上啓用分頁。
但是這個代碼導致三重故障。在x86中啓用分頁Qemu

該代碼段在保護模式被執行。
代碼:https://github.com/mridulv/simpleOperatingSystem

這是內核入口文件

[bits 32] 

[extern main] 
[extern main2] 
[extern page_table] 

call main 

lea ECX, [page_table - 0xC0000000] 
mov CR3, ECX 

mov ECX, CR0 
or ECX, 0x80000000 
mov CR0, ECX 

;lea ECX, [StartInHigherHalf] 
;jmp ECX 

;StartInHigherHalf: 
; call main2 

jmp $ 

這是創建的頁面目錄,表內核文件。

unsigned int page_table[1024] __attribute__((aligned(4096)));; 

void set_page_tables() { 
    unsigned int pages_entry[1024 * 1024] __attribute__((aligned(4096))); 

    unsigned int KERNEL_VIRTUAL_OFFSET = 0xC0000000; 
    unsigned int KERNEL_FIRST_VIRTUAL_ADDRESS = 0xC0000000 >> 12; 

    int numPageTables = 4; 
    int numPagesInPageTable = 1024; 
    int numPageTableEntriesInPageDirectory = 1024; 
    int totalPages = numPageTables * numPagesInPageTable; 

    unsigned int index = 0; 
    unsigned int *pages_ptr = (unsigned int *)(pages_entry - KERNEL_VIRTUAL_OFFSET); 
    unsigned int *page_table_ptr = (unsigned int *)(pages_entry - KERNEL_VIRTUAL_OFFSET); 

    unsigned int positionAndFlags = 7; 

    while (index < totalPages) { 
     pages_ptr[index] = positionAndFlags; 
     index = index + 1; 
     positionAndFlags += 4096; 
    } 

    positionAndFlags = 7; 
    index = KERNEL_FIRST_VIRTUAL_ADDRESS; 
    unsigned int totalPagesLeft = KERNEL_FIRST_VIRTUAL_ADDRESS + totalPages; 
    while (index < totalPagesLeft) { 
     pages_ptr[index] = positionAndFlags; 
     index = index + 1; 
     positionAndFlags += 4096; 
    } 

    positionAndFlags = (unsigned int)&pages_ptr[0]; 
    positionAndFlags = positionAndFlags | 7; 
    index = 0; 
    while (index < numPageTableEntriesInPageDirectory) { 
     page_table_ptr[index] = positionAndFlags; 
     index = index + 1; 
     positionAndFlags += 4096; 
    } 
} 

void main() { 
    char* video_memory = (char*) 0xb8000; 
    *video_memory = 'X'; 
    set_page_tables(); 
} 

void main2() { 
    char* video_memory = (char*) 0xb8004; 
    *video_memory = 'Y'; 
    // __asm__ 
    // (
    // "leal (page_table,), %ecx\n\t" // 0xC0000000 = KERNEL_VIRTUAL_BASE 
    // "movl %cr3, %ecx" 
    //); 
} 

Linker.ld

SECTIONS { 
    . = 0xC0100000; 

    .text : AT(ADDR(.text) - 0xC0000000) { 
     *(.text); 
    } 

    . = ALIGN(0x1000); 
    .bss : AT(ADDR(.bss) - 0xC0000000) { 
     *(.text); 
    } 

    . = ALIGN(0x1000); 
    .data : AT(ADDR(.data) - 0xC0000000) { 
     *(.text); 
    } 
} 
+0

一些明顯的事情。您不能啓用我可以說的[A20行](http://wiki.osdev.org/A20_Line)。在'boot.asm'中,開始時保存_DL_(啓動驅動器),然後立即放置數據('PROTECTED_MODE_STR'和'BEGIN_STR')。 CPU將嘗試執行數據。在所有代碼之後放置數據(嘗試將它們移至引導簽名之前)。另一個大問題是,你在內存中加載你的內核在0x1000。您的鏈接器腳本使用「0xC0100000」的基礎。這假定你的內核是在0x100000加載的,但你的是在0x1000。所以在你的情況下,你可能需要'0xC0001000' –

+0

我甚至沒有超越那個。但是,即使遇到嘗試啓用分頁的代碼,您也有足夠的問題。 –

+0

我還建議改變之類的東西'LEA ECX,[page_table - 0xC0000000的]''到MOV ECX,page_table - 0xC0000000' –

回答

0

我會建議你在你的代碼的頂部添加部分報關,把事情說清楚 -

section .text 

和錯誤在你的碼是在執行前

call main 

你的代碼沒有(完全)通過填寫ESP寄存器來設置堆棧。

要做到這一點,你的代碼應該像

  1. 創建這樣一個常量 'STACK_SIZE' -

    STACK_SIZE equ <valueOfSizeOfStack> 
    
  2. 用於堆

    section .bss 
    kernelStack: RESB <valueOfSizeOfStack> 
    
創造空間

在「valueOfSi zeOfStack「字段中,您可以爲您的堆棧添加4096(4-KB)或其任意倍數(不會太大,它將以您的二進制大小計算)。

+0

在GitHub上,搜索CircuitKernel以查看我正在創建的完整內核示例。 –