Skip to content

Some Aarch64 system registers not available via the debugger

Goal

There are some interesting system registers that cannot be queried from the GDB interface. Ones I have noticed are, e.g., MIDR_EL1, MPIDR_EL1 and ID_AA64PFR0. In addition, the entire GICv3 CPU interface registers do not seem to be accessible either.

So see this, launch qemu-system-aarch64 on your favorite image and attach a remote debugger (I'm using LLDB locally, but my understanding is that the interface is generic). You will notice interactions like the following:

(lldb) script
Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.
>>> lldb.frame.FindRegister('TTBR0_EL1')
(unsigned long) TTBR0_EL1 = 0x0000000000000000
>>> lldb.frame.FindRegister('ID_AA64PFR1_EL1')
(unsigned long) ID_AA64PFR1_EL1 = 0x0000000000000020
>>> lldb.frame.FindRegister('ID_AA64PFR0_EL1')
No value
>>> lldb.frame.FindRegister('MIDR_EL1')
No value
>>> lldb.frame.FindRegister('MPIDR_EL1')
No value
>>> lldb.frame.FindRegister('HCR_EL2')
(unsigned long) HCR_EL2 = 0x0000000000000000
>>> lldb.frame.FindRegister('ICH_HCR_EL2')
No value

Being able to query these registers would be useful for me for some automatic testing and debugging procedures.

Technical details

For MIDR_EL1, MPIDR_EL1 and ID_AA64PFR0_EL1, the issue seems pretty straightforward. In target/arm/helper.c, these registers are all specified using the ARM_CP_NO_RAW type, which is filtered out later by the arm_register_sysreg_for_feature function from target/arm/gdbstub.c. A suitable fix seems to be to remove this type descriptor from these registers and install .writefn = arm_cp_write_ignore as necessary (to prevent a failed assertion elsewhere). With these changes, the debug interface exposes the registers in question.

The GICv3 CPU interface registers are also pretty much all specified with the ARM_CP_NO_RAW type. However, similar updates to these registers do not succeed to expose them through the GDB interface. Some local hacking shows that this is probably some kind of initialization order issue. The function arm_gen_dynamic_sysreg_feature (which I gather is mainly responsible for informing GDB about what registers exist based on the contents of the cpu->cp_regs field) is running prior to the gicv3_init_cpuif function (which populates the cpu->cp_regs hashmap with GIC-related registers).

I am happy to work on a patch to address these issues, but as a QEMU hacking novice, I'm not sure how I might go about solving this init-order problem, and could use some advice. I also wonder if simply removing the ARM_CP_NO_RAW type might have other unintended effects.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information