iT邦幫忙

2025 iThome 鐵人賽

DAY 18
0
自我挑戰組

30 天 hypervisor 入門系列 第 18

Day18 掛載簡易 BIOS

  • 分享至 

  • xImage
  •  

在 x86 架構中,CPU 上電後會從固定地址 reset vector (0xFFFF0) 開始執行。BIOS 在這裡會放置一條 far jump 指令,將控制權轉交給真正的 BIOS 入口 (通常位於 0xF000:0x0000,也就是實體位址 0xF0000),再展開後續的初始化流程。

今天的目標是,在 Hypervisor 中掛載一顆 最小化 BIOS 韌體:

  • 透過 bios_firmware_load(封裝 open + read) 將 bios.bin 複製到 ROM 區塊 (0xF0000–0xFFFFF)。
  • 在 0xFFFF0 放置 far jump,跳到 0xF000:0000,跑 BIOS 初始化邏輯。
  • 而 BIOS 初始化則包括,建立中斷向量表 (IVT),配置到 0x0000–0x03FF 與安裝一些中斷服務程式。

記憶體配置

在我們的 Hypervisor 環境中,系統的記憶體布局如下:

0x00000 -------------------------
         Interrupt Vector Table (IVT, 256 個 entry)
         每個 entry 4 bytes → offset:segment

0x07C00 -------------------------
         Boot 入口 (Boot Sector, 512 bytes)
         BIOS 最後會跳到這裡開始執行開機程式

0xF0000 -------------------------
         BIOS 韌體入口 (初始化邏輯)
         - 建立 IVT
         - 跳往 boot sector

0xFFFF0 -------------------------
         Reset Vector
         jmp far F000:0000   ; 將控制權交給 BIOS 韌體入口

0xFFFE -------------------------
         0xAA55 簽名 (BIOS ROM header)
         標記這是一段有效的 BIOS ROM

BIOS 初始化內容

目前 bios.bin 的設計相當單純,主要分為幾個部分:

  1. Reset Vector (0xFFFF0)
    在 ROM 最尾端放置一條 jmp far F000:0100 指令,將控制權交給 BIOS 主程式。同時在 ROM 結尾補上 0xAA55,標示這是一段合法 BIOS。

2.BIOS 入口 (0xF0000)
這裡會先關閉中斷確保初始化過程不會被任何事情打擾,並清空暫存器。接著建置 IVT,在0x0~0x3FF 配置好 IVT。接著透過 out 命令向 Host 輸出 [BIOS] reset complete banner,驗證 BIOS 已掛載並正常運行。
最後開啟中斷,讓系統進入正常中斷處理階段,並交付控制權給 0x7C00 的 Bootloader。

3.中斷向量表 (IVT)
IVT 位於 Real mode 的 0x0000–0x03FF,共有 256 個 entry,每個 entry 4 bytes (offset + segment)。我們將常見的幾個中斷號掛上測試用的 ISR:

  • INT 10h -> 顯示服務
  • INT 13h -> 磁碟服務
  • INT 16h -> 鍵盤服務
  • INT 1Ah -> 定時器服務

4.ISR(中斷服務程式)
由於目前尚未模擬真實裝置,這些 ISR 只做一件事:
透過 out dx, al 將訊息送到 0xE9 debug port,由 Hypervisor/host 端處理。
如:
調用 INT 10h → 輸出 [BIOS] INT 10h

程式碼

.code16
.intel_syntax noprefix


.equ ROM_SEGMENT, 0xF000
/* ROM 起始地址 */
.equ DEBUG_PORT, 0x00E9

.section .text
.globl _start

_start = bios_reset_entry
.org 0x0000

bios_default_isr:
    push ax
    push dx
    mov al, '!'
    call bios_putc
    pop dx
    pop ax
    iret
/* 未實現的中斷服務程式一律打印 ! */
.org 0x0100
bios_reset_entry:
    cli
    cld
    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0x8000

    call setup_ivt

    mov ax, cs
    mov ds, ax
    mov es, ax

    mov si, offset bios_banner
    call bios_puts

    mov ax, 0
    mov ds, ax
    mov es, ax
    sti
    jmp far ptr 0x0000:0x7C00
    /* 執行 boot loader */

setup_ivt:
    push ax
    push ds
    push bx

    xor ax, ax
    mov ds, ax
    mov bx, ROM_SEGMENT

    mov word ptr ds:[0x0000], offset bios_default_isr
    mov word ptr ds:[0x0002], bx

    mov word ptr ds:[0x10 * 4], offset bios_video_handler
    mov word ptr ds:[0x10 * 4 + 2], bx

    mov word ptr ds:[0x13 * 4], offset bios_disk_handler
    mov word ptr ds:[0x13 * 4 + 2], bx

    mov word ptr ds:[0x16 * 4], offset bios_keyboard_handler
    mov word ptr ds:[0x16 * 4 + 2], bx

    mov word ptr ds:[0x1A * 4], offset bios_timer_handler
    mov word ptr ds:[0x1A * 4 + 2], bx

    pop bx
    pop ds
    pop ax
    ret

bios_putc:
    push dx
    mov dx, DEBUG_PORT
    out dx, al
    pop dx
    ret

bios_puts:
    push ax
    push si
    pushf
    cld

1:
    lodsb
    test al, al
    jz 2f
    call bios_putc
    jmp 1b

2:
    popf
    pop si
    pop ax
    ret

bios_video_handler:
    push ax
    push dx
    push ds

    push cs
    pop ds
    mov si, offset bios_msg_int10
    call bios_puts

    pop ds
    pop dx
    pop ax
    iret

bios_disk_handler:
    push ax
    push dx
    push ds

    push cs
    pop ds
    mov si, offset bios_msg_int13
    call bios_puts

    pop ds
    pop dx
    pop ax
    iret

bios_keyboard_handler:
    push ax
    push dx
    push ds

    push cs
    pop ds
    mov si, offset bios_msg_int16
    call bios_puts

    pop ds
    pop dx
    pop ax
    iret

bios_timer_handler:
    push ax
    push dx
    push ds

    push cs
    pop ds
    mov si, offset bios_msg_int1a
    call bios_puts

    pop ds
    pop dx
    pop ax
    iret

bios_banner:
    .ascii "[BIOS] reset complete\r\n"
    .byte 0

bios_msg_int10:
    .ascii "[BIOS] INT 10h\r\n"
    .byte 0

bios_msg_int13:
    .ascii "[BIOS] INT 13h\r\n"
    .byte 0

bios_msg_int16:
    .ascii "[BIOS] INT 16h\r\n"
    .byte 0

bios_msg_int1a:
    .ascii "[BIOS] INT 1Ah\r\n"
    .byte 0

.org 0xFFF0
bios_reset_vector:
    jmp far ptr ROM_SEGMENT:0x0100
    .byte 0x00, 0x00, 0x00

.org 0xFFFE
bios_signature:
    .word 0xAA55

執行結果

https://ithelp.ithome.com.tw/upload/images/20251003/20178814hh1oFiPcIA.png


上一篇
Day 17 簡易 Bios 載入器
下一篇
Day 19 實現 INT 13h 磁碟功能
系列文
30 天 hypervisor 入門20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言