[RFC PATCH 21/45] KVM: arm64: iommu: Add SMMUv3 driver

Jean-Philippe Brucker
2023-02-01T14:25:14Z

Add the skeleton for an Arm SMMUv3 driver at EL2.

Signed-off-by: Jean-Philippe Brucker <jean-philippe@linaro.org>
---
drivers/iommu/Kconfig | 10 ++++++++
arch/arm64/kvm/hyp/nvhe/Makefile | 1 +
arch/arm64/include/asm/kvm_host.h | 1 +
arch/arm64/kvm/hyp/include/nvhe/iommu.h | 9 +++++++
include/kvm/arm_smmu_v3.h | 22 +++++++++++++++++
arch/arm64/kvm/hyp/nvhe/iommu/arm-smmu-v3.c | 27 +++++++++++++++++++++
arch/arm64/kvm/hyp/nvhe/setup.c | 2 ++
7 files changed, 72 insertions(+)
create mode 100644 include/kvm/arm_smmu_v3.h
create mode 100644 arch/arm64/kvm/hyp/nvhe/iommu/arm-smmu-v3.c

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 79707685d54a..1689d416ccd8 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -410,6 +410,16 @@ config ARM_SMMU_V3_SVA
Say Y here if your system supports SVA extensions such as PCIe PASID
and PRI.

+config ARM_SMMU_V3_PKVM
+ bool "ARM SMMUv3 support for protected Virtual Machines"
+ depends on KVM && ARM64
+ select KVM_IOMMU
+ help
+ Enable a SMMUv3 driver in the KVM hypervisor, to protect VMs against
+ memory accesses from devices owned by the host.
+
+ Say Y here if you intend to enable KVM in protected mode.
+
config S390_IOMMU
def_bool y if S390 && PCI
depends on S390 && PCI
diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
index f7dfc88c9f5b..349c874762c8 100644
--- a/arch/arm64/kvm/hyp/nvhe/Makefile
+++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -29,6 +29,7 @@ hyp-obj-$(CONFIG_DEBUG_LIST) += list_debug.o
hyp-obj-y += $(lib-objs)

hyp-obj-$(CONFIG_KVM_IOMMU) += iommu/iommu.o
+hyp-obj-$(CONFIG_ARM_SMMU_V3_PKVM) += iommu/arm-smmu-v3.o

##
## Build rules for compiling nVHE hyp code
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index b8e032bda022..c98ce17f8148 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -379,6 +379,7 @@ extern u64 kvm_nvhe_sym(hyp_cpu_logical_map)[NR_CPUS];

enum kvm_iommu_driver {
KVM_IOMMU_DRIVER_NONE,
+ KVM_IOMMU_DRIVER_SMMUV3,
};

struct vcpu_reset_state {
diff --git a/arch/arm64/kvm/hyp/include/nvhe/iommu.h b/arch/arm64/kvm/hyp/include/nvhe/iommu.h
index 76d3fa6ce331..0ba59d20bef3 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/iommu.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/iommu.h
@@ -5,6 +5,15 @@
#include <kvm/iommu.h>
#include <linux/io-pgtable.h>

+#if IS_ENABLED(CONFIG_ARM_SMMU_V3_PKVM)
+int kvm_arm_smmu_v3_register(void);
+#else /* CONFIG_ARM_SMMU_V3_PKVM */
+static inline int kvm_arm_smmu_v3_register(void)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_ARM_SMMU_V3_PKVM */
+
#if IS_ENABLED(CONFIG_KVM_IOMMU)
int kvm_iommu_init(void);
int kvm_iommu_init_device(struct kvm_hyp_iommu *iommu);
diff --git a/include/kvm/arm_smmu_v3.h b/include/kvm/arm_smmu_v3.h
new file mode 100644
index 000000000000..ebe488b2f93c
--- /dev/null
+++ b/include/kvm/arm_smmu_v3.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __KVM_ARM_SMMU_V3_H
+#define __KVM_ARM_SMMU_V3_H
+
+#include <asm/kvm_asm.h>
+#include <kvm/iommu.h>
+
+#if IS_ENABLED(CONFIG_ARM_SMMU_V3_PKVM)
+
+struct hyp_arm_smmu_v3_device {
+ struct kvm_hyp_iommu iommu;
+};
+
+extern size_t kvm_nvhe_sym(kvm_hyp_arm_smmu_v3_count);
+#define kvm_hyp_arm_smmu_v3_count kvm_nvhe_sym(kvm_hyp_arm_smmu_v3_count)
+
+extern struct hyp_arm_smmu_v3_device *kvm_nvhe_sym(kvm_hyp_arm_smmu_v3_smmus);
+#define kvm_hyp_arm_smmu_v3_smmus kvm_nvhe_sym(kvm_hyp_arm_smmu_v3_smmus)
+
+#endif /* CONFIG_ARM_SMMU_V3_PKVM */
+
+#endif /* __KVM_ARM_SMMU_V3_H */
diff --git a/arch/arm64/kvm/hyp/nvhe/iommu/arm-smmu-v3.c b/arch/arm64/kvm/hyp/nvhe/iommu/arm-smmu-v3.c
new file mode 100644
index 000000000000..c167e4dbd28d
--- /dev/null
+++ b/arch/arm64/kvm/hyp/nvhe/iommu/arm-smmu-v3.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * pKVM hyp driver for the Arm SMMUv3
+ *
+ * Copyright (C) 2022 Linaro Ltd.
+ */
+#include <asm/kvm_hyp.h>
+#include <kvm/arm_smmu_v3.h>
+#include <nvhe/iommu.h>
+
+size_t __ro_after_init kvm_hyp_arm_smmu_v3_count;
+struct hyp_arm_smmu_v3_device __ro_after_init *kvm_hyp_arm_smmu_v3_smmus;
+
+static int smmu_init(void)
+{
+ return -ENOSYS;
+}
+
+static struct kvm_iommu_ops smmu_ops = {
+ .init = smmu_init,
+};
+
+int kvm_arm_smmu_v3_register(void)
+{
+ kvm_iommu_ops = smmu_ops;
+ return 0;
+}
diff --git a/arch/arm64/kvm/hyp/nvhe/setup.c b/arch/arm64/kvm/hyp/nvhe/setup.c
index 3e73c066d560..a25de8c5d489 100644
--- a/arch/arm64/kvm/hyp/nvhe/setup.c
+++ b/arch/arm64/kvm/hyp/nvhe/setup.c
@@ -294,6 +294,8 @@ static int select_iommu_ops(enum kvm_iommu_driver driver)
switch (driver) {
case KVM_IOMMU_DRIVER_NONE:
return 0;
+ case KVM_IOMMU_DRIVER_SMMUV3:
+ return kvm_arm_smmu_v3_register();
}

return -EINVAL;
--
2.39.0