4. 读取键盘输入并回显

任务目标

在BIOS/UEFI固件开发环境中,实现从键盘读取按键输入并将字符回显到屏幕的功能。本案例聚焦于最底层的键盘控制器轮询方式,不依赖操作系统服务,直接通过端口I/O操作获取键盘扫描码并转换为ASCII字符。

环境与依赖

  • 开发环境:任何支持x86实模式汇编的编译器(如NASM、MASM)
  • 运行环境:x86模拟器(如QEMU、Bochs)或真实硬件
  • 无需额外库,直接使用端口I/O指令

核心实现原理

键盘控制器使用Intel 8042芯片,通过两个I/O端口访问:0x60(数据端口,读取扫描码)和0x64(状态端口,检查缓冲区状态)。读取流程为:先轮询0x64端口的状态字节,检查bit0(输出缓冲区满标志)是否为1;若为1,则从0x60端口读取扫描码。本案例仅处理按键按下事件(扫描码最高位为0),并将扫描码通过查表转换为ASCII字符后调用BIOS中断0x10的0x0E号功能回显。

关键完整代码

; keyboard_echo.asm
; 汇编:nasm -f bin keyboard_echo.asm -o keyboard_echo.bin
; 运行:qemu-system-x86_64 -drive format=raw,file=keyboard_echo.bin

[org 0x7c00]
    ; 初始化段寄存器
    mov ax, 0
    mov ds, ax
    mov es, ax

main_loop:
    ; 等待键盘输出缓冲区满
    call wait_for_key
    ; 读取扫描码
    in al, 0x60
    ; 检查是否为按下事件(bit7=0)
    test al, 0x80
    jnz main_loop          ; 释放事件,忽略

    ; 扫描码转ASCII
    movzx bx, al
    mov al, [scancode_table + bx]
    test al, al
    jz main_loop           ; 无对应字符,忽略

    ; 调用BIOS中断回显字符
    mov ah, 0x0e
    int 0x10

    ; 检查是否为Esc键(扫描码0x01)
    cmp byte [scancode_table + bx], 27
    jne main_loop
    ; 退出到BIOS
    int 0x19

; 等待键盘缓冲区有数据
wait_for_key:
    push ax
.wait:
    in al, 0x64
    test al, 0x01
    jz .wait
    pop ax
    ret

; 扫描码到ASCII转换表(仅常用键)
scancode_table:
    db 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 0x08
    db 0x09, 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0x0d
    db 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'", '`', 0, '\'
    db 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, '*', 0, ' '
    times 510-($-$$) db 0
    dw 0xaa55

运行与验证

  1. 编译:使用NASM编译上述代码生成引导扇区镜像:nasm -f bin keyboard_echo.asm -o keyboard_echo.bin
  2. 运行:在QEMU中执行:qemu-system-x86_64 -drive format=raw,file=keyboard_echo.bin
  3. 验证方法:系统启动后,依次按下字母键、数字键和符号键,观察屏幕是否回显对应字符。按Esc键应退出并重新启动。
  4. 通过条件:所有按下的可打印字符均正确显示在屏幕上,无乱码或重复;按Esc键能正常触发重启。

常见问题

  • 按键无反应:检查QEMU窗口是否获得焦点,或确认编译后的bin文件大小是否为512字节(引导扇区要求)。
  • 回显乱码:确认扫描码表索引正确,部分扩展键(如方向键)会产生两字节扫描码(0xE0前缀),本案例未处理,属预期行为。
  • 大小写问题:本案例未处理Shift键状态,因此字母始终显示为小写。如需支持大写,需额外跟踪Shift键的按下/释放状态。