QEMU Linux Bash init脚本未打印到控制台。

huangapple go评论75阅读模式
英文:

QEMU Linux Bash init scripts not printing to the console

问题

我在模拟一块搭载 ARM-Cortex A15 处理器的 TI 开发板。该开发板使用 UART8250, 默认的串口号是 3,地址是 0x48020000。我使用 U-boot 引导 Linux 内核,并且通过以下命令运行 qemu:

qemu-system-arm -machine vexpress-a15 -smp 1 -m 1G -kernel u-boot.elf \
-drive file="nandflash.bin",if=mtd,index=0,format=raw \
-chardev file,id=char1,path="${HOME}/serial1.txt",signal=on \
-chardev file,id=char2,path="${HOME}/serial2.txt",signal=on \
-s -S -serial chardev:char1 -serial chardev:char2 -serial stdio

Linux 映像,跳过 rbs!
OK!正在启动 Image main.bin,带有引导参数 console=ttyO2,9600 rdinit=/sbin/init quiet loglevel=7 log_buf_len=1M...

从 Legacy Image 位置 84000200 启动内核...

镜像名称: linux
镜像类型: ARM Linux Kernel 镜像(未压缩)
数据大小: 4086200 字节 = 3.9 MiB
载入地址: 82000000
入口点: 82000000

从 Legacy Image 位置 843fae14 加载 init Ramdisk ...

镜像名称: rootfs
镜像类型: ARM Linux RAMDisk 镜像(未压缩)
数据大小: 23410472 字节 = 22.3 MiB
载入地址: 00000000
入口点: 00000000

位于 843e5df8 处的扁平设备树 blob

使用位于 0x843e5df8 处的 fdt blob 引导
正在加载内核镜像 ... 完成
正在加载 Ramdisk 到 9c8db000,结束于 9df2e728 ... 完成
正在加载设备树到 9c8c3000,结束于 9c8dae19 ... 完成
开始启动内核 ...

SF: 检测到 n25q256,页面大小 256 字节,擦除大小 4 KiB,总共 32 MiB,在 5c000000 处映射
正在解压 Linux... 完成,正在引导内核。
[ 0.000000] 在物理 CPU 0x0 上引导 Linux
[ 0.000000] Linux 版本 4.14.115-rt59 (lamnguyen@DENEC1LT0933) (gcc 版本 11.3.0) #1 PREEMPT RT Mon Jul 17 10:48:38 UTC 2023
[ 0.000000] CPU: ARMv7 处理器 [414fc0f0] 修订 0 (ARMv7),cr=30c53c7d
[ 0.000000] CPU: 支持 div 指令: 正在修补除法代码
[ 0.000000] CPU: PIPT / VIPT 非别名数据缓存,PIPT 指令缓存
[ 0.000000] OF: fdt: 机器型号: Hirschmann Greyhound 交换机
[ 0.000000] 内存策略: 数据缓存写回
[ 0.000000] cma: 在 0x000000009e400000 处保留 24 MiB
[ 0.000000] OMAP4: 将 0x000000009fd00000 映射到 fe600000 以用于 ddr 屏障
[ 0.000000] 所有 CPU 在 SVC 模式下启动。


我可以从 U-Boot 获取所有消息,从 Linux 内核获取消息,但来自应用程序的消息不会打印到控制台上。当内核运行我的初始化脚本时,它只会打印输出到 /dev/kmsg 中的消息。例如:

```shell
# 下面这条不会打印到我的控制台 (ttyS2)
echo -n "挂载 /dev/pts          : " 
# 这条会,但格式类似于内核消息,带有时间戳
echo -n "挂载 /dev/pts          : " | tee /dev/kmsg 

这些脚本实际上是在运行,但问题是我不能用正常的命令 "echo" 看到任何输出。我认为我的串口终端工作正常。除非,否则我将看不到包括内核消息在内的任何东西。在运行初始化脚本时,我加入了 dmesg | grep "tty" | tee /dev/kmsg 并得到:

[   16.141290] [    0.000000] 内核命令行: console=ttyO2,9600 rdinit=/sbin/init quiet loglevel=7 log_buf_len=1M
[   16.141290] [    0.017880] 警告: 你的 'console=ttyO2' 已被替换为 'ttyS2'
[   16.141290] [    3.235689] 48020000.serial: ttyS2 在 MMIO 0x48020000 处 (irq = 45, base_baud = 3000000) 是一个 8250
[   16.141290] [    7.652801] 控制台 [ttyS2] 已启用

我的目标是让没有使用 tee /dev/kmsg 的 "echo" 输出打印到我的控制台上。我无法使用 GDB 进行调试,因为在执行这些初始化脚本时,我只看到 CPU 进入 WFI 和 NOP。我是新手学习者,所以你的任何建议对我来说都非常有价值。

英文:

I am emulating a board from TI which run ARM-Cortex A15. The board using UART8250 and the default uart number is 3 at address 0x48020000. I use U-boot to boot the Linux kernel and run qemu with:

qemu-system-arm -machine vexpress-a15 -smp 1 -m 1G -kernel u-boot.elf \
-drive file="nandflash.bin",if=mtd,index=0,format=raw \														  -chardev file,id=char1,path="${HOME}/serial1.txt",signal=on\														   -chardev file,id=char2,path="${HOME}/serial2.txt",signal=on\
-s -S -serial chardev:char1 -serial chardev:char2  -serial stdio
Linux image, skipping rbs!
OK! Booting Image main.bin with bootargs console=ttyO2,9600 rdinit=/sbin/init quiet loglevel=7 log_buf_len=1M...
## Booting kernel from Legacy Image at 84000200 ...
   Image Name:   linux
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    4086200 Bytes = 3.9 MiB
   Load Address: 82000000
   Entry Point:  82000000
## Loading init Ramdisk from Legacy Image at 843fae14 ...
   Image Name:   rootfs
   Image Type:   ARM Linux RAMDisk Image (uncompressed)
   Data Size:    23410472 Bytes = 22.3 MiB
   Load Address: 00000000
   Entry Point:  00000000
## Flattened Device Tree blob at 843e5df8
   Booting using the fdt blob at 0x843e5df8
   Loading Kernel Image ... OK
   Loading Ramdisk to 9c8db000, end 9df2e728 ... OK
   Loading Device Tree to 9c8c3000, end 9c8dae19 ... OK
Starting kernel ...

SF: Detected n25q256 with page size 256 Bytes, erase size 4 KiB, total 32 MiB, mapped at 5c000000
Uncompressing Linux... done, booting the kernel.
[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 4.14.115-rt59 (lamnguyen@DENEC1LT0933) (gcc version 11.3.0) #1 PREEMPT RT Mon Jul 17 10:48:38 UTC 2023
[    0.000000] CPU: ARMv7 Processor [414fc0f0] revision 0 (ARMv7), cr=30c53c7d
[    0.000000] CPU: div instructions available: patching division code
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, PIPT instruction cache
[    0.000000] OF: fdt: Machine model: Hirschmann Greyhound Switch
[    0.000000] Memory policy: Data cache writeback
[    0.000000] cma: Reserved 24 MiB at 0x000000009e400000
[    0.000000] OMAP4: Map 0x000000009fd00000 to fe600000 for dram barrier
[    0.000000] CPU: All CPU(s) started in SVC mode.

I can get all the message from U-Boot and the kernel messages from Linux but messages from application are not printed to the console. When the kernel run my init scripts, it only print the messages which tee to /dev/kmsg. For example:

#This one below will not print to my console (ttyS2)
echo -n " Mounting /dev/pts          : " 
#This one will but in the format of kernel message with the timestamp
echo -n " Mounting /dev/pts          : " | tee /dev/kmsg 

Those scripts are actually running, but the problem is that I will see nothing with the normal command "echo". I think my serial terminal is working well. Unless, I won't see not things include the kernel messages. I put dmesg | grep "tty" | tee /dev/kmsg when running init script and get:

[   16.141290] [    0.000000] Kernel command line: console=ttyO2,9600 rdinit=/sbin/init quiet loglevel=7 log_buf_len=1M
[   16.141290] [    0.017880] WARNING: Your 'console=ttyO2' has been replaced by 'ttyS2'
[   16.141290] [    3.235689] 48020000.serial: ttyS2 at MMIO 0x48020000 (irq = 45, base_baud = 3000000) is a 8250
[   16.141290] [    7.652801] console [ttyS2] enabled

My goal is to get the output from "echo without tee /dev/kmsg" printed to my console. I can not debug with GDB since when those init scripts executed, the only thing I saw is CPU go to WFI and NOP. I am new learner so any advices from you would be considerably valued to me.

答案1

得分: 1

第一,'console=ttyO2' 在内核命令行上告诉内核使用该串行端口,但不一定告诉/sbin/init使用该串行端口(例如,用于生成登录提示符)。因此,在虚拟机文件系统中可能有一些配置来控制这一点。检查一下您的虚拟机用户空间进程是否尝试发送数据给内核以传输到串行端口。

第二,有可能内核中的打印使用了非中断驱动的方式来使用UART,而通过tty层打印则使用了带有中断的UART。由于您说这是一个自定义的板型模型,您应该检查是否正确处理了中断(即它们是否与中断控制器连接,正如虚拟机的UART驱动程序所期望的那样)。

英文:

I can think of two lines of attack for debugging this:

Firstly, 'console=ttyO2' on the kernel command line tells the kernel to use that serial port, but it doesn't necessarily tell /sbin/init to use that serial port (eg for spawning a login prompt). So there might be some config within the guest filesystem that controls that. Check whether your guest userspace processes are even trying to send data to the kernel to go to the serial port.

Secondly, it's possible that the in-kernel printing is using the UART in a non-interrupt-driven way, whereas printing via the tty layer uses the UART with interrupts. Since you say this is a custom board model, you should check whether you've handled the interrupts correctly (i.e. whether they are wired up to the interrupt controller as the guest's UART driver expects).

答案2

得分: 0

问题已解决。Peter Maydell的第二个假设是正确的,echo命令需要与QEMU中的pic[]正确映射的UART中断。由于DRA72X板使用了中断交叉连接器来复用中断源,但是QEMU没有实现这些功能,我必须在QEMU中使用内核的交叉连接器中断来硬编码中断UART。

英文:

The problem has been solved. The second assumption of Peter Maydell is correct, the echo command needs interrupt of UART mapped appropriately with the pic[] in QEMU. Since the DRA72X board used an interrupt crossbar to mux the interrupt sources but QEMU did not implement such those things, I must hardcode interrupt UART in QEMU with the crossbar interrupt from the kernel.

huangapple
  • 本文由 发表于 2023年7月20日 16:49:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/76728176.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定