6.828: Operating System Engineering (94)

ええと、load_icode 検討の前にこないだスケッチした segment_alloc 手続きを控えておきます。

static void
segment_alloc(struct Env *e, void *va, size_t len)
{
	// LAB 3: Your code here.
	// (But only if you need it for load_icode.)
	//
	// Hint: It is easier to use segment_alloc if the caller can pass
	//   'va' and 'len' values that are not page-aligned.
	//   You should round va down, and round len up.
    int i;
    struct Page *pp;
    va = ROUNDDOWN(va, PGSIZE);
    len = ROUNDUP(len, PGSIZE);
    for(i = 0; i < len; i += PGSIZE, va += PGSIZE) {
        if (!page_alloc(&pp))
	   panic("cannot page allocate");
	if (!page_insert(e->env_pgdir, pp, va, PTE_U))
	   panic("cannot page insert");
    }   
}

本当かなぁ。とりあえずこれで良いってことにしといて次。
# あ、コメントに Pages should be writable by user and kernel. ってあるな

load_icode 手続き

static void
load_icode(struct Env *e, uint8_t *binary, size_t size)

を踏まえると ELF バイナリの先頭アドレスとサイズが渡されるのか。あとなんとなくヘッダのエラーチェックとかしなくてよさげ。
そーゆー意味では手順としては

  • binary + e_phoff がプログラムヘッダの先頭アドレス
  • ELF ヘッダの e_phnum 属性の値の回数繰り返し
  • プログラムヘッダの先頭アドレスは binary + e_phoff + (e_phentsize * i) で取得できる
  • プログラムヘッダの p_type 属性が ELF_PROG_LOAD が処理対象

あら? これ、どうやってコピィすりゃ良いのかな。あ、ここで segment_alloc が出てくるのか。page_lookup して NULL が戻ってこなければ確保すれば良い?
あまり細かいこと気にせずにヤッツケれば OK かなぁ。処理対象であれば

  • segment_alloc でページ確保
  • p_filesz な領域を確保すりゃ良いか

確保した領域を 0 で memset して p_memsz 分 memcpy すれば良いんだとは思うのですが、どこにコピーするんだろ。ちょっと頭が混乱してるカンジ。
ええと、page_lookup で page table entry 取得できるってことはそこプラス PGOFF(va) な要素が該当する位置にあたると思うんですが、ページを跨ぐ場合どうなるんでしょ。

落ち着け

なんとなくページング周辺なリハビリ不足 (つーか理解不足) をなんとかしないと。てゆーかページが連続してる保証はどこにも無いのでこのあたりは頑張って、ということになるのかどうなのか。
まずどうやって 0 で memset するか、ということから考えてみましょう。

  • page_lookup すれば va から該当する page table entry が分かる
  • そこに格納可能なのは PGSIZE - PGOFF(va) になる?
  • PGOFF(va) に p_filesz を加えた値が PGSIZE を超えたらページ跨がり
  • 跨がる場合 va + (PGSIZE - PGOFF(va)) を page_lookup に渡して戻ってくるソレが次のページの先頭?
    • 跨がる場合の残サイズは PGSIZE - (PGOFF(va) + p_filesz) になるのか
    • む、これは繰り返しになるのか

もう少し Hints なコメント読んで実装書いてみる方向。なんとなくループが沢山ネストしそうで嫌だなぁ。