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.