On 09.06.22 17:27, Dongjiu Geng wrote: > ping,sorry for the noise >
No need to be sorry, I unfortunately didn't find the time to fully understand this. > > Dongjiu Geng <[email protected]> 于2022年6月3日周五 21:11写道: >> >> The HPFAR can be invalid if the stage 2 fault did not happen during a >> stage 1 page table walk (the ESR_EL2.S1PTW bit is clear) and one of the >> two following cases are true: >> 1). The fault was due to a permission fault >> 2). The processor carries errata 834220 >> >> Therefore, for all non S1PTW faults where we either have a permission >> fault or the errata workaround is enabled, we resolve the IPA using the >> AT instruction. >> >> Signed-off-by: Dongjiu Geng <[email protected]> >> --- >> hypervisor/arch/arm64/include/asm/paging.h | 8 ++ >> hypervisor/arch/arm64/include/asm/sysregs.h | 8 ++ >> hypervisor/arch/arm64/include/asm/traps.h | 2 + >> hypervisor/arch/arm64/mmio.c | 7 +- >> hypervisor/arch/arm64/traps.c | 89 +++++++++++++++++++-- >> 5 files changed, 105 insertions(+), 9 deletions(-) >> >> diff --git a/hypervisor/arch/arm64/include/asm/paging.h >> b/hypervisor/arch/arm64/include/asm/paging.h >> index e600cf58..4f0cb81c 100644 >> --- a/hypervisor/arch/arm64/include/asm/paging.h >> +++ b/hypervisor/arch/arm64/include/asm/paging.h >> @@ -198,6 +198,14 @@ unsigned int get_cpu_parange(void); >> | (cpu_parange_encoded << TCR_PS_SHIFT) \ >> | VTCR_RES1) >> >> +/* Flags for get fault ipa from gva */ >> +#define GV2M_READ (0u<<0) >> +#define GV2M_WRITE (1u<<0) >> + >> +/* Indicates address translation aborted */ >> +#define PAR_F (1UL) >> +#define PADDR_MASK ((1UL << 48) - 1UL) >> + >> int arm_paging_cell_init(struct cell *cell); >> void arm_paging_cell_destroy(struct cell *cell); >> >> diff --git a/hypervisor/arch/arm64/include/asm/sysregs.h >> b/hypervisor/arch/arm64/include/asm/sysregs.h >> index 868ef887..2c683832 100644 >> --- a/hypervisor/arch/arm64/include/asm/sysregs.h >> +++ b/hypervisor/arch/arm64/include/asm/sysregs.h >> @@ -117,6 +117,14 @@ >> #define ESR_IL(esr) GET_FIELD((esr), 25, 25) >> /* Instruction specific syndrome */ >> #define ESR_ISS(esr) GET_FIELD((esr), 24, 0) >> + >> +/* Fault status code of instruction specific syndrome */ >> +#define ESR_ISS_FSC(esr) GET_FIELD((esr), 5, 0) >> + >> +/* Shared ISS fault status code(IFSC/DFSC) for Data/Instruction aborts */ >> +#define ESR_ISS_FSC_TYPE (0x3C) >> +#define ESR_ISS_FSC_PERM (0x0C) >> + >> /* Exception classes values */ >> #define ESR_EC_UNKNOWN 0x00 >> #define ESR_EC_WFx 0x01 >> diff --git a/hypervisor/arch/arm64/include/asm/traps.h >> b/hypervisor/arch/arm64/include/asm/traps.h >> index a7c07624..0efedef1 100644 >> --- a/hypervisor/arch/arm64/include/asm/traps.h >> +++ b/hypervisor/arch/arm64/include/asm/traps.h >> @@ -25,6 +25,8 @@ struct trap_context { >> >> void arch_handle_trap(union registers *guest_regs); >> void arch_el2_abt(union registers *regs); >> +bool arch_get_fault_ipa(struct trap_context *ctx, unsigned long *ipa, >> + unsigned int flag); >> >> /* now include from arm-common */ >> #include_next <asm/traps.h> >> diff --git a/hypervisor/arch/arm64/mmio.c b/hypervisor/arch/arm64/mmio.c >> index 7fbfef75..70301ab3 100644 >> --- a/hypervisor/arch/arm64/mmio.c >> +++ b/hypervisor/arch/arm64/mmio.c >> @@ -43,7 +43,6 @@ enum trap_return arch_handle_dabt(struct trap_context *ctx) >> { >> enum mmio_result mmio_result; >> struct mmio_access mmio; >> - unsigned long hpfar; >> unsigned long hdfar; >> /* Decode the syndrome fields */ >> u32 iss = ESR_ISS(ctx->esr); >> @@ -57,10 +56,10 @@ enum trap_return arch_handle_dabt(struct trap_context >> *ctx) >> u32 is_write = iss >> 6 & 0x1; >> u32 size = 1 << sas; >> >> - arm_read_sysreg(HPFAR_EL2, hpfar); >> arm_read_sysreg(FAR_EL2, hdfar); >> - mmio.address = hpfar << 8; >> - mmio.address |= hdfar & 0xfff; >> + >> + if (!arch_get_fault_ipa(ctx, &mmio.address, GV2M_READ)) >> + return TRAP_HANDLED; /* Try again */ So, this means we need to make the guest trap again, and then HPFAR is valid?? >> >> this_cpu_public()->stats[JAILHOUSE_CPU_STAT_VMEXITS_MMIO]++; >> >> diff --git a/hypervisor/arch/arm64/traps.c b/hypervisor/arch/arm64/traps.c >> index 488dd7f8..10441b4b 100644 >> --- a/hypervisor/arch/arm64/traps.c >> +++ b/hypervisor/arch/arm64/traps.c >> @@ -33,6 +33,85 @@ void arch_skip_instruction(struct trap_context *ctx) >> arm_write_sysreg(ELR_EL2, pc); >> } >> >> +static bool check_workaround_834220(void) >> +{ >> + unsigned long midr; >> + unsigned int variant, revision, part; >> + >> + arm_read_sysreg(MIDR_EL1, midr); >> + >> + variant = (midr >> 20) & 0xf; >> + revision = midr & 0xf; >> + part = (midr >> 4) & 0xfff; >> + >> + /* Cortex-A57 r0p0 - r1p2 */ >> + if (part == 0xD07 && variant <= 1 && revision <= 2) >> + return true; >> + >> + return false; >> +} >> + >> +static bool hpfar_is_not_valid(bool s1ptw, u8 fsc) >> +{ >> + /* >> + * The HPFAR can be invalid if the stage 2 fault did not >> + * happen during a stage 1 page table walk (the ESR_EL2.S1PTW >> + * bit is clear) and one of the two following cases are true: >> + * 1. The fault was due to a permission fault >> + * 2. The processor carries errata 834220 >> + * >> + */ >> + return (s1ptw == 0U) && (((fsc & ESR_ISS_FSC_TYPE) == >> ESR_ISS_FSC_PERM) || check_workaround_834220()); >> +} >> + >> +bool arch_get_fault_ipa(struct trap_context *ctx, unsigned long *ipa, >> unsigned int flags) >> +{ >> + unsigned long hpfar, hdfar, par, tmp; >> + >> + u32 s1ptw = ESR_ISS(ctx->esr) >> 7 & 0x1; >> + u8 fsc = ESR_ISS_FSC(ctx->esr); >> + >> + arm_read_sysreg(FAR_EL2, hdfar); >> + >> + if (hpfar_is_not_valid(s1ptw, fsc)) { >> + >> + /* Save current PAR_EL1 */ >> + arm_read_sysreg(PAR_EL1, tmp); >> + >> + /* >> + * Performs stage 1 address translation, with permissions >> as if >> + * writing to or reading from the given virtual address >> from EL1 >> + */ >> + if ( (flags & GV2M_WRITE) == GV2M_WRITE ) { >> + asm volatile ("at s1e1w, %0;" : : "r" (hdfar)); >> + } else { >> + asm volatile ("at s1e1r, %0;" : : "r" (hdfar)); >> + } >> + >> + isb(); >> + >> + /* The resulting address can be read from the PAR_EL1 */ >> + arm_read_sysreg(PAR_EL1, par); >> + >> + /* Recover current PAR_EL1 */ >> + arm_write_sysreg(PAR_EL1, tmp); >> + >> + /* If PAR_EL1.F = 1, address translation aborted */ >> + if ((par & PAR_F) == PAR_F) { >> + printk("Failed to ipa!\n"); >> + return false; >> + } else { >> + *ipa = (par & PADDR_MASK & PAGE_MASK) | (hdfar & >> (~PAGE_MASK)); >> + } >> + } else { >> + arm_read_sysreg(HPFAR_EL2, hpfar); >> + *ipa = hpfar << 8; >> + *ipa |= hdfar & 0xfff; >> + } >> + >> + return true; >> +} >> + >> static enum trap_return handle_hvc(struct trap_context *ctx) >> { >> unsigned long *regs = ctx->regs; >> @@ -71,7 +150,7 @@ static enum trap_return handle_sysreg(struct trap_context >> *ctx) >> >> static enum trap_return handle_iabt(struct trap_context *ctx) >> { >> - unsigned long hpfar, hdfar; >> + unsigned long hpfar; >> >> if (this_cpu_data()->sdei_event) { >> this_cpu_data()->sdei_event = false; >> @@ -83,11 +162,11 @@ static enum trap_return handle_iabt(struct trap_context >> *ctx) >> return TRAP_HANDLED; >> } >> >> - arm_read_sysreg(HPFAR_EL2, hpfar); >> - arm_read_sysreg(FAR_EL2, hdfar); >> + if (arch_get_fault_ipa(ctx, &hpfar, GV2M_READ)) >> + panic_printk("FATAL: instruction abort at 0x%lx\n", hpfar); >> + else >> + panic_printk("FATAL: instruction abort and can not get >> ipa\n"); >> >> - panic_printk("FATAL: instruction abort at 0x%lx\n", >> - (hpfar << 8) | (hdfar & 0xfff)); >> return TRAP_FORBIDDEN; >> } >> >> -- >> 2.25.1 >> How common is this erratum? Is it already affecting real boards? Just to get a feeling for the urgency. Thanks, Jan -- Siemens AG, Technology Competence Center Embedded Linux -- You received this message because you are subscribed to the Google Groups "Jailhouse" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/jailhouse-dev/c078ec55-8565-b2a9-581a-32903625c73b%40siemens.com.
