1. 初始化串口调试环境

任务目标

在BIOS早期初始化阶段(进入保护模式前),通过直接操作UART 16550寄存器完成串口初始化,并实现单字符输出函数,为后续调试信息打印建立基础通道。

环境与依赖

  • 目标平台:x86实模式,使用NASM汇编
  • 串口基地址:0x3F8(COM1,标准PC约定)
  • 无需额外库,直接端口I/O指令in/out

核心实现

;----------------------------------------------------------
; serial_init.asm - BIOS阶段串口初始化与字符输出
; 汇编: nasm -f bin serial_init.asm -o serial_init.bin
;----------------------------------------------------------
    BITS 16
    CPU 8086

; 串口寄存器偏移(基地址0x3F8)
UART_BASE   EQU 0x3F8
UART_THR    EQU 0x0    ; 发送保持寄存器(写)
UART_IER    EQU 0x1    ; 中断使能
UART_FCR    EQU 0x2    ; FIFO控制
UART_LCR    EQU 0x3    ; 线路控制
UART_MCR    EQU 0x4    ; 调制解调器控制
UART_LSR    EQU 0x5    ; 线路状态(读)

; 波特率分频值:115200 / 9600 = 12
BAUD_DIV_LO EQU 0x0C
BAUD_DIV_HI EQU 0x00

    ; 入口点
start:
    call    serial_init
    mov     si, msg_hello
print_loop:
    lodsb
    or      al, al
    jz      done
    call    serial_putc
    jmp     print_loop
done:
    hlt
    jmp     done

;----------------------------------------------------------
; serial_init - 初始化COM1为9600-8N1
; 破坏: AX, DX
;----------------------------------------------------------
serial_init:
    mov     dx, UART_BASE + UART_LCR
    mov     al, 0x80        ; DLAB=1,允许设置波特率
    out     dx, al

    mov     dx, UART_BASE + 0x0
    mov     al, BAUD_DIV_LO ; 分频低字节
    out     dx, al
    mov     dx, UART_BASE + 0x1
    mov     al, BAUD_DIV_HI ; 分频高字节
    out     dx, al

    mov     dx, UART_BASE + UART_LCR
    mov     al, 0x03        ; 8位数据,无校验,1停止位,DLAB=0
    out     dx, al

    mov     dx, UART_BASE + UART_IER
    xor     al, al          ; 关闭所有中断
    out     dx, al

    mov     dx, UART_BASE + UART_FCR
    mov     al, 0x01        ; 启用FIFO
    out     dx, al

    mov     dx, UART_BASE + UART_MCR
    mov     al, 0x03        ; DTR+RTS就绪
    out     dx, al
    ret

;----------------------------------------------------------
; serial_putc - 输出单字符到串口
; 输入: AL = 字符
; 破坏: DX
;----------------------------------------------------------
serial_putc:
    push    ax
    mov     dx, UART_BASE + UART_LSR
wait_tx:
    in      al, dx
    test    al, 0x20        ; 发送保持寄存器空?
    jz      wait_tx
    pop     ax
    mov     dx, UART_BASE + UART_THR
    out     dx, al
    ret

msg_hello   db 'BIOS UART OK', 0x0D, 0x0A, 0

运行与验证

  1. 汇编:nasm -f bin serial_init.asm -o serial_init.bin
  2. 运行方式:将serial_init.bin作为软盘引导扇区启动(需在虚拟机如QEMU中配合-serial stdio参数),或烧录到BIOS ROM的初始化入口位置。
  3. 验证方法:在宿主机串口终端(如minicom、PuTTY)以9600波特率、8数据位、无校验、1停止位连接,启动目标后应收到字符串BIOS UART OK并换行。
  4. 通过条件:串口终端完整显示上述字符串且无乱码,即证明初始化时序正确、波特率匹配、字符输出通路正常。

关键说明

  • 初始化顺序不可颠倒:必须先设DLAB=1写分频值,再设DLAB=0配置数据格式。
  • wait_tx循环检测LSR位5(THR空),确保前一字符发送完毕再写入新字符,避免数据覆盖。
  • 本代码在实模式下直接端口I/O,不依赖BIOS中断,适用于BIOS最早期的初始化环境。