Skip to content

Commit 7bfe3b8

Browse files
Naman Jainliuw
authored andcommitted
Drivers: hv: Introduce mshv_vtl driver
Provide an interface for Virtual Machine Monitor like OpenVMM and its use as OpenHCL paravisor to control VTL0 (Virtual trust Level). Expose devices and support IOCTLs for features like VTL creation, VTL0 memory management, context switch, making hypercalls, mapping VTL0 address space to VTL2 userspace, getting new VMBus messages and channel events in VTL2 etc. Co-developed-by: Roman Kisel <romank@linux.microsoft.com> Signed-off-by: Roman Kisel <romank@linux.microsoft.com> Co-developed-by: Saurabh Sengar <ssengar@linux.microsoft.com> Signed-off-by: Saurabh Sengar <ssengar@linux.microsoft.com> Reviewed-by: Michael Kelley <mhklinux@outlook.com> Signed-off-by: Naman Jain <namjain@linux.microsoft.com> Signed-off-by: Wei Liu <wei.liu@kernel.org>
1 parent cffe9f5 commit 7bfe3b8

11 files changed

Lines changed: 1861 additions & 3 deletions

File tree

arch/x86/hyperv/Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
# SPDX-License-Identifier: GPL-2.0-only
22
obj-y := hv_init.o mmu.o nested.o irqdomain.o ivm.o
33
obj-$(CONFIG_X86_64) += hv_apic.o
4-
obj-$(CONFIG_HYPERV_VTL_MODE) += hv_vtl.o
4+
obj-$(CONFIG_HYPERV_VTL_MODE) += hv_vtl.o mshv_vtl_asm.o
5+
6+
$(obj)/mshv_vtl_asm.o: $(obj)/mshv-asm-offsets.h
7+
8+
$(obj)/mshv-asm-offsets.h: $(obj)/mshv-asm-offsets.s FORCE
9+
$(call filechk,offsets,__MSHV_ASM_OFFSETS_H__)
510

611
ifdef CONFIG_X86_64
712
obj-$(CONFIG_PARAVIRT_SPINLOCKS) += hv_spinlock.o
@@ -12,3 +17,6 @@ obj-$(CONFIG_PARAVIRT_SPINLOCKS) += hv_spinlock.o
1217
obj-$(CONFIG_CRASH_DUMP) += hv_crash.o hv_trampoline.o
1318
endif
1419
endif
20+
21+
targets += mshv-asm-offsets.s
22+
clean-files += mshv-asm-offsets.h

arch/x86/hyperv/hv_vtl.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,17 @@
99
#include <asm/apic.h>
1010
#include <asm/boot.h>
1111
#include <asm/desc.h>
12+
#include <asm/fpu/api.h>
13+
#include <asm/fpu/types.h>
1214
#include <asm/i8259.h>
1315
#include <asm/mshyperv.h>
1416
#include <asm/msr.h>
1517
#include <asm/realmode.h>
1618
#include <asm/reboot.h>
19+
#include <asm/smap.h>
20+
#include <linux/export.h>
1721
#include <../kernel/smpboot.h>
22+
#include "../../kernel/fpu/legacy.h"
1823

1924
extern struct boot_params boot_params;
2025
static struct real_mode_header hv_vtl_real_mode_header;
@@ -249,3 +254,28 @@ int __init hv_vtl_early_init(void)
249254

250255
return 0;
251256
}
257+
258+
DEFINE_STATIC_CALL_NULL(__mshv_vtl_return_hypercall, void (*)(void));
259+
260+
void mshv_vtl_return_call_init(u64 vtl_return_offset)
261+
{
262+
static_call_update(__mshv_vtl_return_hypercall,
263+
(void *)((u8 *)hv_hypercall_pg + vtl_return_offset));
264+
}
265+
EXPORT_SYMBOL(mshv_vtl_return_call_init);
266+
267+
void mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0)
268+
{
269+
struct hv_vp_assist_page *hvp;
270+
271+
hvp = hv_vp_assist_page[smp_processor_id()];
272+
hvp->vtl_ret_x64rax = vtl0->rax;
273+
hvp->vtl_ret_x64rcx = vtl0->rcx;
274+
275+
kernel_fpu_begin_mask(0);
276+
fxrstor(&vtl0->fx_state);
277+
__mshv_vtl_return_call(vtl0);
278+
fxsave(&vtl0->fx_state);
279+
kernel_fpu_end();
280+
}
281+
EXPORT_SYMBOL(mshv_vtl_return_call);

arch/x86/hyperv/mshv-asm-offsets.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Generate definitions needed by assembly language modules.
4+
* This code generates raw asm output which is post-processed to extract
5+
* and format the required data.
6+
*
7+
* Copyright (c) 2025, Microsoft Corporation.
8+
*
9+
* Author:
10+
* Naman Jain <namjain@microsoft.com>
11+
*/
12+
#define COMPILE_OFFSETS
13+
14+
#include <linux/kbuild.h>
15+
#include <asm/mshyperv.h>
16+
17+
static void __used common(void)
18+
{
19+
if (IS_ENABLED(CONFIG_HYPERV_VTL_MODE)) {
20+
OFFSET(MSHV_VTL_CPU_CONTEXT_rax, mshv_vtl_cpu_context, rax);
21+
OFFSET(MSHV_VTL_CPU_CONTEXT_rcx, mshv_vtl_cpu_context, rcx);
22+
OFFSET(MSHV_VTL_CPU_CONTEXT_rdx, mshv_vtl_cpu_context, rdx);
23+
OFFSET(MSHV_VTL_CPU_CONTEXT_rbx, mshv_vtl_cpu_context, rbx);
24+
OFFSET(MSHV_VTL_CPU_CONTEXT_rbp, mshv_vtl_cpu_context, rbp);
25+
OFFSET(MSHV_VTL_CPU_CONTEXT_rsi, mshv_vtl_cpu_context, rsi);
26+
OFFSET(MSHV_VTL_CPU_CONTEXT_rdi, mshv_vtl_cpu_context, rdi);
27+
OFFSET(MSHV_VTL_CPU_CONTEXT_r8, mshv_vtl_cpu_context, r8);
28+
OFFSET(MSHV_VTL_CPU_CONTEXT_r9, mshv_vtl_cpu_context, r9);
29+
OFFSET(MSHV_VTL_CPU_CONTEXT_r10, mshv_vtl_cpu_context, r10);
30+
OFFSET(MSHV_VTL_CPU_CONTEXT_r11, mshv_vtl_cpu_context, r11);
31+
OFFSET(MSHV_VTL_CPU_CONTEXT_r12, mshv_vtl_cpu_context, r12);
32+
OFFSET(MSHV_VTL_CPU_CONTEXT_r13, mshv_vtl_cpu_context, r13);
33+
OFFSET(MSHV_VTL_CPU_CONTEXT_r14, mshv_vtl_cpu_context, r14);
34+
OFFSET(MSHV_VTL_CPU_CONTEXT_r15, mshv_vtl_cpu_context, r15);
35+
OFFSET(MSHV_VTL_CPU_CONTEXT_cr2, mshv_vtl_cpu_context, cr2);
36+
}
37+
}

arch/x86/hyperv/mshv_vtl_asm.S

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/* SPDX-License-Identifier: GPL-2.0
2+
*
3+
* Assembly level code for mshv_vtl VTL transition
4+
*
5+
* Copyright (c) 2025, Microsoft Corporation.
6+
*
7+
* Author:
8+
* Naman Jain <namjain@microsoft.com>
9+
*/
10+
11+
#include <linux/linkage.h>
12+
#include <linux/static_call_types.h>
13+
#include <asm/asm.h>
14+
#include <asm/asm-offsets.h>
15+
#include <asm/frame.h>
16+
#include "mshv-asm-offsets.h"
17+
18+
.text
19+
.section .noinstr.text, "ax"
20+
/*
21+
* void __mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0)
22+
*
23+
* This function is used to context switch between different Virtual Trust Levels.
24+
* It is marked as 'noinstr' to prevent against instrumentation and debugging facilities.
25+
* NMIs aren't a problem because the NMI handler saves/restores CR2 specifically to guard
26+
* against #PFs in NMI context clobbering the guest state.
27+
*/
28+
SYM_FUNC_START(__mshv_vtl_return_call)
29+
/* Push callee save registers */
30+
pushq %rbp
31+
mov %rsp, %rbp
32+
pushq %r12
33+
pushq %r13
34+
pushq %r14
35+
pushq %r15
36+
pushq %rbx
37+
38+
/* register switch to VTL0 clobbers all registers except rax/rcx */
39+
mov %_ASM_ARG1, %rax
40+
41+
/* grab rbx/rbp/rsi/rdi/r8-r15 */
42+
mov MSHV_VTL_CPU_CONTEXT_rbx(%rax), %rbx
43+
mov MSHV_VTL_CPU_CONTEXT_rbp(%rax), %rbp
44+
mov MSHV_VTL_CPU_CONTEXT_rsi(%rax), %rsi
45+
mov MSHV_VTL_CPU_CONTEXT_rdi(%rax), %rdi
46+
mov MSHV_VTL_CPU_CONTEXT_r8(%rax), %r8
47+
mov MSHV_VTL_CPU_CONTEXT_r9(%rax), %r9
48+
mov MSHV_VTL_CPU_CONTEXT_r10(%rax), %r10
49+
mov MSHV_VTL_CPU_CONTEXT_r11(%rax), %r11
50+
mov MSHV_VTL_CPU_CONTEXT_r12(%rax), %r12
51+
mov MSHV_VTL_CPU_CONTEXT_r13(%rax), %r13
52+
mov MSHV_VTL_CPU_CONTEXT_r14(%rax), %r14
53+
mov MSHV_VTL_CPU_CONTEXT_r15(%rax), %r15
54+
55+
mov MSHV_VTL_CPU_CONTEXT_cr2(%rax), %rdx
56+
mov %rdx, %cr2
57+
mov MSHV_VTL_CPU_CONTEXT_rdx(%rax), %rdx
58+
59+
/* stash host registers on stack */
60+
pushq %rax
61+
pushq %rcx
62+
63+
xor %ecx, %ecx
64+
65+
/* make a hypercall to switch VTL */
66+
call STATIC_CALL_TRAMP_STR(__mshv_vtl_return_hypercall)
67+
68+
/* stash guest registers on stack, restore saved host copies */
69+
pushq %rax
70+
pushq %rcx
71+
mov 16(%rsp), %rcx
72+
mov 24(%rsp), %rax
73+
74+
mov %rdx, MSHV_VTL_CPU_CONTEXT_rdx(%rax)
75+
mov %cr2, %rdx
76+
mov %rdx, MSHV_VTL_CPU_CONTEXT_cr2(%rax)
77+
pop MSHV_VTL_CPU_CONTEXT_rcx(%rax)
78+
pop MSHV_VTL_CPU_CONTEXT_rax(%rax)
79+
add $16, %rsp
80+
81+
/* save rbx/rbp/rsi/rdi/r8-r15 */
82+
mov %rbx, MSHV_VTL_CPU_CONTEXT_rbx(%rax)
83+
mov %rbp, MSHV_VTL_CPU_CONTEXT_rbp(%rax)
84+
mov %rsi, MSHV_VTL_CPU_CONTEXT_rsi(%rax)
85+
mov %rdi, MSHV_VTL_CPU_CONTEXT_rdi(%rax)
86+
mov %r8, MSHV_VTL_CPU_CONTEXT_r8(%rax)
87+
mov %r9, MSHV_VTL_CPU_CONTEXT_r9(%rax)
88+
mov %r10, MSHV_VTL_CPU_CONTEXT_r10(%rax)
89+
mov %r11, MSHV_VTL_CPU_CONTEXT_r11(%rax)
90+
mov %r12, MSHV_VTL_CPU_CONTEXT_r12(%rax)
91+
mov %r13, MSHV_VTL_CPU_CONTEXT_r13(%rax)
92+
mov %r14, MSHV_VTL_CPU_CONTEXT_r14(%rax)
93+
mov %r15, MSHV_VTL_CPU_CONTEXT_r15(%rax)
94+
95+
/* pop callee-save registers r12-r15, rbx */
96+
pop %rbx
97+
pop %r15
98+
pop %r14
99+
pop %r13
100+
pop %r12
101+
102+
pop %rbp
103+
RET
104+
SYM_FUNC_END(__mshv_vtl_return_call)
105+
/*
106+
* Make sure that static_call_key symbol: __SCK____mshv_vtl_return_hypercall is accessible here.
107+
* Below code is inspired from __ADDRESSABLE(sym) macro. Symbol name is kept simple, to avoid
108+
* naming it something like "__UNIQUE_ID_addressable___SCK____mshv_vtl_return_hypercall_662.0"
109+
* which would otherwise have been generated by the macro.
110+
*/
111+
.section .discard.addressable,"aw"
112+
.align 8
113+
.type mshv_vtl_return_sym, @object
114+
.size mshv_vtl_return_sym, 8
115+
mshv_vtl_return_sym:
116+
.quad __SCK____mshv_vtl_return_hypercall

arch/x86/include/asm/mshyperv.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <asm/paravirt.h>
1212
#include <asm/msr.h>
1313
#include <hyperv/hvhdk.h>
14+
#include <asm/fpu/types.h>
1415

1516
/*
1617
* Hyper-V always provides a single IO-APIC at this MMIO address.
@@ -269,13 +270,46 @@ static inline u64 hv_get_non_nested_msr(unsigned int reg) { return 0; }
269270
static inline int hv_apicid_to_vp_index(u32 apic_id) { return -EINVAL; }
270271
#endif /* CONFIG_HYPERV */
271272

273+
struct mshv_vtl_cpu_context {
274+
union {
275+
struct {
276+
u64 rax;
277+
u64 rcx;
278+
u64 rdx;
279+
u64 rbx;
280+
u64 cr2;
281+
u64 rbp;
282+
u64 rsi;
283+
u64 rdi;
284+
u64 r8;
285+
u64 r9;
286+
u64 r10;
287+
u64 r11;
288+
u64 r12;
289+
u64 r13;
290+
u64 r14;
291+
u64 r15;
292+
};
293+
u64 gp_regs[16];
294+
};
295+
296+
struct fxregs_state fx_state;
297+
};
272298

273299
#ifdef CONFIG_HYPERV_VTL_MODE
274300
void __init hv_vtl_init_platform(void);
275301
int __init hv_vtl_early_init(void);
302+
void mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0);
303+
void mshv_vtl_return_call_init(u64 vtl_return_offset);
304+
void mshv_vtl_return_hypercall(void);
305+
void __mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0);
276306
#else
277307
static inline void __init hv_vtl_init_platform(void) {}
278308
static inline int __init hv_vtl_early_init(void) { return 0; }
309+
static inline void mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0) {}
310+
static inline void mshv_vtl_return_call_init(u64 vtl_return_offset) {}
311+
static inline void mshv_vtl_return_hypercall(void) {}
312+
static inline void __mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0) {}
279313
#endif
280314

281315
#include <asm-generic/mshyperv.h>

drivers/hv/Kconfig

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ config HYPERV
1717

1818
config HYPERV_VTL_MODE
1919
bool "Enable Linux to boot in VTL context"
20-
depends on (X86_64 || ARM64) && HYPERV
20+
depends on (X86_64 && HAVE_STATIC_CALL) || ARM64
21+
depends on HYPERV
2122
depends on SMP
2223
default n
2324
help
@@ -82,4 +83,28 @@ config MSHV_ROOT
8283

8384
If unsure, say N.
8485

86+
config MSHV_VTL
87+
tristate "Microsoft Hyper-V VTL driver"
88+
depends on X86_64 && HYPERV_VTL_MODE
89+
depends on HYPERV_VMBUS
90+
# Mapping VTL0 memory to a userspace process in VTL2 is supported in OpenHCL.
91+
# VTL2 for OpenHCL makes use of Huge Pages to improve performance on VMs,
92+
# specially with large memory requirements.
93+
depends on TRANSPARENT_HUGEPAGE
94+
# MTRRs are controlled by VTL0, and are not specific to individual VTLs.
95+
# Therefore, do not attempt to access or modify MTRRs here.
96+
depends on !MTRR
97+
select CPUMASK_OFFSTACK
98+
select VIRT_XFER_TO_GUEST_WORK
99+
default n
100+
help
101+
Select this option to enable Hyper-V VTL driver support.
102+
This driver provides interfaces for Virtual Machine Manager (VMM) running in VTL2
103+
userspace to create VTLs and partitions, setup and manage VTL0 memory and
104+
allow userspace to make direct hypercalls. This also allows to map VTL0's address
105+
space to a usermode process in VTL2 and supports getting new VMBus messages and channel
106+
events in VTL2.
107+
108+
If unsure, say N.
109+
85110
endmenu

drivers/hv/Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ obj-$(CONFIG_HYPERV_VMBUS) += hv_vmbus.o
33
obj-$(CONFIG_HYPERV_UTILS) += hv_utils.o
44
obj-$(CONFIG_HYPERV_BALLOON) += hv_balloon.o
55
obj-$(CONFIG_MSHV_ROOT) += mshv_root.o
6+
obj-$(CONFIG_MSHV_VTL) += mshv_vtl.o
67

78
CFLAGS_hv_trace.o = -I$(src)
89
CFLAGS_hv_balloon.o = -I$(src)
@@ -14,7 +15,11 @@ hv_vmbus-$(CONFIG_HYPERV_TESTING) += hv_debugfs.o
1415
hv_utils-y := hv_util.o hv_kvp.o hv_snapshot.o hv_utils_transport.o
1516
mshv_root-y := mshv_root_main.o mshv_synic.o mshv_eventfd.o mshv_irq.o \
1617
mshv_root_hv_call.o mshv_portid_table.o
18+
mshv_vtl-y := mshv_vtl_main.o
1719

1820
# Code that must be built-in
1921
obj-$(CONFIG_HYPERV) += hv_common.o
20-
obj-$(subst m,y,$(CONFIG_MSHV_ROOT)) += hv_proc.o mshv_common.o
22+
obj-$(subst m,y,$(CONFIG_MSHV_ROOT)) += hv_proc.o
23+
ifneq ($(CONFIG_MSHV_ROOT)$(CONFIG_MSHV_VTL),)
24+
obj-y += mshv_common.o
25+
endif

drivers/hv/mshv_vtl.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2+
#ifndef _MSHV_VTL_H
3+
#define _MSHV_VTL_H
4+
5+
#include <linux/mshv.h>
6+
#include <linux/types.h>
7+
8+
struct mshv_vtl_run {
9+
u32 cancel;
10+
u32 vtl_ret_action_size;
11+
u32 pad[2];
12+
char exit_message[MSHV_MAX_RUN_MSG_SIZE];
13+
union {
14+
struct mshv_vtl_cpu_context cpu_context;
15+
16+
/*
17+
* Reserving room for the cpu context to grow and to maintain compatibility
18+
* with user mode.
19+
*/
20+
char reserved[1024];
21+
};
22+
char vtl_ret_actions[MSHV_MAX_RUN_MSG_SIZE];
23+
};
24+
25+
#endif /* _MSHV_VTL_H */

0 commit comments

Comments
 (0)