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
运行与验证
- 汇编:
nasm -f bin serial_init.asm -o serial_init.bin - 运行方式:将
serial_init.bin作为软盘引导扇区启动(需在虚拟机如QEMU中配合-serial stdio参数),或烧录到BIOS ROM的初始化入口位置。 - 验证方法:在宿主机串口终端(如minicom、PuTTY)以9600波特率、8数据位、无校验、1停止位连接,启动目标后应收到字符串
BIOS UART OK并换行。 - 通过条件:串口终端完整显示上述字符串且无乱码,即证明初始化时序正确、波特率匹配、字符输出通路正常。
关键说明
- 初始化顺序不可颠倒:必须先设DLAB=1写分频值,再设DLAB=0配置数据格式。
wait_tx循环检测LSR位5(THR空),确保前一字符发送完毕再写入新字符,避免数据覆盖。- 本代码在实模式下直接端口I/O,不依赖BIOS中断,适用于BIOS最早期的初始化环境。