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読む へ続く