しばらくxv6のRISC-Vへの移植で、ブートアップが上手くいかずに悩んでいた。
どの部分でコケていたかというと、bootmain.cでロードイメージの判定をして、ブートアップをするのだが、
void bootmain(void) { struct elfhdr *elf; struct proghdr *ph, *eph; void (*entry)(void); uchar* pa; elf = (struct elfhdr*)0x10000; // scratch space // Read 1st page off disk readseg((uchar*)elf, 4096, 0); // Is this an ELF executable? if(elf->magic != ELF_MAGIC) return; // let bootasm.S handle error ...
elfの判定部分でコケていた。readsegが、イメージファイルのロードの部分なのだが、内部はどのようになっているのだろう。
xv6をコンパイルしたイメージファイルをダンプする
hexdumpでxv6.imgをダンプしてみる(x86版)。
0000000 31fa 8ec0 8ed8 8ec0 e4d0 a864 7502 b0fa 0000010 e6d1 e464 a864 7502 b0fa e6df 0f60 1601 0000020 7c78 200f 66c0 c883 0f01 c022 31ea 087c 0000030 6600 10b8 8e00 8ed8 8ec0 66d0 00b8 8e00 0000040 8ee0 bce8 7c00 0000 dfe8 0000 6600 00b8 0000050 668a c289 ef66 b866 8ae0 ef66 feeb 9066 0000060 0000 0000 0000 0000 ffff 0000 9a00 00cf 0000070 ffff 0000 9200 00cf 0017 7c60 0000 8955 0000080 bae5 01f7 0000 83ec c0e0 403c f875 c35d 0000090 8955 57e5 8b53 0c5d e1e8 ffff baff 01f2 00000a0 0000 01b8 0000 ee00 f3b2 d889 89ee c1d8 00000b0 08e8 f4b2 89ee c1d8 10e8 f5b2 89ee c1d8 00000c0 18e8 c883 b2e0 eef6 f7b2 20b8 0000 ee00 00000d0 a9e8 ffff 8bff 087d 80b9 0000 ba00 01f0 00000e0 0000 f3fc 5b6d 5d5f 55c3 e589 5657 8b53 00000f0 085d 758b 8910 03df 0c7d f089 ff25 0001 0000100 2900 c1c3 09ee c683 3901 76df 5617 e853 0000110 ff7c ffff c381 0200 0000 c683 8301 08c4 0000120 df39 e977 658d 5bf4 5f5e c35d 8955 57e5 0000130 5356 ec83 6a0c 6800 1000 0000 0068 0100 0000140 e800 ffa3 ffff c483 810c 003d 0100 7f00 0000150 4c45 7546 a150 001c 0001 988d 0000 0001 0000160 b70f 2c35 0100 c100 05e6 de01 f339 2f73 0000170 7b8b ff0c 0473 73ff 5710 6ae8 ffff 8bff 0000180 144b 438b 8310 0cc4 c139 0c76 c701 c129 0000190 00b8 0000 fc00 aaf3 c383 3920 77de ffd1 00001a0 1815 0100 8d00 f465 5e5b 5d5f 00c3 0000 00001b0 0000 0000 0000 0000 0000 0000 0000 0000 * 00001f0 0000 0000 0000 0000 0000 0000 0000 aa55 0000200 457f 464c 0101 0001 0000 0000 0000 0000 0000210 0002 0003 0001 0000 000c 0010 0034 0000
ここで注目すべきは0x200の部分で、ELFのマジックナンバーである0x4c467f45が格納されていることが分かる。これを判定している部分が、
if(elf->magic != ELF_MAGIC) return; // let bootasm.S handle error
上記のif文ということになる。ということは、elfは0x10000へロードされており、readseg()ではオフセットとして1が加算されていることから、MBRを除いた最初の256バイトをロードしていることが分かる。
// Translate from bytes to sectors; kernel starts at sector 1. offset = (offset / SECTSIZE) + 1; // If this is too slow, we could read lots of sectors at a time. // We'd write more to memory than asked, but it doesn't matter -- // we load in increasing order. for(; pa < epa; pa += SECTSIZE, offset++) readsect(pa, offset); }
ただし問題なのは、0x200ってRISC-VのPCの初期値であり、最初に実行されるプログラムが0x200に格納されていなければならない。 したがって、イメージをロードするときはelfの先頭を少しずらし、0x800からロードされるようにする。そして、先頭のMBRを除く0x600からイメージをロードするように設定すれば、イメージファイルをロードできるようになるという訳だ。
bootmain(void) { struct elfhdr *elf; struct proghdr *ph, *eph; void (*entry)(void); uchar* pa; elf = (struct elfhdr*)0x10000; // scratch space // Read 1st page off disk // readseg((uchar*)elf, 4096, 0); readseg((uchar*)elf, 4096, 0x600); // RISC-V binary start from 0x800
これで、まずは先頭のイメージをロードできるようになった。次は、各種デバイスを初期化できるようになりたい。続く。
参考にした本
自作エミュレータで学ぶx86アーキテクチャ コンピュータが動く仕組みを徹底理解!
- 作者: 内田公太,上川大介
- 出版社/メーカー: マイナビ出版
- 発売日: 2015/08/28
- メディア: Kindle版
- この商品を含むブログを見る
はじめてのOSコードリーディング ~UNIX V6で学ぶカーネルのしくみ (Software Design plus)
- 作者: 青柳隆宏
- 出版社/メーカー: 技術評論社
- 発売日: 2013/01/09
- メディア: 単行本(ソフトカバー)
- 購入: 56人 クリック: 1,959回
- この商品を含むブログ (29件) を見る