You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARM AArch64平台QEMU模拟器键盘输入与GUI显示问题排查

QEMU ARM AArch64 virt模拟器UART显示与键盘输入问题解决

问题1:非-nographic GUI模式下无内容显示

原因

  1. UART基地址错误:QEMU virt平台的PL011 UART默认基地址是0x09000000,而非代码中写的0x1c090000。
  2. QEMU参数配置不当:-serial mon:stdio仅将串口输出绑定到终端,未关联GUI窗口的虚拟控制台,导致GUI无输出。

解决方法

  • 修正代码中的UART基地址为0x09000000。
  • 修改QEMU启动命令,添加虚拟控制台串口,让终端和GUI同时显示输出:
    qemu-system-aarch64 -M virt -cpu cortex-a53 -m 128 -serial mon:stdio -serial vc -kernel os.bin
    

问题2:键盘输入无响应

原因

  1. UART未初始化:PL011 UART必须先配置控制寄存器使能收发功能,直接读写数据寄存器无法正常工作。
  2. 读写逻辑错误:未检查UART状态寄存器,直接读数据寄存器会得到无效值,也无法判断是否有输入数据。

解决方法

添加UART初始化逻辑,并修改读写函数,通过状态寄存器判断可读写状态。修改后的完整C代码如下:

#include <stdint.h>

// PL011 UART寄存器定义
#define UART_BASE 0x09000000
#define UART_DR   (*(volatile uint32_t *)(UART_BASE + 0x00))  // 数据寄存器
#define UART_FR   (*(volatile uint32_t *)(UART_BASE + 0x18))  // 状态寄存器
#define UART_CR   (*(volatile uint32_t *)(UART_BASE + 0x30))  // 控制寄存器
#define UART_IBRD (*(volatile uint32_t *)(UART_BASE + 0x24))  // 整数波特率寄存器
#define UART_FBRD (*(volatile uint32_t *)(UART_BASE + 0x28))  // 小数波特率寄存器
#define UART_LCRH (*(volatile uint32_t *)(UART_BASE + 0x2C))  // 线路控制寄存器

// 状态寄存器标志位
#define FR_TXFE (1 << 7)  // 发送寄存器为空
#define FR_RXNE (1 << 4)  // 接收寄存器非空

void uart_init(void);
void uart_puts(const char *str);
void uart_putc(char c);
char uart_getc(void);

void notmain(void) {
    char c;

    uart_init();
    uart_puts("UART test...\n");

    while (1) {
        c = uart_getc();  // 等待并读取输入字符
        uart_putc(c);     // 回显到输出
    }
}

void uart_init(void) {
    // 先禁用UART
    UART_CR = 0;
    // 设置波特率为115200(适配QEMU virt的24MHz时钟)
    UART_IBRD = 13;
    UART_FBRD = 1;
    // 配置线路:8位数据、无校验、1位停止位
    UART_LCRH = (0x3 << 5);
    // 使能UART、发送和接收功能
    UART_CR = (1 << 0) | (1 << 8) | (1 << 9);
}

void uart_puts(const char *str) {
    while (*str) {
        uart_putc(*str++);
    }
}

void uart_putc(char c) {
    // 等待发送寄存器空闲
    while (!(UART_FR & FR_TXFE));
    UART_DR = c;
    // 自动补充回车,适配终端换行显示
    if (c == '\n') {
        while (!(UART_FR & FR_TXFE));
        UART_DR = '\r';
    }
}

char uart_getc(void) {
    // 等待有输入数据
    while (!(UART_FR & FR_RXNE));
    return (char)(UART_DR & 0xFF);
}

编译链接与运行

原有的编译、链接命令无需修改,直接重新编译生成os.bin后,使用修改后的QEMU命令启动即可。

内容的提问来源于stack exchange,提问作者Dmytro Parkhomenko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 04:22:03