How to observe aarch64 system registers in QEMU? - arm

I have some baremetal AARCH64 software running in QEMU. I connect GDB to it as a remote target. GDB multi-arch shows general purpose registers from x0 to x30, the SP, and PC.
However, I can't find a way to access the system registers to inspect things like the DAIF system register, the Fault Address Register, Fault Syndrome Register, etc. These are essential for debugging. I've tried within QEMU using info all-registers but the output doesn't seem relevant.
Am I missing something obvious?
PS, the QEMU model is the following:
qemu-system-aarch64 -machine virt,gic_version=3 -cpu cortex-a57 -smp 4
-m 4096

No, you dont missing anything: it is impossible to view aarch64 system registers with the stock qemu as a gdb remote target.
But you could add a small changes to qemu to view them.
Gdb client connects to QEMU over GDB RSP protocol. Server part of this protocol implemented at QEMU is called "gdb stub" (also it is common term for many other simulators/embedded software).
At the very beginning of client and stub communications, stub sends to client a target desription - a xml file with all registers that client allowed to request. Here is a such file for qemu aarch64 target. As you can see, info all-registers command at client prints all this registers, not more.
If you simple add required registers to that file it doesn`t work, you also need to add a few lines to aarch64_cpu_gdb_read_register - that functions reads registers from qemu internals and pass them to gdbstub.
After that build qemu, and you got it.
Also that question
will help you to view a client/stub communication details, if something goes wrong.

QEMU 3.x+ exposes the aarch64 system registers in the normal info registers command. For example:
(gdb) info registers
...
MVFR1_EL1 0x12111111 303108369
MDRAR_EL1 0x0 0
OSLSR_EL1 0xa 10
CTR_EL0 0x8444c004 2219098116
REVIDR_EL1 0x0 0
SCTLR 0xc50838 12912696
ACTLR_EL1 0x0 0
CPACR 0x0 0
...
It was implemented in https://github.com/qemu/qemu/commit/200bf5b7ffe.

QEMU tells GDB which registers it knows about by sending XML files in GDB's Target Description format: https://sourceware.org/gdb/onlinedocs/gdb/Target-Descriptions.html#Target-Descriptions
Some of those, are simply tracked in-tree as XML files directly: https://github.com/qemu/qemu/tree/v3.0.0/gdb-xml and may be from the GDB tree: https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/features/aarch64-core.xml;h=eb6364eb0996313420a4098509cb7f0e0fc32bec
But others are generated on the fly to reflect system configuration.
In particular, system registers are generated on the fly and sent as system-registers.xml, see: https://github.com/qemu/qemu/blob/v3.0.0/target/arm/gdbstub.c#L174
So, whatever registers you are missing, you should add them to that XML, and populate them with the correct values like the others.
And then send a patch to upstream QEMU :-)

Related

Cortex M33 unable to get stack pointer and pc from word offset 0/1 with qemu

I tried to bringup cortex m33 with QEMU, and I used board MPS2-AN505, but QEMU always abort with HardFault error, so I checked system registers with GDB and I found that the T bit of ESPR reg is 0 after CPU boot, and the pc/sp is 0 too, but I have already write SP value and PC value into memory word offset 0/1
I also checked VTOR which defines the vector tables and it is 0, so sp /pc should be read out from word offset 0/1
But if I used GDB to load elf files again, the T bit of ESPR is 1 but pc/sp still not be loaded. so the program start from address 0.
I also tried with board type MPS3-AN547 which used corte-m55 with the same software code and vector table, and it works fine. PC / SP can be loaded correctly from word offset 0/1.
the QEMU version that I used is 6.2.0, and I used option -kernel xxx.bin to load my software image.
qemu error
as described above ...
qemu error debug info

gdb commands gdbstub to write to _Unwind_DebugHook memory location

I ported a gdbstub for an OS I'm working on which runs on x86_64. The host which is running gdb is connected to the target that has the stub and the OS over serial. I have an int3 instruction in the source code to force the OS to jump into the stub's code which it does. The problem is if I try to step to the next instruction using nexti the stub stops responding and the host keeps timing out.
Looking at the packets that the host is sending I see this:
Sending packet: $Me1dc20,1:cc#6c...Ack
Timed out.
Timed out.
Timed out.
Ignoring packet error, continuing...
which means that the host is telling the stub to write cc (which is the opcode for int3) to memory location 0xe1dc20. I looked into that memory location and found this:
(gdb) x/16i 0xe1dc20
0xe1dc20 <_Unwind_DebugHook>: retq
0xe1dc21: data16 nopw %cs:0x0(%rax,%rax,1)
0xe1dc2c: nopl 0x0(%rax)
This function is part of gcc's code here https://github.com/gcc-mirror/gcc/blob/master/libgcc/unwind-dw2.c but it is not used anywhere in the source file that I am debugging.
Now obviously it is causing me troubles so I disabled memory writing functionality in my stub so that it longer responds to memory writing commands $M and $X and when I did I was able to execute nexti and step in gdb without issues. The stub uses the RFLAGS.TF for flow control.
The question is why is gdb trying to set a breakpoint in a function that I am not using anywhere and how do I prevent it from doing so? I thought about adding an if statement in the stub to ignore writes to this memory location but is there a less intrusive way of doing it?
The _Unwind_DebugHook symbol exists as a place for GDB (or any other debugger) to place a breakpoint and so catch exceptions. GDB will look for this symbol (in the debug info), and it it exists, place a breakpoint there.
These breakpoints will always get inserted, even when doing something as simple as a stepi, just in case - you might be about to step to that address.
One problem I see with the remote trace is that GDB will be expecting an OK packet to indicate that the write succeeded, this is why you're seeing the timeout messages.

Linux register read arm i.mx257 from userland - devmem not working

I'm currently working on a i.mx257 platform and want to read some peripheral registers (the iomux register to be specific) to see how it is configured or if it is set right.
I've read about the devmem from busybox and devmem2, too. Tried both and both get an error. Currently there the custom board is running linux kernel version 4.6.0-rc7 from the meta-fsl-arm yocto meta package. The system is built with yocto.
root#system /]#./tmp/devmem2 0x43fac190
/dev/mem opened.
Unhandled fault: external abort on non-linefetch (0x008) at 0xb6f3a190
pgd = c3334000
[b6f3a190] *pgd=8285e831, *pte=43fac103, *ppte=43facaa2
Memory mapped at address 0xb6f3a000.
Bus error
The tool gets an Signal Err. The CONFIG_STRICT_DEVMEM option is not set in the kernel config.
I found another post http://thread.gmane.org/gmane.linux.ports.arm.kernel/26878 but I can't find some information about these registers for an i-mx25.
Is there another kernel security feature or something I'm missing?
The devmem or devmem2 is only working with values below 0x4000. For all addresses above i get the signal bus error.
Okay,
i found an answer to my own question.
The AIPS control registers have to be added to the devicetree. They are protecting the register i want to read. After i added these patches it worked.
https://github.com/torvalds/linux/commit/24bb244e02a6bead5b854d842002df0d38ae7b7b
https://github.com/torvalds/linux/commit/c33576cbf86bedf9ad3812479c3b4f36d5fadba8#diff-64c444a874c565fd98cf1ab538c1e0cd

How to correctly use a startup-ipi to start an application processor?

My goal is to let my own kernel start an application cpu. It uses the same mechanism as the linux kernel:
Send asserting and level triggered init-IPI
Wait...
Send deasserting and level triggered init-IPI
Wait...
Send up to two startup-IPIs with vector number (0x40000 >> 12) (the entry code for the application processor lies there)
Currently I'm just interested in making it work with QEMU. Unfortunately, instead of jumping to 0x40000, the application cpu jumps to 0x0 with the cs register set to 0x4000. (I checked with gdb).
The Intel MultiProcessor Specification (B.4.2) explains that the behavior that I noticed is valid if the target processor is halted immediately after RESET or INIT. But shouldn't this also apply to the code of the linux kernel? It sends the startup-IPI after the init-IPI. Or do I misunderstand the specification?
What can I do to have the application processor jump to 0x000VV000 and not to 0x0 with the cs register set to 0xVV00? I really can't see, where linux does something that changes the behavior.
It seems that I really misunderstood the specification: Since the application cpu is started in real mode 0x000VV000 is equivalent to 0xVV00:0x0000. It is not possible to represent the address just in the 16 bit ip register. Therefore a segment offset for the code segment is required.
Additionally, debugging real mode code with gdb is comparable complicated because it does not respect the segment offset. When required to see the disassembled code of the trampoline at the current position, it is necessary to calculate the physical location:
x/20i $eip+0xVV000
This makes gdb print the next 20 instructions at 0xVV00:$eip.

Setting up Interrupt Vector Table, ARMv6

I'm trying to use usermode and SVC in my ARMv6 bare metal application, but for this I need to set up the SVC entry of the ARMv6 interrupt vector table to branch to my interrupt handler. But, I can't find a good example on how to do this (ie: what memory address exactly I need to set, and to what). I have done similar things in the past, but always with a more comprehensive bootloader (RedBoot) that set up some of this for me. Any help would be appreciated.
I am testing my application using:
qemu-system-arm -M versatilepb -cpu arm1176
Are you talking about the SWI interrupt? Or one of the others (FIQ, IRQ). In either case I think I know what the problem is. Qemu is for running linux, your binary is not loaded at address 0x00000 so your entry points are not used by qemu for handling exceptions.
I have an example that uses qemu and implements a solution. Go to the qemu directory of http://github.com/dwelch67/yagbat. The qemu example is not really related to the gba thing in the yagbat repo, the gba is a 32 bit ARM thing so it was easy to borrow code from so I stuck it there.
The example was specifically written for your question as I tried to figure out how to use qemu in this manner. It appears that the address 0x00000000 space is simulated as ram, so you can re-write the qemu exception table and have the exceptions call code in the 0x10000 address space that your binary loads.
A quick and dirty solution is to make the entry point of the binary (that qemu loads to 0x10000) resemble a vector table at address 0x00000. The ldr pc instruction is relative to the program counter, the disassembly might show that it is loading an address at 0x10000 but it is really relative to the pc and the disassembler used the pc assuming the linked address being used.
.globl _start
_start:
ldr pc,start_vector_add
ldr pc,undef_vector_add
ldr pc,swi_vector_add
start_vector_add: .word start_vector
undef_vector_add: .word undef_vector
swi_vector_add: .word swi_vector
Then before you want to cause any interrupts, in the example I use the swi instruction to cause an swi interrupt. You copy enough of the code from 0x10000 to 0x00000 to include the exception table and the list of addresses that it loads into the pc. by linking your program to 0x10000 those addresses are in the 0x10000 range. When the interrupt occurs, the exception handler that you have now modified will load the 0x10000 based address into the pc and your handler in the 0x10000 range will get called.
Using this command line to run the binary in my example
qemu-system-arm -M versatilepb -m 128M -kernel hello_world.bin
and then ctrl-alt-3 (not F3 but 3) will switch to the serial console and you can see the output, and close that window to close out of qemu and stop the simulation.

Resources