0

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.

Dong Lam
  • 3
  • 3
  • Something is very weird about your setup, because your command line says "-machine vexpress-a15", but your question and the kernel output says you're running on an OMAP board with 8250-based UARTs. The vexpress-a15 is a completely different system with different UARTs. – Peter Maydell Jul 20 '23 at 08:57
  • Hi, I have modified the source code from vexpress-a15 since it is using the same CPU Cortex-a15. I have borrowed the timer, i2c, spi, and and uart from omap2. My serial uart is: ``` serial_mm_init(sysmem, map[DRA_UART1], 2, pic[67], 9600, serial_hd(0), DEVICE_LITTLE_ENDIAN); serial_mm_init(sysmem, map[DRA_UART2], 2, pic[68], 9600, serial_hd(1), DEVICE_LITTLE_ENDIAN); serial_mm_init(sysmem, map[DRA_UART3], 2, pic[69], 9600, serial_hd(2), DEVICE_LITTLE_ENDIAN); ``` – Dong Lam Jul 20 '23 at 09:14
  • Why didn't you create a new board model with a new name? – Peter Maydell Jul 20 '23 at 10:16

2 Answers2

1

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).

Peter Maydell
  • 9,707
  • 1
  • 19
  • 25
  • I take the irq information from dra7.dtsi and cat /proc/interrupts file on real device 45: 590 CBAR 69 Level 48020000.serial In vexpress.c, `serial_mm_init(sysmem, map[DRA_UART3], 2, pic[69], 9600, serial_hd(2), DEVICE_LITTLE_ENDIAN);` Was it mapped correctly? How could I know I have mapped the irq correctly? At the moment, I am doing your first step. – Dong Lam Jul 20 '23 at 11:55
  • Check whether your interrupt numbers start from the same place -- some places number with 0 being the first external interrupt (which is what the pic[] array is) and some with 0 being the first internal interrupt, so external interrupts start at 32. And I have a feeling the kernel's numbering of interrupts is not necessarily what the hardware's is -- check the OMAP TRM – Peter Maydell Jul 20 '23 at 20:42
  • Hi, I check OMAP TRM, the register MPU_IRQ_74 (ID106) | 69 | CTRL_CORE_MPU_IRQ_74_75[8:0] | 69 |UART3_IRQ|. Shared peripheral interrupts begin from ID32, so I created "serial_mm_init(sysmem, map[DRA_UART3], 2, pic[74], 9600, serial_hd(2), DEVICE_LITTLE_ENDIAN)". And the uart still not working. – Dong Lam Jul 24 '23 at 10:50
  • Did you also make sure the pic[] array is big enough and that the loop in init_cpus() had its upper bound set to match ? Otherwise, this is probably the point where you ought to try to model the SoC properly, rather than hacking about in vexpress.c. – Peter Maydell Jul 24 '23 at 11:58
  • I have increased the upper bound to 128. I am just a newbie and since the constraint of time, I couldn't model the SoC properly. So to my knowledge, we can only use a maximum of 128 SPI (160 - 32 (internal one))? – Dong Lam Jul 24 '23 at 12:50
  • I put a debugging message after "qemu_irq_raise(s->irq)" in serial.c. I realized whatever pic[n] I initialized serial_mm_init with, qemu always raises an interrupt. And interrupts were raised only after init process executing. So I think your second idea 50% right and 50% wrong. – Dong Lam Jul 31 '23 at 14:01
  • OK, so that tells you that the device is correctly setting its output interrupt line. It doesn't tell you whether you wired that line up to the right bit of the GIC (but you do now have a fairly good idea that the problem is in your board's interrupt wiring and interrupt controller setup) – Peter Maydell Jul 31 '23 at 14:11
  • Do we have any chance to debug qemu with gdb? I mean I want to see how qemu handles an interrupt. gdb -p is not a thing I expected. – Dong Lam Aug 01 '23 at 08:20
  • Yes, you can run QEMU under a host gdb if you want. Though obviously you'll need to understand a fair amount of QEMU's internals to make sense of it (and you'll want to build a debug version of QEMU so you have the symbols and so on, as with debugging any C program). – Peter Maydell Aug 01 '23 at 10:04
  • You may also find the tracepoints in the GIC useful -- if you run QEMU with '-d trace:gic_*' it will print out lines whenever the GIC model does certain things, and you can get an idea of its internal state and why it is or is not signalling an interrupt to the CPU. – Peter Maydell Aug 01 '23 at 10:06
  • I used the trace:gic-* and realized the major irq usually was set and cleared is ID27 ( which is virtual timer event). I also figured out irq ID106 ( my uart) was set and cleared but always gic_update_bestirq irq 27 and CPU always acknowledged irq 27. Could you please tell me how to fix this one? – Dong Lam Aug 02 '23 at 08:24
  • I also found out that after booting Linux kernel, the GIC registers started to be read and written to. In the tracing log file, only "gic_enable_irq irq 27 enabled" was logged. So I think the CPU won't care whether Uart interrupt raising or not. – Dong Lam Aug 02 '23 at 09:45
  • Something is clearly wrong with how you're modelling the board interrupts versus what the guest is trying to do. At this point I think I'm back to "you need to model the actual hardware, not hack about with a board model for a totally different and much simpler system" – Peter Maydell Aug 03 '23 at 10:23
  • Thanks for your advice. After debugging the kernel code, I figured out that I didn't implement IRQ_CROSSBAR so any interrupt sources that came from IRQ_CROSSBAR were incorrectly unmasked by the kernel. I am a new learner so modeling a new board might be an overwhelming task for me, especially in a shortage of time. – Dong Lam Aug 04 '23 at 09:47
0

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.

Dong Lam
  • 3
  • 3