diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 0fd184b816b3..973ab0378d01 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -930,6 +930,12 @@ bool kvm_arm_vcpu_is_finalized(struct kvm_vcpu *vcpu);
#define kvm_arm_vcpu_sve_finalized(vcpu) \
((vcpu)->arch.flags & KVM_ARM64_VCPU_SVE_FINALIZED)
+DECLARE_STATIC_KEY_FALSE(pkvm_mte_supported);
+
+#define kvm_supports_mte(kvm) \
+ (system_supports_mte() && \
+ (!kvm_vm_is_protected(kvm) || \
+ static_branch_unlikely(&pkvm_mte_supported)))
#define kvm_has_mte(kvm) \
(system_supports_mte() && \
test_bit(KVM_ARCH_FLAG_MTE_ENABLED, &(kvm)->arch.flags))
diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h
index cd56438a34be..ef5d4870c043 100644
--- a/arch/arm64/include/asm/kvm_pkvm.h
+++ b/arch/arm64/include/asm/kvm_pkvm.h
@@ -73,10 +73,12 @@ void kvm_shadow_destroy(struct kvm *kvm);
* Allow for protected VMs:
* - Branch Target Identification
* - Speculative Store Bypassing
+ * - Memory Tagging Extension
*/
#define PVM_ID_AA64PFR1_ALLOW (\
ARM64_FEATURE_MASK(ID_AA64PFR1_BT) | \
- ARM64_FEATURE_MASK(ID_AA64PFR1_SSBS) \
+ ARM64_FEATURE_MASK(ID_AA64PFR1_SSBS) | \
+ ARM64_FEATURE_MASK(ID_AA64PFR1_MTE) \
)
/*
diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h
index 2d4d6836ff47..26a9b31478aa 100644
--- a/arch/arm64/kernel/image-vars.h
+++ b/arch/arm64/kernel/image-vars.h
@@ -84,6 +84,9 @@ KVM_NVHE_ALIAS(__hyp_stub_vectors);
KVM_NVHE_ALIAS(arm64_const_caps_ready);
KVM_NVHE_ALIAS(cpu_hwcap_keys);
+/* Kernel symbol needed for kvm_supports_mte() check. */
+KVM_NVHE_ALIAS(pkvm_mte_supported);
+
/* Static keys which are set if a vGIC trap should be handled in hyp. */
KVM_NVHE_ALIAS(vgic_v2_cpuif_trap);
KVM_NVHE_ALIAS(vgic_v3_cpuif_trap);
diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 38f0900b7ddb..5a780a0f59e3 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -60,6 +60,7 @@ static bool vgic_present;
static DEFINE_PER_CPU(unsigned char, kvm_arm_hardware_enabled);
DEFINE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
+DEFINE_STATIC_KEY_FALSE(pkvm_mte_supported);
int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
{@@ -96,9 +97,7 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
break;
case KVM_CAP_ARM_MTE:
mutex_lock(&kvm->lock);
- if (!system_supports_mte() ||
- kvm_vm_is_protected(kvm) ||
- kvm->created_vcpus) {
+ if (!kvm_supports_mte(kvm) || kvm->created_vcpus) {
r = -EINVAL;
} else {
r = 0;@@ -334,6 +333,9 @@ static int pkvm_check_extension(struct kvm *kvm, long ext, int kvm_cap)
case KVM_CAP_ARM_VM_IPA_SIZE:
r = kvm_cap;
break;
+ case KVM_CAP_ARM_MTE:
+ r = kvm_cap && static_branch_unlikely(&pkvm_mte_supported);
+ break;
case KVM_CAP_GUEST_DEBUG_HW_BPS:
r = min(kvm_cap, pkvm_get_max_brps());
break;
@@ -1948,9 +1950,36 @@ static void kvm_reserved_memory_init(void)
if (!of_get_property(node, "compatible", NULL) &&
of_get_property(node, "no-map", NULL))
disown_reserved_memory(node);
+
+ if (of_device_is_compatible(node, "arm,mte-tag-storage"))
+ disown_reserved_memory(node);
}
}
+static void kvm_mte_init(void)
+{
+ struct device_node *memory;
+
+ if (!system_supports_mte() || !acpi_disabled ||
+ !is_protected_kvm_enabled())
+ return;
+
+ /*
+ * It is only safe to turn on MTE for protected VMs if we can protect
+ * the guests from host accesses to their tag storage. If every memory
+ * region has an arm,mte-alloc property we know that all tag storage
+ * regions exposed to physical memory, if any, are described by a
+ * reserved-memory compatible with arm,mte-tag-storage. We can use these
+ * descriptions to unmap these regions from the host's stage 2 page
+ * tables (see kvm_reserved_memory_init).
+ */
+ for_each_node_by_type(memory, "memory")
+ if (!of_get_property(memory, "arm,mte-alloc", NULL))
+ return;
+
+ static_branch_enable(&pkvm_mte_supported);
+}
+
static int init_subsystems(void)
{
int err = 0;@@ -1993,6 +2022,8 @@ static int init_subsystems(void)
kvm_reserved_memory_init();
+ kvm_mte_init();
+
out:
if (err || !is_protected_kvm_enabled())
on_each_cpu(_kvm_arch_hardware_disable, NULL, 1);
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index e81a6dd676d0..dcc3084161b3 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -88,7 +88,7 @@ static void pvm_init_traps_aa64pfr1(struct kvm_vcpu *vcpu)
/* Memory Tagging: Trap and Treat as Untagged if not supported. */
if (!FIELD_GET(ARM64_FEATURE_MASK(ID_AA64PFR1_MTE), feature_ids)) {
hcr_set |= HCR_TID5;
- hcr_clear |= HCR_DCT | HCR_ATA;
+ hcr_clear |= HCR_ATA;
}
vcpu->arch.hcr_el2 |= hcr_set;@@ -179,8 +179,8 @@ static void pvm_init_trap_regs(struct kvm_vcpu *vcpu)
* - Feature id registers: to control features exposed to guests
* - Implementation-defined features
*/
- vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS |
- HCR_TID3 | HCR_TACR | HCR_TIDCP | HCR_TID1;
+ vcpu->arch.hcr_el2 = HCR_GUEST_FLAGS | HCR_TID3 | HCR_TACR | HCR_TIDCP |
+ HCR_TID1 | HCR_ATA;
if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN)) {
/* route synchronous external abort exceptions to EL2 */@@ -459,6 +459,8 @@ static int init_shadow_structs(struct kvm *kvm, struct kvm_shadow_vm *vm,
vm->host_kvm = kvm;
vm->kvm.created_vcpus = nr_vcpus;
vm->kvm.arch.vtcr = host_kvm.arch.vtcr;
+ if (kvm_supports_mte(kvm) && test_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags))
+ set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &vm->kvm.arch.flags);
vm->kvm.arch.pkvm.enabled = READ_ONCE(kvm->arch.pkvm.enabled);
vm->kvm.arch.mmu.last_vcpu_ran = last_ran;
vm->last_ran_size = last_ran_size;
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index bca90b7354b9..5e079daf2d8e 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -1228,8 +1228,10 @@ static int pkvm_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
goto dec_account;
}
- write_lock(&kvm->mmu_lock);
pfn = page_to_pfn(page);
+ sanitise_mte_tags(kvm, pfn, PAGE_SIZE);
+
+ write_lock(&kvm->mmu_lock);
ret = pkvm_host_map_guest(pfn, fault_ipa >> PAGE_SHIFT);
if (ret) {
if (ret == -EAGAIN)--
2.37.0.rc0.104.g0611611a94-goog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel