--- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -477,6 +477,11 @@ APGAKEYLO_EL1, APGAKEYHI_EL1, + /* Apple implementation-defined PAuth virtualization state. */ + APCTL_EL1, + KERNKEYLO_EL1, + KERNKEYHI_EL1, + /* Memory Tagging Extension registers */ RGSR_EL1, /* Random Allocation Tag Seed Register */ GCR_EL1, /* Tag Control Register */ --- a/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h +++ b/arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h @@ -17,6 +17,12 @@ #include #define SYS_IMP_APL_ACTLR_EL12 sys_reg(3, 6, 15, 14, 6) +#define SYS_IMP_APL_APVMKEYLO_EL2 sys_reg(3, 6, 15, 14, 4) +#define SYS_IMP_APL_APVMKEYHI_EL2 sys_reg(3, 6, 15, 14, 5) +#define SYS_IMP_APL_APSTS_EL12 sys_reg(3, 6, 15, 14, 7) +#define SYS_IMP_APL_APCTL_EL12 sys_reg(3, 6, 15, 15, 0) +#define SYS_IMP_APL_KERNKEYLO_EL12 sys_reg(3, 6, 15, 2, 3) +#define SYS_IMP_APL_KERNKEYHI_EL12 sys_reg(3, 6, 15, 2, 4) #define SYS_ACTLR_EL12 sys_reg(3, 5, 1, 0, 1) static inline bool ctxt_has_s1poe(struct kvm_cpu_context *ctxt); @@ -182,6 +188,17 @@ else if (alternative_has_cap_unlikely(ARM64_HAS_ACTLR_VIRT_APPLE)) ctxt_sys_reg(ctxt, ACTLR_EL1) = read_sysreg_s(SYS_IMP_APL_ACTLR_EL12); } + + if (ctxt_is_guest(ctxt) && + (alternative_has_cap_unlikely(ARM64_HAS_ACTLR_VIRT) || + alternative_has_cap_unlikely(ARM64_HAS_ACTLR_VIRT_APPLE))) { + ctxt_sys_reg(ctxt, APCTL_EL1) = + read_sysreg_s(SYS_IMP_APL_APCTL_EL12); + ctxt_sys_reg(ctxt, KERNKEYLO_EL1) = + read_sysreg_s(SYS_IMP_APL_KERNKEYLO_EL12); + ctxt_sys_reg(ctxt, KERNKEYHI_EL1) = + read_sysreg_s(SYS_IMP_APL_KERNKEYHI_EL12); + } } static inline void __sysreg_save_el2_return_state(struct kvm_cpu_context *ctxt) @@ -224,6 +241,30 @@ write_sysreg(midr, vpidr_el2); write_sysreg(mpidr, vmpidr_el2); + /* + * Apple's PAuth virtualization derives the guest key space from a + * hypervisor-owned VM key. APSTS_EL12 selects that virtualized state. + * m1n1 performs the same initialization before entering its guest. + * + * This is deliberately limited to Apple CPUs and guest contexts: the + * host kernel's PAuth state must remain unchanged. + */ + if (ctxt_is_guest(ctxt) && + (alternative_has_cap_unlikely(ARM64_HAS_ACTLR_VIRT) || + alternative_has_cap_unlikely(ARM64_HAS_ACTLR_VIRT_APPLE))) { + write_sysreg_s(0x4e7672476f6e6147ULL, + SYS_IMP_APL_APVMKEYLO_EL2); + write_sysreg_s(0x697665596f755570ULL, + SYS_IMP_APL_APVMKEYHI_EL2); + write_sysreg_s(1, SYS_IMP_APL_APSTS_EL12); + write_sysreg_s(ctxt_sys_reg(ctxt, APCTL_EL1), + SYS_IMP_APL_APCTL_EL12); + write_sysreg_s(ctxt_sys_reg(ctxt, KERNKEYLO_EL1), + SYS_IMP_APL_KERNKEYLO_EL12); + write_sysreg_s(ctxt_sys_reg(ctxt, KERNKEYHI_EL1), + SYS_IMP_APL_KERNKEYHI_EL12); + } + if (has_vhe() || !cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT)) { write_sysreg_el1(ctxt_sys_reg(ctxt, SCTLR_EL1), SYS_SCTLR); --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1432,6 +1432,17 @@ return vcpu_has_ptrauth(vcpu) ? 0 : REG_HIDDEN; } +#define SYS_IMP_APL_KERNKEYLO_EL12 sys_reg(3, 6, 15, 2, 3) +#define SYS_IMP_APL_KERNKEYHI_EL12 sys_reg(3, 6, 15, 2, 4) +#define SYS_IMP_APL_APCTL_EL12 sys_reg(3, 6, 15, 15, 0) + +static unsigned int vmapple_pac_visibility(const struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd) +{ + return (cpus_have_final_cap(ARM64_HAS_ACTLR_VIRT) || + cpus_have_final_cap(ARM64_HAS_ACTLR_VIRT_APPLE)) ? 0 : REG_HIDDEN; +} + /* * If we land here on a PtrAuth access, that is because we didn't * fixup the access on exit by allowing the PtrAuth sysregs. The only @@ -3781,6 +3792,13 @@ { SYS_DESC(SYS_CNTV_CVAL_EL02), access_arch_timer }, EL2_REG(SP_EL2, NULL, reset_unknown, 0), + + { SYS_DESC(SYS_IMP_APL_KERNKEYLO_EL12), undef_access, reset_val, + KERNKEYLO_EL1, 0, .visibility = vmapple_pac_visibility }, + { SYS_DESC(SYS_IMP_APL_KERNKEYHI_EL12), undef_access, reset_val, + KERNKEYHI_EL1, 0, .visibility = vmapple_pac_visibility }, + { SYS_DESC(SYS_IMP_APL_APCTL_EL12), undef_access, reset_val, + APCTL_EL1, 0, .visibility = vmapple_pac_visibility }, }; static bool handle_at_s1e01(struct kvm_vcpu *vcpu, struct sys_reg_params *p,