linux/arch/arm64/kvm/hyp/nvhe/tlb.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2015 - ARM Ltd
   4 * Author: Marc Zyngier <marc.zyngier@arm.com>
   5 */
   6
   7#include <asm/kvm_hyp.h>
   8#include <asm/kvm_mmu.h>
   9#include <asm/tlbflush.h>
  10
  11#include <nvhe/mem_protect.h>
  12
  13struct tlb_inv_context {
  14        u64             tcr;
  15};
  16
  17static void __tlb_switch_to_guest(struct kvm_s2_mmu *mmu,
  18                                  struct tlb_inv_context *cxt)
  19{
  20        if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT)) {
  21                u64 val;
  22
  23                /*
  24                 * For CPUs that are affected by ARM 1319367, we need to
  25                 * avoid a host Stage-1 walk while we have the guest's
  26                 * VMID set in the VTTBR in order to invalidate TLBs.
  27                 * We're guaranteed that the S1 MMU is enabled, so we can
  28                 * simply set the EPD bits to avoid any further TLB fill.
  29                 */
  30                val = cxt->tcr = read_sysreg_el1(SYS_TCR);
  31                val |= TCR_EPD1_MASK | TCR_EPD0_MASK;
  32                write_sysreg_el1(val, SYS_TCR);
  33                isb();
  34        }
  35
  36        /*
  37         * __load_stage2() includes an ISB only when the AT
  38         * workaround is applied. Take care of the opposite condition,
  39         * ensuring that we always have an ISB, but not two ISBs back
  40         * to back.
  41         */
  42        __load_stage2(mmu, kern_hyp_va(mmu->arch));
  43        asm(ALTERNATIVE("isb", "nop", ARM64_WORKAROUND_SPECULATIVE_AT));
  44}
  45
  46static void __tlb_switch_to_host(struct tlb_inv_context *cxt)
  47{
  48        __load_host_stage2();
  49
  50        if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT)) {
  51                /* Ensure write of the host VMID */
  52                isb();
  53                /* Restore the host's TCR_EL1 */
  54                write_sysreg_el1(cxt->tcr, SYS_TCR);
  55        }
  56}
  57
  58void __kvm_tlb_flush_vmid_ipa(struct kvm_s2_mmu *mmu,
  59                              phys_addr_t ipa, int level)
  60{
  61        struct tlb_inv_context cxt;
  62
  63        dsb(ishst);
  64
  65        /* Switch to requested VMID */
  66        __tlb_switch_to_guest(mmu, &cxt);
  67
  68        /*
  69         * We could do so much better if we had the VA as well.
  70         * Instead, we invalidate Stage-2 for this IPA, and the
  71         * whole of Stage-1. Weep...
  72         */
  73        ipa >>= 12;
  74        __tlbi_level(ipas2e1is, ipa, level);
  75
  76        /*
  77         * We have to ensure completion of the invalidation at Stage-2,
  78         * since a table walk on another CPU could refill a TLB with a
  79         * complete (S1 + S2) walk based on the old Stage-2 mapping if
  80         * the Stage-1 invalidation happened first.
  81         */
  82        dsb(ish);
  83        __tlbi(vmalle1is);
  84        dsb(ish);
  85        isb();
  86
  87        /*
  88         * If the host is running at EL1 and we have a VPIPT I-cache,
  89         * then we must perform I-cache maintenance at EL2 in order for
  90         * it to have an effect on the guest. Since the guest cannot hit
  91         * I-cache lines allocated with a different VMID, we don't need
  92         * to worry about junk out of guest reset (we nuke the I-cache on
  93         * VMID rollover), but we do need to be careful when remapping
  94         * executable pages for the same guest. This can happen when KSM
  95         * takes a CoW fault on an executable page, copies the page into
  96         * a page that was previously mapped in the guest and then needs
  97         * to invalidate the guest view of the I-cache for that page
  98         * from EL1. To solve this, we invalidate the entire I-cache when
  99         * unmapping a page from a guest if we have a VPIPT I-cache but
 100         * the host is running at EL1. As above, we could do better if
 101         * we had the VA.
 102         *
 103         * The moral of this story is: if you have a VPIPT I-cache, then
 104         * you should be running with VHE enabled.
 105         */
 106        if (icache_is_vpipt())
 107                icache_inval_all_pou();
 108
 109        __tlb_switch_to_host(&cxt);
 110}
 111
 112void __kvm_tlb_flush_vmid(struct kvm_s2_mmu *mmu)
 113{
 114        struct tlb_inv_context cxt;
 115
 116        dsb(ishst);
 117
 118        /* Switch to requested VMID */
 119        __tlb_switch_to_guest(mmu, &cxt);
 120
 121        __tlbi(vmalls12e1is);
 122        dsb(ish);
 123        isb();
 124
 125        __tlb_switch_to_host(&cxt);
 126}
 127
 128void __kvm_flush_cpu_context(struct kvm_s2_mmu *mmu)
 129{
 130        struct tlb_inv_context cxt;
 131
 132        /* Switch to requested VMID */
 133        __tlb_switch_to_guest(mmu, &cxt);
 134
 135        __tlbi(vmalle1);
 136        asm volatile("ic iallu");
 137        dsb(nsh);
 138        isb();
 139
 140        __tlb_switch_to_host(&cxt);
 141}
 142
 143void __kvm_flush_vm_context(void)
 144{
 145        dsb(ishst);
 146        __tlbi(alle1is);
 147
 148        /*
 149         * VIPT and PIPT caches are not affected by VMID, so no maintenance
 150         * is necessary across a VMID rollover.
 151         *
 152         * VPIPT caches constrain lookup and maintenance to the active VMID,
 153         * so we need to invalidate lines with a stale VMID to avoid an ABA
 154         * race after multiple rollovers.
 155         *
 156         */
 157        if (icache_is_vpipt())
 158                asm volatile("ic ialluis");
 159
 160        dsb(ish);
 161}
 162