Merge branch kvm-arm64/psci-relay-fixes into kvmarm/next
authorOliver Upton <oliver.upton@linux.dev>
Mon, 13 Feb 2023 23:30:37 +0000 (23:30 +0000)
committerOliver Upton <oliver.upton@linux.dev>
Mon, 13 Feb 2023 23:30:37 +0000 (23:30 +0000)
* kvm-arm64/psci-relay-fixes:
  : Fixes for CPU on/resume with pKVM, courtesy Quentin Perret.
  :
  : A consequence of deprivileging the host is that pKVM relays PSCI calls
  : on behalf of the host. pKVM's CPU initialization failed to fully
  : initialize the CPU's EL2 state, which notably led to unexpected SVE
  : traps resulting in a hyp panic.
  :
  : The issue is addressed by reusing parts of __finalise_el2 to restore CPU
  : state in the PSCI relay.
  KVM: arm64: Finalise EL2 state from pKVM PSCI relay
  KVM: arm64: Use sanitized values in __check_override in nVHE
  KVM: arm64: Introduce finalise_el2_state macro
  KVM: arm64: Provide sanitized SYS_ID_AA64SMFR0_EL1 to nVHE

1  2 
arch/arm64/include/asm/el2_setup.h
arch/arm64/kvm/arm.c

        __init_el2_nvhe_prepare_eret
  .endm
  
+ #ifndef __KVM_NVHE_HYPERVISOR__
+ // This will clobber tmp1 and tmp2, and expect tmp1 to contain
+ // the id register value as read from the HW
+ .macro __check_override idreg, fld, width, pass, fail, tmp1, tmp2
+       ubfx    \tmp1, \tmp1, #\fld, #\width
+       cbz     \tmp1, \fail
+       adr_l   \tmp1, \idreg\()_override
+       ldr     \tmp2, [\tmp1, FTR_OVR_VAL_OFFSET]
+       ldr     \tmp1, [\tmp1, FTR_OVR_MASK_OFFSET]
+       ubfx    \tmp2, \tmp2, #\fld, #\width
+       ubfx    \tmp1, \tmp1, #\fld, #\width
+       cmp     \tmp1, xzr
+       and     \tmp2, \tmp2, \tmp1
+       csinv   \tmp2, \tmp2, xzr, ne
+       cbnz    \tmp2, \pass
+       b       \fail
+ .endm
+ // This will clobber tmp1 and tmp2
+ .macro check_override idreg, fld, pass, fail, tmp1, tmp2
+       mrs     \tmp1, \idreg\()_el1
+       __check_override \idreg \fld 4 \pass \fail \tmp1 \tmp2
+ .endm
+ #else
+ // This will clobber tmp
+ .macro __check_override idreg, fld, width, pass, fail, tmp, ignore
+       ldr_l   \tmp, \idreg\()_el1_sys_val
+       ubfx    \tmp, \tmp, #\fld, #\width
+       cbnz    \tmp, \pass
+       b       \fail
+ .endm
+ .macro check_override idreg, fld, pass, fail, tmp, ignore
+       __check_override \idreg \fld 4 \pass \fail \tmp \ignore
+ .endm
+ #endif
+ .macro finalise_el2_state
+       check_override id_aa64pfr0, ID_AA64PFR0_EL1_SVE_SHIFT, .Linit_sve_\@, .Lskip_sve_\@, x1, x2
+ .Linit_sve_\@:        /* SVE register access */
+       mrs     x0, cptr_el2                    // Disable SVE traps
+       bic     x0, x0, #CPTR_EL2_TZ
+       msr     cptr_el2, x0
+       isb
+       mov     x1, #ZCR_ELx_LEN_MASK           // SVE: Enable full vector
+       msr_s   SYS_ZCR_EL2, x1                 // length for EL1.
+ .Lskip_sve_\@:
+       check_override id_aa64pfr1, ID_AA64PFR1_EL1_SME_SHIFT, .Linit_sme_\@, .Lskip_sme_\@, x1, x2
+ .Linit_sme_\@:        /* SME register access and priority mapping */
+       mrs     x0, cptr_el2                    // Disable SME traps
+       bic     x0, x0, #CPTR_EL2_TSM
+       msr     cptr_el2, x0
+       isb
+       mrs     x1, sctlr_el2
+       orr     x1, x1, #SCTLR_ELx_ENTP2        // Disable TPIDR2 traps
+       msr     sctlr_el2, x1
+       isb
+       mov     x0, #0                          // SMCR controls
+       // Full FP in SM?
+       mrs_s   x1, SYS_ID_AA64SMFR0_EL1
+       __check_override id_aa64smfr0, ID_AA64SMFR0_EL1_FA64_SHIFT, 1, .Linit_sme_fa64_\@, .Lskip_sme_fa64_\@, x1, x2
+ .Linit_sme_fa64_\@:
+       orr     x0, x0, SMCR_ELx_FA64_MASK
+ .Lskip_sme_fa64_\@:
++      // ZT0 available?
++      mrs_s   x1, SYS_ID_AA64SMFR0_EL1
++      __check_override id_aa64smfr0, ID_AA64SMFR0_EL1_SMEver_SHIFT, 4, .Linit_sme_zt0_\@, .Lskip_sme_zt0_\@, x1, x2
++.Linit_sme_zt0_\@:
++      orr     x0, x0, SMCR_ELx_EZT0_MASK
++.Lskip_sme_zt0_\@:
++
+       orr     x0, x0, #SMCR_ELx_LEN_MASK      // Enable full SME vector
+       msr_s   SYS_SMCR_EL2, x0                // length for EL1.
+       mrs_s   x1, SYS_SMIDR_EL1               // Priority mapping supported?
+       ubfx    x1, x1, #SMIDR_EL1_SMPS_SHIFT, #1
+       cbz     x1, .Lskip_sme_\@
+       msr_s   SYS_SMPRIMAP_EL2, xzr           // Make all priorities equal
+       mrs     x1, id_aa64mmfr1_el1            // HCRX_EL2 present?
+       ubfx    x1, x1, #ID_AA64MMFR1_EL1_HCX_SHIFT, #4
+       cbz     x1, .Lskip_sme_\@
+       mrs_s   x1, SYS_HCRX_EL2
+       orr     x1, x1, #HCRX_EL2_SMPME_MASK    // Enable priority mapping
+       msr_s   SYS_HCRX_EL2, x1
+ .Lskip_sme_\@:
+ .endm
  #endif /* __ARM_KVM_INIT_H__ */
Simple merge