💽

OSを1000行で書いてみた(をやってみる): 02

に公開

printf関数,カーネルパニックと例外処理,メモリ割り当ての実装を行いました.気づいたことを備忘録としてまとめていきます.以下サイトを基に実装しています.

https://operating-system-in-1000-lines.vercel.app/ja/09-memory-allocation

05 Hello World!

いまさらながら,.hの役割について学んだ.今までただ関数をそこで定義しているだけだと思っていたが,定数や型をここでラップすることで,*.hを書き換えれば処理系にあわせられるようにできることに気づいてなるほど…となった.

06 C標準ライブラリ

基本的な型(intとか)とマクロ(文字列操作関数)を実装する.一般的にはstdint.h やstring.hを使用するが,今回はゼロから作る.
(意義) 他の処理系(バージョンが異なる/gcc以外)でも個々の部分を書き換えれば動く

07 Panicの実装

カーネル:中心となって制御を行う司令塔
Panic:カーネルの処理中に続行不能なエラーが起きた時に発生させる
(具体的な実装)動かしている部分の行数とエラーメッセージを表示

08 例外処理の実装

パニックと例外処理って似てるが,何が違うの?
パニック:回復不能なエラー(メモリ破損,リソース不足など)によって呼ばれる強制終了。処理を中止し計算資源の保護を目的とする
例外処理:予期しないエラーを検出し,それに対処する(処理の続行を目的とする)

例外の受け取り(何かが起きる→保存する)a0にポインタをさして,全部lwしてメモリに保存.
呼び出されたhandle_trap関数にはscauseとsepcを取得し,先ほど実装したカーネルパニックでエラー内容を表示
(要は間に合わせの例外処理として,情報を保存してpanicを呼んでエラーを表示していると解釈)

実行結果
PANIC: kernel.c:179: unexpected trap scause=00000002, stval=00000000, sepc=802001fa

09 メモリ割り当て

09-1 リンカスクリプト

64MBの動的割り当て可能なメモリ領域を追加.4KB境界でアラインメント

kernel.ld
   . = ALIGN(4);
   . += 128 * 1024; /* 128KB */
   __stack_top = .;

   . = ALIGN(4096);
   __free_ram = .;
   . += 64 * 1024 * 1024; /* 64MB */
   __free_ram_end = .;
}

09-2 たぶん世界一シンプルなメモリ割り当てアルゴリズム

バイト長とか気にせずページという大きな単位で割り当てる&メモリ開放機能がないので,メモリリークしっぱなしの実装.
割り当てアルゴリズムのことはBumpアロケータまたはLinearアロケータと呼ばれており、解放処理が必要ない場面で実際に使われている。数行に実装できて高速に動作する、魅力的な割り当てアルゴリズム

kernel.c
extern char __free_ram[], __free_ram_end[];

paddr_t alloc_pages(uint32_t n) {
    static paddr_t next_paddr = (paddr_t) __free_ram;
    paddr_t paddr = next_paddr;
    next_paddr += n * PAGE_SIZE;

    if (next_paddr > (paddr_t) __free_ram_end)
        PANIC("out of memory");

    memset((void *) paddr, 0, n * PAGE_SIZE);
    return paddr;
}

メモリ割り当てのテスト

void kernel_main(void) {
    memset(__bss, 0, (size_t) __bss_end - (size_t) __bss);

    paddr_t paddr0 = alloc_pages(2);
    paddr_t paddr1 = alloc_pages(1);
    printf("alloc_pages test: paddr0=%x\n", paddr0);
    printf("alloc_pages test: paddr1=%x\n", paddr1);

    PANIC("booted");
}
実行結果
alloc_pages test: paddr0=80221000
alloc_pages test: paddr1=80223000
PANIC: kernel.c:155: booted
実行結果
llvm-nm kernel.elf | grep __free_ram
80221000 B __free_ram
84221000 B __free_ram_end

無事に2ページ分のメモリ(2*0x1000)(0x1000=4KB)分がmallocされたことが分かる.

Discussion