Arm: GICv3: Enable reading GICR_TYPER via two sys_read32() on AArch32

GICR_TYPER is a 64 bit register. On AArch32 when one uses sys_read64(),
this results in ldrd instruction. When Zephyr runs as a VM, 'LDRD'
instruction on an emulated MMIO region gets trapped to the hypervisor as
data abort.

Refer the following paragraph from ARM DDI 0487G.b ID072021 :-

Section - "ISS encoding for an exception from a Data Abort",
"For other faults reported in ESR_EL2, ISV is 0 except for the following
stage 2 aborts:

AArch32 instructions where the instruction:
— Is an LDR, LDA, LDRT, LDRSH, LDRSHT, LDRH, LDAH, LDRHT, LDRSB, LDRSBT,
LDRB, LDAB, LDRBT, STR, STL, STRT, STRH, STLH, STRHT, STRB, STLB, or STRBT
instruction."

As 'LDRD' is not in the list, so ISV==0. This implies that Arm could not
decode the instruction for the hypervisor (in EL2) to execute it.

Thus, we have abstracted this read into arm_gic_get_typer().
For AArch64, we use sys_read64() as before.
For AArch32, we use sys_read32() twice to read the lower and upper 32 bits
of GICR_TYPER.

Thus, we ensure that when the access is trapped for AArch32, Arm generates
a valid ISS so that hypervisor can execute it.

Signed-off-by: Ayan Kumar Halder <ayankuma@amd.com>
This commit is contained in:
Ayan Kumar Halder 2022-10-27 11:46:15 +01:00 committed by Carles Cufí
commit 2174501a10

View file

@ -507,6 +507,20 @@ static bool arm_gic_aff_matching(uint64_t gicr_aff, uint64_t aff)
#endif
}
static inline uint64_t arm_gic_get_typer(mem_addr_t addr)
{
uint64_t val;
#if defined(CONFIG_ARM)
val = sys_read32(addr);
val |= (uint64_t)sys_read32(addr + 4) << 32;
#else
val = sys_read64(addr);
#endif
return val;
}
static mem_addr_t arm_gic_iterate_rdists(void)
{
uint64_t aff = arm_gic_mpidr_to_affinity(GET_MPIDR());
@ -514,7 +528,7 @@ static mem_addr_t arm_gic_iterate_rdists(void)
for (mem_addr_t rdist_addr = GIC_RDIST_BASE;
rdist_addr < GIC_RDIST_BASE + GIC_RDIST_SIZE;
rdist_addr += 0x20000) {
uint64_t val = sys_read64(rdist_addr + GICR_TYPER);
uint64_t val = arm_gic_get_typer(rdist_addr + GICR_TYPER);
uint64_t gicr_aff = GICR_TYPER_AFFINITY_VALUE_GET(val);
if (arm_gic_aff_matching(gicr_aff, aff)) {