私自身のカーネルを実装していますが、私は立ち往生しています。私はカーネルを上位半の仮想アドレスにロードしようとしています。私は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は応答を停止し、システムは絶えず再起動します。画面がフラッシュされてから、繰り返し印刷されます。これがなぜ起こっているのか?どのように私はそれを修正することができます?
最小限の完全な検証可能な例を提供するのに役立つものは何ですか。すべての_C_ファイル(部分的です)を提供するわけではなく、使用している定義を提供していません。私はいくつかは何かを推測することができますが、正しく定義されているかどうかはわかりません。誰もが独立してコンパイル/アセンブル/リンクできるように十分なコードを提供する利点 - コンパイル/アセンブル/リンクに使用する実際のコマンドは何ですか?このような質問でも、それはしばしば価値があります。 –
@MichaelPetchひどい夜のデバッグの後、私は解決策に出た。問題は、自分自身を使用するのではなく、GRUBのGDTを使用していたことでした。私が推測しているのは、私が直面していた線形アドレスの1つが自分のページディレクトリにマップされておらず、これがページフォールトまたは未定義の動作を引き起こしたことです。 – Delights
[マルチブート仕様](https://www.gnu.org/software/grub/manual/multiboot/multiboot.html)にはそれほど言及されていません。関連する引用符:_GDTR セグメントレジスタは上記のように設定されていても、 'GDTR'は無効なので、** OSイメージはセグメントレジスタをロードしてはいけません**(同じ値を再ロードするだけです)自身の 'GDT'を設定するまで** _ –