目的
Pentiumの古いパソコンを所有しており、ベアメタルの実験をしたいのですが、あまりに古くHDDと光学ドライブからの起動にしか対応していない為、アセンブリで書いたコードをDVDに書き込み実機で動かすまでの手順を纏めました。
今回動かしたのは起動してから32ビットモードに入るだけの単純なコードです。
検証
ThinkPad X280
dybabook SS M10 11L/2
コンパイルからDVD書き込み
nasm -f bin boot.asm -o boot.bin
mkdir iso
cp boot.bin iso/
xorriso -as mkisofs \
-o os.iso \
-b boot.bin \
-c boot.cat \
-no-emul-boot \
-boot-load-size 4 \
iso
qemu-system-x86_64 -cdrom os.iso -m 512 -boot d
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
mov ax, 0x0003
int 0x10
; GDTロード
lgdt [gdt_descriptor]
; 32bitモード有効化
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
; ----------------------
; 32ビット突入
; ----------------------
[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
cli
;lidt [idt_descriptor]
; ===== VRAM に文字列描画 =====
mov edi, 0xB8000 ; VRAM 開始
mov esi, msg_32bit
.draw_char:
lodsb ; AL = *ESI++
test al, al
jz .next
mov ah, 0xCE ; 赤背景 + 明るい黄色文字
stosw ; [EDI] = AX
jmp .draw_char
.next:
.hlt_loop:
hlt
jmp .hlt_loop
; set_idt_gate(irq, handler)
; EAX = IRQ番号
; EBX = ハンドラアドレス
set_idt_gate:
push esi
mov esi, idt_start
imul eax, 8
add esi, eax
mov word [esi + 0], bx
shr ebx, 16
mov word [esi + 6], bx
mov word [esi + 2], 0x08 ; コードセグメント
mov byte [esi + 4], 0x00;
mov byte [esi + 5], 0x8F ; Trap Gate(INT1用)
pop esi
ret
; ----------------------
; データ領域
; ----------------------
msg_32bit db "32-bit protected mode entered!", 0
; x86 の IDT は最大 256 個
idt_start:
times 256 * 8 db 0
idt_end:
idt_descriptor:
dw idt_end - idt_start - 1
dd idt_start
times 3072-($-$$) db 0