2016-07-02 7 views
3

私自身のカーネルを実装していますが、私は立ち往生しています。私はカーネルを上位半の仮想アドレスにロードしようとしています。私はIDのアドレスを解決するためにアイデンティティを解決しました.1MのRAMをマッピングしています。私はinitセクションを作成しました。このセクションは、ページングの初期化を処理するために、カーネルの物理アドレスに再配置されています。私のカーネルの仮想オフセットは0xc0000000です。これは私のリンカースクリプトです:QEMUページングを有効にするときに3重の障害が発生する

OUTPUT_FORMAT(elf32-i386) 
ENTRY(start) 

KERNEL_VIRTUAL_OFFSET = 0xC0000000; 

SECTIONS 
{ 
    . = 1M; 
    kernel_start = .; 

    start_init = .; 
    .init ALIGN(4K) : 
          { *(.multiboot); 
          *(.init); 
          *(.tables); 
          } 
    end_init = .; 

    . += KERNEL_VIRTUAL_OFFSET; 

    kernel_high_half_start = .; 
    .text ALIGN(4K) : AT(ADDR(.text) - KERNEL_VIRTUAL_OFFSET) 
         {*(.text) } 
    .data ALIGN(4K) : AT(ADDR(.data) - KERNEL_VIRTUAL_OFFSET) 
         { *(.data) } 
    .rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_VIRTUAL_OFFSET) 
         { *(.rodata) } 
    .bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_VIRTUAL_OFFSET) 
         { *(.bss) } 
    kernel_high_half_end = .; 

    kernel_end = . - KERNEL_VIRTUAL_OFFSET; 
} 

ここに私のエントリーポイントがあります。私はブートローダとしてGRUBを使用しています。

its 32 
    section .multiboot 
    ;grub bootloader header 
      align 4 
      dd 0x1BADB002   ;magic 
      dd 0x00     ;flags 
      dd - (0x1BADB002 + 0x00) ;checksum. m+f+c should be zero 

    ; Declarations 
    global start 
    extern kmain 
    extern paging_init 
    extern kernel_page_directory 

    section .init 

    enable_paging: 
     mov eax, kernel_page_directory 
     mov cr3, eax 
     mov eax, cr0 
     or eax, 0x80000000 
     mov cr0, eax ; ***** PAGING ENABLED HERE ***** 
     ret 

    start: 
     cli   ;block interrupts 
     mov esp, init_stack 
     call paging_init 
     call enable_paging 

     ;mov eax, 0xb8000 
     ;mov byte[eax], 'h' 
     ;mov byte[eax+1], 0x7 

     ; Now high half kernel is mapped to the page directory 
     mov esp, stack_space ;set stack pointer 
     push ebx ; grub boot info 
     call kmain 

    loop: 
     hlt   ;halt the CPU 
     jmp loop 

    resb 4096; 4KB small stack for my init section. 
    init_stack: 

    section .bss 
    resb 8192 ;8KB for stack 
    stack_space: 

は、こちらのページテーブルとカーネルのページディレクトリを埋める私のコードです:それは正常に起動して、ためinitセクションの私のエントリポイントにジャンプします。あなたが見ることができるように、全体のコードは、再配置の問題を避けるために、initセクションにリンクされている:

page_table_t kernel_page_directory[PAGE_DIR_SIZE] 
__attribute__((aligned(PAGE_SIZE))) __attribute__((section(".tables"))) = {0}; 

page_pointer_t kernel_page_tables[PAGE_TABLE_SIZE] 
__attribute__((aligned(PAGE_SIZE))) __attribute__((section(".tables"))) = {0}; 

page_pointer_t identity_page_table[PAGE_TABLE_SIZE] 
__attribute__((aligned(PAGE_SIZE))) __attribute__((section(".tables"))) = {0}; 

/* Identity map the low 1M 
* In early boot stage. 
*/ 
static void __attribute__((section(".init"))) map_identity() 
{ 
    //map bios 
    unsigned int current_page = 0; 
    for(int i = 0; i < BIOS_PAGE_TABLE_ENTRIES; i++, current_page += PAGE_SIZE) 
    { 
     identity_page_table[i] = (current_page) | 0x3; 
    } 

    //map init 
    current_page = INIT_START; 
    for(int i = INIT_START >> 12 & 0x3FF; 
     i < ((INIT_START >> 12 & 0x3FF) + (INIT_SIZE/PAGE_SIZE)); 
     i++, current_page += PAGE_SIZE) 
    { 
     identity_page_table[i] = (current_page) | 0x3; 
    } 

    kernel_page_directory[0] = ((unsigned long)(identity_page_table)) | 0x3; 
} 

/* Map the kernel memory to its page directory, 
* **in early boot stage. 
* We don't need to map the init section, we don't need it anymore. 
*/ 

__attribute__((section(".init"))) static void map_kernel_memory() 
{ 
    //Identity map the init section 
    //Start at 1MB i.e. its page aligned. 
    unsigned int start_index = 256; 
    unsigned long current_page = KERNEL_START; 

    for(int i = start_index; 
     i < start_index + (KERNEL_SIZE/PAGE_SIZE) + 1; 
     i++, current_page += PAGE_SIZE) 
    { 
     kernel_page_tables[i] = current_page | 0x3; 
    } 

    kernel_page_directory[KERNEL_DIRECTORY_ENTRY] = ((unsigned long)kernel_page_tables) | 0x3; 
} 

__attribute__((section(".init"))) void paging_init() 
{ 
    map_identity(); 

    map_kernel_memory(); 
} 

私は、正確なアセンブリ命令を指すようにしようとしたが、それは間違って私のカーネルの作業を行い、私はそれがあるためだと思いますページングを有効にするとmov cr0, eaxになります。 CR3には、kernel_page_directoryのアドレスまたは0x3のアドレスが含まれています。ページングを有効にすると、QEMUは応答を停止し、システムは絶えず再起動します。画面がフラッシュされてから、繰り返し印刷されます。これがなぜ起こっているのか?どのように私はそれを修正することができます?

+1

最小限の完全な検証可能な例を提供するのに役立つものは何ですか。すべての_C_ファイル(部分的です)を提供するわけではなく、使用している定義を提供していません。私はいくつかは何かを推測することができますが、正しく定義されているかどうかはわかりません。誰もが独立してコンパイル/アセンブル/リンクできるように十分なコードを提供する利点 - コンパイル/アセンブル/リンクに使用する実際のコマンドは何ですか?このような質問でも、それはしばしば価値があります。 –

+1

@MichaelPetchひどい夜のデバッグの後、私は解決策に出た。問題は、自分自身を使用するのではなく、GRUBのGDTを使用していたことでした。私が推測しているのは、私が直面していた線形アドレスの1つが自分のページディレクトリにマップされておらず、これがページフォールトまたは未定義の動作を引き起こしたことです。 – Delights

+2

[マルチブート仕様](https://www.gnu.org/software/grub/manual/multiboot/multiboot.html)にはそれほど言及されていません。関連する引用符:_GDTR セグメントレジスタは上記のように設定されていても、 'GDTR'は無効なので、** OSイメージはセグメントレジスタをロードしてはいけません**(同じ値を再ロードするだけです)自身の 'GDT'を設定するまで** _ –

答えて

0

ページディレクトリのアドレスはページアラインですか?各ページ(フレーム)のサイズは4 KBです。

typedef struct page_directory{ 
    page_table_t *tables[1024]; 
    size_t tablesPhysical[1024]; // Physical address of page tables 
    size_t physicalAddr;   // Physical address of `tablesPhysical' 
} page_directory_t; 

したがって、ディレクトリのアドレスは4 KB(0x1000)の倍数でなければなりません。 James Molloy's Tutorialがお手伝いします。

+0

彼は '__attribute __((aligned(PAGE_SIZE)))'を使います。 PAGE_SIZEが4096であることは、残りのコードから推測できます。したがって、彼が使用している整列された属性は、4k境界で整列します。コメントでは彼は彼が彼の問題を見つけたと言い、それはGRUBのGDTを使用することに関連していて、彼が作ったものではないことに言及しています。 –

関連する問題