QEMU MIPS32 - 定制板上的 16550 Uart 实现
QEMU MIPS32 - 16550 Uart Implementation on a Custom Board
我正在尝试使用 QEMU 来模拟一个固件,但我无法让 UART 设备正确更新线路状态寄存器并显示输入字符。
详情:
目标设备:Qualcomm QCA9533(Documentation here 如果你好奇的话)
目标固件:带有 U-Boot 引导加载的 VxWorks 6.6
CPU:MIPS 24Kc
板子:mipssim(已修改)
内存:512MB
使用的命令:qemu-system-mips -S -s -cpu 24Kc -M mipssim –nographic -device loader,addr=0xBF000000,cpu-num=0 -serial /dev/ttyS0 -bios target_image.bin
在这里我必须道歉,但我无法分享我的来源。然而,由于我正在尝试重组mipssim板,所以我只对代码做了一些小改动,如下:
将 bios 内存区域重新设置为 0x1F000000
将load_image_targphys()目标地址改为0x1F000000
将 $pc 初始值更改为 0xBF000000(0x1F000000 的 TLB 重映射)
用 serial_mm_init(isa, 0x20000, env- >irq[0], 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN)。
虽然看起来 serial_init() 可能是当前公认的标准,但我没有运气重新映射它。我注意到马耳他板在我给它的 MIPS 测试内核上没有输出问题,所以我试图模仿那里所做的事情。但是,我仍然不明白 QEMU 是如何工作的,而且我找不到很多好的资源来解释它。我在源代码和包含的文档中苦苦挣扎,但与此同时,我希望有人能对我做错的事情有所了解。
二进制文件从地址 0xBF000000 正确加载和执行,但在遇到第一个 UART 轮询循环时挂起。查看 QEMU 监视器中的 mtree 显示 I/O 设备正确映射到地址范围 0x18020000-0x1802003F,当固件写入 Tx 缓冲区时,gdb 显示字符成功写入内存。串行设备没有进一步的操作来提取该字符并显示它,因此固件不断地轮询 LSR 以等待更新。
当涉及到 QEMU 中的 serial/hardware 交互时,我是否遗漏了什么?我本以为重新映射 mipssim 板的所有现有功能组件就足以至少让串行通信正常工作,尤其是因为目标使用与 mipssim 相同的 16550 UART。如果您有任何见解,请告诉我。如果我能找到一种使用符号调试 QEMU 本身的方法,那将会很有帮助,但与此同时,我并不完全确定我要寻找的是什么。即使是关于如何缩小问题范围的建议也会很有用。
谢谢!
好吧,经过大量的努力,我让 UART 工作了。问题的答案在于 serial_ioport_read()
和 serial_ioport_write()
函数。这两个方法被分配为 QEMU 在读取数据或将数据写入串行设备的 MemoryRegion
时调用的回调(在 serial_init()
或 serial_mm_init()
中初始化)。这些函数对地址(作为 addr
传递到函数中)做一些掩码以确定正在引用哪个寄存器,然后 return 来自与该寄存器对应的 SerialState
结构的值.它非常简单,但我想一旦你弄明白了,一切似乎都很简单。最大的转折点是认识到 QEMU 有效地将串行设备实现为具有在内存操作时触发的特殊功能的 MemoryRegion
。
无论如何,希望这能帮助将来的人避免我经历的噩梦。干杯!
我正在尝试使用 QEMU 来模拟一个固件,但我无法让 UART 设备正确更新线路状态寄存器并显示输入字符。
详情:
目标设备:Qualcomm QCA9533(Documentation here 如果你好奇的话)
目标固件:带有 U-Boot 引导加载的 VxWorks 6.6
CPU:MIPS 24Kc
板子:mipssim(已修改)
内存:512MB
使用的命令:qemu-system-mips -S -s -cpu 24Kc -M mipssim –nographic -device loader,addr=0xBF000000,cpu-num=0 -serial /dev/ttyS0 -bios target_image.bin
在这里我必须道歉,但我无法分享我的来源。然而,由于我正在尝试重组mipssim板,所以我只对代码做了一些小改动,如下:
将 bios 内存区域重新设置为 0x1F000000
将load_image_targphys()目标地址改为0x1F000000
将 $pc 初始值更改为 0xBF000000(0x1F000000 的 TLB 重映射)
用 serial_mm_init(isa, 0x20000, env- >irq[0], 115200, serial_hd(0), DEVICE_NATIVE_ENDIAN)。
虽然看起来 serial_init() 可能是当前公认的标准,但我没有运气重新映射它。我注意到马耳他板在我给它的 MIPS 测试内核上没有输出问题,所以我试图模仿那里所做的事情。但是,我仍然不明白 QEMU 是如何工作的,而且我找不到很多好的资源来解释它。我在源代码和包含的文档中苦苦挣扎,但与此同时,我希望有人能对我做错的事情有所了解。
二进制文件从地址 0xBF000000 正确加载和执行,但在遇到第一个 UART 轮询循环时挂起。查看 QEMU 监视器中的 mtree 显示 I/O 设备正确映射到地址范围 0x18020000-0x1802003F,当固件写入 Tx 缓冲区时,gdb 显示字符成功写入内存。串行设备没有进一步的操作来提取该字符并显示它,因此固件不断地轮询 LSR 以等待更新。
当涉及到 QEMU 中的 serial/hardware 交互时,我是否遗漏了什么?我本以为重新映射 mipssim 板的所有现有功能组件就足以至少让串行通信正常工作,尤其是因为目标使用与 mipssim 相同的 16550 UART。如果您有任何见解,请告诉我。如果我能找到一种使用符号调试 QEMU 本身的方法,那将会很有帮助,但与此同时,我并不完全确定我要寻找的是什么。即使是关于如何缩小问题范围的建议也会很有用。
谢谢!
好吧,经过大量的努力,我让 UART 工作了。问题的答案在于 serial_ioport_read()
和 serial_ioport_write()
函数。这两个方法被分配为 QEMU 在读取数据或将数据写入串行设备的 MemoryRegion
时调用的回调(在 serial_init()
或 serial_mm_init()
中初始化)。这些函数对地址(作为 addr
传递到函数中)做一些掩码以确定正在引用哪个寄存器,然后 return 来自与该寄存器对应的 SerialState
结构的值.它非常简单,但我想一旦你弄明白了,一切似乎都很简单。最大的转折点是认识到 QEMU 有效地将串行设备实现为具有在内存操作时触发的特殊功能的 MemoryRegion
。
无论如何,希望这能帮助将来的人避免我经历的噩梦。干杯!