Merge tag 'kvmarm-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm...
authorPaolo Bonzini <pbonzini@redhat.com>
Sun, 9 Aug 2020 16:58:23 +0000 (12:58 -0400)
committerPaolo Bonzini <pbonzini@redhat.com>
Sun, 9 Aug 2020 16:58:23 +0000 (12:58 -0400)
KVM/arm64 updates for Linux 5.9:

- Split the VHE and nVHE hypervisor code bases, build the EL2 code
  separately, allowing for the VHE code to now be built with instrumentation

- Level-based TLB invalidation support

- Restructure of the vcpu register storage to accomodate the NV code

- Pointer Authentication available for guests on nVHE hosts

- Simplification of the system register table parsing

- MMU cleanups and fixes

- A number of post-32bit cleanups and other fixes

12 files changed:
1  2 
arch/arm64/Kconfig
arch/arm64/include/asm/kvm_coproc.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/kernel/cpu_errata.c
arch/arm64/kvm/arm.c
arch/arm64/kvm/handle_exit.c
arch/arm64/kvm/hyp/nvhe/hyp-init.S
arch/arm64/kvm/mmio.c
arch/arm64/kvm/mmu.c
arch/arm64/kvm/reset.c
arch/arm64/kvm/sys_regs.c

Simple merge
@@@ -19,20 -19,12 +19,12 @@@ struct kvm_sys_reg_table 
        size_t num;
  };
  
- struct kvm_sys_reg_target_table {
-       struct kvm_sys_reg_table table64;
-       struct kvm_sys_reg_table table32;
- };
- void kvm_register_target_sys_reg_table(unsigned int target,
-                                      struct kvm_sys_reg_target_table *table);
 -int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run);
 -int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
 -int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
 -int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run);
 -int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run);
 -int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run);
 +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);
  
  #define kvm_coproc_table_init kvm_sys_reg_table_init
  void kvm_sys_reg_table_init(void);
@@@ -369,24 -416,24 +405,29 @@@ struct kvm_vcpu_arch 
  #define vcpu_has_sve(vcpu) (system_supports_sve() && \
                            ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_SVE))
  
 -#define vcpu_has_ptrauth(vcpu)        ((system_supports_address_auth() || \
 -                                system_supports_generic_auth()) && \
 -                               ((vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_PTRAUTH))
 +#ifdef CONFIG_ARM64_PTR_AUTH
 +#define vcpu_has_ptrauth(vcpu)                                                \
 +      ((cpus_have_final_cap(ARM64_HAS_ADDRESS_AUTH) ||                \
 +        cpus_have_final_cap(ARM64_HAS_GENERIC_AUTH)) &&               \
 +       (vcpu)->arch.flags & KVM_ARM64_GUEST_HAS_PTRAUTH)
 +#else
 +#define vcpu_has_ptrauth(vcpu)                false
 +#endif
  
- #define vcpu_gp_regs(v)               (&(v)->arch.ctxt.gp_regs)
+ #define vcpu_gp_regs(v)               (&(v)->arch.ctxt.regs)
  
  /*
-  * Only use __vcpu_sys_reg if you know you want the memory backed version of a
-  * register, and not the one most recently accessed by a running VCPU.  For
-  * example, for userspace access or for system registers that are never context
-  * switched, but only emulated.
+  * Only use __vcpu_sys_reg/ctxt_sys_reg if you know you want the
+  * memory backed version of a register, and not the one most recently
+  * accessed by a running VCPU.  For example, for userspace access or
+  * for system registers that are never context switched, but only
+  * emulated.
   */
- #define __vcpu_sys_reg(v,r)   ((v)->arch.ctxt.sys_regs[(r)])
+ #define __ctxt_sys_reg(c,r)   (&(c)->sys_regs[(r)])
+ #define ctxt_sys_reg(c,r)     (*__ctxt_sys_reg(c,r))
+ #define __vcpu_sys_reg(v,r)   (ctxt_sys_reg(&(v)->arch.ctxt, (r)))
  
  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);
Simple merge
Simple merge
Simple merge
@@@ -87,9 -87,9 +87,9 @@@ static int handle_no_fpsimd(struct kvm_
   * world-switches and schedule other host processes until there is an
   * incoming IRQ or FIQ to the VM.
   */
 -static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run)
 +static int kvm_handle_wfx(struct kvm_vcpu *vcpu)
  {
-       if (kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WFx_ISS_WFE) {
+       if (kvm_vcpu_get_esr(vcpu) & ESR_ELx_WFx_ISS_WFE) {
                trace_kvm_wfx_arm64(*vcpu_pc(vcpu), true);
                vcpu->stat.wfe_exit_stat++;
                kvm_vcpu_on_spin(vcpu, vcpu_mode_priv(vcpu));
   * guest and host are using the same debug facilities it will be up to
   * userspace to re-inject the correct exception for guest delivery.
   *
 - * @return: 0 (while setting run->exit_reason), -1 for error
 + * @return: 0 (while setting vcpu->run->exit_reason), -1 for error
   */
 -static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu, struct kvm_run *run)
 +static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu)
  {
-       u32 hsr = kvm_vcpu_get_hsr(vcpu);
 +      struct kvm_run *run = vcpu->run;
+       u32 esr = kvm_vcpu_get_esr(vcpu);
        int ret = 0;
  
        run->exit_reason = KVM_EXIT_DEBUG;
        return ret;
  }
  
 -static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu, struct kvm_run *run)
 +static int kvm_handle_unknown_ec(struct kvm_vcpu *vcpu)
  {
-       u32 hsr = kvm_vcpu_get_hsr(vcpu);
+       u32 esr = kvm_vcpu_get_esr(vcpu);
  
-       kvm_pr_unimpl("Unknown exception class: hsr: %#08x -- %s\n",
-                     hsr, esr_get_class_string(hsr));
+       kvm_pr_unimpl("Unknown exception class: esr: %#08x -- %s\n",
+                     esr, esr_get_class_string(esr));
  
        kvm_inject_undefined(vcpu);
        return 1;
@@@ -237,12 -237,11 +237,12 @@@ static int handle_trap_exceptions(struc
   * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on
   * proper exit to userspace.
   */
 -int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
 -                     int exception_index)
 +int handle_exit(struct kvm_vcpu *vcpu, int exception_index)
  {
 +      struct kvm_run *run = vcpu->run;
 +
        if (ARM_SERROR_PENDING(exception_index)) {
-               u8 hsr_ec = ESR_ELx_EC(kvm_vcpu_get_hsr(vcpu));
+               u8 esr_ec = ESR_ELx_EC(kvm_vcpu_get_esr(vcpu));
  
                /*
                 * HVC/SMC already have an adjusted PC, which we need
index 0000000,1587d14..d9434e9
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,168 +1,172 @@@
 -reset:
+ /* SPDX-License-Identifier: GPL-2.0-only */
+ /*
+  * Copyright (C) 2012,2013 - ARM Ltd
+  * Author: Marc Zyngier <marc.zyngier@arm.com>
+  */
+ #include <linux/linkage.h>
++#include <asm/alternative.h>
+ #include <asm/assembler.h>
+ #include <asm/kvm_arm.h>
+ #include <asm/kvm_mmu.h>
+ #include <asm/pgtable-hwdef.h>
+ #include <asm/sysreg.h>
+ #include <asm/virt.h>
+       .text
+       .pushsection    .hyp.idmap.text, "ax"
+       .align  11
+ SYM_CODE_START(__kvm_hyp_init)
+       ventry  __invalid               // Synchronous EL2t
+       ventry  __invalid               // IRQ EL2t
+       ventry  __invalid               // FIQ EL2t
+       ventry  __invalid               // Error EL2t
+       ventry  __invalid               // Synchronous EL2h
+       ventry  __invalid               // IRQ EL2h
+       ventry  __invalid               // FIQ EL2h
+       ventry  __invalid               // Error EL2h
+       ventry  __do_hyp_init           // Synchronous 64-bit EL1
+       ventry  __invalid               // IRQ 64-bit EL1
+       ventry  __invalid               // FIQ 64-bit EL1
+       ventry  __invalid               // Error 64-bit EL1
+       ventry  __invalid               // Synchronous 32-bit EL1
+       ventry  __invalid               // IRQ 32-bit EL1
+       ventry  __invalid               // FIQ 32-bit EL1
+       ventry  __invalid               // Error 32-bit EL1
+ __invalid:
+       b       .
+       /*
+        * x0: HYP pgd
+        * x1: HYP stack
+        * x2: HYP vectors
+        * x3: per-CPU offset
+        */
+ __do_hyp_init:
+       /* Check for a stub HVC call */
+       cmp     x0, #HVC_STUB_HCALL_NR
+       b.lo    __kvm_handle_stub_hvc
+       phys_to_ttbr x4, x0
+ alternative_if ARM64_HAS_CNP
+       orr     x4, x4, #TTBR_CNP_BIT
+ alternative_else_nop_endif
+       msr     ttbr0_el2, x4
+       mrs     x4, tcr_el1
+       mov_q   x5, TCR_EL2_MASK
+       and     x4, x4, x5
+       mov     x5, #TCR_EL2_RES1
+       orr     x4, x4, x5
+       /*
+        * 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.
+        */
+       ldr_l   x5, idmap_t0sz
+       bfi     x4, x5, TCR_T0SZ_OFFSET, TCR_TxSZ_WIDTH
+       /*
+        * Set the PS bits in TCR_EL2.
+        */
+       tcr_compute_pa_size x4, #TCR_EL2_PS_SHIFT, x5, x6
+       msr     tcr_el2, x4
+       mrs     x4, mair_el1
+       msr     mair_el2, x4
+       isb
+       /* Invalidate the stale TLBs from Bootloader */
+       tlbi    alle2
+       dsb     sy
+       /*
+        * Preserve all the RES1 bits while setting the default flags,
+        * as well as the EE bit on BE. Drop the A flag since the compiler
+        * is allowed to generate unaligned accesses.
+        */
+       mov_q   x4, (SCTLR_EL2_RES1 | (SCTLR_ELx_FLAGS & ~SCTLR_ELx_A))
+ CPU_BE(       orr     x4, x4, #SCTLR_ELx_EE)
+ alternative_if ARM64_HAS_ADDRESS_AUTH
+       mov_q   x5, (SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | \
+                    SCTLR_ELx_ENDA | SCTLR_ELx_ENDB)
+       orr     x4, x4, x5
+ alternative_else_nop_endif
+       msr     sctlr_el2, x4
+       isb
+       /* Set the stack and new vectors */
+       kern_hyp_va     x1
+       mov     sp, x1
+       msr     vbar_el2, x2
+       /* Set tpidr_el2 for use by HYP */
+       msr     tpidr_el2, x3
+       /* Hello, World! */
+       eret
+ SYM_CODE_END(__kvm_hyp_init)
+ SYM_CODE_START(__kvm_handle_stub_hvc)
+       cmp     x0, #HVC_SOFT_RESTART
+       b.ne    1f
+       /* This is where we're about to jump, staying at EL2 */
+       msr     elr_el2, x1
+       mov     x0, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT | PSR_MODE_EL2h)
+       msr     spsr_el2, x0
+       /* Shuffle the arguments, and don't come back */
+       mov     x0, x2
+       mov     x1, x3
+       mov     x2, x4
+       b       reset
+ 1:    cmp     x0, #HVC_RESET_VECTORS
+       b.ne    1f
 -       * Reset kvm back to the hyp stub. Do not clobber x0-x4 in
 -       * case we coming via HVC_SOFT_RESTART.
++
+       /*
 -      mov     x0, xzr
++       * Set the HVC_RESET_VECTORS return code before entering the common
++       * path so that we do not clobber x0-x2 in case we are coming via
++       * HVC_SOFT_RESTART.
+        */
++      mov     x0, xzr
++reset:
++      /* Reset kvm back to the hyp stub. */
+       mrs     x5, sctlr_el2
+       mov_q   x6, SCTLR_ELx_FLAGS
+       bic     x5, x5, x6              // Clear SCTL_M and etc
+       pre_disable_mmu_workaround
+       msr     sctlr_el2, x5
+       isb
+       /* Install stub vectors */
+       adr_l   x5, __hyp_stub_vectors
+       msr     vbar_el2, x5
+       eret
+ 1:    /* Bad stub call */
+       mov_q   x0, HVC_STUB_ERR
+       eret
+ SYM_CODE_END(__kvm_handle_stub_hvc)
+       .popsection
Simple merge
@@@ -124,11 -127,44 +127,12 @@@ static void stage2_dissolve_pud(struct 
        put_page(virt_to_page(pudp));
  }
  
- static void clear_stage2_pgd_entry(struct kvm *kvm, pgd_t *pgd, phys_addr_t addr)
 -static int mmu_topup_memory_cache(struct kvm_mmu_memory_cache *cache,
 -                                int min, int max)
 -{
 -      void *page;
 -
 -      BUG_ON(max > KVM_NR_MEM_OBJS);
 -      if (cache->nobjs >= min)
 -              return 0;
 -      while (cache->nobjs < max) {
 -              page = (void *)__get_free_page(GFP_PGTABLE_USER);
 -              if (!page)
 -                      return -ENOMEM;
 -              cache->objects[cache->nobjs++] = page;
 -      }
 -      return 0;
 -}
 -
 -static void mmu_free_memory_cache(struct kvm_mmu_memory_cache *mc)
 -{
 -      while (mc->nobjs)
 -              free_page((unsigned long)mc->objects[--mc->nobjs]);
 -}
 -
 -static void *mmu_memory_cache_alloc(struct kvm_mmu_memory_cache *mc)
 -{
 -      void *p;
 -
 -      BUG_ON(!mc || !mc->nobjs);
 -      p = mc->objects[--mc->nobjs];
 -      return p;
 -}
 -
+ static void clear_stage2_pgd_entry(struct kvm_s2_mmu *mmu, pgd_t *pgd, phys_addr_t addr)
  {
+       struct kvm *kvm = mmu->kvm;
        p4d_t *p4d_table __maybe_unused = stage2_p4d_offset(kvm, pgd, 0UL);
        stage2_pgd_clear(kvm, pgd);
-       kvm_tlb_flush_vmid_ipa(kvm, addr);
+       kvm_tlb_flush_vmid_ipa(mmu, addr, S2_NO_LEVEL_HINT);
        stage2_p4d_free(kvm, p4d_table);
        put_page(virt_to_page(pgd));
  }
@@@ -1294,7 -1356,7 +1324,7 @@@ static bool stage2_get_leaf_entry(struc
        return true;
  }
  
- static bool stage2_is_exec(struct kvm *kvm, phys_addr_t addr, unsigned long sz)
 -static bool stage2_is_exec(struct kvm_s2_mmu *mmu, phys_addr_t addr)
++static bool stage2_is_exec(struct kvm_s2_mmu *mmu, phys_addr_t addr, unsigned long sz)
  {
        pud_t *pudp;
        pmd_t *pmdp;
                return false;
  
        if (pudp)
 -              return kvm_s2pud_exec(pudp);
 +              return sz <= PUD_SIZE && kvm_s2pud_exec(pudp);
        else if (pmdp)
 -              return kvm_s2pmd_exec(pmdp);
 +              return sz <= PMD_SIZE && kvm_s2pmd_exec(pmdp);
        else
 -              return kvm_s2pte_exec(ptep);
 +              return sz == PAGE_SIZE && kvm_s2pte_exec(ptep);
  }
  
- static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
+ static int stage2_set_pte(struct kvm_s2_mmu *mmu,
+                         struct kvm_mmu_memory_cache *cache,
                          phys_addr_t addr, const pte_t *new_pte,
                          unsigned long flags)
  {
@@@ -1924,8 -1995,7 +1961,8 @@@ static int user_mem_abort(struct kvm_vc
         * execute permissions, and we preserve whatever we have.
         */
        needs_exec = exec_fault ||
 -              (fault_status == FSC_PERM && stage2_is_exec(mmu, fault_ipa));
 +              (fault_status == FSC_PERM &&
-                stage2_is_exec(kvm, fault_ipa, vma_pagesize));
++               stage2_is_exec(mmu, fault_ipa, vma_pagesize));
  
        if (vma_pagesize == PUD_SIZE) {
                pud_t new_pud = kvm_pfn_pud(pfn, mem_type);
Simple merge
@@@ -2335,40 -2327,24 +2327,24 @@@ static int kvm_handle_cp_32(struct kvm_
        return 1;
  }
  
 -int kvm_handle_cp15_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
 +int kvm_handle_cp15_64(struct kvm_vcpu *vcpu)
  {
-       const struct sys_reg_desc *target_specific;
-       size_t num;
-       target_specific = get_target_table(vcpu->arch.target, false, &num);
-       return kvm_handle_cp_64(vcpu,
-                               cp15_64_regs, ARRAY_SIZE(cp15_64_regs),
-                               target_specific, num);
+       return kvm_handle_cp_64(vcpu, cp15_64_regs, ARRAY_SIZE(cp15_64_regs));
  }
  
 -int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
 +int kvm_handle_cp15_32(struct kvm_vcpu *vcpu)
  {
-       const struct sys_reg_desc *target_specific;
-       size_t num;
-       target_specific = get_target_table(vcpu->arch.target, false, &num);
-       return kvm_handle_cp_32(vcpu,
-                               cp15_regs, ARRAY_SIZE(cp15_regs),
-                               target_specific, num);
+       return kvm_handle_cp_32(vcpu, cp15_regs, ARRAY_SIZE(cp15_regs));
  }
  
 -int kvm_handle_cp14_64(struct kvm_vcpu *vcpu, struct kvm_run *run)
 +int kvm_handle_cp14_64(struct kvm_vcpu *vcpu)
  {
-       return kvm_handle_cp_64(vcpu,
-                               cp14_64_regs, ARRAY_SIZE(cp14_64_regs),
-                               NULL, 0);
+       return kvm_handle_cp_64(vcpu, cp14_64_regs, ARRAY_SIZE(cp14_64_regs));
  }
  
 -int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
 +int kvm_handle_cp14_32(struct kvm_vcpu *vcpu)
  {
-       return kvm_handle_cp_32(vcpu,
-                               cp14_regs, ARRAY_SIZE(cp14_regs),
-                               NULL, 0);
+       return kvm_handle_cp_32(vcpu, cp14_regs, ARRAY_SIZE(cp14_regs));
  }
  
  static bool is_imp_def_sys_reg(struct sys_reg_params *params)
@@@ -2416,11 -2392,12 +2392,11 @@@ void kvm_reset_sys_regs(struct kvm_vcp
  /**
   * kvm_handle_sys_reg -- handles a mrs/msr trap on a guest sys_reg access
   * @vcpu: The VCPU pointer
 - * @run:  The kvm_run struct
   */
 -int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run)
 +int kvm_handle_sys_reg(struct kvm_vcpu *vcpu)
  {
        struct sys_reg_params params;
-       unsigned long esr = kvm_vcpu_get_hsr(vcpu);
+       unsigned long esr = kvm_vcpu_get_esr(vcpu);
        int Rt = kvm_vcpu_sys_get_rt(vcpu);
        int ret;