]> Git Repo - linux.git/commitdiff
Merge remote-tracking branch 'origin/kvm-arm64/psci-relay' into kvmarm-master/next
authorMarc Zyngier <[email protected]>
Wed, 9 Dec 2020 10:00:24 +0000 (10:00 +0000)
committerMarc Zyngier <[email protected]>
Wed, 9 Dec 2020 10:00:24 +0000 (10:00 +0000)
Signed-off-by: Marc Zyngier <[email protected]>
13 files changed:
1  2 
arch/arm64/include/asm/cpucaps.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/kvm_asm.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/include/asm/sysreg.h
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/process.c
arch/arm64/kernel/proton-pack.c
arch/arm64/kvm/arm.c
arch/arm64/kvm/hyp/nvhe/Makefile
arch/arm64/kvm/hyp/nvhe/switch.c
arch/arm64/kvm/va_layout.c

index 162539d4c8cd0e5aac951ecbc5b65ba00f1ef644,350c98103d45ef3977190487d79a447682bcf3f0..b77d997b173bc7f7eba63a2025fbe8702d812ac1
  #define ARM64_WORKAROUND_CAVIUM_23154         6
  #define ARM64_WORKAROUND_834220                       7
  #define ARM64_HAS_NO_HW_PREFETCH              8
- #define ARM64_HAS_UAO                         9
- #define ARM64_ALT_PAN_NOT_UAO                 10
  #define ARM64_HAS_VIRT_HOST_EXTN              11
  #define ARM64_WORKAROUND_CAVIUM_27456         12
  #define ARM64_HAS_32BIT_EL0                   13
 -#define ARM64_HARDEN_EL2_VECTORS              14
 +#define ARM64_SPECTRE_V3A                     14
  #define ARM64_HAS_CNP                         15
  #define ARM64_HAS_NO_FPSIMD                   16
  #define ARM64_WORKAROUND_REPEAT_TLBI          17
@@@ -66,7 -64,9 +64,9 @@@
  #define ARM64_HAS_TLB_RANGE                   56
  #define ARM64_MTE                             57
  #define ARM64_WORKAROUND_1508412              58
+ #define ARM64_HAS_LDAPR                               59
+ #define ARM64_KVM_PROTECTED_MODE              60
  
- #define ARM64_NCAPS                           59
+ #define ARM64_NCAPS                           61
  
  #endif /* __ASM_CPUCAPS_H */
index 461277ae7a48fbba6d024687ab3e1793bd742255,092092177128ed69bc45732f38883362a8d468cb..16063c813dcda807883088c2edf34faf4096cd49
@@@ -268,8 -268,6 +268,8 @@@ extern struct arm64_ftr_reg arm64_ftr_r
  /*
   * CPU feature detected at boot time based on feature of one or more CPUs.
   * All possible conflicts for a late CPU are ignored.
 + * NOTE: this means that a late CPU with the feature will *not* cause the
 + * capability to be advertised by cpus_have_*cap()!
   */
  #define ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE           \
        (ARM64_CPUCAP_SCOPE_LOCAL_CPU           |       \
@@@ -669,10 -667,16 +669,16 @@@ static __always_inline bool system_supp
        return !cpus_have_const_cap(ARM64_HAS_NO_FPSIMD);
  }
  
+ static inline bool system_uses_hw_pan(void)
+ {
+       return IS_ENABLED(CONFIG_ARM64_PAN) &&
+               cpus_have_const_cap(ARM64_HAS_PAN);
+ }
  static inline bool system_uses_ttbr0_pan(void)
  {
        return IS_ENABLED(CONFIG_ARM64_SW_TTBR0_PAN) &&
-               !cpus_have_const_cap(ARM64_HAS_PAN);
+               !system_uses_hw_pan();
  }
  
  static __always_inline bool system_supports_sve(void)
@@@ -699,11 -703,6 +705,11 @@@ static inline bool system_supports_gene
                cpus_have_const_cap(ARM64_HAS_GENERIC_AUTH);
  }
  
 +static inline bool system_has_full_ptr_auth(void)
 +{
 +      return system_supports_address_auth() && system_supports_generic_auth();
 +}
 +
  static __always_inline bool system_uses_irq_prio_masking(void)
  {
        return IS_ENABLED(CONFIG_ARM64_PSEUDO_NMI) &&
@@@ -769,6 -768,13 +775,13 @@@ static inline bool cpu_has_hw_af(void
                                                ID_AA64MMFR1_HADBS_SHIFT);
  }
  
+ static inline bool cpu_has_pan(void)
+ {
+       u64 mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
+       return cpuid_feature_extract_unsigned_field(mmfr1,
+                                                   ID_AA64MMFR1_PAN_SHIFT);
+ }
  #ifdef CONFIG_ARM64_AMU_EXTN
  /* Check whether the cpu supports the Activity Monitors Unit (AMU) */
  extern bool cpu_has_amu_feat(int cpu);
index 4a6a77d8d13ed4e4420acf3d90e328d718148bd8,4e2661d1ae2b74046bd70a0295bb2b9cb32c5c78..7ccf770c53d926b89410bfa1cf31128bb64b5721
@@@ -34,6 -34,8 +34,6 @@@
   */
  #define KVM_VECTOR_PREAMBLE   (2 * AARCH64_INSN_SIZE)
  
 -#define __SMCCC_WORKAROUND_1_SMC_SZ 36
 -
  #define KVM_HOST_SMCCC_ID(id)                                         \
        ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,                         \
                           ARM_SMCCC_SMC_64,                            \
@@@ -148,6 -150,14 +148,14 @@@ extern void *__vhe_undefined_symbol
  
  #endif
  
+ struct kvm_nvhe_init_params {
+       unsigned long mair_el2;
+       unsigned long tcr_el2;
+       unsigned long tpidr_el2;
+       unsigned long stack_hyp_va;
+       phys_addr_t pgd_pa;
+ };
  /* Translate a kernel address @ptr into its equivalent linear mapping */
  #define kvm_ksym_ref(ptr)                                             \
        ({                                                              \
@@@ -163,16 -173,15 +171,14 @@@ struct kvm_vcpu
  struct kvm_s2_mmu;
  
  DECLARE_KVM_NVHE_SYM(__kvm_hyp_init);
- DECLARE_KVM_NVHE_SYM(__kvm_hyp_host_vector);
  DECLARE_KVM_HYP_SYM(__kvm_hyp_vector);
  #define __kvm_hyp_init                CHOOSE_NVHE_SYM(__kvm_hyp_init)
- #define __kvm_hyp_host_vector CHOOSE_NVHE_SYM(__kvm_hyp_host_vector)
  #define __kvm_hyp_vector      CHOOSE_HYP_SYM(__kvm_hyp_vector)
  
  extern unsigned long kvm_arm_hyp_percpu_base[NR_CPUS];
  DECLARE_KVM_NVHE_SYM(__per_cpu_start);
  DECLARE_KVM_NVHE_SYM(__per_cpu_end);
  
 -extern atomic_t arm64_el2_vector_last_slot;
  DECLARE_KVM_HYP_SYM(__bp_harden_hyp_vecs);
  #define __bp_harden_hyp_vecs  CHOOSE_HYP_SYM(__bp_harden_hyp_vecs)
  
@@@ -193,6 -202,8 +199,6 @@@ extern void __vgic_v3_init_lrs(void)
  
  extern u32 __kvm_get_mdcr_el2(void);
  
 -extern char __smccc_workaround_1_smc[__SMCCC_WORKAROUND_1_SMC_SZ];
 -
  /*
   * Obtain the PC-relative address of a kernel symbol
   * s: symbol
index 21ce5c42024767d5463fe83d6b3c20e4e3338ad5,7119d38e3c5601327b48f648f9936b189231284b..11beda85ee7e536693fd65751aebe880421f0c20
  #define KVM_DIRTY_LOG_MANUAL_CAPS   (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | \
                                     KVM_DIRTY_LOG_INITIALLY_SET)
  
+ /*
+  * Mode of operation configurable with kvm-arm.mode early param.
+  * See Documentation/admin-guide/kernel-parameters.txt for more information.
+  */
+ enum kvm_mode {
+       KVM_MODE_DEFAULT,
+       KVM_MODE_PROTECTED,
+ };
+ enum kvm_mode kvm_get_mode(void);
  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
  
  extern unsigned int kvm_sve_max_vl;
@@@ -58,6 -68,8 +68,6 @@@ int kvm_arm_init_sve(void)
  int __attribute_const__ kvm_target_cpu(void);
  int kvm_reset_vcpu(struct kvm_vcpu *vcpu);
  void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu);
 -int kvm_arch_vm_ioctl_check_extension(struct kvm *kvm, long ext);
 -void __extended_idmap_trampoline(phys_addr_t boot_pgd, phys_addr_t idmap_start);
  
  struct kvm_vmid {
        /* The VMID generation used for the virt. memory system */
@@@ -87,9 -99,6 +97,9 @@@ struct kvm_s2_mmu 
        struct kvm *kvm;
  };
  
 +struct kvm_arch_memory_slot {
 +};
 +
  struct kvm_arch {
        struct kvm_s2_mmu mmu;
  
         */
        unsigned long *pmu_filter;
        unsigned int pmuver;
 +
 +      u8 pfr0_csv2;
 +      u8 pfr0_csv3;
  };
  
  struct kvm_vcpu_fault_info {
@@@ -205,6 -211,48 +215,6 @@@ enum vcpu_sysreg 
        NR_SYS_REGS     /* Nothing after this line! */
  };
  
 -/* 32bit mapping */
 -#define c0_MPIDR      (MPIDR_EL1 * 2) /* MultiProcessor ID Register */
 -#define c0_CSSELR     (CSSELR_EL1 * 2)/* Cache Size Selection Register */
 -#define c1_SCTLR      (SCTLR_EL1 * 2) /* System Control Register */
 -#define c1_ACTLR      (ACTLR_EL1 * 2) /* Auxiliary Control Register */
 -#define c1_CPACR      (CPACR_EL1 * 2) /* Coprocessor Access Control */
 -#define c2_TTBR0      (TTBR0_EL1 * 2) /* Translation Table Base Register 0 */
 -#define c2_TTBR0_high (c2_TTBR0 + 1)  /* TTBR0 top 32 bits */
 -#define c2_TTBR1      (TTBR1_EL1 * 2) /* Translation Table Base Register 1 */
 -#define c2_TTBR1_high (c2_TTBR1 + 1)  /* TTBR1 top 32 bits */
 -#define c2_TTBCR      (TCR_EL1 * 2)   /* Translation Table Base Control R. */
 -#define c3_DACR               (DACR32_EL2 * 2)/* Domain Access Control Register */
 -#define c5_DFSR               (ESR_EL1 * 2)   /* Data Fault Status Register */
 -#define c5_IFSR               (IFSR32_EL2 * 2)/* Instruction Fault Status Register */
 -#define c5_ADFSR      (AFSR0_EL1 * 2) /* Auxiliary Data Fault Status R */
 -#define c5_AIFSR      (AFSR1_EL1 * 2) /* Auxiliary Instr Fault Status R */
 -#define c6_DFAR               (FAR_EL1 * 2)   /* Data Fault Address Register */
 -#define c6_IFAR               (c6_DFAR + 1)   /* Instruction Fault Address Register */
 -#define c7_PAR                (PAR_EL1 * 2)   /* Physical Address Register */
 -#define c7_PAR_high   (c7_PAR + 1)    /* PAR top 32 bits */
 -#define c10_PRRR      (MAIR_EL1 * 2)  /* Primary Region Remap Register */
 -#define c10_NMRR      (c10_PRRR + 1)  /* Normal Memory Remap Register */
 -#define c12_VBAR      (VBAR_EL1 * 2)  /* Vector Base Address Register */
 -#define c13_CID               (CONTEXTIDR_EL1 * 2)    /* Context ID Register */
 -#define c13_TID_URW   (TPIDR_EL0 * 2) /* Thread ID, User R/W */
 -#define c13_TID_URO   (TPIDRRO_EL0 * 2)/* Thread ID, User R/O */
 -#define c13_TID_PRIV  (TPIDR_EL1 * 2) /* Thread ID, Privileged */
 -#define c10_AMAIR0    (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */
 -#define c10_AMAIR1    (c10_AMAIR0 + 1)/* Aux Memory Attr Indirection Reg */
 -#define c14_CNTKCTL   (CNTKCTL_EL1 * 2) /* Timer Control Register (PL1) */
 -
 -#define cp14_DBGDSCRext       (MDSCR_EL1 * 2)
 -#define cp14_DBGBCR0  (DBGBCR0_EL1 * 2)
 -#define cp14_DBGBVR0  (DBGBVR0_EL1 * 2)
 -#define cp14_DBGBXVR0 (cp14_DBGBVR0 + 1)
 -#define cp14_DBGWCR0  (DBGWCR0_EL1 * 2)
 -#define cp14_DBGWVR0  (DBGWVR0_EL1 * 2)
 -#define cp14_DBGDCCINT        (MDCCINT_EL1 * 2)
 -#define cp14_DBGVCR   (DBGVCR32_EL2 * 2)
 -
 -#define NR_COPRO_REGS (NR_SYS_REGS * 2)
 -
  struct kvm_cpu_context {
        struct user_pt_regs regs;       /* sp = sp_el0 */
  
  
        struct user_fpsimd_state fp_regs;
  
 -      union {
 -              u64 sys_regs[NR_SYS_REGS];
 -              u32 copro[NR_COPRO_REGS];
 -      };
 +      u64 sys_regs[NR_SYS_REGS];
  
        struct kvm_vcpu *__hyp_running_vcpu;
  };
@@@ -366,33 -417,8 +376,33 @@@ struct kvm_vcpu_arch 
  #define KVM_ARM64_GUEST_HAS_SVE               (1 << 5) /* SVE exposed to guest */
  #define KVM_ARM64_VCPU_SVE_FINALIZED  (1 << 6) /* SVE config completed */
  #define KVM_ARM64_GUEST_HAS_PTRAUTH   (1 << 7) /* PTRAUTH exposed to guest */
 +#define KVM_ARM64_PENDING_EXCEPTION   (1 << 8) /* Exception pending */
 +#define KVM_ARM64_EXCEPT_MASK         (7 << 9) /* Target EL/MODE */
 +
 +/*
 + * When KVM_ARM64_PENDING_EXCEPTION is set, KVM_ARM64_EXCEPT_MASK can
 + * take the following values:
 + *
 + * For AArch32 EL1:
 + */
 +#define KVM_ARM64_EXCEPT_AA32_UND     (0 << 9)
 +#define KVM_ARM64_EXCEPT_AA32_IABT    (1 << 9)
 +#define KVM_ARM64_EXCEPT_AA32_DABT    (2 << 9)
 +/* For AArch64: */
 +#define KVM_ARM64_EXCEPT_AA64_ELx_SYNC        (0 << 9)
 +#define KVM_ARM64_EXCEPT_AA64_ELx_IRQ (1 << 9)
 +#define KVM_ARM64_EXCEPT_AA64_ELx_FIQ (2 << 9)
 +#define KVM_ARM64_EXCEPT_AA64_ELx_SERR        (3 << 9)
 +#define KVM_ARM64_EXCEPT_AA64_EL1     (0 << 11)
 +#define KVM_ARM64_EXCEPT_AA64_EL2     (1 << 11)
  
 -#define vcpu_has_sve(vcpu) (system_supports_sve() && \
 +/*
 + * Overlaps with KVM_ARM64_EXCEPT_MASK on purpose so that it can't be
 + * set together with an exception...
 + */
 +#define KVM_ARM64_INCREMENT_PC                (1 << 9) /* Increment PC */
 +
 +#define vcpu_has_sve(vcpu) (system_supports_sve() &&                  \
                            ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
  
  #ifdef CONFIG_ARM64_PTR_AUTH
  u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg);
  void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg);
  
 -/*
 - * CP14 and CP15 live in the same array, as they are backed by the
 - * same system registers.
 - */
 -#define CPx_BIAS              IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)
 +static inline bool __vcpu_read_sys_reg_from_cpu(int reg, u64 *val)
 +{
 +      /*
 +       * *** VHE ONLY ***
 +       *
 +       * System registers listed in the switch are not saved on every
 +       * exit from the guest but are only saved on vcpu_put.
 +       *
 +       * Note that MPIDR_EL1 for the guest is set by KVM via VMPIDR_EL2 but
 +       * should never be listed below, because the guest cannot modify its
 +       * own MPIDR_EL1 and MPIDR_EL1 is accessed for VCPU A from VCPU B's
 +       * thread when emulating cross-VCPU communication.
 +       */
 +      if (!has_vhe())
 +              return false;
 +
 +      switch (reg) {
 +      case CSSELR_EL1:        *val = read_sysreg_s(SYS_CSSELR_EL1);   break;
 +      case SCTLR_EL1:         *val = read_sysreg_s(SYS_SCTLR_EL12);   break;
 +      case CPACR_EL1:         *val = read_sysreg_s(SYS_CPACR_EL12);   break;
 +      case TTBR0_EL1:         *val = read_sysreg_s(SYS_TTBR0_EL12);   break;
 +      case TTBR1_EL1:         *val = read_sysreg_s(SYS_TTBR1_EL12);   break;
 +      case TCR_EL1:           *val = read_sysreg_s(SYS_TCR_EL12);     break;
 +      case ESR_EL1:           *val = read_sysreg_s(SYS_ESR_EL12);     break;
 +      case AFSR0_EL1:         *val = read_sysreg_s(SYS_AFSR0_EL12);   break;
 +      case AFSR1_EL1:         *val = read_sysreg_s(SYS_AFSR1_EL12);   break;
 +      case FAR_EL1:           *val = read_sysreg_s(SYS_FAR_EL12);     break;
 +      case MAIR_EL1:          *val = read_sysreg_s(SYS_MAIR_EL12);    break;
 +      case VBAR_EL1:          *val = read_sysreg_s(SYS_VBAR_EL12);    break;
 +      case CONTEXTIDR_EL1:    *val = read_sysreg_s(SYS_CONTEXTIDR_EL12);break;
 +      case TPIDR_EL0:         *val = read_sysreg_s(SYS_TPIDR_EL0);    break;
 +      case TPIDRRO_EL0:       *val = read_sysreg_s(SYS_TPIDRRO_EL0);  break;
 +      case TPIDR_EL1:         *val = read_sysreg_s(SYS_TPIDR_EL1);    break;
 +      case AMAIR_EL1:         *val = read_sysreg_s(SYS_AMAIR_EL12);   break;
 +      case CNTKCTL_EL1:       *val = read_sysreg_s(SYS_CNTKCTL_EL12); break;
 +      case ELR_EL1:           *val = read_sysreg_s(SYS_ELR_EL12);     break;
 +      case PAR_EL1:           *val = read_sysreg_par();               break;
 +      case DACR32_EL2:        *val = read_sysreg_s(SYS_DACR32_EL2);   break;
 +      case IFSR32_EL2:        *val = read_sysreg_s(SYS_IFSR32_EL2);   break;
 +      case DBGVCR32_EL2:      *val = read_sysreg_s(SYS_DBGVCR32_EL2); break;
 +      default:                return false;
 +      }
 +
 +      return true;
 +}
  
 -#define vcpu_cp14(v,r)                ((v)->arch.ctxt.copro[(r) ^ CPx_BIAS])
 -#define vcpu_cp15(v,r)                ((v)->arch.ctxt.copro[(r) ^ CPx_BIAS])
 +static inline bool __vcpu_write_sys_reg_to_cpu(u64 val, int reg)
 +{
 +      /*
 +       * *** VHE ONLY ***
 +       *
 +       * System registers listed in the switch are not restored on every
 +       * entry to the guest but are only restored on vcpu_load.
 +       *
 +       * Note that MPIDR_EL1 for the guest is set by KVM via VMPIDR_EL2 but
 +       * should never be listed below, because the MPIDR should only be set
 +       * once, before running the VCPU, and never changed later.
 +       */
 +      if (!has_vhe())
 +              return false;
 +
 +      switch (reg) {
 +      case CSSELR_EL1:        write_sysreg_s(val, SYS_CSSELR_EL1);    break;
 +      case SCTLR_EL1:         write_sysreg_s(val, SYS_SCTLR_EL12);    break;
 +      case CPACR_EL1:         write_sysreg_s(val, SYS_CPACR_EL12);    break;
 +      case TTBR0_EL1:         write_sysreg_s(val, SYS_TTBR0_EL12);    break;
 +      case TTBR1_EL1:         write_sysreg_s(val, SYS_TTBR1_EL12);    break;
 +      case TCR_EL1:           write_sysreg_s(val, SYS_TCR_EL12);      break;
 +      case ESR_EL1:           write_sysreg_s(val, SYS_ESR_EL12);      break;
 +      case AFSR0_EL1:         write_sysreg_s(val, SYS_AFSR0_EL12);    break;
 +      case AFSR1_EL1:         write_sysreg_s(val, SYS_AFSR1_EL12);    break;
 +      case FAR_EL1:           write_sysreg_s(val, SYS_FAR_EL12);      break;
 +      case MAIR_EL1:          write_sysreg_s(val, SYS_MAIR_EL12);     break;
 +      case VBAR_EL1:          write_sysreg_s(val, SYS_VBAR_EL12);     break;
 +      case CONTEXTIDR_EL1:    write_sysreg_s(val, SYS_CONTEXTIDR_EL12);break;
 +      case TPIDR_EL0:         write_sysreg_s(val, SYS_TPIDR_EL0);     break;
 +      case TPIDRRO_EL0:       write_sysreg_s(val, SYS_TPIDRRO_EL0);   break;
 +      case TPIDR_EL1:         write_sysreg_s(val, SYS_TPIDR_EL1);     break;
 +      case AMAIR_EL1:         write_sysreg_s(val, SYS_AMAIR_EL12);    break;
 +      case CNTKCTL_EL1:       write_sysreg_s(val, SYS_CNTKCTL_EL12);  break;
 +      case ELR_EL1:           write_sysreg_s(val, SYS_ELR_EL12);      break;
 +      case PAR_EL1:           write_sysreg_s(val, SYS_PAR_EL1);       break;
 +      case DACR32_EL2:        write_sysreg_s(val, SYS_DACR32_EL2);    break;
 +      case IFSR32_EL2:        write_sysreg_s(val, SYS_IFSR32_EL2);    break;
 +      case DBGVCR32_EL2:      write_sysreg_s(val, SYS_DBGVCR32_EL2);  break;
 +      default:                return false;
 +      }
 +
 +      return true;
 +}
  
  struct kvm_vm_stat {
        ulong remote_tlb_flush;
@@@ -537,12 -481,6 +547,12 @@@ unsigned long kvm_arm_num_regs(struct k
  int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
  int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
  int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
 +
 +unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu);
 +int kvm_arm_copy_sys_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices);
 +int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
 +int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *);
 +
  int __kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
                              struct kvm_vcpu_events *events);
  
@@@ -605,17 -543,6 +615,17 @@@ void kvm_mmu_wp_memory_region(struct kv
  int handle_exit(struct kvm_vcpu *vcpu, int exception_index);
  void handle_exit_early(struct kvm_vcpu *vcpu, int exception_index);
  
 +int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu);
 +int kvm_handle_cp14_32(struct kvm_vcpu *vcpu);
 +int kvm_handle_cp14_64(struct kvm_vcpu *vcpu);
 +int kvm_handle_cp15_32(struct kvm_vcpu *vcpu);
 +int kvm_handle_cp15_64(struct kvm_vcpu *vcpu);
 +int kvm_handle_sys_reg(struct kvm_vcpu *vcpu);
 +
 +void kvm_reset_sys_regs(struct kvm_vcpu *vcpu);
 +
 +void kvm_sys_reg_table_init(void);
 +
  /* MMIO helpers */
  void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
  unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
@@@ -735,7 -662,4 +745,7 @@@ bool kvm_arm_vcpu_is_finalized(struct k
  #define kvm_arm_vcpu_sve_finalized(vcpu) \
        ((vcpu)->arch.flags & KVM_ARM64_VCPU_SVE_FINALIZED)
  
 +#define kvm_vcpu_has_pmu(vcpu)                                        \
 +      (test_bit(KVM_ARM_VCPU_PMU_V3, (vcpu)->arch.features))
 +
  #endif /* __ARM64_KVM_HOST_H__ */
index e298191a854d65d954c66b639a008d388b2904fc,ab6f96df20dfbffb8b9243cea96d435fd625eda0..e52d82aeadca53d0d2300a957f81413166977887
@@@ -94,6 -94,30 +94,30 @@@ alternative_cb_en
        sub     \reg, \reg, \tmp
  .endm
  
+ /*
+  * Convert a kernel image address to a hyp VA
+  * reg: kernel address to be converted in place
+  * tmp: temporary register
+  *
+  * The actual code generation takes place in kvm_get_kimage_voffset, and
+  * the instructions below are only there to reserve the space and
+  * perform the register allocation (kvm_update_kimg_phys_offset uses the
+  * specific registers encoded in the instructions).
+  */
+ .macro kimg_hyp_va reg, tmp
+ alternative_cb kvm_update_kimg_phys_offset
+       movz    \tmp, #0
+       movk    \tmp, #0, lsl #16
+       movk    \tmp, #0, lsl #32
+       movk    \tmp, #0, lsl #48
+ alternative_cb_end
+       sub     \reg, \reg, \tmp
+       mov_q   \tmp, PAGE_OFFSET
+       orr     \reg, \reg, \tmp
+       kern_hyp_va \reg
+ .endm
  #else
  
  #include <linux/pgtable.h>
@@@ -248,6 -272,52 +272,6 @@@ static inline int kvm_write_guest_lock(
        return ret;
  }
  
 -/*
 - * EL2 vectors can be mapped and rerouted in a number of ways,
 - * depending on the kernel configuration and CPU present:
 - *
 - * - If the CPU is affected by Spectre-v2, the hardening sequence is
 - *   placed in one of the vector slots, which is executed before jumping
 - *   to the real vectors.
 - *
 - * - If the CPU also has the ARM64_HARDEN_EL2_VECTORS cap, the slot
 - *   containing the hardening sequence is mapped next to the idmap page,
 - *   and executed before jumping to the real vectors.
 - *
 - * - If the CPU only has the ARM64_HARDEN_EL2_VECTORS cap, then an
 - *   empty slot is selected, mapped next to the idmap page, and
 - *   executed before jumping to the real vectors.
 - *
 - * Note that ARM64_HARDEN_EL2_VECTORS is somewhat incompatible with
 - * VHE, as we don't have hypervisor-specific mappings. If the system
 - * is VHE and yet selects this capability, it will be ignored.
 - */
 -extern void *__kvm_bp_vect_base;
 -extern int __kvm_harden_el2_vector_slot;
 -
 -static inline void *kvm_get_hyp_vector(void)
 -{
 -      struct bp_hardening_data *data = arm64_get_bp_hardening_data();
 -      void *vect = kern_hyp_va(kvm_ksym_ref(__kvm_hyp_vector));
 -      int slot = -1;
 -
 -      if (cpus_have_const_cap(ARM64_SPECTRE_V2) && data->fn) {
 -              vect = kern_hyp_va(kvm_ksym_ref(__bp_harden_hyp_vecs));
 -              slot = data->hyp_vectors_slot;
 -      }
 -
 -      if (this_cpu_has_cap(ARM64_HARDEN_EL2_VECTORS) && !has_vhe()) {
 -              vect = __kvm_bp_vect_base;
 -              if (slot == -1)
 -                      slot = __kvm_harden_el2_vector_slot;
 -      }
 -
 -      if (slot != -1)
 -              vect += slot * SZ_2K;
 -
 -      return vect;
 -}
 -
  #define kvm_phys_to_vttbr(addr)               phys_to_ttbr(addr)
  
  static __always_inline u64 kvm_get_vttbr(struct kvm_s2_mmu *mmu)
index 500efe405b4880073e7a58d41a94f54a1af0dd31,9d77fda6e937fe6a7543220253d3b7e312d214a4..82521cdbfc1c21056b44fd6320f07074df72211d
  #define SET_PSTATE_SSBS(x)            __emit_inst(0xd500401f | PSTATE_SSBS | ((!!x) << PSTATE_Imm_shift))
  #define SET_PSTATE_TCO(x)             __emit_inst(0xd500401f | PSTATE_TCO | ((!!x) << PSTATE_Imm_shift))
  
+ #define set_pstate_pan(x)             asm volatile(SET_PSTATE_PAN(x))
+ #define set_pstate_uao(x)             asm volatile(SET_PSTATE_UAO(x))
+ #define set_pstate_ssbs(x)            asm volatile(SET_PSTATE_SSBS(x))
  #define __SYS_BARRIER_INSN(CRm, op2, Rt) \
        __emit_inst(0xd5000000 | sys_insn(0, 3, 3, (CRm), (op2)) | ((Rt) & 0x1f))
  
  #define SYS_CONTEXTIDR_EL1            sys_reg(3, 0, 13, 0, 1)
  #define SYS_TPIDR_EL1                 sys_reg(3, 0, 13, 0, 4)
  
 +#define SYS_SCXTNUM_EL1                       sys_reg(3, 0, 13, 0, 7)
 +
  #define SYS_CNTKCTL_EL1                       sys_reg(3, 0, 14, 1, 0)
  
  #define SYS_CCSIDR_EL1                        sys_reg(3, 1, 0, 0, 0)
  #define SYS_TPIDR_EL0                 sys_reg(3, 3, 13, 0, 2)
  #define SYS_TPIDRRO_EL0                       sys_reg(3, 3, 13, 0, 3)
  
 +#define SYS_SCXTNUM_EL0                       sys_reg(3, 3, 13, 0, 7)
 +
  /* Definitions for system register interface to AMU for ARMv8.4 onwards */
  #define SYS_AM_EL0(crm, op2)          sys_reg(3, 3, 13, (crm), (op2))
  #define SYS_AMCR_EL0                  SYS_AM_EL0(2, 0)
  #define ENDIAN_SET_EL2                0
  #endif
  
+ #define INIT_SCTLR_EL2_MMU_OFF \
+       (SCTLR_EL2_RES1 | ENDIAN_SET_EL2)
  /* SCTLR_EL1 specific flags. */
  #define SCTLR_EL1_ATA0                (BIT(42))
  
  #define ENDIAN_SET_EL1                0
  #endif
  
- #define SCTLR_EL1_SET (SCTLR_ELx_M    | SCTLR_ELx_C    | SCTLR_ELx_SA   |\
-                        SCTLR_EL1_SA0  | SCTLR_EL1_SED  | SCTLR_ELx_I    |\
-                        SCTLR_EL1_DZE  | SCTLR_EL1_UCT                   |\
-                        SCTLR_EL1_NTWE | SCTLR_ELx_IESB | SCTLR_EL1_SPAN |\
-                        SCTLR_ELx_ITFSB| SCTLR_ELx_ATA  | SCTLR_EL1_ATA0 |\
-                        ENDIAN_SET_EL1 | SCTLR_EL1_UCI  | SCTLR_EL1_RES1)
+ #define INIT_SCTLR_EL1_MMU_OFF \
+       (ENDIAN_SET_EL1 | SCTLR_EL1_RES1)
+ #define INIT_SCTLR_EL1_MMU_ON \
+       (SCTLR_ELx_M    | SCTLR_ELx_C    | SCTLR_ELx_SA   | SCTLR_EL1_SA0   | \
+        SCTLR_EL1_SED  | SCTLR_ELx_I    | SCTLR_EL1_DZE  | SCTLR_EL1_UCT   | \
+        SCTLR_EL1_NTWE | SCTLR_ELx_IESB | SCTLR_EL1_SPAN | SCTLR_ELx_ITFSB | \
+        SCTLR_ELx_ATA  | SCTLR_EL1_ATA0 | ENDIAN_SET_EL1 | SCTLR_EL1_UCI   | \
+        SCTLR_EL1_RES1)
  
  /* MAIR_ELx memory attributes (used by Linux) */
  #define MAIR_ATTR_DEVICE_nGnRnE               UL(0x00)
index 280b10762f6b77e15138019ac5c4d905ecd365cb,0c029adf72d33082e384c5caa0fe283849f928dd..d96f4554282df9f6828ce83dc66b32fbe6178d92
@@@ -74,6 -74,7 +74,7 @@@
  #include <asm/cpufeature.h>
  #include <asm/cpu_ops.h>
  #include <asm/fpsimd.h>
+ #include <asm/kvm_host.h>
  #include <asm/mmu_context.h>
  #include <asm/mte.h>
  #include <asm/processor.h>
@@@ -153,10 -154,6 +154,6 @@@ EXPORT_SYMBOL(cpu_hwcap_keys)
                .width = 0,                             \
        }
  
- /* meta feature for alternatives */
- static bool __maybe_unused
- cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused);
  static void cpu_enable_cnp(struct arm64_cpu_capabilities const *cap);
  
  static bool __system_matches_cap(unsigned int n);
@@@ -1337,8 -1334,6 +1334,8 @@@ static bool unmap_kernel_at_el0(const s
                MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
                MIDR_ALL_VERSIONS(MIDR_HISI_TSV110),
                MIDR_ALL_VERSIONS(MIDR_NVIDIA_CARMEL),
 +              MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_2XX_GOLD),
 +              MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_2XX_SILVER),
                MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_3XX_SILVER),
                MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_SILVER),
                { /* sentinel */ }
@@@ -1600,7 -1595,7 +1597,7 @@@ static void cpu_enable_pan(const struc
        WARN_ON_ONCE(in_interrupt());
  
        sysreg_clear_set(sctlr_el1, SCTLR_EL1_SPAN, 0);
-       asm(SET_PSTATE_PAN(1));
+       set_pstate_pan(1);
  }
  #endif /* CONFIG_ARM64_PAN */
  
@@@ -1709,6 -1704,21 +1706,21 @@@ static void cpu_enable_mte(struct arm64
  }
  #endif /* CONFIG_ARM64_MTE */
  
+ #ifdef CONFIG_KVM
+ static bool is_kvm_protected_mode(const struct arm64_cpu_capabilities *entry, int __unused)
+ {
+       if (kvm_get_mode() != KVM_MODE_PROTECTED)
+               return false;
+       if (is_kernel_in_hyp_mode()) {
+               pr_warn("Protected KVM not available with VHE\n");
+               return false;
+       }
+       return true;
+ }
+ #endif /* CONFIG_KVM */
  /* Internal helper functions to match cpu capability type */
  static bool
  cpucap_late_cpu_optional(const struct arm64_cpu_capabilities *cap)
@@@ -1770,28 -1780,6 +1782,6 @@@ static const struct arm64_cpu_capabilit
                .type = ARM64_CPUCAP_WEAK_LOCAL_CPU_FEATURE,
                .matches = has_no_hw_prefetch,
        },
- #ifdef CONFIG_ARM64_UAO
-       {
-               .desc = "User Access Override",
-               .capability = ARM64_HAS_UAO,
-               .type = ARM64_CPUCAP_SYSTEM_FEATURE,
-               .matches = has_cpuid_feature,
-               .sys_reg = SYS_ID_AA64MMFR2_EL1,
-               .field_pos = ID_AA64MMFR2_UAO_SHIFT,
-               .min_field_value = 1,
-               /*
-                * We rely on stop_machine() calling uao_thread_switch() to set
-                * UAO immediately after patching.
-                */
-       },
- #endif /* CONFIG_ARM64_UAO */
- #ifdef CONFIG_ARM64_PAN
-       {
-               .capability = ARM64_ALT_PAN_NOT_UAO,
-               .type = ARM64_CPUCAP_SYSTEM_FEATURE,
-               .matches = cpufeature_pan_not_uao,
-       },
- #endif /* CONFIG_ARM64_PAN */
  #ifdef CONFIG_ARM64_VHE
        {
                .desc = "Virtualization Host Extensions",
                .field_pos = ID_AA64PFR0_EL1_SHIFT,
                .min_field_value = ID_AA64PFR0_EL1_32BIT_64BIT,
        },
+       {
+               .desc = "Protected KVM",
+               .capability = ARM64_KVM_PROTECTED_MODE,
+               .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+               .matches = is_kvm_protected_mode,
+       },
  #endif
        {
                .desc = "Kernel page table isolation (KPTI)",
                .cpu_enable = cpu_enable_mte,
        },
  #endif /* CONFIG_ARM64_MTE */
+       {
+               .desc = "RCpc load-acquire (LDAPR)",
+               .capability = ARM64_HAS_LDAPR,
+               .type = ARM64_CPUCAP_SYSTEM_FEATURE,
+               .sys_reg = SYS_ID_AA64ISAR1_EL1,
+               .sign = FTR_UNSIGNED,
+               .field_pos = ID_AA64ISAR1_LRCPC_SHIFT,
+               .matches = has_cpuid_feature,
+               .min_field_value = 1,
+       },
        {},
  };
  
@@@ -2652,7 -2656,7 +2658,7 @@@ bool this_cpu_has_cap(unsigned int n
   * - The SYSTEM_FEATURE cpu_hwcaps may not have been set.
   * In all other cases cpus_have_{const_}cap() should be used.
   */
- static bool __system_matches_cap(unsigned int n)
+ static bool __maybe_unused __system_matches_cap(unsigned int n)
  {
        if (n < ARM64_NCAPS) {
                const struct arm64_cpu_capabilities *cap = cpu_hwcaps_ptrs[n];
@@@ -2732,12 -2736,6 +2738,6 @@@ void __init setup_cpu_features(void
                        ARCH_DMA_MINALIGN);
  }
  
- static bool __maybe_unused
- cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused)
- {
-       return (__system_matches_cap(ARM64_HAS_PAN) && !__system_matches_cap(ARM64_HAS_UAO));
- }
  static void __maybe_unused cpu_enable_cnp(struct arm64_cpu_capabilities const *cap)
  {
        cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
@@@ -2846,28 -2844,14 +2846,28 @@@ static int __init enable_mrs_emulation(
  
  core_initcall(enable_mrs_emulation);
  
 +enum mitigation_state arm64_get_meltdown_state(void)
 +{
 +      if (__meltdown_safe)
 +              return SPECTRE_UNAFFECTED;
 +
 +      if (arm64_kernel_unmapped_at_el0())
 +              return SPECTRE_MITIGATED;
 +
 +      return SPECTRE_VULNERABLE;
 +}
 +
  ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr,
                          char *buf)
  {
 -      if (__meltdown_safe)
 +      switch (arm64_get_meltdown_state()) {
 +      case SPECTRE_UNAFFECTED:
                return sprintf(buf, "Not affected\n");
  
 -      if (arm64_kernel_unmapped_at_el0())
 +      case SPECTRE_MITIGATED:
                return sprintf(buf, "Mitigation: PTI\n");
  
 -      return sprintf(buf, "Vulnerable\n");
 +      default:
 +              return sprintf(buf, "Vulnerable\n");
 +      }
  }
index a47a40ec6ad91154d965425821d683ceb3378869,569910ac0fd2253ce48bcf73c65dd51cf712d2ab..71005cb0f4e004a0cf2635725deafb430a443208
@@@ -422,16 -422,15 +422,15 @@@ int copy_thread(unsigned long clone_fla
                if (clone_flags & CLONE_SETTLS)
                        p->thread.uw.tp_value = tls;
        } else {
+               /*
+                * A kthread has no context to ERET to, so ensure any buggy
+                * ERET is treated as an illegal exception return.
+                *
+                * When a user task is created from a kthread, childregs will
+                * be initialized by start_thread() or start_compat_thread().
+                */
                memset(childregs, 0, sizeof(struct pt_regs));
-               childregs->pstate = PSR_MODE_EL1h;
-               if (IS_ENABLED(CONFIG_ARM64_UAO) &&
-                   cpus_have_const_cap(ARM64_HAS_UAO))
-                       childregs->pstate |= PSR_UAO_BIT;
-               spectre_v4_enable_task_mitigation(p);
-               if (system_uses_irq_prio_masking())
-                       childregs->pmr_save = GIC_PRIO_IRQON;
+               childregs->pstate = PSR_MODE_EL1h | PSR_IL_BIT;
  
                p->thread.cpu_context.x19 = stack_start;
                p->thread.cpu_context.x20 = stk_sz;
@@@ -461,17 -460,6 +460,6 @@@ static void tls_thread_switch(struct ta
        write_sysreg(*task_user_tls(next), tpidr_el0);
  }
  
- /* Restore the UAO state depending on next's addr_limit */
- void uao_thread_switch(struct task_struct *next)
- {
-       if (IS_ENABLED(CONFIG_ARM64_UAO)) {
-               if (task_thread_info(next)->addr_limit == KERNEL_DS)
-                       asm(ALTERNATIVE("nop", SET_PSTATE_UAO(1), ARM64_HAS_UAO));
-               else
-                       asm(ALTERNATIVE("nop", SET_PSTATE_UAO(0), ARM64_HAS_UAO));
-       }
- }
  /*
   * Force SSBS state on context-switch, since it may be lost after migrating
   * from a CPU which treats the bit as RES0 in a heterogeneous system.
@@@ -522,13 -510,14 +510,13 @@@ static void erratum_1418040_thread_swit
        bool prev32, next32;
        u64 val;
  
 -      if (!(IS_ENABLED(CONFIG_ARM64_ERRATUM_1418040) &&
 -            cpus_have_const_cap(ARM64_WORKAROUND_1418040)))
 +      if (!IS_ENABLED(CONFIG_ARM64_ERRATUM_1418040))
                return;
  
        prev32 = is_compat_thread(task_thread_info(prev));
        next32 = is_compat_thread(task_thread_info(next));
  
 -      if (prev32 == next32)
 +      if (prev32 == next32 || !this_cpu_has_cap(ARM64_WORKAROUND_1418040))
                return;
  
        val = read_sysreg(cntkctl_el1);
@@@ -554,7 -543,6 +542,6 @@@ __notrace_funcgraph struct task_struct 
        hw_breakpoint_thread_switch(next);
        contextidr_thread_switch(next);
        entry_task_switch(next);
-       uao_thread_switch(next);
        ssbs_thread_switch(next);
        erratum_1418040_thread_switch(prev, next);
  
index fca03648e2709e09f9fa739065c914a2c2e3c267,6809b556538fde87e1838b1ede9c05cdb7249de5..902e4084c4775251fa77a4aecdb6617969b31784
@@@ -1,6 -1,6 +1,6 @@@
  // SPDX-License-Identifier: GPL-2.0-only
  /*
 - * Handle detection, reporting and mitigation of Spectre v1, v2 and v4, as
 + * Handle detection, reporting and mitigation of Spectre v1, v2, v3a and v4, as
   * detailed at:
   *
   *   https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability
  #include <linux/prctl.h>
  #include <linux/sched/task_stack.h>
  
+ #include <asm/insn.h>
  #include <asm/spectre.h>
  #include <asm/traps.h>
 +#include <asm/virt.h>
  
  /*
   * We try to ensure that the mitigation state can never change as the result of
@@@ -119,7 -119,6 +120,7 @@@ static enum mitigation_state spectre_v2
                MIDR_ALL_VERSIONS(MIDR_CORTEX_A55),
                MIDR_ALL_VERSIONS(MIDR_BRAHMA_B53),
                MIDR_ALL_VERSIONS(MIDR_HISI_TSV110),
 +              MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_2XX_SILVER),
                MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_3XX_SILVER),
                MIDR_ALL_VERSIONS(MIDR_QCOM_KRYO_4XX_SILVER),
                { /* sentinel */ }
@@@ -171,26 -170,72 +172,26 @@@ bool has_spectre_v2(const struct arm64_
        return true;
  }
  
 -DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
 -
  enum mitigation_state arm64_get_spectre_v2_state(void)
  {
        return spectre_v2_state;
  }
  
 -#ifdef CONFIG_KVM
 -#include <asm/cacheflush.h>
 -#include <asm/kvm_asm.h>
 -
 -atomic_t arm64_el2_vector_last_slot = ATOMIC_INIT(-1);
 -
 -static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
 -                              const char *hyp_vecs_end)
 -{
 -      void *dst = lm_alias(__bp_harden_hyp_vecs + slot * SZ_2K);
 -      int i;
 -
 -      for (i = 0; i < SZ_2K; i += 0x80)
 -              memcpy(dst + i, hyp_vecs_start, hyp_vecs_end - hyp_vecs_start);
 -
 -      __flush_icache_range((uintptr_t)dst, (uintptr_t)dst + SZ_2K);
 -}
 +DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data);
  
  static void install_bp_hardening_cb(bp_hardening_cb_t fn)
  {
 -      static DEFINE_RAW_SPINLOCK(bp_lock);
 -      int cpu, slot = -1;
 -      const char *hyp_vecs_start = __smccc_workaround_1_smc;
 -      const char *hyp_vecs_end = __smccc_workaround_1_smc +
 -                                 __SMCCC_WORKAROUND_1_SMC_SZ;
 +      __this_cpu_write(bp_hardening_data.fn, fn);
  
        /*
         * Vinz Clortho takes the hyp_vecs start/end "keys" at
         * the door when we're a guest. Skip the hyp-vectors work.
         */
 -      if (!is_hyp_mode_available()) {
 -              __this_cpu_write(bp_hardening_data.fn, fn);
 +      if (!is_hyp_mode_available())
                return;
 -      }
 -
 -      raw_spin_lock(&bp_lock);
 -      for_each_possible_cpu(cpu) {
 -              if (per_cpu(bp_hardening_data.fn, cpu) == fn) {
 -                      slot = per_cpu(bp_hardening_data.hyp_vectors_slot, cpu);
 -                      break;
 -              }
 -      }
 -
 -      if (slot == -1) {
 -              slot = atomic_inc_return(&arm64_el2_vector_last_slot);
 -              BUG_ON(slot >= BP_HARDEN_EL2_SLOTS);
 -              __copy_hyp_vect_bpi(slot, hyp_vecs_start, hyp_vecs_end);
 -      }
  
 -      __this_cpu_write(bp_hardening_data.hyp_vectors_slot, slot);
 -      __this_cpu_write(bp_hardening_data.fn, fn);
 -      raw_spin_unlock(&bp_lock);
 +      __this_cpu_write(bp_hardening_data.slot, HYP_VECTOR_SPECTRE_DIRECT);
  }
 -#else
 -static void install_bp_hardening_cb(bp_hardening_cb_t fn)
 -{
 -      __this_cpu_write(bp_hardening_data.fn, fn);
 -}
 -#endif        /* CONFIG_KVM */
  
  static void call_smc_arch_workaround_1(void)
  {
@@@ -271,33 -316,6 +272,33 @@@ void spectre_v2_enable_mitigation(cons
        update_mitigation_state(&spectre_v2_state, state);
  }
  
 +/*
 + * Spectre-v3a.
 + *
 + * Phew, there's not an awful lot to do here! We just instruct EL2 to use
 + * an indirect trampoline for the hyp vectors so that guests can't read
 + * VBAR_EL2 to defeat randomisation of the hypervisor VA layout.
 + */
 +bool has_spectre_v3a(const struct arm64_cpu_capabilities *entry, int scope)
 +{
 +      static const struct midr_range spectre_v3a_unsafe_list[] = {
 +              MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
 +              MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
 +              {},
 +      };
 +
 +      WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
 +      return is_midr_in_range_list(read_cpuid_id(), spectre_v3a_unsafe_list);
 +}
 +
 +void spectre_v3a_enable_mitigation(const struct arm64_cpu_capabilities *__unused)
 +{
 +      struct bp_hardening_data *data = this_cpu_ptr(&bp_hardening_data);
 +
 +      if (this_cpu_has_cap(ARM64_SPECTRE_V3A))
 +              data->slot += HYP_VECTOR_INDIRECT;
 +}
 +
  /*
   * Spectre v4.
   *
@@@ -520,12 -538,12 +521,12 @@@ static enum mitigation_state spectre_v4
  
        if (spectre_v4_mitigations_off()) {
                sysreg_clear_set(sctlr_el1, 0, SCTLR_ELx_DSSBS);
-               asm volatile(SET_PSTATE_SSBS(1));
+               set_pstate_ssbs(1);
                return SPECTRE_VULNERABLE;
        }
  
        /* SCTLR_EL1.DSSBS was initialised to 0 during boot */
-       asm volatile(SET_PSTATE_SSBS(0));
+       set_pstate_ssbs(0);
        return SPECTRE_MITIGATED;
  }
  
diff --combined arch/arm64/kvm/arm.c
index 7e86207fa2fc4a8e797284ae0063b2cfe169fed5,fadcc94931f99ffecf078396ab527ea6e8635183..6e637d2b4cfb7fe0978fd491f4506da0cc7793e7
@@@ -19,6 -19,7 +19,7 @@@
  #include <linux/kvm_irqfd.h>
  #include <linux/irqbypass.h>
  #include <linux/sched/stat.h>
+ #include <linux/psci.h>
  #include <trace/events/kvm.h>
  
  #define CREATE_TRACE_POINTS
@@@ -35,6 -36,7 +36,6 @@@
  #include <asm/kvm_asm.h>
  #include <asm/kvm_mmu.h>
  #include <asm/kvm_emulate.h>
 -#include <asm/kvm_coproc.h>
  #include <asm/sections.h>
  
  #include <kvm/arm_hypercalls.h>
  __asm__(".arch_extension      virt");
  #endif
  
+ static enum kvm_mode kvm_mode = KVM_MODE_DEFAULT;
+ DEFINE_STATIC_KEY_FALSE(kvm_protected_mode_initialized);
  DECLARE_KVM_HYP_PER_CPU(unsigned long, kvm_hyp_vector);
  
  static DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page);
  unsigned long kvm_arm_hyp_percpu_base[NR_CPUS];
+ DECLARE_KVM_NVHE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params);
  
  /* The VMID used in the VTTBR */
  static atomic64_t kvm_vmid_gen = ATOMIC64_INIT(1);
@@@ -60,6 -66,10 +65,10 @@@ static bool vgic_present
  static DEFINE_PER_CPU(unsigned char, kvm_arm_hardware_enabled);
  DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
  
+ extern u64 kvm_nvhe_sym(__cpu_logical_map)[NR_CPUS];
+ extern u32 kvm_nvhe_sym(kvm_host_psci_version);
+ extern struct psci_0_1_function_ids kvm_nvhe_sym(kvm_host_psci_0_1_function_ids);
  int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
  {
        return kvm_vcpu_exiting_guest_mode(vcpu) == IN_GUEST_MODE;
@@@ -101,22 -111,6 +110,22 @@@ static int kvm_arm_default_max_vcpus(vo
        return vgic_present ? kvm_vgic_get_max_vcpus() : KVM_MAX_VCPUS;
  }
  
 +static void set_default_spectre(struct kvm *kvm)
 +{
 +      /*
 +       * The default is to expose CSV2 == 1 if the HW isn't affected.
 +       * Although this is a per-CPU feature, we make it global because
 +       * asymmetric systems are just a nuisance.
 +       *
 +       * Userspace can override this as long as it doesn't promise
 +       * the impossible.
 +       */
 +      if (arm64_get_spectre_v2_state() == SPECTRE_UNAFFECTED)
 +              kvm->arch.pfr0_csv2 = 1;
 +      if (arm64_get_meltdown_state() == SPECTRE_UNAFFECTED)
 +              kvm->arch.pfr0_csv3 = 1;
 +}
 +
  /**
   * kvm_arch_init_vm - initializes a VM data structure
   * @kvm:      pointer to the KVM struct
@@@ -142,8 -136,6 +151,8 @@@ int kvm_arch_init_vm(struct kvm *kvm, u
        /* The maximum number of VCPUs is limited by the host's GIC model */
        kvm->arch.max_vcpus = kvm_arm_default_max_vcpus();
  
 +      set_default_spectre(kvm);
 +
        return ret;
  out_free_stage2_pgd:
        kvm_free_stage2_pgd(&kvm->arch.mmu);
@@@ -199,8 -191,6 +208,8 @@@ int kvm_vm_ioctl_check_extension(struc
        case KVM_CAP_ARM_IRQ_LINE_LAYOUT_2:
        case KVM_CAP_ARM_NISV_TO_USER:
        case KVM_CAP_ARM_INJECT_EXT_DABT:
 +      case KVM_CAP_SET_GUEST_DEBUG:
 +      case KVM_CAP_VCPU_ATTRIBUTES:
                r = 1;
                break;
        case KVM_CAP_ARM_SET_DEVICE_ADDR:
        case KVM_CAP_STEAL_TIME:
                r = kvm_arm_pvtime_supported();
                break;
 -      default:
 -              r = kvm_arch_vm_ioctl_check_extension(kvm, ext);
 +      case KVM_CAP_ARM_EL1_32BIT:
 +              r = cpus_have_const_cap(ARM64_HAS_32BIT_EL1);
 +              break;
 +      case KVM_CAP_GUEST_DEBUG_HW_BPS:
 +              r = get_num_brps();
 +              break;
 +      case KVM_CAP_GUEST_DEBUG_HW_WPS:
 +              r = get_num_wrps();
 +              break;
 +      case KVM_CAP_ARM_PMU_V3:
 +              r = kvm_arm_support_pmu_v3();
 +              break;
 +      case KVM_CAP_ARM_INJECT_SERROR_ESR:
 +              r = cpus_have_const_cap(ARM64_HAS_RAS_EXTN);
 +              break;
 +      case KVM_CAP_ARM_VM_IPA_SIZE:
 +              r = get_kvm_ipa_limit();
 +              break;
 +      case KVM_CAP_ARM_SVE:
 +              r = system_supports_sve();
 +              break;
 +      case KVM_CAP_ARM_PTRAUTH_ADDRESS:
 +      case KVM_CAP_ARM_PTRAUTH_GENERIC:
 +              r = system_has_full_ptr_auth();
                break;
 +      default:
 +              r = 0;
        }
 +
        return r;
  }
  
@@@ -1339,54 -1304,45 +1348,52 @@@ static unsigned long nvhe_percpu_order(
        return size ? get_order(size) : 0;
  }
  
 -static int kvm_map_vectors(void)
 +/* A lookup table holding the hypervisor VA for each vector slot */
 +static void *hyp_spectre_vector_selector[BP_HARDEN_EL2_SLOTS];
 +
 +static int __kvm_vector_slot2idx(enum arm64_hyp_spectre_vector slot)
  {
 -      /*
 -       * SV2  = ARM64_SPECTRE_V2
 -       * HEL2 = ARM64_HARDEN_EL2_VECTORS
 -       *
 -       * !SV2 + !HEL2 -> use direct vectors
 -       *  SV2 + !HEL2 -> use hardened vectors in place
 -       * !SV2 +  HEL2 -> allocate one vector slot and use exec mapping
 -       *  SV2 +  HEL2 -> use hardened vectors and use exec mapping
 -       */
 -      if (cpus_have_const_cap(ARM64_SPECTRE_V2)) {
 -              __kvm_bp_vect_base = kvm_ksym_ref(__bp_harden_hyp_vecs);
 -              __kvm_bp_vect_base = kern_hyp_va(__kvm_bp_vect_base);
 -      }
 +      return slot - (slot != HYP_VECTOR_DIRECT);
 +}
  
 -      if (cpus_have_const_cap(ARM64_HARDEN_EL2_VECTORS)) {
 -              phys_addr_t vect_pa = __pa_symbol(__bp_harden_hyp_vecs);
 -              unsigned long size = __BP_HARDEN_HYP_VECS_SZ;
 +static void kvm_init_vector_slot(void *base, enum arm64_hyp_spectre_vector slot)
 +{
 +      int idx = __kvm_vector_slot2idx(slot);
  
 -              /*
 -               * Always allocate a spare vector slot, as we don't
 -               * know yet which CPUs have a BP hardening slot that
 -               * we can reuse.
 -               */
 -              __kvm_harden_el2_vector_slot = atomic_inc_return(&arm64_el2_vector_last_slot);
 -              BUG_ON(__kvm_harden_el2_vector_slot >= BP_HARDEN_EL2_SLOTS);
 -              return create_hyp_exec_mappings(vect_pa, size,
 -                                              &__kvm_bp_vect_base);
 +      hyp_spectre_vector_selector[slot] = base + (idx * SZ_2K);
 +}
 +
 +static int kvm_init_vector_slots(void)
 +{
 +      int err;
 +      void *base;
 +
 +      base = kern_hyp_va(kvm_ksym_ref(__kvm_hyp_vector));
 +      kvm_init_vector_slot(base, HYP_VECTOR_DIRECT);
 +
 +      base = kern_hyp_va(kvm_ksym_ref(__bp_harden_hyp_vecs));
 +      kvm_init_vector_slot(base, HYP_VECTOR_SPECTRE_DIRECT);
 +
 +      if (!cpus_have_const_cap(ARM64_SPECTRE_V3A))
 +              return 0;
 +
 +      if (!has_vhe()) {
 +              err = create_hyp_exec_mappings(__pa_symbol(__bp_harden_hyp_vecs),
 +                                             __BP_HARDEN_HYP_VECS_SZ, &base);
 +              if (err)
 +                      return err;
        }
  
 +      kvm_init_vector_slot(base, HYP_VECTOR_INDIRECT);
 +      kvm_init_vector_slot(base, HYP_VECTOR_SPECTRE_INDIRECT);
        return 0;
  }
  
  static void cpu_init_hyp_mode(void)
  {
-       phys_addr_t pgd_ptr;
-       unsigned long hyp_stack_ptr;
-       unsigned long vector_ptr;
-       unsigned long tpidr_el2;
+       struct kvm_nvhe_init_params *params = this_cpu_ptr_nvhe_sym(kvm_init_params);
        struct arm_smccc_res res;
+       unsigned long tcr;
  
        /* Switch from the HYP stub to our own HYP init vector */
        __hyp_set_vectors(kvm_get_idmap_vector());
         * kernel's mapping to the linear mapping, and store it in tpidr_el2
         * so that we can use adr_l to access per-cpu variables in EL2.
         */
-       tpidr_el2 = (unsigned long)this_cpu_ptr_nvhe_sym(__per_cpu_start) -
-                   (unsigned long)kvm_ksym_ref(CHOOSE_NVHE_SYM(__per_cpu_start));
+       params->tpidr_el2 = (unsigned long)this_cpu_ptr_nvhe_sym(__per_cpu_start) -
+                           (unsigned long)kvm_ksym_ref(CHOOSE_NVHE_SYM(__per_cpu_start));
+       params->mair_el2 = read_sysreg(mair_el1);
+       /*
+        * The ID map may be configured to use an extended virtual address
+        * range. This is only the case if system RAM is out of range for the
+        * currently configured page size and VA_BITS, in which case we will
+        * also need the extended virtual range for the HYP ID map, or we won't
+        * be able to enable the EL2 MMU.
+        *
+        * However, at EL2, there is only one TTBR register, and we can't switch
+        * between translation tables *and* update TCR_EL2.T0SZ at the same
+        * time. Bottom line: we need to use the extended range with *both* our
+        * translation tables.
+        *
+        * So use the same T0SZ value we use for the ID map.
+        */
+       tcr = (read_sysreg(tcr_el1) & TCR_EL2_MASK) | TCR_EL2_RES1;
+       tcr &= ~TCR_T0SZ_MASK;
+       tcr |= (idmap_t0sz & GENMASK(TCR_TxSZ_WIDTH - 1, 0)) << TCR_T0SZ_OFFSET;
+       params->tcr_el2 = tcr;
+       params->stack_hyp_va = kern_hyp_va(__this_cpu_read(kvm_arm_hyp_stack_page) + PAGE_SIZE);
+       params->pgd_pa = kvm_mmu_get_httbr();
  
-       pgd_ptr = kvm_mmu_get_httbr();
-       hyp_stack_ptr = __this_cpu_read(kvm_arm_hyp_stack_page) + PAGE_SIZE;
-       hyp_stack_ptr = kern_hyp_va(hyp_stack_ptr);
-       vector_ptr = (unsigned long)kern_hyp_va(kvm_ksym_ref(__kvm_hyp_host_vector));
+       /*
+        * Flush the init params from the data cache because the struct will
+        * be read while the MMU is off.
+        */
+       kvm_flush_dcache_to_poc(params, sizeof(*params));
  
        /*
         * Call initialization code, and switch to the full blown HYP code.
         * cpus_have_const_cap() wrapper.
         */
        BUG_ON(!system_capabilities_finalized());
-       arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(__kvm_hyp_init),
-                         pgd_ptr, tpidr_el2, hyp_stack_ptr, vector_ptr, &res);
+       arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(__kvm_hyp_init), virt_to_phys(params), &res);
        WARN_ON(res.a0 != SMCCC_RET_SUCCESS);
  
        /*
@@@ -1431,40 -1411,13 +1462,40 @@@ static void cpu_hyp_reset(void
                __hyp_reset_vectors();
  }
  
 +/*
 + * EL2 vectors can be mapped and rerouted in a number of ways,
 + * depending on the kernel configuration and CPU present:
 + *
 + * - If the CPU is affected by Spectre-v2, the hardening sequence is
 + *   placed in one of the vector slots, which is executed before jumping
 + *   to the real vectors.
 + *
 + * - If the CPU also has the ARM64_SPECTRE_V3A cap, the slot
 + *   containing the hardening sequence is mapped next to the idmap page,
 + *   and executed before jumping to the real vectors.
 + *
 + * - If the CPU only has the ARM64_SPECTRE_V3A cap, then an
 + *   empty slot is selected, mapped next to the idmap page, and
 + *   executed before jumping to the real vectors.
 + *
 + * Note that ARM64_SPECTRE_V3A is somewhat incompatible with
 + * VHE, as we don't have hypervisor-specific mappings. If the system
 + * is VHE and yet selects this capability, it will be ignored.
 + */
 +static void cpu_set_hyp_vector(void)
 +{
 +      struct bp_hardening_data *data = this_cpu_ptr(&bp_hardening_data);
 +      void *vector = hyp_spectre_vector_selector[data->slot];
 +
 +      *this_cpu_ptr_hyp_sym(kvm_hyp_vector) = (unsigned long)vector;
 +}
 +
  static void cpu_hyp_reinit(void)
  {
        kvm_init_host_cpu_context(&this_cpu_ptr_hyp_sym(kvm_host_data)->host_ctxt);
  
        cpu_hyp_reset();
 -
 -      *this_cpu_ptr_hyp_sym(kvm_hyp_vector) = (unsigned long)kvm_get_hyp_vector();
 +      cpu_set_hyp_vector();
  
        if (is_kernel_in_hyp_mode())
                kvm_timer_init_vhe();
@@@ -1501,7 -1454,8 +1532,8 @@@ static void _kvm_arch_hardware_disable(
  
  void kvm_arch_hardware_disable(void)
  {
-       _kvm_arch_hardware_disable(NULL);
+       if (!is_protected_kvm_enabled())
+               _kvm_arch_hardware_disable(NULL);
  }
  
  #ifdef CONFIG_CPU_PM
@@@ -1544,11 -1498,13 +1576,13 @@@ static struct notifier_block hyp_init_c
  
  static void __init hyp_cpu_pm_init(void)
  {
-       cpu_pm_register_notifier(&hyp_init_cpu_pm_nb);
+       if (!is_protected_kvm_enabled())
+               cpu_pm_register_notifier(&hyp_init_cpu_pm_nb);
  }
  static void __init hyp_cpu_pm_exit(void)
  {
-       cpu_pm_unregister_notifier(&hyp_init_cpu_pm_nb);
+       if (!is_protected_kvm_enabled())
+               cpu_pm_unregister_notifier(&hyp_init_cpu_pm_nb);
  }
  #else
  static inline void hyp_cpu_pm_init(void)
@@@ -1559,6 -1515,36 +1593,36 @@@ static inline void hyp_cpu_pm_exit(void
  }
  #endif
  
+ static void init_cpu_logical_map(void)
+ {
+       unsigned int cpu;
+       /*
+        * Copy the MPIDR <-> logical CPU ID mapping to hyp.
+        * Only copy the set of online CPUs whose features have been chacked
+        * against the finalized system capabilities. The hypervisor will not
+        * allow any other CPUs from the `possible` set to boot.
+        */
+       for_each_online_cpu(cpu)
+               kvm_nvhe_sym(__cpu_logical_map)[cpu] = cpu_logical_map(cpu);
+ }
+ static bool init_psci_relay(void)
+ {
+       /*
+        * If PSCI has not been initialized, protected KVM cannot install
+        * itself on newly booted CPUs.
+        */
+       if (!psci_ops.get_version) {
+               kvm_err("Cannot initialize protected mode without PSCI\n");
+               return false;
+       }
+       kvm_nvhe_sym(kvm_host_psci_version) = psci_ops.get_version();
+       kvm_nvhe_sym(kvm_host_psci_0_1_function_ids) = get_psci_0_1_function_ids();
+       return true;
+ }
  static int init_common_resources(void)
  {
        return kvm_set_ipa_limit();
@@@ -1603,10 -1589,11 +1667,11 @@@ static int init_subsystems(void
                goto out;
  
        kvm_perf_init();
 -      kvm_coproc_table_init();
 +      kvm_sys_reg_table_init();
  
  out:
-       on_each_cpu(_kvm_arch_hardware_disable, NULL, 1);
+       if (err || !is_protected_kvm_enabled())
+               on_each_cpu(_kvm_arch_hardware_disable, NULL, 1);
  
        return err;
  }
@@@ -1680,6 -1667,14 +1745,14 @@@ static int init_hyp_mode(void
                goto out_err;
        }
  
+       err = create_hyp_mappings(kvm_ksym_ref(__hyp_data_ro_after_init_start),
+                                 kvm_ksym_ref(__hyp_data_ro_after_init_end),
+                                 PAGE_HYP_RO);
+       if (err) {
+               kvm_err("Cannot map .hyp.data..ro_after_init section\n");
+               goto out_err;
+       }
        err = create_hyp_mappings(kvm_ksym_ref(__start_rodata),
                                  kvm_ksym_ref(__end_rodata), PAGE_HYP_RO);
        if (err) {
                goto out_err;
        }
  
 -      err = kvm_map_vectors();
 -      if (err) {
 -              kvm_err("Cannot map vectors\n");
 -              goto out_err;
 -      }
 -
        /*
         * Map the Hyp stack pages
         */
                }
        }
  
+       if (is_protected_kvm_enabled()) {
+               init_cpu_logical_map();
+               if (!init_psci_relay())
+                       goto out_err;
+       }
        return 0;
  
  out_err:
@@@ -1837,20 -1845,18 +1917,24 @@@ int kvm_arch_init(void *opaque
                        goto out_err;
        }
  
 +      err = kvm_init_vector_slots();
 +      if (err) {
 +              kvm_err("Cannot initialise vector slots\n");
 +              goto out_err;
 +      }
 +
        err = init_subsystems();
        if (err)
                goto out_hyp;
  
-       if (in_hyp_mode)
+       if (is_protected_kvm_enabled()) {
+               static_branch_enable(&kvm_protected_mode_initialized);
+               kvm_info("Protected nVHE mode initialized successfully\n");
+       } else if (in_hyp_mode) {
                kvm_info("VHE mode initialized successfully\n");
-       else
+       } else {
                kvm_info("Hyp mode initialized successfully\n");
+       }
  
        return 0;
  
@@@ -1868,6 -1874,25 +1952,25 @@@ void kvm_arch_exit(void
        kvm_perf_teardown();
  }
  
+ static int __init early_kvm_mode_cfg(char *arg)
+ {
+       if (!arg)
+               return -EINVAL;
+       if (strcmp(arg, "protected") == 0) {
+               kvm_mode = KVM_MODE_PROTECTED;
+               return 0;
+       }
+       return -EINVAL;
+ }
+ early_param("kvm-arm.mode", early_kvm_mode_cfg);
+ enum kvm_mode kvm_get_mode(void)
+ {
+       return kvm_mode;
+ }
  static int arm_init(void)
  {
        int rc = kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE);
index 77b8c4e06f2f6db7308e0d08d92732f51d56856d,bf62c8e42ab23d3d447ef72336a0cdca6327315c..1f1e351c5fe2b2d1175316257c54ef0893753b53
@@@ -6,9 -6,10 +6,10 @@@
  asflags-y := -D__KVM_NVHE_HYPERVISOR__
  ccflags-y := -D__KVM_NVHE_HYPERVISOR__
  
- obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o hyp-init.o host.o hyp-main.o
+ obj-y := timer-sr.o sysreg-sr.o debug-sr.o switch.o tlb.o hyp-init.o host.o \
+        hyp-main.o hyp-smp.o psci-relay.o
  obj-y += ../vgic-v3-sr.o ../aarch32.o ../vgic-v2-cpuif-proxy.o ../entry.o \
 -       ../fpsimd.o ../hyp-entry.o
 +       ../fpsimd.o ../hyp-entry.o ../exception.o
  
  ##
  ## Build rules for compiling nVHE hyp code
index 3e50ff35aa4f1e93e0fde948ec9d11fc4636cb6f,e1f8e0797144ec139ddcab201022f8db16a5a2b9..f3d0e9eca56cd2a62de3f31a77926ee8c478390a
@@@ -4,7 -4,6 +4,7 @@@
   * Author: Marc Zyngier <[email protected]>
   */
  
 +#include <hyp/adjust_pc.h>
  #include <hyp/switch.h>
  #include <hyp/sysreg-sr.h>
  
@@@ -97,7 -96,10 +97,10 @@@ static void __deactivate_traps(struct k
        mdcr_el2 |= MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT;
  
        write_sysreg(mdcr_el2, mdcr_el2);
-       write_sysreg(HCR_HOST_NVHE_FLAGS, hcr_el2);
+       if (is_protected_kvm_enabled())
+               write_sysreg(HCR_HOST_NVHE_PROTECTED_FLAGS, hcr_el2);
+       else
+               write_sysreg(HCR_HOST_NVHE_FLAGS, hcr_el2);
        write_sysreg(CPTR_EL2_DEFAULT, cptr_el2);
        write_sysreg(__kvm_hyp_host_vector, vbar_el2);
  }
@@@ -190,8 -192,6 +193,8 @@@ int __kvm_vcpu_run(struct kvm_vcpu *vcp
  
        __sysreg_save_state_nvhe(host_ctxt);
  
 +      __adjust_pc(vcpu);
 +
        /*
         * We must restore the 32-bit state before the sysregs, thanks
         * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
index 4130b72e6891d79ea649c4af438e6779cd490dd5,16aa8615c279f9d72b8063411f5aa27bb7756412..d8cc51bd60bf22a7769de23536fca461413f7bb9
@@@ -23,6 -23,30 +23,30 @@@ static u8 tag_lsb
  static u64 tag_val;
  static u64 va_mask;
  
+ /*
+  * Compute HYP VA by using the same computation as kern_hyp_va().
+  */
+ static u64 __early_kern_hyp_va(u64 addr)
+ {
+       addr &= va_mask;
+       addr |= tag_val << tag_lsb;
+       return addr;
+ }
+ /*
+  * Store a hyp VA <-> PA offset into a hyp-owned variable.
+  */
+ static void init_hyp_physvirt_offset(void)
+ {
+       extern s64 kvm_nvhe_sym(hyp_physvirt_offset);
+       u64 kern_va, hyp_va;
+       /* Compute the offset from the hyp VA and PA of a random symbol. */
+       kern_va = (u64)kvm_ksym_ref(__hyp_text_start);
+       hyp_va = __early_kern_hyp_va(kern_va);
+       CHOOSE_NVHE_SYM(hyp_physvirt_offset) = (s64)__pa(kern_va) - (s64)hyp_va;
+ }
  /*
   * We want to generate a hyp VA with the following format (with V ==
   * vabits_actual):
@@@ -54,6 -78,8 +78,8 @@@ __init void kvm_compute_layout(void
                tag_val |= get_random_long() & GENMASK_ULL(vabits_actual - 2, tag_lsb);
        }
        tag_val >>= tag_lsb;
+       init_hyp_physvirt_offset();
  }
  
  static u32 compute_instruction(int n, u32 rd, u32 rn)
@@@ -132,23 -158,26 +158,21 @@@ void __init kvm_update_va_mask(struct a
        }
  }
  
 -void *__kvm_bp_vect_base;
 -int __kvm_harden_el2_vector_slot;
 -
  void kvm_patch_vector_branch(struct alt_instr *alt,
                             __le32 *origptr, __le32 *updptr, int nr_inst)
  {
        u64 addr;
        u32 insn;
  
 -      BUG_ON(nr_inst != 5);
 +      BUG_ON(nr_inst != 4);
  
 -      if (has_vhe() || !cpus_have_const_cap(ARM64_HARDEN_EL2_VECTORS)) {
 -              WARN_ON_ONCE(cpus_have_const_cap(ARM64_HARDEN_EL2_VECTORS));
 +      if (!cpus_have_const_cap(ARM64_SPECTRE_V3A) || WARN_ON_ONCE(has_vhe()))
                return;
 -      }
  
        /*
         * Compute HYP VA by using the same computation as kern_hyp_va()
         */
-       addr = (uintptr_t)kvm_ksym_ref(__kvm_hyp_vector);
-       addr &= va_mask;
-       addr |= tag_val << tag_lsb;
+       addr = __early_kern_hyp_va((u64)kvm_ksym_ref(__kvm_hyp_vector));
  
        /* Use PC[10:7] to branch to the same vector in KVM */
        addr |= ((u64)origptr & GENMASK_ULL(10, 7));
         */
        addr += KVM_VECTOR_PREAMBLE;
  
 -      /* stp x0, x1, [sp, #-16]! */
 -      insn = aarch64_insn_gen_load_store_pair(AARCH64_INSN_REG_0,
 -                                              AARCH64_INSN_REG_1,
 -                                              AARCH64_INSN_REG_SP,
 -                                              -16,
 -                                              AARCH64_INSN_VARIANT_64BIT,
 -                                              AARCH64_INSN_LDST_STORE_PAIR_PRE_INDEX);
 -      *updptr++ = cpu_to_le32(insn);
 -
        /* movz x0, #(addr & 0xffff) */
        insn = aarch64_insn_gen_movewide(AARCH64_INSN_REG_0,
                                         (u16)addr,
This page took 0.171074 seconds and 4 git commands to generate.