問題
カーネルが配置されているメモリ(0xffffffff80000000 - 0xffffffff80017000
)の直後のページにてページフォルト発生.
check_exception old: 0xffffffff new 0xe 118: v=0e e=0002 i=0 cpl=0 IP=0038:ffffffff80000083 pc=ffffffff80000083 SP=0030:ffffffffa000dde8 CR2=ffffffff80017060
カーネルのバイナリファイルは93184バイト.
%\ls -l build/kernel.bin -rwxr-xr-x 1 93184 5月 3 12:27 build/kernel.bin
93184 < 0x17000 = 94208であるため,カーネルのバイナリファイルを全て覆うほどのメモリを割り当てていると考えた.
試したこと
リンカスクリプトにMEMORY
セクションを追加.
OUTPUT_FORMAT(binary); ENTRY(os_main) MEMORY{ kernel (WX) : ORIGIN = 0xFFFFFFFF80000000, LENGTH = 0x17000 } SECTIONS { .text 0xFFFFFFFF80000000 : { *(.text.os_main) *(.text*) } > kernel .data : { *(.data) *(.rodata*) *(.bss) } > kernel /DISCARD/ : { *(.eh_frame) } }
make
を実行してカーネルのコンパイルを試みたが,以下のエラーが発生した.
ld -nostdlib -T os.ld -o build/kernel.bin build/libramen_os.a build/func.asm.o ld: build/kernel.bin section `.bss._ZN74_$LT$ramen_os..interrupt..KEY_QUEUE$u20$as$u20$core..ops..deref..Deref$GT$5deref11__stability4LAZY17hcd65e345238f5cbeE' will not fit in region `kernel' ld: region `kernel' overflowed by 100 bytes make: *** [Makefile:79: build/kernel.bin] エラー 1
LENGTH = 0x18000
とするとエラーは出なくなった.
原因:.bss
セクション
.bss
セクションが必要とする領域の大きさはバイナリファイルに記録されるが,実際にその分の大きさがバイナリファイル内で占められるわけではないということがわかった.
つまり,バイナリファイルのバイト数が,実際にそのバイナリがメモリ上で使用する総バイト数ではない,という事になる.
解決策
バイナリファイルのバイト数を基準にページングの設定を行なうことは出来ないことがわかったが,そもそもカーネルが占める領域を予め0xffffffff80000000 - 0xffffffffa0000000
と想定しているため,バイナリの物理アドレスから2GB分をマッピングすることにする.
また,カーネルが2GB以上のメモリを参照しないために,LENGTH = 0x20000000
を指定する.これで,もしオーバーした場合,ld
がエラーを出してコンパイルできなくなる.