Commit 7bfe3b8e authored by Naman Jain's avatar Naman Jain Committed by Wei Liu
Browse files

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: default avatarRoman Kisel <romank@linux.microsoft.com>
Signed-off-by: default avatarRoman Kisel <romank@linux.microsoft.com>
Co-developed-by: default avatarSaurabh Sengar <ssengar@linux.microsoft.com>
Signed-off-by: default avatarSaurabh Sengar <ssengar@linux.microsoft.com>
Reviewed-by: default avatarMichael Kelley <mhklinux@outlook.com>
Signed-off-by: default avatarNaman Jain <namjain@linux.microsoft.com>
Signed-off-by: default avatarWei Liu <wei.liu@kernel.org>
parent cffe9f58
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
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
obj-$(CONFIG_HYPERV_VTL_MODE)	+= hv_vtl.o mshv_vtl_asm.o

$(obj)/mshv_vtl_asm.o: $(obj)/mshv-asm-offsets.h

$(obj)/mshv-asm-offsets.h: $(obj)/mshv-asm-offsets.s FORCE
	$(call filechk,offsets,__MSHV_ASM_OFFSETS_H__)

ifdef CONFIG_X86_64
obj-$(CONFIG_PARAVIRT_SPINLOCKS)	+= hv_spinlock.o
@@ -12,3 +17,6 @@ obj-$(CONFIG_PARAVIRT_SPINLOCKS) += hv_spinlock.o
  obj-$(CONFIG_CRASH_DUMP)      += hv_crash.o hv_trampoline.o
 endif
endif

targets += mshv-asm-offsets.s
clean-files += mshv-asm-offsets.h
+30 −0
Original line number Diff line number Diff line
@@ -9,12 +9,17 @@
#include <asm/apic.h>
#include <asm/boot.h>
#include <asm/desc.h>
#include <asm/fpu/api.h>
#include <asm/fpu/types.h>
#include <asm/i8259.h>
#include <asm/mshyperv.h>
#include <asm/msr.h>
#include <asm/realmode.h>
#include <asm/reboot.h>
#include <asm/smap.h>
#include <linux/export.h>
#include <../kernel/smpboot.h>
#include "../../kernel/fpu/legacy.h"

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

	return 0;
}

DEFINE_STATIC_CALL_NULL(__mshv_vtl_return_hypercall, void (*)(void));

void mshv_vtl_return_call_init(u64 vtl_return_offset)
{
	static_call_update(__mshv_vtl_return_hypercall,
			   (void *)((u8 *)hv_hypercall_pg + vtl_return_offset));
}
EXPORT_SYMBOL(mshv_vtl_return_call_init);

void mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0)
{
	struct hv_vp_assist_page *hvp;

	hvp = hv_vp_assist_page[smp_processor_id()];
	hvp->vtl_ret_x64rax = vtl0->rax;
	hvp->vtl_ret_x64rcx = vtl0->rcx;

	kernel_fpu_begin_mask(0);
	fxrstor(&vtl0->fx_state);
	__mshv_vtl_return_call(vtl0);
	fxsave(&vtl0->fx_state);
	kernel_fpu_end();
}
EXPORT_SYMBOL(mshv_vtl_return_call);
+37 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Generate definitions needed by assembly language modules.
 * This code generates raw asm output which is post-processed to extract
 * and format the required data.
 *
 * Copyright (c) 2025, Microsoft Corporation.
 *
 * Author:
 *   Naman Jain <namjain@microsoft.com>
 */
#define COMPILE_OFFSETS

#include <linux/kbuild.h>
#include <asm/mshyperv.h>

static void __used common(void)
{
	if (IS_ENABLED(CONFIG_HYPERV_VTL_MODE)) {
		OFFSET(MSHV_VTL_CPU_CONTEXT_rax, mshv_vtl_cpu_context, rax);
		OFFSET(MSHV_VTL_CPU_CONTEXT_rcx, mshv_vtl_cpu_context, rcx);
		OFFSET(MSHV_VTL_CPU_CONTEXT_rdx, mshv_vtl_cpu_context, rdx);
		OFFSET(MSHV_VTL_CPU_CONTEXT_rbx, mshv_vtl_cpu_context, rbx);
		OFFSET(MSHV_VTL_CPU_CONTEXT_rbp, mshv_vtl_cpu_context, rbp);
		OFFSET(MSHV_VTL_CPU_CONTEXT_rsi, mshv_vtl_cpu_context, rsi);
		OFFSET(MSHV_VTL_CPU_CONTEXT_rdi, mshv_vtl_cpu_context, rdi);
		OFFSET(MSHV_VTL_CPU_CONTEXT_r8,  mshv_vtl_cpu_context, r8);
		OFFSET(MSHV_VTL_CPU_CONTEXT_r9,  mshv_vtl_cpu_context, r9);
		OFFSET(MSHV_VTL_CPU_CONTEXT_r10, mshv_vtl_cpu_context, r10);
		OFFSET(MSHV_VTL_CPU_CONTEXT_r11, mshv_vtl_cpu_context, r11);
		OFFSET(MSHV_VTL_CPU_CONTEXT_r12, mshv_vtl_cpu_context, r12);
		OFFSET(MSHV_VTL_CPU_CONTEXT_r13, mshv_vtl_cpu_context, r13);
		OFFSET(MSHV_VTL_CPU_CONTEXT_r14, mshv_vtl_cpu_context, r14);
		OFFSET(MSHV_VTL_CPU_CONTEXT_r15, mshv_vtl_cpu_context, r15);
		OFFSET(MSHV_VTL_CPU_CONTEXT_cr2, mshv_vtl_cpu_context, cr2);
	}
}
+116 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0
 *
 * Assembly level code for mshv_vtl VTL transition
 *
 * Copyright (c) 2025, Microsoft Corporation.
 *
 * Author:
 *   Naman Jain <namjain@microsoft.com>
 */

#include <linux/linkage.h>
#include <linux/static_call_types.h>
#include <asm/asm.h>
#include <asm/asm-offsets.h>
#include <asm/frame.h>
#include "mshv-asm-offsets.h"

	.text
	.section .noinstr.text, "ax"
/*
 * void __mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0)
 *
 * This function is used to context switch between different Virtual Trust Levels.
 * It is marked as 'noinstr' to prevent against instrumentation and debugging facilities.
 * NMIs aren't a problem because the NMI handler saves/restores CR2 specifically to guard
 * against #PFs in NMI context clobbering the guest state.
 */
SYM_FUNC_START(__mshv_vtl_return_call)
	/* Push callee save registers */
	pushq %rbp
	mov %rsp, %rbp
	pushq %r12
	pushq %r13
	pushq %r14
	pushq %r15
	pushq %rbx

	/* register switch to VTL0 clobbers all registers except rax/rcx */
	mov %_ASM_ARG1, %rax

	/* grab rbx/rbp/rsi/rdi/r8-r15 */
	mov MSHV_VTL_CPU_CONTEXT_rbx(%rax), %rbx
	mov MSHV_VTL_CPU_CONTEXT_rbp(%rax), %rbp
	mov MSHV_VTL_CPU_CONTEXT_rsi(%rax), %rsi
	mov MSHV_VTL_CPU_CONTEXT_rdi(%rax), %rdi
	mov MSHV_VTL_CPU_CONTEXT_r8(%rax), %r8
	mov MSHV_VTL_CPU_CONTEXT_r9(%rax), %r9
	mov MSHV_VTL_CPU_CONTEXT_r10(%rax), %r10
	mov MSHV_VTL_CPU_CONTEXT_r11(%rax), %r11
	mov MSHV_VTL_CPU_CONTEXT_r12(%rax), %r12
	mov MSHV_VTL_CPU_CONTEXT_r13(%rax), %r13
	mov MSHV_VTL_CPU_CONTEXT_r14(%rax), %r14
	mov MSHV_VTL_CPU_CONTEXT_r15(%rax), %r15

	mov MSHV_VTL_CPU_CONTEXT_cr2(%rax), %rdx
	mov %rdx, %cr2
	mov MSHV_VTL_CPU_CONTEXT_rdx(%rax), %rdx

	/* stash host registers on stack */
	pushq %rax
	pushq %rcx

	xor %ecx, %ecx

	/* make a hypercall to switch VTL */
	call STATIC_CALL_TRAMP_STR(__mshv_vtl_return_hypercall)

	/* stash guest registers on stack, restore saved host copies */
	pushq %rax
	pushq %rcx
	mov 16(%rsp), %rcx
	mov 24(%rsp), %rax

	mov %rdx, MSHV_VTL_CPU_CONTEXT_rdx(%rax)
	mov %cr2, %rdx
	mov %rdx, MSHV_VTL_CPU_CONTEXT_cr2(%rax)
	pop MSHV_VTL_CPU_CONTEXT_rcx(%rax)
	pop MSHV_VTL_CPU_CONTEXT_rax(%rax)
	add $16, %rsp

	/* save rbx/rbp/rsi/rdi/r8-r15 */
	mov %rbx, MSHV_VTL_CPU_CONTEXT_rbx(%rax)
	mov %rbp, MSHV_VTL_CPU_CONTEXT_rbp(%rax)
	mov %rsi, MSHV_VTL_CPU_CONTEXT_rsi(%rax)
	mov %rdi, MSHV_VTL_CPU_CONTEXT_rdi(%rax)
	mov %r8,  MSHV_VTL_CPU_CONTEXT_r8(%rax)
	mov %r9,  MSHV_VTL_CPU_CONTEXT_r9(%rax)
	mov %r10, MSHV_VTL_CPU_CONTEXT_r10(%rax)
	mov %r11, MSHV_VTL_CPU_CONTEXT_r11(%rax)
	mov %r12, MSHV_VTL_CPU_CONTEXT_r12(%rax)
	mov %r13, MSHV_VTL_CPU_CONTEXT_r13(%rax)
	mov %r14, MSHV_VTL_CPU_CONTEXT_r14(%rax)
	mov %r15, MSHV_VTL_CPU_CONTEXT_r15(%rax)

	/* pop callee-save registers r12-r15, rbx */
	pop %rbx
	pop %r15
	pop %r14
	pop %r13
	pop %r12

	pop %rbp
	RET
SYM_FUNC_END(__mshv_vtl_return_call)
/*
 * Make sure that static_call_key symbol: __SCK____mshv_vtl_return_hypercall is accessible here.
 * Below code is inspired from __ADDRESSABLE(sym) macro. Symbol name is kept simple, to avoid
 * naming it something like "__UNIQUE_ID_addressable___SCK____mshv_vtl_return_hypercall_662.0"
 * which would otherwise have been generated by the macro.
 */
	.section	.discard.addressable,"aw"
	.align 8
	.type	mshv_vtl_return_sym, @object
	.size	mshv_vtl_return_sym, 8
mshv_vtl_return_sym:
	.quad	__SCK____mshv_vtl_return_hypercall
+34 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <asm/paravirt.h>
#include <asm/msr.h>
#include <hyperv/hvhdk.h>
#include <asm/fpu/types.h>

/*
 * 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; }
static inline int hv_apicid_to_vp_index(u32 apic_id) { return -EINVAL; }
#endif /* CONFIG_HYPERV */

struct mshv_vtl_cpu_context {
	union {
		struct {
			u64 rax;
			u64 rcx;
			u64 rdx;
			u64 rbx;
			u64 cr2;
			u64 rbp;
			u64 rsi;
			u64 rdi;
			u64 r8;
			u64 r9;
			u64 r10;
			u64 r11;
			u64 r12;
			u64 r13;
			u64 r14;
			u64 r15;
		};
		u64 gp_regs[16];
	};

	struct fxregs_state fx_state;
};

#ifdef CONFIG_HYPERV_VTL_MODE
void __init hv_vtl_init_platform(void);
int __init hv_vtl_early_init(void);
void mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0);
void mshv_vtl_return_call_init(u64 vtl_return_offset);
void mshv_vtl_return_hypercall(void);
void __mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0);
#else
static inline void __init hv_vtl_init_platform(void) {}
static inline int __init hv_vtl_early_init(void) { return 0; }
static inline void mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0) {}
static inline void mshv_vtl_return_call_init(u64 vtl_return_offset) {}
static inline void mshv_vtl_return_hypercall(void) {}
static inline void __mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0) {}
#endif

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