Merge tag 'v5.10-rc1' into kvmarm-master/next
authorMarc Zyngier <maz@kernel.org>
Thu, 12 Nov 2020 21:20:43 +0000 (21:20 +0000)
committerMarc Zyngier <maz@kernel.org>
Thu, 12 Nov 2020 21:20:43 +0000 (21:20 +0000)
Linux 5.10-rc1

Signed-off-by: Marc Zyngier <maz@kernel.org>
12 files changed:
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/virt.h
arch/arm64/kernel/image-vars.h
arch/arm64/kvm/arm.c
arch/arm64/kvm/hyp/nvhe/host.S
arch/arm64/kvm/hyp/nvhe/hyp-init.S
arch/arm64/kvm/hyp/nvhe/tlb.c
arch/arm64/kvm/hyp/pgtable.c
arch/arm64/kvm/mmu.c
arch/arm64/kvm/sys_regs.c
arch/arm64/kvm/sys_regs.h

index f7e7144..97244d4 100644 (file)
@@ -375,6 +375,23 @@ cpucap_multi_entry_cap_matches(const struct arm64_cpu_capabilities *entry,
        return false;
 }
 
+static __always_inline bool is_vhe_hyp_code(void)
+{
+       /* Only defined for code run in VHE hyp context */
+       return __is_defined(__KVM_VHE_HYPERVISOR__);
+}
+
+static __always_inline bool is_nvhe_hyp_code(void)
+{
+       /* Only defined for code run in NVHE hyp context */
+       return __is_defined(__KVM_NVHE_HYPERVISOR__);
+}
+
+static __always_inline bool is_hyp_code(void)
+{
+       return is_vhe_hyp_code() || is_nvhe_hyp_code();
+}
+
 extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
 extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS];
 extern struct static_key_false arm64_const_caps_ready;
@@ -428,35 +445,40 @@ static __always_inline bool __cpus_have_const_cap(int num)
 }
 
 /*
- * Test for a capability, possibly with a runtime check.
+ * Test for a capability without a runtime check.
  *
- * Before capabilities are finalized, this behaves as cpus_have_cap().
+ * Before capabilities are finalized, this will BUG().
  * After capabilities are finalized, this is patched to avoid a runtime check.
  *
  * @num must be a compile-time constant.
  */
-static __always_inline bool cpus_have_const_cap(int num)
+static __always_inline bool cpus_have_final_cap(int num)
 {
        if (system_capabilities_finalized())
                return __cpus_have_const_cap(num);
        else
-               return cpus_have_cap(num);
+               BUG();
 }
 
 /*
- * Test for a capability without a runtime check.
+ * Test for a capability, possibly with a runtime check for non-hyp code.
  *
- * Before capabilities are finalized, this will BUG().
+ * For hyp code, this behaves the same as cpus_have_final_cap().
+ *
+ * For non-hyp code:
+ * Before capabilities are finalized, this behaves as cpus_have_cap().
  * After capabilities are finalized, this is patched to avoid a runtime check.
  *
  * @num must be a compile-time constant.
  */
-static __always_inline bool cpus_have_final_cap(int num)
+static __always_inline bool cpus_have_const_cap(int num)
 {
-       if (system_capabilities_finalized())
+       if (is_hyp_code())
+               return cpus_have_final_cap(num);
+       else if (system_capabilities_finalized())
                return __cpus_have_const_cap(num);
        else
-               BUG();
+               return cpus_have_cap(num);
 }
 
 static inline void cpus_set_cap(unsigned int num)
index 0aecbab..781d029 100644 (file)
@@ -239,6 +239,7 @@ enum vcpu_sysreg {
 #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)
 
index 09977ac..6069be5 100644 (file)
@@ -86,13 +86,12 @@ static inline bool is_kernel_in_hyp_mode(void)
 static __always_inline bool has_vhe(void)
 {
        /*
-        * The following macros are defined for code specic to VHE/nVHE.
-        * If has_vhe() is inlined into those compilation units, it can
-        * be determined statically. Otherwise fall back to caps.
+        * Code only run in VHE/NVHE hyp context can assume VHE is present or
+        * absent. Otherwise fall back to caps.
         */
-       if (__is_defined(__KVM_VHE_HYPERVISOR__))
+       if (is_vhe_hyp_code())
                return true;
-       else if (__is_defined(__KVM_NVHE_HYPERVISOR__))
+       else if (is_nvhe_hyp_code())
                return false;
        else
                return cpus_have_final_cap(ARM64_HAS_VIRT_HOST_EXTN);
index 61684a5..c615b28 100644 (file)
@@ -87,7 +87,6 @@ KVM_NVHE_ALIAS(__icache_flags);
 /* Kernel symbols needed for cpus_have_final/const_caps checks. */
 KVM_NVHE_ALIAS(arm64_const_caps_ready);
 KVM_NVHE_ALIAS(cpu_hwcap_keys);
-KVM_NVHE_ALIAS(cpu_hwcaps);
 
 /* Static keys which are set if a vGIC trap should be handled in hyp. */
 KVM_NVHE_ALIAS(vgic_v2_cpuif_trap);
index f56122e..a3b32df 100644 (file)
@@ -808,6 +808,25 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 
                preempt_enable();
 
+               /*
+                * The ARMv8 architecture doesn't give the hypervisor
+                * a mechanism to prevent a guest from dropping to AArch32 EL0
+                * if implemented by the CPU. If we spot the guest in such
+                * state and that we decided it wasn't supposed to do so (like
+                * with the asymmetric AArch32 case), return to userspace with
+                * a fatal error.
+                */
+               if (!system_supports_32bit_el0() && vcpu_mode_is_32bit(vcpu)) {
+                       /*
+                        * As we have caught the guest red-handed, decide that
+                        * it isn't fit for purpose anymore by making the vcpu
+                        * invalid. The VMM can try and fix it by issuing  a
+                        * KVM_ARM_VCPU_INIT if it really wants to.
+                        */
+                       vcpu->arch.target = -1;
+                       ret = ARM_EXCEPTION_IL;
+               }
+
                ret = handle_exit(vcpu, ret);
        }
 
index ff9a0f5..ed27f06 100644 (file)
@@ -17,8 +17,6 @@ SYM_FUNC_START(__host_exit)
 
        get_host_ctxt   x0, x1
 
-       ALTERNATIVE(nop, SET_PSTATE_PAN(1), ARM64_HAS_PAN, CONFIG_ARM64_PAN)
-
        /* Store the host regs x2 and x3 */
        stp     x2, x3,   [x0, #CPU_XREG_OFFSET(2)]
 
index 47224dc..b11a9d7 100644 (file)
@@ -57,16 +57,25 @@ __do_hyp_init:
        cmp     x0, #HVC_STUB_HCALL_NR
        b.lo    __kvm_handle_stub_hvc
 
-       /* Set tpidr_el2 for use by HYP to free a register */
-       msr     tpidr_el2, x2
-
-       mov     x2, #KVM_HOST_SMCCC_FUNC(__kvm_hyp_init)
-       cmp     x0, x2
-       b.eq    1f
+       // We only actively check bits [24:31], and everything
+       // else has to be zero, which we check at build time.
+#if (KVM_HOST_SMCCC_FUNC(__kvm_hyp_init) & 0xFFFFFFFF00FFFFFF)
+#error Unexpected __KVM_HOST_SMCCC_FUNC___kvm_hyp_init value
+#endif
+
+       ror     x0, x0, #24
+       eor     x0, x0, #((KVM_HOST_SMCCC_FUNC(__kvm_hyp_init) >> 24) & 0xF)
+       ror     x0, x0, #4
+       eor     x0, x0, #((KVM_HOST_SMCCC_FUNC(__kvm_hyp_init) >> 28) & 0xF)
+       cbz     x0, 1f
        mov     x0, #SMCCC_RET_NOT_SUPPORTED
        eret
 
-1:     phys_to_ttbr x0, x1
+1:
+       /* Set tpidr_el2 for use by HYP to free a register */
+       msr     tpidr_el2, x2
+
+       phys_to_ttbr x0, x1
 alternative_if ARM64_HAS_CNP
        orr     x0, x0, #TTBR_CNP_BIT
 alternative_else_nop_endif
index 39ca71a..fbde89a 100644 (file)
@@ -128,7 +128,6 @@ void __kvm_tlb_flush_local_vmid(struct kvm_s2_mmu *mmu)
        struct tlb_inv_context cxt;
 
        /* Switch to requested VMID */
-       mmu = kern_hyp_va(mmu);
        __tlb_switch_to_guest(mmu, &cxt);
 
        __tlbi(vmalle1);
index 0cdf6e4..0271b4a 100644 (file)
@@ -635,7 +635,7 @@ static void stage2_flush_dcache(void *addr, u64 size)
 
 static bool stage2_pte_cacheable(kvm_pte_t pte)
 {
-       u64 memattr = FIELD_GET(KVM_PTE_LEAF_ATTR_LO_S2_MEMATTR, pte);
+       u64 memattr = pte & KVM_PTE_LEAF_ATTR_LO_S2_MEMATTR;
        return memattr == PAGE_S2_MEMATTR(NORMAL);
 }
 
@@ -846,7 +846,7 @@ int kvm_pgtable_stage2_init(struct kvm_pgtable *pgt, struct kvm *kvm)
        u32 start_level = VTCR_EL2_TGRAN_SL0_BASE - sl0;
 
        pgd_sz = kvm_pgd_pages(ia_bits, start_level) * PAGE_SIZE;
-       pgt->pgd = alloc_pages_exact(pgd_sz, GFP_KERNEL | __GFP_ZERO);
+       pgt->pgd = alloc_pages_exact(pgd_sz, GFP_KERNEL_ACCOUNT | __GFP_ZERO);
        if (!pgt->pgd)
                return -ENOMEM;
 
index 19aacc7..1a01da9 100644 (file)
@@ -787,14 +787,28 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
                vma_shift = PAGE_SHIFT;
        }
 
-       if (vma_shift == PUD_SHIFT &&
-           !fault_supports_stage2_huge_mapping(memslot, hva, PUD_SIZE))
-              vma_shift = PMD_SHIFT;
-
-       if (vma_shift == PMD_SHIFT &&
-           !fault_supports_stage2_huge_mapping(memslot, hva, PMD_SIZE)) {
-               force_pte = true;
+       switch (vma_shift) {
+#ifndef __PAGETABLE_PMD_FOLDED
+       case PUD_SHIFT:
+               if (fault_supports_stage2_huge_mapping(memslot, hva, PUD_SIZE))
+                       break;
+               fallthrough;
+#endif
+       case CONT_PMD_SHIFT:
+               vma_shift = PMD_SHIFT;
+               fallthrough;
+       case PMD_SHIFT:
+               if (fault_supports_stage2_huge_mapping(memslot, hva, PMD_SIZE))
+                       break;
+               fallthrough;
+       case CONT_PTE_SHIFT:
                vma_shift = PAGE_SHIFT;
+               force_pte = true;
+               fallthrough;
+       case PAGE_SHIFT:
+               break;
+       default:
+               WARN_ONCE(1, "Unknown vma_shift %d", vma_shift);
        }
 
        vma_pagesize = 1UL << vma_shift;
@@ -839,6 +853,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
 
        if (kvm_is_device_pfn(pfn)) {
                device = true;
+               force_pte = true;
        } else if (logging_active && !write_fault) {
                /*
                 * Only actually map the page as writable if this was a write
index d9117bc..6d287ee 100644 (file)
@@ -1069,7 +1069,7 @@ static bool trap_ptrauth(struct kvm_vcpu *vcpu,
 static unsigned int ptrauth_visibility(const struct kvm_vcpu *vcpu,
                        const struct sys_reg_desc *rd)
 {
-       return vcpu_has_ptrauth(vcpu) ? 0 : REG_HIDDEN_USER | REG_HIDDEN_GUEST;
+       return vcpu_has_ptrauth(vcpu) ? 0 : REG_HIDDEN;
 }
 
 #define __PTRAUTH_KEY(k)                                               \
@@ -1153,6 +1153,22 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
        return val;
 }
 
+static unsigned int id_visibility(const struct kvm_vcpu *vcpu,
+                                 const struct sys_reg_desc *r)
+{
+       u32 id = sys_reg((u32)r->Op0, (u32)r->Op1,
+                        (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);
+
+       switch (id) {
+       case SYS_ID_AA64ZFR0_EL1:
+               if (!vcpu_has_sve(vcpu))
+                       return REG_RAZ;
+               break;
+       }
+
+       return 0;
+}
+
 /* cpufeature ID register access trap handlers */
 
 static bool __access_id_reg(struct kvm_vcpu *vcpu,
@@ -1171,7 +1187,9 @@ static bool access_id_reg(struct kvm_vcpu *vcpu,
                          struct sys_reg_params *p,
                          const struct sys_reg_desc *r)
 {
-       return __access_id_reg(vcpu, p, r, false);
+       bool raz = sysreg_visible_as_raz(vcpu, r);
+
+       return __access_id_reg(vcpu, p, r, raz);
 }
 
 static bool access_raz_id_reg(struct kvm_vcpu *vcpu,
@@ -1192,72 +1210,7 @@ static unsigned int sve_visibility(const struct kvm_vcpu *vcpu,
        if (vcpu_has_sve(vcpu))
                return 0;
 
-       return REG_HIDDEN_USER | REG_HIDDEN_GUEST;
-}
-
-/* Visibility overrides for SVE-specific ID registers */
-static unsigned int sve_id_visibility(const struct kvm_vcpu *vcpu,
-                                     const struct sys_reg_desc *rd)
-{
-       if (vcpu_has_sve(vcpu))
-               return 0;
-
-       return REG_HIDDEN_USER;
-}
-
-/* Generate the emulated ID_AA64ZFR0_EL1 value exposed to the guest */
-static u64 guest_id_aa64zfr0_el1(const struct kvm_vcpu *vcpu)
-{
-       if (!vcpu_has_sve(vcpu))
-               return 0;
-
-       return read_sanitised_ftr_reg(SYS_ID_AA64ZFR0_EL1);
-}
-
-static bool access_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
-                                  struct sys_reg_params *p,
-                                  const struct sys_reg_desc *rd)
-{
-       if (p->is_write)
-               return write_to_read_only(vcpu, p, rd);
-
-       p->regval = guest_id_aa64zfr0_el1(vcpu);
-       return true;
-}
-
-static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
-               const struct sys_reg_desc *rd,
-               const struct kvm_one_reg *reg, void __user *uaddr)
-{
-       u64 val;
-
-       if (WARN_ON(!vcpu_has_sve(vcpu)))
-               return -ENOENT;
-
-       val = guest_id_aa64zfr0_el1(vcpu);
-       return reg_to_user(uaddr, &val, reg->id);
-}
-
-static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
-               const struct sys_reg_desc *rd,
-               const struct kvm_one_reg *reg, void __user *uaddr)
-{
-       const u64 id = sys_reg_to_index(rd);
-       int err;
-       u64 val;
-
-       if (WARN_ON(!vcpu_has_sve(vcpu)))
-               return -ENOENT;
-
-       err = reg_from_user(&val, uaddr, id);
-       if (err)
-               return err;
-
-       /* This is what we mean by invariant: you can't change it. */
-       if (val != guest_id_aa64zfr0_el1(vcpu))
-               return -EINVAL;
-
-       return 0;
+       return REG_HIDDEN;
 }
 
 /*
@@ -1299,13 +1252,17 @@ static int __set_id_reg(const struct kvm_vcpu *vcpu,
 static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
                      const struct kvm_one_reg *reg, void __user *uaddr)
 {
-       return __get_id_reg(vcpu, rd, uaddr, false);
+       bool raz = sysreg_visible_as_raz(vcpu, rd);
+
+       return __get_id_reg(vcpu, rd, uaddr, raz);
 }
 
 static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
                      const struct kvm_one_reg *reg, void __user *uaddr)
 {
-       return __set_id_reg(vcpu, rd, uaddr, false);
+       bool raz = sysreg_visible_as_raz(vcpu, rd);
+
+       return __set_id_reg(vcpu, rd, uaddr, raz);
 }
 
 static int get_raz_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
@@ -1397,6 +1354,7 @@ static bool access_mte_regs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
        .access = access_id_reg,                \
        .get_user = get_id_reg,                 \
        .set_user = set_id_reg,                 \
+       .visibility = id_visibility,            \
 }
 
 /*
@@ -1518,7 +1476,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
        ID_SANITISED(ID_AA64PFR1_EL1),
        ID_UNALLOCATED(4,2),
        ID_UNALLOCATED(4,3),
-       { SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility },
+       ID_SANITISED(ID_AA64ZFR0_EL1),
        ID_UNALLOCATED(4,5),
        ID_UNALLOCATED(4,6),
        ID_UNALLOCATED(4,7),
@@ -1897,9 +1855,9 @@ static const struct sys_reg_desc cp14_regs[] = {
        { Op1( 0), CRn( 0), CRm( 1), Op2( 0), trap_raz_wi },
        DBG_BCR_BVR_WCR_WVR(1),
        /* DBGDCCINT */
-       { Op1( 0), CRn( 0), CRm( 2), Op2( 0), trap_debug32 },
+       { Op1( 0), CRn( 0), CRm( 2), Op2( 0), trap_debug32, NULL, cp14_DBGDCCINT },
        /* DBGDSCRext */
-       { Op1( 0), CRn( 0), CRm( 2), Op2( 2), trap_debug32 },
+       { Op1( 0), CRn( 0), CRm( 2), Op2( 2), trap_debug32, NULL, cp14_DBGDSCRext },
        DBG_BCR_BVR_WCR_WVR(2),
        /* DBGDTR[RT]Xint */
        { Op1( 0), CRn( 0), CRm( 3), Op2( 0), trap_raz_wi },
@@ -1914,7 +1872,7 @@ static const struct sys_reg_desc cp14_regs[] = {
        { Op1( 0), CRn( 0), CRm( 6), Op2( 2), trap_raz_wi },
        DBG_BCR_BVR_WCR_WVR(6),
        /* DBGVCR */
-       { Op1( 0), CRn( 0), CRm( 7), Op2( 0), trap_debug32 },
+       { Op1( 0), CRn( 0), CRm( 7), Op2( 0), trap_debug32, NULL, cp14_DBGVCR },
        DBG_BCR_BVR_WCR_WVR(7),
        DBG_BCR_BVR_WCR_WVR(8),
        DBG_BCR_BVR_WCR_WVR(9),
@@ -2185,7 +2143,7 @@ static void perform_access(struct kvm_vcpu *vcpu,
        trace_kvm_sys_access(*vcpu_pc(vcpu), params, r);
 
        /* Check for regs disabled by runtime config */
-       if (sysreg_hidden_from_guest(vcpu, r)) {
+       if (sysreg_hidden(vcpu, r)) {
                kvm_inject_undefined(vcpu);
                return;
        }
@@ -2684,7 +2642,7 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
                return get_invariant_sys_reg(reg->id, uaddr);
 
        /* Check for regs disabled by runtime config */
-       if (sysreg_hidden_from_user(vcpu, r))
+       if (sysreg_hidden(vcpu, r))
                return -ENOENT;
 
        if (r->get_user)
@@ -2709,7 +2667,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
                return set_invariant_sys_reg(reg->id, uaddr);
 
        /* Check for regs disabled by runtime config */
-       if (sysreg_hidden_from_user(vcpu, r))
+       if (sysreg_hidden(vcpu, r))
                return -ENOENT;
 
        if (r->set_user)
@@ -2780,7 +2738,7 @@ static int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
        if (!(rd->reg || rd->get_user))
                return 0;
 
-       if (sysreg_hidden_from_user(vcpu, rd))
+       if (sysreg_hidden(vcpu, rd))
                return 0;
 
        if (!copy_reg_to_user(rd, uind))
index 5a6fc30..0f95964 100644 (file)
@@ -59,8 +59,8 @@ struct sys_reg_desc {
                                   const struct sys_reg_desc *rd);
 };
 
-#define REG_HIDDEN_USER                (1 << 0) /* hidden from userspace ioctls */
-#define REG_HIDDEN_GUEST       (1 << 1) /* hidden from guest */
+#define REG_HIDDEN             (1 << 0) /* hidden from userspace and guest */
+#define REG_RAZ                        (1 << 1) /* RAZ from userspace and guest */
 
 static __printf(2, 3)
 inline void print_sys_reg_msg(const struct sys_reg_params *p,
@@ -111,22 +111,22 @@ static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r
        __vcpu_sys_reg(vcpu, r->reg) = r->val;
 }
 
-static inline bool sysreg_hidden_from_guest(const struct kvm_vcpu *vcpu,
-                                           const struct sys_reg_desc *r)
+static inline bool sysreg_hidden(const struct kvm_vcpu *vcpu,
+                                const struct sys_reg_desc *r)
 {
        if (likely(!r->visibility))
                return false;
 
-       return r->visibility(vcpu, r) & REG_HIDDEN_GUEST;
+       return r->visibility(vcpu, r) & REG_HIDDEN;
 }
 
-static inline bool sysreg_hidden_from_user(const struct kvm_vcpu *vcpu,
-                                          const struct sys_reg_desc *r)
+static inline bool sysreg_visible_as_raz(const struct kvm_vcpu *vcpu,
+                                        const struct sys_reg_desc *r)
 {
        if (likely(!r->visibility))
                return false;
 
-       return r->visibility(vcpu, r) & REG_HIDDEN_USER;
+       return r->visibility(vcpu, r) & REG_RAZ;
 }
 
 static inline int cmp_sys_reg(const struct sys_reg_desc *i1,