From: Thara Gopinath <tgopinath@linux.microsoft.com>
To: kys@microsoft.com, haiyangz@microsoft.com, wei.liu@kernel.org,
decui@microsoft.com, tglx@kernel.org, mingo@redhat.com,
bp@alien8.de, dave.hansen@linux.intel.com, hpa@zytor.com,
ardb@kernel.org, ilias.apalodimas@linaro.org
Cc: James.Bottomley@HansenPartnership.com,
"longli@microsoft.com--cc=tzimmermann"@suse.de,
javierm@redhat.com, lszubowi@redhat.com,
francescopompo2@gmail.com, tgopinath@microsoft.com,
x86@kernel.org, linux-hyperv@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-efi@vger.kernel.org,
Thara Gopinath <tgopinath@linux.microsoft.com>
Subject: [RFC PATCH 10/12] arch: x86: hyperv: hv_vtl_vsm: Introduce vtlcall
Date: Tue, 1 Sep 2026 09:55:24 -0700 [thread overview]
Message-ID: <20260901165647.3160413-11-tgopinath@linux.microsoft.com> (raw)
In-Reply-To: <20260901165647.3160413-1-tgopinath@linux.microsoft.com>
A vtlcall is the mechanism by which a lower VTL (VTL0) transitions
into a higher VTL (VTL1) on Microsoft Hyper-V. It is issued as a
call to a fixed offset within the hypercall page; the hypervisor
saves the lower-VTL context, restores the upper-VTL context, and
resumes execution at the upper VTL. Control returns to VTL0 when
the upper VTL executes a vtlreturn.
Introduce the x86 VTL0-side vtlcall infrastructure:
- hv_vsm_vtlcall(): runtime entry point. Preserves state VTL1 can
clobber (IRQs, FPU, CR2) and invokes the assembly trampoline.
Returns the signed 64-bit status the secure kernel places in a3.
- hv_vsm_init_vtlcall(u64 vtl_call_offset): one-shot initializer
that installs the vtlcall target into a static_call. The offset
is passed in by the caller so the register read stays outside
arch code, mirroring mshv_vtl_return_call_init().
- struct hv_vtlcall_param and CONFIG_HYPERV_VSM API in
include/hyperv/vsm.h, with no-op stubs when VSM is disabled.
- __hv_vsm_vtlcall assembly trampoline in mshv_vtl_asm.S, plus
asm-offsets for the argument block.
Signed-off-by: Thara Gopinath <tgopinath@linux.microsoft.com>
---
arch/x86/hyperv/Makefile | 2 +-
arch/x86/hyperv/hv_vtl_vsm.c | 29 ++++++++++++
arch/x86/hyperv/mshv-asm-offsets.c | 8 ++++
arch/x86/hyperv/mshv_vtl_asm.S | 75 ++++++++++++++++++++++++++++++
include/hyperv/vsm.h | 22 +++++++++
5 files changed, 135 insertions(+), 1 deletion(-)
diff --git a/arch/x86/hyperv/Makefile b/arch/x86/hyperv/Makefile
index 1fdc20e239243..430f5f2bca40a 100644
--- a/arch/x86/hyperv/Makefile
+++ b/arch/x86/hyperv/Makefile
@@ -2,7 +2,7 @@
obj-y := hv_init.o mmu.o nested.o irqdomain.o ivm.o
obj-$(CONFIG_X86_64) += hv_apic.o
obj-$(CONFIG_HYPERV_VTL_MODE) += hv_vtl.o mshv_vtl_asm.o
-obj-$(CONFIG_HYPERV_VSM) += hv_vtl_vsm.o
+obj-$(CONFIG_HYPERV_VSM) += hv_vtl_vsm.o mshv_vtl_asm.o
$(obj)/mshv_vtl_asm.o: $(obj)/mshv-asm-offsets.h
diff --git a/arch/x86/hyperv/hv_vtl_vsm.c b/arch/x86/hyperv/hv_vtl_vsm.c
index edc55264c4d87..d533a8e113935 100644
--- a/arch/x86/hyperv/hv_vtl_vsm.c
+++ b/arch/x86/hyperv/hv_vtl_vsm.c
@@ -15,6 +15,7 @@
#include <hyperv/vsm.h>
#include <asm/msr-index.h>
#include <asm/processor-flags.h>
+#include <hyperv/hvgdk_mini.h>
#include <asm/mshyperv.h>
/* Define PAGE size and related variables for initial secure kernel pages */
@@ -256,3 +257,31 @@ void __init hv_vsm_arch_init_vp(struct hv_init_vp_context *vp_ctx, Elf64_Addr sk
hv_vsm_init_gdt(vp_ctx, sk_pa);
hv_vsm_init_page_tables(vp_ctx, sk_pa);
}
+
+/* Implemented in mshv_vtl_asm.S */
+void __hv_vsm_vtlcall(struct hv_vtlcall_param *args);
+
+DEFINE_STATIC_CALL_NULL(__hv_vsm_vtlcall_hypercall, void (*)(void));
+
+void __init hv_vsm_init_vtlcall(u64 vtl_call_offset)
+{
+ static_call_update(__hv_vsm_vtlcall_hypercall,
+ (void *)((u8 *)hv_hypercall_pg + vtl_call_offset));
+}
+
+s64 hv_vsm_vtlcall(struct hv_vtlcall_param *args)
+{
+ unsigned long flags;
+ u64 cr2;
+
+ local_irq_save(flags);
+ kernel_fpu_begin_mask(0);
+ cr2 = native_read_cr2();
+ __hv_vsm_vtlcall(args);
+ native_write_cr2(cr2);
+ kernel_fpu_end();
+ local_irq_restore(flags);
+
+ /* The secure kernel returns a signed 64-bit status in a3. */
+ return (s64)args->a3;
+}
diff --git a/arch/x86/hyperv/mshv-asm-offsets.c b/arch/x86/hyperv/mshv-asm-offsets.c
index 882c1db6df16c..0f0470ddaee59 100644
--- a/arch/x86/hyperv/mshv-asm-offsets.c
+++ b/arch/x86/hyperv/mshv-asm-offsets.c
@@ -12,6 +12,7 @@
#define COMPILE_OFFSETS
#include <linux/kbuild.h>
+#include <hyperv/vsm.h>
#include <asm/mshyperv.h>
static void __used common(void)
@@ -34,4 +35,11 @@ static void __used common(void)
OFFSET(MSHV_VTL_CPU_CONTEXT_r15, mshv_vtl_cpu_context, r15);
OFFSET(MSHV_VTL_CPU_CONTEXT_cr2, mshv_vtl_cpu_context, cr2);
}
+
+ if (IS_ENABLED(CONFIG_HYPERV_VSM)) {
+ OFFSET(HV_VTLCALL_PARAM_a0, hv_vtlcall_param, a0);
+ OFFSET(HV_VTLCALL_PARAM_a1, hv_vtlcall_param, a1);
+ OFFSET(HV_VTLCALL_PARAM_a2, hv_vtlcall_param, a2);
+ OFFSET(HV_VTLCALL_PARAM_a3, hv_vtlcall_param, a3);
+ }
}
diff --git a/arch/x86/hyperv/mshv_vtl_asm.S b/arch/x86/hyperv/mshv_vtl_asm.S
index f595eefad9abf..4d7007848ecd4 100644
--- a/arch/x86/hyperv/mshv_vtl_asm.S
+++ b/arch/x86/hyperv/mshv_vtl_asm.S
@@ -15,6 +15,8 @@
#include <asm/frame.h>
#include "mshv-asm-offsets.h"
+#ifdef CONFIG_HYPERV_VTL_MODE
+
.text
.section .noinstr.text, "ax"
/*
@@ -114,3 +116,76 @@ SYM_FUNC_END(__mshv_vtl_return_call)
.size mshv_vtl_return_sym, 8
mshv_vtl_return_sym:
.quad __SCK____mshv_vtl_return_hypercall
+
+#endif /* CONFIG_HYPERV_VTL_MODE */
+
+#ifdef CONFIG_HYPERV_VSM
+ .text
+/*
+ * void __hv_vsm_vtlcall(struct hv_vtlcall_param *args)
+ *
+ * Perform a VTL call to switch to the upper VTL.
+ *
+ * The %rcx register is zeroed before the call and is clobbered by the
+ * hypercall. %rax is not restored by the upper VTL (passed via the assist
+ * page) but is unused and can be ignored.
+ *
+ * The args pointer is preserved on the stack across the VTL call since all
+ * argument registers are repurposed during the VTL call.
+ *
+ * Microsoft Hypervisor preserves %rsp during VTL switches.
+ */
+SYM_FUNC_START(__hv_vsm_vtlcall)
+ /* Save callee-saved registers */
+ pushq %rbp
+ mov %rsp, %rbp
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+ pushq %rbx
+ pushq %rdi
+
+ /* Load struct fields into VTL calling convention registers */
+ mov HV_VTLCALL_PARAM_a3(%rdi), %r8
+ mov HV_VTLCALL_PARAM_a2(%rdi), %rdx
+ mov HV_VTLCALL_PARAM_a1(%rdi), %rsi
+ mov HV_VTLCALL_PARAM_a0(%rdi), %rdi
+
+ /* Zero %rcx */
+ xorl %ecx, %ecx
+
+ /* VTL call */
+ call STATIC_CALL_TRAMP_STR(__hv_vsm_vtlcall_hypercall)
+
+ /* Restore args pointer from stack */
+ popq %rax
+
+ /* Store results back to struct */
+ mov %rdi, HV_VTLCALL_PARAM_a0(%rax)
+ mov %rsi, HV_VTLCALL_PARAM_a1(%rax)
+ mov %rdx, HV_VTLCALL_PARAM_a2(%rax)
+ mov %r8, HV_VTLCALL_PARAM_a3(%rax)
+
+ /* Restore callee-saved registers */
+ popq %rbx
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+
+ popq %rbp
+ RET
+SYM_FUNC_END(__hv_vsm_vtlcall)
+
+/*
+ * Ensure static_call_key symbol __SCK____hv_vsm_vtlcall_hypercall is
+ * accessible. Inspired by __ADDRESSABLE(sym) macro.
+ */
+ .section .discard.addressable,"aw"
+ .align 8
+ .type hv_vsm_vtlcall_sym, @object
+ .size hv_vsm_vtlcall_sym, 8
+hv_vsm_vtlcall_sym:
+ .quad __SCK____hv_vsm_vtlcall_hypercall
+#endif /* CONFIG_HYPERV_VSM */
diff --git a/include/hyperv/vsm.h b/include/hyperv/vsm.h
index 51555c09413d5..c1fa4ef3bccde 100644
--- a/include/hyperv/vsm.h
+++ b/include/hyperv/vsm.h
@@ -11,6 +11,8 @@
#ifndef _HYPERV_VSM_H
#define _HYPERV_VSM_H
+#include <linux/types.h>
+
/*
* Size of memory that is initially mapped for the secure kernel by the
* VTL0-side loader. The secure kernel image itself may be larger than
@@ -18,4 +20,24 @@
*/
#define VSM_SK_INITIAL_MAP_SIZE (16 * 1024 * 1024)
+/*
+ * Argument block passed from VTL0 to VTL1 across a vtlcall. Layout is
+ * shared with the arch-specific assembly trampoline that marshals these
+ * into registers.
+ */
+struct hv_vtlcall_param {
+ u64 a0;
+ u64 a1;
+ u64 a2;
+ u64 a3;
+} __packed;
+
+#ifdef CONFIG_HYPERV_VSM
+s64 hv_vsm_vtlcall(struct hv_vtlcall_param *args);
+void hv_vsm_init_vtlcall(u64 vtl_call_offset);
+#else
+static inline s64 hv_vsm_vtlcall(struct hv_vtlcall_param *args) { return 0; }
+static inline void hv_vsm_init_vtlcall(u64 vtl_call_offset) {}
+#endif
+
#endif /* _HYPERV_VSM_H */
--
2.34.1
next prev parent reply other threads:[~2026-09-01 16:57 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-01 16:55 [RFC PATCH 00/12] Introduce LVBS support for Hyper-V guests Thara Gopinath
2026-09-01 16:55 ` [RFC PATCH 01/12] drivers: hv: Add HYPERV_VSM kconfig option Thara Gopinath
2026-09-01 16:55 ` [RFC PATCH 02/12] drivers: hv: hv_common: Allocate Hyper-V output arg page when VSM is enabled Thara Gopinath
2026-09-01 17:12 ` sashiko-bot
2026-09-01 22:56 ` Wei Liu
2026-09-01 16:55 ` [RFC PATCH 03/12] drivers: hv: Reserve memory for VSM secure kernel during early boot Thara Gopinath
2026-09-01 17:10 ` sashiko-bot
2026-09-02 0:59 ` Wei Liu
2026-09-02 13:38 ` Thara Gopinath
2026-09-01 16:55 ` [RFC PATCH 04/12] firmware: efi: libstub: x86-stub: Enable VSM awareness in efi os indications variable Thara Gopinath
2026-09-01 17:09 ` sashiko-bot
2026-09-02 1:09 ` Wei Liu
2026-09-02 14:23 ` Thara Gopinath
2026-09-01 16:55 ` [RFC PATCH 05/12] include: hyperv: hvgdk_mini.h: Add VTL-specific structures and bits Thara Gopinath
2026-09-01 16:55 ` [RFC PATCH 06/12] drivers: hv: Add VSM boot driver and enable VTL1 at the partition level Thara Gopinath
2026-09-01 17:24 ` sashiko-bot
2026-09-02 1:16 ` Wei Liu
2026-09-02 14:28 ` Thara Gopinath
2026-09-02 4:43 ` Wei Liu
2026-09-04 13:23 ` Thara Gopinath
2026-09-01 16:55 ` [RFC PATCH 07/12] drivers: hv: hv_vsm_boot: load secure kernel image from firmware Thara Gopinath
2026-09-01 17:20 ` sashiko-bot
2026-09-02 4:37 ` Wei Liu
2026-09-02 16:22 ` Thara Gopinath
2026-09-02 22:58 ` Wei Liu
2026-09-01 16:55 ` [RFC PATCH 08/12] arch: x86: hyperv: Build initial vCPU context for VTL1 secure kernel Thara Gopinath
2026-09-01 17:25 ` sashiko-bot
2026-09-01 16:55 ` [RFC PATCH 09/12] drivers: hv: hv_vsm_boot: Enable VTL1 on the boot processor Thara Gopinath
2026-09-01 17:36 ` sashiko-bot
2026-09-01 16:55 ` Thara Gopinath [this message]
2026-09-01 16:55 ` [RFC PATCH 11/12] drivers: hv: hv_vsm_boot: Boot primary processor in VTL1 Thara Gopinath
2026-09-01 17:35 ` sashiko-bot
2026-09-01 16:55 ` [RFC PATCH 12/12] drivers: hv: hv_vsm_boot: Boot secondary processors " Thara Gopinath
2026-09-01 17:44 ` sashiko-bot
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=20260901165647.3160413-11-tgopinath@linux.microsoft.com \
--to=tgopinath@linux.microsoft.com \
--cc="longli@microsoft.com--cc=tzimmermann"@suse.de \
--cc=James.Bottomley@HansenPartnership.com \
--cc=ardb@kernel.org \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=decui@microsoft.com \
--cc=francescopompo2@gmail.com \
--cc=haiyangz@microsoft.com \
--cc=hpa@zytor.com \
--cc=ilias.apalodimas@linaro.org \
--cc=javierm@redhat.com \
--cc=kys@microsoft.com \
--cc=linux-efi@vger.kernel.org \
--cc=linux-hyperv@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lszubowi@redhat.com \
--cc=mingo@redhat.com \
--cc=tglx@kernel.org \
--cc=tgopinath@microsoft.com \
--cc=wei.liu@kernel.org \
--cc=x86@kernel.org \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.