備忘録やめた

備忘録として使用していたけどやめた.このブログに載せてあるコードのライセンスは別途記載がない限りWTFPL OR NYSLです.

カーネルの直後のページがページフォルトを起こした

問題

カーネルが配置されているメモリ(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セクションが必要とする領域の大きさはバイナリファイルに記録されるが,実際にその分の大きさがバイナリファイル内で占められるわけではないということがわかった.

stackoverflow.com

つまり,バイナリファイルのバイト数が,実際にそのバイナリがメモリ上で使用する総バイト数ではない,という事になる.

解決策

バイナリファイルのバイト数を基準にページングの設定を行なうことは出来ないことがわかったが,そもそもカーネルが占める領域を予め0xffffffff80000000 - 0xffffffffa0000000と想定しているため,バイナリの物理アドレスから2GB分をマッピングすることにする.

また,カーネルが2GB以上のメモリを参照しないために,LENGTH = 0x20000000を指定する.これで,もしオーバーした場合,ldがエラーを出してコンパイルできなくなる.