目的
DVDから直接C言語のコードを直接起動する手順をまとめました。
お金に困ってThinkPad X280を売ってしまったのでこれまでの様にUSB起動の実験が出来なくなってしまい、これからはCD起動での実験を行っていきます。
参考にした筆者の過去記事
【OS自作の第一歩】16bit ブートローダから 32bit プロテクトモードへ移行し、C 関数を呼び出すまで
x86アセンブリをDVDから起動し32bit切り替え迄の手順
手順
コンパイル
rmdir tmp
mkdir tmp
nasm -f bin boot.asm -o tmp/boot.bin
gcc -m32 -ffreestanding -c kernel.c -o tmp/kernel.o
nasm -f elf32 swtc.asm -o tmp/swtc.o
ld -m elf_i386 -T linker.ld -o tmp/kernel.elf tmp/swtc.o tmp/kernel.o
objcopy -O binary tmp/kernel.elf tmp/kernel.bin
cat tmp/boot.bin tmp/kernel.bin > tmp/disk.img
mkdir iso
cp tmp/disk.img iso/
xorriso -as mkisofs \
-o os.iso \
-b disk.img \
-c boot.cat \
-no-emul-boot \
-boot-load-size 4 \
iso
動作確認
QEMU
qemu-system-i386 -cdrom os.iso -m 512 -boot d
dybabook SS M10 11L/2
sudo dvd+rw-format -blank=fast /dev/sr0
sudo growisofs -dvd-compat -Z /dev/sr0=os.iso
コード
boot.asm
[org 0x7C00]
bits 16
start:
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
sti
jmp 0x0000:0x7E00
disk_error:
hlt
jmp disk_error
times 512-($-$$) db 0 ;CDの為0xAA55は不要
swtc.asm
bits 16
global start
extern kernel_main
start:
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
mov ax, 0x0003
int 0x10
; VGAリアルモード表示
mov ax, 0xB800
mov es, ax
; GDTロード
lgdt [gdt_descriptor]
; プロテクトモード有効化
mov eax, cr0
or eax, 1
mov cr0, eax
; 32ビットコードへ移行
jmp 0x08:pm_start
; -----------------------------
gdt_start:
dq 0x0000000000000000 ; NULL
gdt_code:
dw 0xFFFF ; limit 0-15
dw 0x0000 ; base 0-15
db 0x00 ; base 16-23
db 0x9A ; code segment
db 0xCF ; flags
db 0x00 ; base 24-31
gdt_data:
dw 0xFFFF
dw 0x0000
db 0x00
db 0x92 ; data segment
db 0xCF
db 0x00
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1
dd gdt_start
; -----------------------------
[bits 32]
pm_start:
; データセグメント設定
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, 0x9FC00
call kernel_main
.hlt_loop:
hlt
jmp .hlt_loop
linker.ld
ENTRY(start)
SECTIONS {
. = 0x7E00;
.text : {
*(.text*)
}
.rodata : {
*(.rodata*)
}
.data : {
*(.data*)
}
.bss : {
*(.bss*)
*(COMMON)
}
}
kernel.c
void putc(char c) {
static int pos = 0;
volatile unsigned short* vram = (unsigned short*)0xB8000;
vram[pos++] = 0x0F00 | c; //属性 背景色 = 0x0 = 黒 文字色 = 0xF = 白
}
void puts(const char* s) {
while (*s) putc(*s++);
}
void kernel_main() {
puts("Hello from C!");
while(1);
}