4. 配置串口调试输出

任务目标

在Coreboot固件开发中,串口是早期调试阶段最重要的输出通道。本案例目标是在Coreboot的早期初始化阶段(bootblock或romstage)启用并配置UART串口调试输出,使固件启动日志能够通过串口终端实时查看。

环境与依赖

  • Coreboot源码树(已执行make menuconfig生成.config)
  • 目标平台:QEMU x86(qemu-i440fx或qemu-q35)或真实硬件(需确认板载UART地址)
  • 串口终端工具:minicom / screen / PuTTY(宿主机侧)

核心实现

Coreboot的串口驱动位于src/drivers/uart/。对于x86平台,最常用的是16550 UART。以下代码展示在romstage中直接操作UART寄存器输出字符的最小实现,不依赖Coreboot的uart_init()高层封装,便于理解底层机制。

// romstage_uart_debug.c
#include <stdint.h>
#include <arch/io.h>

#define UART_BASE 0x3F8   // COM1 标准端口地址
#define UART_THR  (UART_BASE + 0)  // 发送保持寄存器
#define UART_LSR  (UART_BASE + 5)  // 线路状态寄存器
#define LSR_THRE  (1 << 5)         // 发送保持寄存器空标志

// 初始化16550 UART:8N1,波特率115200
static void uart_debug_init(void) {
    uint16_t divisor = 1;  // 1.8432MHz晶振 / (16 * 115200) ≈ 1

    outb(0x00, UART_BASE + 1);   // 关闭中断
    outb(0x80, UART_BASE + 3);   // DLAB=1,允许设置波特率
    outb(divisor & 0xFF, UART_BASE + 0);       // 除数低字节
    outb((divisor >> 8) & 0xFF, UART_BASE + 1); // 除数高字节
    outb(0x03, UART_BASE + 3);   // DLAB=0,8位数据,无校验,1停止位
    outb(0x00, UART_BASE + 2);   // 关闭FIFO(或设0xC7启用并清空)
}

// 输出单个字符(忙等待THR空)
static void uart_debug_putc(unsigned char c) {
    if (c == '\n') {
        // 自动将换行符扩展为CR+LF
        while (!(inb(UART_LSR) & LSR_THRE));
        outb('\r', UART_THR);
    }
    while (!(inb(UART_LSR) & LSR_THRE));
    outb(c, UART_THR);
}

// 输出字符串
static void uart_debug_puts(const char *s) {
    while (*s)
        uart_debug_putc((unsigned char)*s++);
}

// romstage入口调用示例
void romstage_main(void) {
    uart_debug_init();
    uart_debug_puts("Coreboot romstage: UART debug output OK\n");
    // ... 其余romstage初始化代码
}

集成到Coreboot构建

将上述文件放入src/mainboard/<vendor>/<board>/目录,并在该目录的romstage.c中调用uart_debug_init()和uart_debug_puts()。更简洁的方式是直接使用Coreboot已有的uart_init()和uart_tx_byte()接口(定义于src/include/uart.h),它们会根据Kconfig配置自动选择驱动。若使用标准接口,需在menuconfig中启用:

Devices --->
  [*] Enable early (bootblock/romstage) console output
  [*] Send console output to a serial port
  Console --->
    (0x3F8) Base address of serial port
    (115200) Default baud rate

运行与验证

  1. 构建固件:在Coreboot根目录执行make,生成build/coreboot.rom。
  2. 启动QEMU:
    qemu-system-x86_64 -serial stdio -display none -bios build/coreboot.rom
  3. 观察输出:终端应显示Coreboot romstage: UART debug output OK。若使用真实硬件,将串口线连接至COM1(0x3F8),用minicom以115200-8N1连接。

通过条件:串口终端出现上述字符串,且无乱码、无超时。若输出乱码,检查波特率分频系数是否匹配晶振频率;若无输出,用逻辑分析仪或示波器测量UART_TX引脚是否有电平跳变。