@@ -67,6 +67,7 @@ extern bool __forward_traps(struct kvm_vcpu *vcpu, unsigned int reg,
u64 control_bit);
extern bool forward_traps(struct kvm_vcpu *vcpu, u64 control_bit);
extern bool forward_nv_traps(struct kvm_vcpu *vcpu);
+unsigned int ttl_to_size(u8 ttl);
struct sys_reg_params;
struct sys_reg_desc;
@@ -351,6 +351,62 @@ int kvm_walk_nested_s2(struct kvm_vcpu *vcpu, phys_addr_t gipa,
return ret;
}
+
+unsigned int ttl_to_size(u8 ttl)
+{
+ int level = ttl & 3;
+ unsigned int max_size = 0;
+
+ switch (ttl >> 2) {
+ case 0: /* No size information */
+ break;
+ case 1: /* 4kB translation granule */
+ switch (level) {
+ case 0:
+ break;
+ case 1:
+ max_size = SZ_1G;
+ break;
+ case 2:
+ max_size = SZ_2M;
+ break;
+ case 3:
+ max_size = SZ_4K;
+ break;
+ }
+ break;
+ case 2: /* 16kB translation granule */
+ switch (level) {
+ case 0:
+ case 1:
+ break;
+ case 2:
+ max_size = SZ_32M;
+ break;
+ case 3:
+ max_size = SZ_16K;
+ break;
+ }
+ break;
+ case 3: /* 64kB translation granule */
+ switch (level) {
+ case 0:
+ case 1:
+ /* No 52bit IPA support */
+ break;
+ case 2:
+ max_size = SZ_512M;
+ break;
+ case 3:
+ max_size = SZ_64K;
+ break;
+ }
+ break;
+ }
+
+ return max_size;
+}
+
/* Must be called with kvm->lock held */
struct kvm_s2_mmu *lookup_s2_mmu(struct kvm *kvm, u64 vttbr, u64 hcr)
{
@@ -9,6 +9,7 @@
* Christoffer Dall <c.dall@virtualopensystems.com>
*/
+#include <linux/bitfield.h>
#include <linux/bsearch.h>
#include <linux/kvm_host.h>
#include <linux/mm.h>
@@ -2583,59 +2584,81 @@ static bool handle_vmalls12e1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
return true;
}
+static unsigned long compute_tlb_inval_range(struct kvm_vcpu *vcpu,
+ struct kvm_s2_mmu *mmu,
+ u64 val)
+{
+ unsigned long max_size;
+ u8 ttl = 0;
+
+ if (cpus_have_const_cap(ARM64_HAS_ARMv8_4_TTL)) {
+ ttl = FIELD_GET(GENMASK_ULL(47, 44), val);
+ }
+
+ max_size = ttl_to_size(ttl);
+
+ if (!max_size) {
+ u64 vtcr = vcpu_read_sys_reg(vcpu, VTCR_EL2);
+
+ /* Compute the maximum extent of the invalidation */
+ switch ((vtcr & VTCR_EL2_TG0_MASK)) {
+ case VTCR_EL2_TG0_4K:
+ max_size = SZ_1G;
+ break;
+ case VTCR_EL2_TG0_16K:
+ max_size = SZ_32M;
+ break;
+ case VTCR_EL2_TG0_64K:
+ /*
+ * No, we do not support 52bit IPA in nested yet. Once
+ * we do, this should be 4TB.
+ */
+ /* FIXME: remove the 52bit PA support from the IDregs */
+ max_size = SZ_512M;
+ break;
+ default:
+ BUG();
+ }
+ }
+
+ WARN_ON(!max_size);
+ return max_size;
+}
+
static bool handle_ipas2e1is(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
u64 vttbr = vcpu_read_sys_reg(vcpu, VTTBR_EL2);
- u64 vtcr = vcpu_read_sys_reg(vcpu, VTCR_EL2);
struct kvm_s2_mmu *mmu;
u64 base_addr;
- int max_size;
+ unsigned long max_size;
/*
* We drop a number of things from the supplied value:
*
* - NS bit: we're non-secure only.
*
- * - TTL field: We already have the granule size from the
- * VTCR_EL2.TG0 field, and the level is only relevant to the
- * guest's S2PT.
- *
* - IPA[51:48]: We don't support 52bit IPA just yet...
*
* And of course, adjust the IPA to be on an actual address.
*/
base_addr = (p->regval & GENMASK_ULL(35, 0)) << 12;
- /* Compute the maximum extent of the invalidation */
- switch ((vtcr & VTCR_EL2_TG0_MASK)) {
- case VTCR_EL2_TG0_4K:
- max_size = SZ_1G;
- break;
- case VTCR_EL2_TG0_16K:
- max_size = SZ_32M;
- break;
- case VTCR_EL2_TG0_64K:
- /*
- * No, we do not support 52bit IPA in nested yet. Once
- * we do, this should be 4TB.
- */
- /* FIXME: remove the 52bit PA support from the IDregs */
- max_size = SZ_512M;
- break;
- default:
- BUG();
- }
-
spin_lock(&vcpu->kvm->mmu_lock);
mmu = lookup_s2_mmu(vcpu->kvm, vttbr, HCR_VM);
- if (mmu)
+ if (mmu) {
+ max_size = compute_tlb_inval_range(vcpu, mmu, p->regval);
+ base_addr &= ~(max_size - 1);
kvm_unmap_stage2_range(mmu, base_addr, max_size);
+ }
mmu = lookup_s2_mmu(vcpu->kvm, vttbr, 0);
- if (mmu)
+ if (mmu) {
+ max_size = compute_tlb_inval_range(vcpu, mmu, p->regval);
+ base_addr &= ~(max_size - 1);
kvm_unmap_stage2_range(mmu, base_addr, max_size);
+ }
spin_unlock(&vcpu->kvm->mmu_lock);
Support guest-provided information information to find out about the range of required invalidation. Signed-off-by: Marc Zyngier <maz@kernel.org> --- arch/arm64/include/asm/kvm_nested.h | 1 + arch/arm64/kvm/nested.c | 56 ++++++++++++++++++++ arch/arm64/kvm/sys_regs.c | 79 +++++++++++++++++++---------- 3 files changed, 108 insertions(+), 28 deletions(-)