Search code examples
gdbqemuriscv

qemu-system-riscv32 -M sifive_u cannot be debugged using GDB if started with OpenSBI (-bios default)


I am working on a kind of custom assembler for RISC-V, and am testing it with qemu.

The best way that I could find to get some raw machine code into qemu-system-riscv32 was to create an ELF file and place the entrypoint at 0x80000000 and use the -machine sifive_u, which also has memory-mapped UART that I can use to print to the serial console. By adding -S -s flags, I could attach gdb and and step through the machine code (layout asm; ni).

At some point, presumably by updating qemu, this stopped working until I set -bios none. When I found that solution I was happy, but also curious about what the benefits of the "default BIOS", which seems to be OpenSBI.

Through trial and error I figured out that with OpenSBI, I can put the code anywhere between 0x80020000 and 0x90000000 and it will jump to the entrypoint set in the ELF file. Before jumping to my code it will print out a POST message like this:

OpenSBI v0.9
   ____                    _____ ____ _____
  / __ \                  / ____|  _ \_   _|
 | |  | |_ __   ___ _ __ | (___ | |_) || |
 | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
 | |__| | |_) |  __/ | | |____) | |_) || |_
  \____/| .__/ \___|_| |_|_____/|____/_____|
        | |
        |_|

Platform Name             : SiFive HiFive Unleashed A00
Platform Features         : timer,mfdeleg
Platform HART Count       : 2
Firmware Base             : 0x80000000
Firmware Size             : 108 KB
Runtime SBI Version       : 0.2

Domain0 Name              : root
Domain0 Boot HART         : 1
Domain0 HARTs             : 0*,1*
Domain0 Region00          : 0x80000000-0x8001ffff ()
Domain0 Region01          : 0x00000000-0xffffffff (R,W,X)
Domain0 Next Address      : 0x80440000
Domain0 Next Arg1         : 0x87000000
Domain0 Next Mode         : S-mode
Domain0 SysReset          : yes

Boot HART ID              : 1
Boot HART Domain          : root
Boot HART ISA             : rv32imafdcsu
Boot HART Features        : scounteren,mcounteren
Boot HART PMP Count       : 16
Boot HART PMP Granularity : 4
Boot HART PMP Address Bits: 32
Boot HART MHPM Count      : 0
Boot HART MHPM Count      : 0
Boot HART MIDELEG         : 0x00000222
Boot HART MEDELEG         : 0x0000b109

However, if I now start qemu with -S -s and continue using c, it seems that qemu gets stuck in the OpenSBI code at address 0x80000978 on the instruction csrr a5,mip. Entering c or ni at this point will simply freeze until I interrupt with CTRL-C. However as soon as I detach GDB, the program continues running as normal.

How can I get past this instruction and/or start debugging at my entrypoint? I would prefer testing my code after OpenSBI, which gives me access to the device-tree file, which I would be interested in using in the future.

EDIT: I've managed to port my code to use the virt riscv32 machine, which has a different Serial device, and have no problems with debugging there. At this point this is perhaps more of a bug report, but I will leave the question up for a bit just in case.


Solution

  • The reason is multi core boot.

    In gdb's view, two parallel process flow is abstracted by inferiors, and in qemu's view each cpu cluster which have same cpu is one inferior, and each cpu is abstracted by thread under its inferior.

    On the other hand, qemu will select default hart 0 as the first boot hart with the machine you set, but sifive has an extra core e51, which is not your real "boot hart", the real boot hart is u54 hart with index '1'. With qemu that means two different cpu clusters; e51 is the index 0 and gdb will default attach to that one.

    So your code will get stuck because in the view of qemu you just do nothing on your boot hart.

    What you just need do is follow the qemu multi core debug guide; here is an example what you need set in gdb:

    (gdb) target extended-remote :1234
    (gdb) add-inferior
    (gdb) inferior 2
    (gdb) attach 2
    

    Then you can contine your operation.