memo
[[2022-03-27]] 11.5-18
OS周辺の学習として, 友人と xv6 を読んでいきます. この記事はその為の備忘録です. 前提知識が何もないので都度フォールバックしています.
-
GitHub - uva-reiss-cs4414/xv6: xv6 OS [version for Reiss's CS4414]
-
Ubuntu20.04 on WSL2に [[QEMU]] 入れた
Makefile を見る
dd command
単位512byte, countブロックファイル読み書き
dd if=/dev/zero of xv6.img count=10000
電源が入ってから起動するまで
[[UEFI]] or [[BIOS]] -> [[ブートローダー]] -> [[systemd]] 起動, サービス起動
BIOS: bootloaderを探す
xv6.img: [bootloader(1blk) || kernel(..)] ? -> ぽい
MBRの探索は、優先順位の高いブートデバイスから順に、そのデバイスの先頭1セクタの末尾2バイトが0x55 0xaa (Boot Signature) であるか確認することによって行われる。BIOSは、Boot Signatureが存在するセクタを発見すると、そのセクタの内容を0x7c00 番地にロードし、実行を移す。
-
ブートローダーは Master Boot Record(MBR) に入っていて, 512B

55 aa あった.
$buf .= "\0" x (510-$n);
$buf .= "\x55\xAA";
bootloader(446B) + partition table(64B) で 510B. つじつまあう.
objcopy
$ objcopy -S -O binary -j .text bootblock.o bootblock
# bootblock.o: ELF
# bootblock: binary
-S: 再配置とシンボルの情報を入力ファイルからコピーしません
-O binary: binaryにする
-j .text: .text section取り出す.
$ readelf bootblock.oのでの.textの Off(000074) を見ると一致- #todo
kernelをldする時.dataに行くのはなぜなのか,kernel.ldにそれらしきことは書いて有りそう

ld $(LDFLAGS) -N -e start -Ttext 0x7C00 -o bootblock.o bootasm.o bootmain.o
objdump -S bootblock.o > bootblock.asm
-Ttext でこっちが勝手に0x7C00 して良いのか
- xv6 のブートローダーを読む
- 仕様でhistorical reasonだった, 絶対に
0x7C00にロードされる. x86 - BIOS and Address 0x07C00 - Stack Overflow
Makefile から見るとソースコードの依存関係がわかり読む助けになる
為.
-
#idea [[適当なコマンド列渡すと,
manから引っ張って意味を解説してくれるツール]] 欲しい
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);
...
// Read 'count' bytes at 'offset' from kernel into physical address 'pa'.
// Might copy more than asked.
void
readseg(uchar* pa, uint count, uint offset) {
uchar *epa;
epa = pa + count;
pa -= offset % SECTSIZE;
// 1セクタ目=(kernelの先頭)から
offset = (offset / SECTSIZE) + 1;
// セクタごとに読み込み
for (; pa < epa; pa += SECTSIZE, offset++)
readsect(pa, offset);
}
xv6.img の先頭4096Bを [[ELF]] header として読んで, Entry point addr(elf->entry) を見つけ, 関数ポインタとして実行する (示す先は entry.S の _start, kernel.ld で ENTRY(_start) と指定しているので) .
-
misc: zellijのトリガ:
C-t -
offset = (offset / SECTSIZE) + 1;- 罠: ここで単位がセクタに変換される
- 0ブロック目はbootloader, それ以降はkernel
outb: I/O portにデータを読み書きする
kernel.ld
SECTOINS {
// must equal to KERNLINK
. = 0x80100000;
.text : AT(0x100000) {
}
}
0x80100000は [[VMA]],0x100000は [[LMA]]- #todo kernel は 213KiBしかないので,
AT()の意味がわからない- 関係なかった, [[ld Linker Script]] 参照
- xv6 Kernel-12: Linking the Kernel - YouTube
- #todo kernel は 213KiBしかないので,
[xv6] paging読む へ続く