public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
From: Sumit Garg <sumit.garg@kernel.org>
To: Aswin Murugan <aswin.murugan@oss.qualcomm.com>
Cc: trini@konsulko.com, casey.connolly@linaro.org,
	neil.armstrong@linaro.org, sughosh.ganu@arm.com,
	gchan9527@gmail.com, u-boot-qcom@groups.io, u-boot@lists.denx.de
Subject: Re: [PATCH v1] mach-snapdragon: Add KVM hypervisor support
Date: Mon, 20 Apr 2026 19:15:13 +0530	[thread overview]
Message-ID: <aeYt6cz5AVXFc5m3@sumit-xelite> (raw)
In-Reply-To: <20260419173829.1074404-1-aswin.murugan@oss.qualcomm.com>

On Sun, Apr 19, 2026 at 11:08:29PM +0530, Aswin Murugan wrote:
> 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

Please don't switch EL1 -> EL2 in the middle of U-Boot execution which
just adds these expensive MMU operations during boot.

Rather than that just follow the upstream edk2 example to switch from
EL1 -> EL2 on the first platform specific init code code sequence. Have
a look at this reference [1]. Surely you can keep the switch under a
config option. This will make U-Boot to properly execute either in EL1
or EL2.

[1] https://github.com/tianocore/edk2-platforms/blob/master/Silicon/Qualcomm/KodiakPkg/Library/KodiakLib/KodiakHelper.S

-Sumit

>  - 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
> 

      parent reply	other threads:[~2026-04-20 13:45 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aeYt6cz5AVXFc5m3@sumit-xelite \
    --to=sumit.garg@kernel.org \
    --cc=aswin.murugan@oss.qualcomm.com \
    --cc=casey.connolly@linaro.org \
    --cc=gchan9527@gmail.com \
    --cc=neil.armstrong@linaro.org \
    --cc=sughosh.ganu@arm.com \
    --cc=trini@konsulko.com \
    --cc=u-boot-qcom@groups.io \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox