public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
* [PATCH v1] mach-snapdragon: Add KVM hypervisor support
@ 2026-04-19 17:38 Aswin Murugan
  2026-04-20  4:32 ` Simon Glass
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Aswin Murugan @ 2026-04-19 17:38 UTC (permalink / raw)
  To: trini, casey.connolly, neil.armstrong, sumit.garg, aswin.murugan,
	sughosh.ganu, gchan9527, u-boot-qcom, u-boot

Enable Linux KVM virtualization on Snapdragon SoCs.

Introduce CONFIG_QCOM_KVM_SUPPORT to select KVM or Gunyah
hypervisor modes at build time.

qcom-priv.h:
 - Add TrustZone SMC interface definitions and parameter IDs
 - Define hypervisor boot types (GUNYAH=0, KVM=1)
 - Add TCR_EL2 bit field definitions for memory config

board.c:
 - Add qcom_configure_kvm_hypervisor() with EL-aware logic
 - EL2: Perform direct SMC call for hypervisor setup
 - EL1: Save context, disable caches, run SMC, restore state,
   reconfigure TCR_EL2, re-enable caches
 - Add qcom_configure_gunyah_hypervisor() for standard flow
 - Add SCM service availability checks

Default mode remains Gunyah. Enable CONFIG_QCOM_KVM_SUPPORT to
select KVM for Linux.

Signed-off-by: Aswin Murugan <aswin.murugan@oss.qualcomm.com>
---
 arch/arm/mach-snapdragon/Kconfig     |   7 ++
 arch/arm/mach-snapdragon/board.c     | 154 +++++++++++++++++++++++++++
 arch/arm/mach-snapdragon/qcom-priv.h |  31 ++++++
 3 files changed, 192 insertions(+)

diff --git a/arch/arm/mach-snapdragon/Kconfig b/arch/arm/mach-snapdragon/Kconfig
index d3de8693b5a..2e5676945ca 100644
--- a/arch/arm/mach-snapdragon/Kconfig
+++ b/arch/arm/mach-snapdragon/Kconfig
@@ -42,4 +42,11 @@ config SYS_CONFIG_NAME
 	  Based on this option include/configs/<CONFIG_SYS_CONFIG_NAME>.h header
 	  will be used for board configuration.
 
+config QCOM_KVM_SUPPORT
+	bool "Enable KVM support for Qualcomm platforms"
+	depends on ARM64
+	help
+	  This configures the hypervisor interface during boot to support
+	  KVM virtualization instead of the default Gunyah hypervisor.
+
 endif
diff --git a/arch/arm/mach-snapdragon/board.c b/arch/arm/mach-snapdragon/board.c
index 5fb3240acc5..2926dd8ccc0 100644
--- a/arch/arm/mach-snapdragon/board.c
+++ b/arch/arm/mach-snapdragon/board.c
@@ -510,6 +510,154 @@ void __weak qcom_late_init(void)
 {
 }
 
+/**
+ * qcom_configure_kvm_hypervisor() - Configure hypervisor for KVM guest mode
+ *
+ * Configures the hypervisor for KVM operation:
+ * - EL2 path: Direct SMC call
+ * - EL1 path: Save context, disable caches, SMC call, restore context
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int qcom_configure_kvm_hypervisor(void)
+{
+	struct arm_smccc_res res;
+	u64 current_el;
+
+	asm volatile("mrs %0, CurrentEL" : "=r" (current_el));
+	current_el = (current_el >> 2) & 0x3;
+
+	log_info("Configuring hypervisor for KVM (EL%llu)\n", current_el);
+
+	arm_smccc_smc(TZ_INFO_IS_SVC_AVAILABLE_ID,
+		      TZ_INFO_IS_SVC_AVAILABLE_ID_PARAM_ID,
+		      TZ_CONFIGURE_MILESTONE_SERVICE_ID,
+		      0, 0, 0, 0, 0, &res);
+
+	if (res.a0 != 0)
+		log_debug("KVM milestone service not available (0x%lx)\n", res.a0);
+
+	if (current_el == 2) {
+		log_debug("At EL2\n");
+
+		arm_smccc_smc(TZ_CONFIGURE_MILESTONE_SERVICE_ID,
+			      TZ_CONFIGURE_MILESTONE_SERVICE_PARAM_ID,
+			      0, 0, QCOM_HYP_BOOT_TYPE_KVM,
+			      0, 0, 0, &res);
+
+		if (res.a0 != 0) {
+			log_err("Hypervisor configuration failed: 0x%lx\n", res.a0);
+			return -EIO;
+		}
+
+		log_info("KVM hypervisor configured\n");
+		return 0;
+	}
+
+	log_debug("At EL1, saving register context\n");
+
+	u64 ttbr0_el1, tcr_el1, tcr_el2, mair_el1;
+	u64 t0sz, phys_addr_size;
+
+	/* Save EL1 system register context */
+	asm volatile("mrs %0, ttbr0_el1" : "=r" (ttbr0_el1));
+	asm volatile("mrs %0, tcr_el1" : "=r" (tcr_el1));
+	asm volatile("mrs %0, mair_el1" : "=r" (mair_el1));
+
+	t0sz = tcr_el1 & TCR_T0SZ_MASK;
+	phys_addr_size = tcr_el1 & TCR_PS_MASK;
+
+	log_debug("Saved context: TTBR0=0x%llx TCR=0x%llx MAIR=0x%llx\n",
+		  ttbr0_el1, tcr_el1, mair_el1);
+
+	icache_disable();
+	dcache_disable();
+
+	arm_smccc_smc(TZ_CONFIGURE_MILESTONE_SERVICE_ID,
+		      TZ_CONFIGURE_MILESTONE_SERVICE_PARAM_ID,
+		      0, 0, QCOM_HYP_BOOT_TYPE_KVM,
+		      0, 0, 0, &res);
+
+	if (res.a0 != 0) {
+		log_err("Hypervisor configuration failed: 0x%lx\n", res.a0);
+		icache_enable();
+		dcache_enable();
+		return -EIO;
+	}
+
+	asm volatile("mrs %0, CurrentEL" : "=r" (current_el));
+	current_el = (current_el >> 2) & 0x3;
+
+	asm volatile("msr ttbr0_el1, %0" : : "r" (ttbr0_el1));
+	asm volatile("isb");
+
+	if (current_el != 2) {
+		log_debug("No EL2 transition, skipping TCR_EL2 config\n");
+		icache_enable();
+		dcache_enable();
+		log_warning("KVM hypervisor configuration failed\n");
+		return 0;
+	}
+
+	/* Read current TCR_EL2 and reconfigure it */
+	asm volatile("mrs %0, tcr_el2" : "=r" (tcr_el2));
+
+	tcr_el2 &= ~(TCR_T0SZ_MASK | (0x7UL << 16));
+	tcr_el2 |= t0sz | (phys_addr_size >> TCR_PS_SHIFT);
+
+	tcr_el2 &= ~TCR_SH_ORGN_IRGN_MASK;
+	tcr_el2 |= TCR_SH_INNER_SHAREABLE |
+		   TCR_ORGN_WRITE_BACK_ALLOC |
+		   TCR_IRGN_WRITE_BACK_ALLOC;
+
+	asm volatile("msr tcr_el2, %0" : : "r" (tcr_el2));
+	asm volatile("msr mair_el1, %0" : : "r" (mair_el1));
+	asm volatile("isb");
+
+	icache_enable();
+	dcache_enable();
+
+	log_info("KVM hypervisor configured\n");
+	return 0;
+}
+
+/**
+ * qcom_configure_gunyah_hypervisor() - Configure hypervisor for Gunyah mode
+ *
+ * Configures the hypervisor for standard Gunyah operation.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+static int qcom_configure_gunyah_hypervisor(void)
+{
+	struct arm_smccc_res res;
+
+	log_info("Configuring hypervisor for Gunyah mode\n");
+
+	arm_smccc_smc(TZ_INFO_IS_SVC_AVAILABLE_ID,
+		      TZ_INFO_IS_SVC_AVAILABLE_ID_PARAM_ID,
+		      TZ_CONFIGURE_MILESTONE_SERVICE_ID,
+		      0, 0, 0, 0, 0, &res);
+
+	if (res.a0 != 0) {
+		log_debug("Hypervisor milestone service not available (0x%lx)\n", res.a0);
+		return 0;
+	}
+
+	arm_smccc_smc(TZ_CONFIGURE_MILESTONE_SERVICE_ID,
+		      TZ_CONFIGURE_MILESTONE_SERVICE_PARAM_ID,
+		      0, 0, QCOM_HYP_BOOT_TYPE_GUNYAH,
+		      0, 0, 0, &res);
+
+	if (res.a0 != 0) {
+		log_err("Hypervisor configuration failed: 0x%lx\n", res.a0);
+		return -EIO;
+	}
+
+	log_info("Gunyah hypervisor configured\n");
+	return 0;
+}
+
 #define KERNEL_COMP_SIZE	SZ_64M
arch/arm/mach-snapdragon/Kconfig #ifdef CONFIG_FASTBOOT_BUF_SIZE
 #define FASTBOOT_BUF_SIZE CONFIG_FASTBOOT_BUF_SIZE
@@ -570,6 +718,12 @@ int board_late_init(void)
 	qcom_late_init();
 
 	qcom_show_boot_source();
+
+	if (IS_ENABLED(CONFIG_QCOM_KVM_SUPPORT))
+		qcom_configure_kvm_hypervisor();
+	else
+		qcom_configure_gunyah_hypervisor();
+
 	/* Configure the dfu_string for capsule updates */
 	qcom_configure_capsule_updates();
 
diff --git a/arch/arm/mach-snapdragon/qcom-priv.h b/arch/arm/mach-snapdragon/qcom-priv.h
index b8bf574e8bb..a5d9dec6aa7 100644
--- a/arch/arm/mach-snapdragon/qcom-priv.h
+++ b/arch/arm/mach-snapdragon/qcom-priv.h
@@ -17,6 +17,37 @@ enum qcom_boot_source {
 
 extern enum qcom_boot_source qcom_boot_source;
 
+/* TrustZone SMC definitions */
+#define TZ_SYSCALL_CREATE_SMC_ID(o, s, f) \
+	((u32)((((o) & 0x3f) << 24) | (((s) & 0xff) << 8) | ((f) & 0xff)))
+
+#define TZ_OWNER_SIP				2
+#define TZ_SVC_BOOT				1
+#define TZ_SVC_INFO				6
+#define TZ_BOOT_CMD_KVM_MILESTONE		0x21
+#define TZ_INFO_IS_SVC_AVAILABLE_CMD		0x01
+
+#define TZ_CONFIGURE_MILESTONE_SERVICE_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, TZ_SVC_BOOT, TZ_BOOT_CMD_KVM_MILESTONE)
+#define TZ_CONFIGURE_MILESTONE_SERVICE_PARAM_ID		0x23
+
+#define TZ_INFO_IS_SVC_AVAILABLE_ID \
+	TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_SIP, TZ_SVC_INFO, TZ_INFO_IS_SVC_AVAILABLE_CMD)
+#define TZ_INFO_IS_SVC_AVAILABLE_ID_PARAM_ID		0x1
+
+/* Hypervisor boot types */
+#define QCOM_HYP_BOOT_TYPE_GUNYAH		0
+#define QCOM_HYP_BOOT_TYPE_KVM			1
+
+/* TCR_EL2 bit field definitions */
+#define TCR_T0SZ_MASK				0x1FUL
+#define TCR_PS_MASK				(0x7UL << 32)
+#define TCR_PS_SHIFT				16
+#define TCR_SH_ORGN_IRGN_MASK			0x3F00UL
+#define TCR_SH_INNER_SHAREABLE			(3UL << 12)
+#define TCR_ORGN_WRITE_BACK_ALLOC		BIT(10)
+#define TCR_IRGN_WRITE_BACK_ALLOC		BIT(8)
+
 #if IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)
 void qcom_configure_capsule_updates(void);
 #else
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-04-20 13:45 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-19 17:38 [PATCH v1] mach-snapdragon: Add KVM hypervisor support Aswin Murugan
2026-04-20  4:32 ` Simon Glass
2026-04-20  7:50 ` neil.armstrong
2026-04-20 13:45 ` Sumit Garg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox