目的
GRUBから直接C言語で書いた自作カーネル(ただHELLOと表示するだけ)を起動する手順をまとめます。
以前自作OSを作っていた時は、ブートローダや、32bitモードに切り替える処理を自分で書いており、C言語コードへ移行するまでにかなり苦労しましたが、GRUBを使うと勝手にやってくれるようなので試してみます。
https://github.com/ooe1220/KansoOS/blob/master/src/kernel/switch32.asm
GRUBと言えば複数のOSを選択して起動する機能が先に浮かびますが、こんな機能があることは知りませんでした。
コード
kmainに跳ぶ処理です。
bits 32
global start
extern kmain
align 4
mb_header:
dd 0x1BADB002 ; magic
dd 0x0 ; flags
dd -(0x1BADB002 + 0x0) ; checksum
start:
cli
mov esp, 0x90000 ; 適当なスタック
call kmain
hlt
VGAの画面を一旦全て空で上書きしてから、HELLOを表示するだけです。
void kmain(void) {
volatile unsigned char *vid = (unsigned char *)0xB8000;
// 画面全体を空白(0x20)+白文字/黒背景(0x07)で埋める
for (int i = 0; i < 80 * 25 * 2; i += 2) {
vid[i] = ' '; // 文字コード
vid[i + 1] = 0x07; // 属性(白/黒)
}
const char *msg = "HELLO";
int i = 0;
for (int j = 0; msg[j]; j++) {
vid[i++] = msg[j]; // ASCII
vid[i++] = 0x07; // 白文字/黒背景
}
for (;;) asm ("hlt");
}
OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
SECTIONS {
. = 0x100000;
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss) }
}
GRUBの設定
set timeout=0
set default=0
menuentry "mykernel" {
multiboot /boot/kernel.bin
boot
}
起動ディスクの作成
grub-mkrescue命令でGRUBのブートローダ等を書き込んでいます。
nasm -f elf32 start.asm -o start.o
gcc -m32 -ffreestanding -nostdlib -c kernel.c -o kernel.o
ld -m elf_i386 -T link.ld -o kernel.bin start.o kernel.o
grub-file --is-x86-multiboot kernel.bin
mkdir -p iso/boot/grub
cp kernel.bin iso/boot/kernel.bin
cp grub.cfg iso/boot/grub/grub.cfg
grub-mkrescue -o myos.iso iso
実行結果
QEMU
GRUBが色々処理をしているのか、自作ブートローダから立ち上げた時よりも画面表示に時間が少しだけかかりました。
qemu-system-i386 -cdrom myos.iso
dynabook SS M10 11L/2実機
sudo dvd+rw-format -blank=fast /dev/sr0
sudo growisofs -dvd-compat -Z /dev/sr0=myos.iso
GRUBで初めに実行される命令
biosからkernel.cが呼ばれる間にGRUBが何をしているか全てを理解するのは難しいですが、せめて初めの数十行くらいを見てみようと思います。
初めに実行されるコードを逆アセンブルします。
xorriso -indev myos.iso -report_el_torito plain
xorriso -indev myos.iso -osirrox on -extract boot/grub/i386-pc/eltorito.img eltorito_extracted.img
dd if=eltorito_extracted.img of=cdboot_extracted.img bs=512 count=1
ndisasm -b 16 eltorito_extracted.img > disasm.txt
大変なのであまり深くは読みませんが、文字表示のint 0x10やディスク読み込みのint 0x13が見えます。
00000000 E80000 call 0x3
00000003 EB3B jmp short 0x40
00000005 0000 add [bx+si],al
00000007 0010 add [bx+si],dl
00000009 0000 add [bx+si],al
0000000B 008D0B00 add [di+0xb],cl
0000000F 00EB add bl,ch
00000011 7100 jno 0x13
00000013 008A9461 add [bp+si+0x6194],cl
00000017 B300 mov bl,0x0
00000019 0000 add [bx+si],al
0000001B 0000 add [bx+si],al
0000001D 0000 add [bx+si],al
0000001F 0000 add [bx+si],al
00000021 0000 add [bx+si],al
00000023 0000 add [bx+si],al
00000025 0000 add [bx+si],al
00000027 0000 add [bx+si],al
00000029 0000 add [bx+si],al
0000002B 0000 add [bx+si],al
0000002D 0000 add [bx+si],al
0000002F 0000 add [bx+si],al
00000031 0000 add [bx+si],al
00000033 0000 add [bx+si],al
00000035 0000 add [bx+si],al
00000037 0000 add [bx+si],al
00000039 0000 add [bx+si],al
0000003B 0000 add [bx+si],al
0000003D 0000 add [bx+si],al
0000003F 005B31 add [bp+di+0x31],bl
00000042 C08ED0BC00 ror byte [bp-0x4330],byte 0x0
00000047 60 pusha
00000048 8ED8 mov ds,ax
0000004A 8EC0 mov es,ax
0000004C BEDD7C mov si,0x7cdd
0000004F 2E668B8F0D00 mov ecx,[cs:bx+0xd]
00000055 6609C9 or ecx,ecx
00000058 7476 jz 0xd0
0000005A 6681C1FF070000 add ecx,0x7ff
00000061 66C1E90B shr ecx,byte 0xb
00000065 2E668BB70900 mov esi,[cs:bx+0x9]
0000006B E80500 call 0x73
0000006E EA00002008 jmp 0x820:0x0
00000073 6631C0 xor eax,eax
00000076 6A10 push byte +0x10
00000078 6646 inc esi
0000007A 6650 push eax
0000007C 6656 push esi
0000007E 680008 push word 0x800
00000081 6650 push eax
00000083 6A10 push byte +0x10
00000085 6631FF xor edi,edi
00000088 89E6 mov si,sp
0000008A 8B7C10 mov di,[si+0x10]
0000008D 6639CF cmp edi,ecx
00000090 7603 jna 0x95
00000092 6689CF mov edi,ecx
00000095 897C02 mov [si+0x2],di
00000098 6651 push ecx
0000009A B442 mov ah,0x42
0000009C CD13 int 0x13
0000009E 7316 jnc 0xb6
000000A0 B442 mov ah,0x42
000000A2 CD13 int 0x13
000000A4 7310 jnc 0xb6
000000A6 D1EF shr di,1
000000A8 7423 jz 0xcd
000000AA 897C10 mov [si+0x10],di
000000AD 897C02 mov [si+0x2],di
000000B0 B442 mov ah,0x42
000000B2 CD13 int 0x13
000000B4 72F0 jc 0xa6
000000B6 89F8 mov ax,di
000000B8 C1E007 shl ax,byte 0x7
000000BB 014406 add [si+0x6],ax
000000BE 66017C08 add [si+0x8],edi
000000C2 6659 pop ecx
000000C4 6629F9 sub ecx,edi
000000C7 75C1 jnz 0x8a
000000C9 83C412 add sp,byte +0x12
000000CC C3 ret
000000CD BEEA7C mov si,0x7cea
000000D0 B40E mov ah,0xe
000000D2 31DB xor bx,bx
000000D4 AC lodsb
000000D5 CD10 int 0x10
...(省略)