目的
x86系のCPUは、電源を入れた時は16ビットモードで動いています。
今回は32ビットモードへ切り替える実験をします。
切り替えたかどうか、見た目で分からないので32ビットのEBXに入れた文字をVRAMへ書き込み、表示されたことを以て32ビットに切り替わっていることの証明とします。
32ビットモードへ入る時にやること
1.GDTの読み込み
2.CR0レジスタの0ビット目を1にする
3.jmp命令を実行し16ビットモードのままのCS:IP
を更新する。
実装
boot.asm
[org 0x7C00]
bits 16
start:
cli
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
mov sp, 0x7C00
sti
; --- INT 13h CHS 読み込み ---
mov ah, 0x02 ; BIOS: Read Sectors
mov al, 1 ; 読み込むセクタ数 (1)
mov ch, 0 ; シリンダ = 0
mov dh, 0 ; ヘッド = 0
mov cl, 2 ; セクタ = 2 (ブートローダの次)
mov dl, 0x80 ; ドライブ番号=HDD
mov bx, 0x7E00 ; ES:BX = 読み込み先
int 0x13
jc disk_error
jmp 0x0000:0x7E00 ; 読み込んだコードへジャンプ
disk_error:
hlt
jmp disk_error
times 510-($-$$) db 0
dw 0xAA55
test.asm
[org 0x7E00]
bits 16
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
mov word [es:0], 0x0F41 ; 'A'
mov word [es:2], 0x0F42 ; 'B'
; 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
mov ebx, 0x32334B4F ; 'O','K','3','2'
mov edi, 0xB8000
mov ecx, 4
display_loop:
mov al, bl ; 下位バイトを取り出す
mov ah, 0x0F ; 属性固定
mov [edi], ax
add edi, 2
shr ebx, 8 ; 次の文字を下位に
loop display_loop
.hlt_loop:
hlt
jmp .hlt_loop
; -----------------------------
times 512-($-$$) db 0
動作確認
nasm -f bin boot.asm -o boot.bin
nasm -f bin test.asm -o test.bin
cat boot.bin test.bin > disk.img
ThinkPad X280
BIOSの設定がUEFIではなく従来のBIOS起動となっていることを確認します。
lsblk
sudo dd if=disk.img of=/dev/sdb bs=512 count=2 conv=notrunc
※thinkpadでは起動出来ましたが、手持ちのゲーミングノートMSI(MS-16R4)は起動出来ませんでした。
OS無しのコードを書くとthinkpadでは大抵動きますが、MSIでは殆ど起動すら出来ません。
低レイヤの好きな方はthinkpadをご購入されることをお薦めします。
QEMU
qemu-system-i386 -hda disk.img