|
|
|
@@ -47,6 +47,7 @@ void kvm_init_nested(struct kvm *kvm)
|
|
|
|
|
{
|
|
|
|
|
kvm->arch.nested_mmus = NULL;
|
|
|
|
|
kvm->arch.nested_mmus_size = 0;
|
|
|
|
|
atomic_set(&kvm->arch.vncr_map_count, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int init_nested_s2_mmu(struct kvm *kvm, struct kvm_s2_mmu *mmu)
|
|
|
|
@@ -756,6 +757,7 @@ void kvm_vcpu_put_hw_mmu(struct kvm_vcpu *vcpu)
|
|
|
|
|
clear_fixmap(vncr_fixmap(vcpu->arch.vncr_tlb->cpu));
|
|
|
|
|
vcpu->arch.vncr_tlb->cpu = -1;
|
|
|
|
|
host_data_clear_flag(L1_VNCR_MAPPED);
|
|
|
|
|
atomic_dec(&vcpu->kvm->arch.vncr_map_count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@@ -855,6 +857,196 @@ static void kvm_invalidate_vncr_ipa(struct kvm *kvm, u64 start, u64 end)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct s1e2_tlbi_scope {
|
|
|
|
|
enum {
|
|
|
|
|
TLBI_ALL,
|
|
|
|
|
TLBI_VA,
|
|
|
|
|
TLBI_VAA,
|
|
|
|
|
TLBI_ASID,
|
|
|
|
|
} type;
|
|
|
|
|
|
|
|
|
|
u16 asid;
|
|
|
|
|
u64 va;
|
|
|
|
|
u64 size;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void invalidate_vncr_va(struct kvm *kvm,
|
|
|
|
|
struct s1e2_tlbi_scope *scope)
|
|
|
|
|
{
|
|
|
|
|
struct kvm_vcpu *vcpu;
|
|
|
|
|
unsigned long i;
|
|
|
|
|
|
|
|
|
|
lockdep_assert_held_write(&kvm->mmu_lock);
|
|
|
|
|
|
|
|
|
|
kvm_for_each_vcpu(i, vcpu, kvm) {
|
|
|
|
|
struct vncr_tlb *vt = vcpu->arch.vncr_tlb;
|
|
|
|
|
u64 va_start, va_end, va_size;
|
|
|
|
|
|
|
|
|
|
if (!vt->valid)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
va_size = ttl_to_size(pgshift_level_to_ttl(vt->wi.pgshift,
|
|
|
|
|
vt->wr.level));
|
|
|
|
|
va_start = vt->gva & (va_size - 1);
|
|
|
|
|
va_end = va_start + va_size;
|
|
|
|
|
|
|
|
|
|
switch (scope->type) {
|
|
|
|
|
case TLBI_ALL:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TLBI_VA:
|
|
|
|
|
if (va_end <= scope->va ||
|
|
|
|
|
va_start >= (scope->va + scope->size))
|
|
|
|
|
continue;
|
|
|
|
|
if (vt->wr.nG && vt->wr.asid != scope->asid)
|
|
|
|
|
continue;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TLBI_VAA:
|
|
|
|
|
if (va_end <= scope->va ||
|
|
|
|
|
va_start >= (scope->va + scope->size))
|
|
|
|
|
continue;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TLBI_ASID:
|
|
|
|
|
if (!vt->wr.nG || vt->wr.asid != scope->asid)
|
|
|
|
|
continue;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
invalidate_vncr(vt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void compute_s1_tlbi_range(struct kvm_vcpu *vcpu, u32 inst, u64 val,
|
|
|
|
|
struct s1e2_tlbi_scope *scope)
|
|
|
|
|
{
|
|
|
|
|
switch (inst) {
|
|
|
|
|
case OP_TLBI_ALLE2:
|
|
|
|
|
case OP_TLBI_ALLE2IS:
|
|
|
|
|
case OP_TLBI_ALLE2OS:
|
|
|
|
|
case OP_TLBI_VMALLE1:
|
|
|
|
|
case OP_TLBI_VMALLE1IS:
|
|
|
|
|
case OP_TLBI_VMALLE1OS:
|
|
|
|
|
case OP_TLBI_ALLE2NXS:
|
|
|
|
|
case OP_TLBI_ALLE2ISNXS:
|
|
|
|
|
case OP_TLBI_ALLE2OSNXS:
|
|
|
|
|
case OP_TLBI_VMALLE1NXS:
|
|
|
|
|
case OP_TLBI_VMALLE1ISNXS:
|
|
|
|
|
case OP_TLBI_VMALLE1OSNXS:
|
|
|
|
|
scope->type = TLBI_ALL;
|
|
|
|
|
break;
|
|
|
|
|
case OP_TLBI_VAE2:
|
|
|
|
|
case OP_TLBI_VAE2IS:
|
|
|
|
|
case OP_TLBI_VAE2OS:
|
|
|
|
|
case OP_TLBI_VAE1:
|
|
|
|
|
case OP_TLBI_VAE1IS:
|
|
|
|
|
case OP_TLBI_VAE1OS:
|
|
|
|
|
case OP_TLBI_VAE2NXS:
|
|
|
|
|
case OP_TLBI_VAE2ISNXS:
|
|
|
|
|
case OP_TLBI_VAE2OSNXS:
|
|
|
|
|
case OP_TLBI_VAE1NXS:
|
|
|
|
|
case OP_TLBI_VAE1ISNXS:
|
|
|
|
|
case OP_TLBI_VAE1OSNXS:
|
|
|
|
|
case OP_TLBI_VALE2:
|
|
|
|
|
case OP_TLBI_VALE2IS:
|
|
|
|
|
case OP_TLBI_VALE2OS:
|
|
|
|
|
case OP_TLBI_VALE1:
|
|
|
|
|
case OP_TLBI_VALE1IS:
|
|
|
|
|
case OP_TLBI_VALE1OS:
|
|
|
|
|
case OP_TLBI_VALE2NXS:
|
|
|
|
|
case OP_TLBI_VALE2ISNXS:
|
|
|
|
|
case OP_TLBI_VALE2OSNXS:
|
|
|
|
|
case OP_TLBI_VALE1NXS:
|
|
|
|
|
case OP_TLBI_VALE1ISNXS:
|
|
|
|
|
case OP_TLBI_VALE1OSNXS:
|
|
|
|
|
scope->type = TLBI_VA;
|
|
|
|
|
scope->size = ttl_to_size(FIELD_GET(TLBI_TTL_MASK, val));
|
|
|
|
|
if (!scope->size)
|
|
|
|
|
scope->size = SZ_1G;
|
|
|
|
|
scope->va = (val << 12) & ~(scope->size - 1);
|
|
|
|
|
scope->asid = FIELD_GET(TLBIR_ASID_MASK, val);
|
|
|
|
|
break;
|
|
|
|
|
case OP_TLBI_ASIDE1:
|
|
|
|
|
case OP_TLBI_ASIDE1IS:
|
|
|
|
|
case OP_TLBI_ASIDE1OS:
|
|
|
|
|
case OP_TLBI_ASIDE1NXS:
|
|
|
|
|
case OP_TLBI_ASIDE1ISNXS:
|
|
|
|
|
case OP_TLBI_ASIDE1OSNXS:
|
|
|
|
|
scope->type = TLBI_ASID;
|
|
|
|
|
scope->asid = FIELD_GET(TLBIR_ASID_MASK, val);
|
|
|
|
|
break;
|
|
|
|
|
case OP_TLBI_VAAE1:
|
|
|
|
|
case OP_TLBI_VAAE1IS:
|
|
|
|
|
case OP_TLBI_VAAE1OS:
|
|
|
|
|
case OP_TLBI_VAAE1NXS:
|
|
|
|
|
case OP_TLBI_VAAE1ISNXS:
|
|
|
|
|
case OP_TLBI_VAAE1OSNXS:
|
|
|
|
|
case OP_TLBI_VAALE1:
|
|
|
|
|
case OP_TLBI_VAALE1IS:
|
|
|
|
|
case OP_TLBI_VAALE1OS:
|
|
|
|
|
case OP_TLBI_VAALE1NXS:
|
|
|
|
|
case OP_TLBI_VAALE1ISNXS:
|
|
|
|
|
case OP_TLBI_VAALE1OSNXS:
|
|
|
|
|
scope->type = TLBI_VAA;
|
|
|
|
|
scope->size = ttl_to_size(FIELD_GET(TLBI_TTL_MASK, val));
|
|
|
|
|
if (!scope->size)
|
|
|
|
|
scope->size = SZ_1G;
|
|
|
|
|
scope->va = (val << 12) & ~(scope->size - 1);
|
|
|
|
|
break;
|
|
|
|
|
case OP_TLBI_RVAE2:
|
|
|
|
|
case OP_TLBI_RVAE2IS:
|
|
|
|
|
case OP_TLBI_RVAE2OS:
|
|
|
|
|
case OP_TLBI_RVAE1:
|
|
|
|
|
case OP_TLBI_RVAE1IS:
|
|
|
|
|
case OP_TLBI_RVAE1OS:
|
|
|
|
|
case OP_TLBI_RVAE2NXS:
|
|
|
|
|
case OP_TLBI_RVAE2ISNXS:
|
|
|
|
|
case OP_TLBI_RVAE2OSNXS:
|
|
|
|
|
case OP_TLBI_RVAE1NXS:
|
|
|
|
|
case OP_TLBI_RVAE1ISNXS:
|
|
|
|
|
case OP_TLBI_RVAE1OSNXS:
|
|
|
|
|
case OP_TLBI_RVALE2:
|
|
|
|
|
case OP_TLBI_RVALE2IS:
|
|
|
|
|
case OP_TLBI_RVALE2OS:
|
|
|
|
|
case OP_TLBI_RVALE1:
|
|
|
|
|
case OP_TLBI_RVALE1IS:
|
|
|
|
|
case OP_TLBI_RVALE1OS:
|
|
|
|
|
case OP_TLBI_RVALE2NXS:
|
|
|
|
|
case OP_TLBI_RVALE2ISNXS:
|
|
|
|
|
case OP_TLBI_RVALE2OSNXS:
|
|
|
|
|
case OP_TLBI_RVALE1NXS:
|
|
|
|
|
case OP_TLBI_RVALE1ISNXS:
|
|
|
|
|
case OP_TLBI_RVALE1OSNXS:
|
|
|
|
|
scope->type = TLBI_VA;
|
|
|
|
|
scope->va = decode_range_tlbi(val, &scope->size, &scope->asid);
|
|
|
|
|
break;
|
|
|
|
|
case OP_TLBI_RVAAE1:
|
|
|
|
|
case OP_TLBI_RVAAE1IS:
|
|
|
|
|
case OP_TLBI_RVAAE1OS:
|
|
|
|
|
case OP_TLBI_RVAAE1NXS:
|
|
|
|
|
case OP_TLBI_RVAAE1ISNXS:
|
|
|
|
|
case OP_TLBI_RVAAE1OSNXS:
|
|
|
|
|
case OP_TLBI_RVAALE1:
|
|
|
|
|
case OP_TLBI_RVAALE1IS:
|
|
|
|
|
case OP_TLBI_RVAALE1OS:
|
|
|
|
|
case OP_TLBI_RVAALE1NXS:
|
|
|
|
|
case OP_TLBI_RVAALE1ISNXS:
|
|
|
|
|
case OP_TLBI_RVAALE1OSNXS:
|
|
|
|
|
scope->type = TLBI_VAA;
|
|
|
|
|
scope->va = decode_range_tlbi(val, &scope->size, NULL);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void kvm_handle_s1e2_tlbi(struct kvm_vcpu *vcpu, u32 inst, u64 val)
|
|
|
|
|
{
|
|
|
|
|
struct s1e2_tlbi_scope scope = {};
|
|
|
|
|
|
|
|
|
|
compute_s1_tlbi_range(vcpu, inst, val, &scope);
|
|
|
|
|
invalidate_vncr_va(vcpu->kvm, &scope);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void kvm_nested_s2_wp(struct kvm *kvm)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
@@ -1191,6 +1383,7 @@ static void kvm_map_l1_vncr(struct kvm_vcpu *vcpu)
|
|
|
|
|
if (pgprot_val(prot) != pgprot_val(PAGE_NONE)) {
|
|
|
|
|
__set_fixmap(vncr_fixmap(vt->cpu), vt->hpa, prot);
|
|
|
|
|
host_data_set_flag(L1_VNCR_MAPPED);
|
|
|
|
|
atomic_inc(&vcpu->kvm->arch.vncr_map_count);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|