> 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 <rom...@linux.microsoft.com>
> Signed-off-by: Roman Kisel <rom...@linux.microsoft.com>
> Co-developed-by: Saurabh Sengar <ssen...@linux.microsoft.com>
> Signed-off-by: Saurabh Sengar <ssen...@linux.microsoft.com>
> Signed-off-by: Naman Jain <namj...@linux.microsoft.com>
> ---
> 
> OpenVMM :
> https://nam06.safelinks.protection.outlook.com/?url=https%3A%2F%2Fopenv
> mm.dev%2Fguide%2F&data=05%7C02%7Cssengar%40microsoft.com%7Ce3b
> 0a61c2c72423aa33408dd8c7af2e9%7C72f988bf86f141af91ab2d7cd011db47%
> 7C1%7C0%7C638821181946438191%7CUnknown%7CTWFpbGZsb3d8eyJFbXB
> 0eU1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFp
> bCIsIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=uYUgaqKTazf0BL8ukdeUEor
> d9hN8NidMLwE19NdprlE%3D&reserved=0
> 
> ---
>  drivers/hv/Kconfig          |   20 +
>  drivers/hv/Makefile         |    3 +
>  drivers/hv/hv.c             |    2 +
>  drivers/hv/hyperv_vmbus.h   |    1 +
>  drivers/hv/mshv_vtl.h       |   52 ++
>  drivers/hv/mshv_vtl_main.c  | 1749
> +++++++++++++++++++++++++++++++++++
>  drivers/hv/vmbus_drv.c      |    3 +-
>  include/hyperv/hvgdk_mini.h |   81 ++
>  include/hyperv/hvhdk.h      |    1 +
>  include/uapi/linux/mshv.h   |   83 ++
>  10 files changed, 1994 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/hv/mshv_vtl.h
>  create mode 100644 drivers/hv/mshv_vtl_main.c
> 
> diff --git a/drivers/hv/Kconfig b/drivers/hv/Kconfig
> index 6c1416167bd2..57dcfcb69b88 100644
> --- a/drivers/hv/Kconfig
> +++ b/drivers/hv/Kconfig
> @@ -72,4 +72,24 @@ config MSHV_ROOT
> 
>         If unsure, say N.
> 
> +config MSHV_VTL
> +     bool "Microsoft Hyper-V VTL driver"
> +     depends on HYPERV && X86_64
> +     depends on TRANSPARENT_HUGEPAGE
> +     depends on OF
> +     # MTRRs are not per-VTL and are controlled by VTL0, so don't look at
> or mutate them.
> +     depends on !MTRR
> +     select CPUMASK_OFFSTACK
> +     select HYPERV_VTL_MODE
> +     default n
> +     help
> +       Select this option to enable Hyper-V VTL driver support.
> +       This driver provides interfaces for Virtual Machine Manager (VMM)
> running in VTL2
> +       userspace to create VTLs and partitions, setup and manage VTL0
> memory and
> +       allow userspace to make direct hypercalls. This also allows to map
> VTL0's address
> +       space to a usermode process in VTL2 and supports getting new
> VMBus messages and channel
> +       events in VTL2.
> +
> +       If unsure, say N.
> +
>  endmenu
> diff --git a/drivers/hv/Makefile b/drivers/hv/Makefile
> index 976189c725dc..5e785dae08cc 100644
> --- a/drivers/hv/Makefile
> +++ b/drivers/hv/Makefile
> @@ -3,6 +3,7 @@ obj-$(CONFIG_HYPERV)          += hv_vmbus.o
>  obj-$(CONFIG_HYPERV_UTILS)   += hv_utils.o
>  obj-$(CONFIG_HYPERV_BALLOON) += hv_balloon.o
>  obj-$(CONFIG_MSHV_ROOT)              += mshv_root.o
> +obj-$(CONFIG_MSHV_VTL)          += mshv_vtl.o
> 
>  CFLAGS_hv_trace.o = -I$(src)
>  CFLAGS_hv_balloon.o = -I$(src)
> @@ -18,3 +19,5 @@ mshv_root-y := mshv_root_main.o mshv_synic.o
> mshv_eventfd.o mshv_irq.o \
>  # Code that must be built-in
>  obj-$(subst m,y,$(CONFIG_HYPERV)) += hv_common.o
>  obj-$(subst m,y,$(CONFIG_MSHV_ROOT)) += hv_proc.o mshv_common.o
> +
> +mshv_vtl-y := mshv_vtl_main.o mshv_common.o
> diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
> index 308c8f279df8..11e8096fe840 100644
> --- a/drivers/hv/hv.c
> +++ b/drivers/hv/hv.c
> @@ -25,6 +25,7 @@
> 
>  /* The one and only */
>  struct hv_context hv_context;
> +EXPORT_SYMBOL_GPL(hv_context);
> 
>  /*
>   * hv_init - Main initialization routine.
> @@ -93,6 +94,7 @@ int hv_post_message(union hv_connection_id
> connection_id,
> 
>       return hv_result(status);
>  }
> +EXPORT_SYMBOL_GPL(hv_post_message);

All the exports should be in separate patch.

> 
>  int hv_synic_alloc(void)
>  {
> diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
> index 0b450e53161e..b61f01fc1960 100644
> --- a/drivers/hv/hyperv_vmbus.h
> +++ b/drivers/hv/hyperv_vmbus.h
> @@ -32,6 +32,7 @@
>   */
>  #define HV_UTIL_NEGO_TIMEOUT 55
> 
> +void vmbus_isr(void);
> 
>  /* Definitions for the monitored notification facility */
>  union hv_monitor_trigger_group {
> diff --git a/drivers/hv/mshv_vtl.h b/drivers/hv/mshv_vtl.h
> new file mode 100644
> index 000000000000..f350e4650d7b
> --- /dev/null
> +++ b/drivers/hv/mshv_vtl.h
> @@ -0,0 +1,52 @@
> +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
> +#ifndef _MSHV_VTL_H
> +#define _MSHV_VTL_H
> +
> +#include <linux/mshv.h>
> +#include <linux/types.h>
> +#include <asm/fpu/types.h>
> +
> +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;
> +};
> +
> +struct mshv_vtl_run {
> +     u32 cancel;
> +     u32 vtl_ret_action_size;
> +     u32 pad[2];
> +     char exit_message[MSHV_MAX_RUN_MSG_SIZE];
> +     union {
> +             struct mshv_vtl_cpu_context cpu_context;
> +
> +             /*
> +              * Reserving room for the cpu context to grow and be
> +              * able to maintain compat with user mode.
> +              */
> +             char reserved[1024];
> +     };
> +     char vtl_ret_actions[MSHV_MAX_RUN_MSG_SIZE];
> +};
> +
> +#endif /* _MSHV_VTL_H */
> diff --git a/drivers/hv/mshv_vtl_main.c b/drivers/hv/mshv_vtl_main.c
> new file mode 100644
> index 000000000000..95db29472fc8
> --- /dev/null
> +++ b/drivers/hv/mshv_vtl_main.c
> @@ -0,0 +1,1749 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2023, Microsoft Corporation.
> + *
> + * Author:
> + *   Roman Kisel <rom...@linux.microsoft.com>
> + *   Saurabh Sengar <ssen...@linux.microsoft.com>
> + *   Naman Jain <namj...@linux.microsoft.com>
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/miscdevice.h>
> +#include <linux/anon_inodes.h>
> +#include <linux/pfn_t.h>
> +#include <linux/cpuhotplug.h>
> +#include <linux/count_zeros.h>
> +#include <linux/eventfd.h>
> +#include <linux/poll.h>
> +#include <linux/file.h>
> +#include <linux/vmalloc.h>
> +#include <asm/debugreg.h>
> +#include <asm/mshyperv.h>
> +#include <trace/events/ipi.h>
> +#include <uapi/asm/mtrr.h>
> +#include <uapi/linux/mshv.h>
> +#include <hyperv/hvhdk.h>
> +
> +#include "../../kernel/fpu/legacy.h"
> +#include "mshv.h"
> +
> +#include "mshv_vtl.h"
> +#include "hyperv_vmbus.h"
> +

<snip>


> +
> +static const struct file_operations mshv_vtl_fops;
> +
> +static long
> +mshv_ioctl_create_vtl(void __user *user_arg, struct device *module_dev)
> +{
> +     struct mshv_vtl *vtl;
> +     struct file *file;
> +     int fd;
> +
> +     vtl = kzalloc(sizeof(*vtl), GFP_KERNEL);
> +     if (!vtl)
> +             return -ENOMEM;
> +
> +     fd = get_unused_fd_flags(O_CLOEXEC);
> +     if (fd < 0)
> +             return fd;
> +     file = anon_inode_getfile("mshv_vtl", &mshv_vtl_fops,
> +                               vtl, O_RDWR);
> +     if (IS_ERR(file))
> +             return PTR_ERR(file);
> +     refcount_set(&vtl->ref_count, 1);

Do we have any use of ref_count ? 

> +     vtl->module_dev = module_dev;
> +
> +     fd_install(fd, file);
> +
> +     return fd;
> +}

<snip>

> +static long
> +mshv_vtl_ioctl_get_set_regs(void __user *user_args, bool set)

I didn't find much use of this function. I don't see any problem with separate 
get and set functions.
But I will let you decide on this.

> +{
> +     struct mshv_vp_registers args;
> +     struct hv_register_assoc *registers;
> +     long ret;
> +
> +     if (copy_from_user(&args, user_args, sizeof(args)))
> +             return -EFAULT;
> +
> +     if (args.count == 0 || args.count > MSHV_VP_MAX_REGISTERS)
> +             return -EINVAL;
> +
> +     registers = kmalloc_array(args.count,
> +                               sizeof(*registers),
> +                               GFP_KERNEL);
> +     if (!registers)
> +             return -ENOMEM;
> +
> +     if (copy_from_user(registers, (void __user *)args.regs_ptr,
> +                        sizeof(*registers) * args.count)) {
> +             ret = -EFAULT;
> +             goto free_return;
> +     }
> +
> +     if (set) {
> +             ret = mshv_vtl_set_reg(registers);
> +             if (!ret)
> +                     goto free_return; /* No need of hypercall */
> +             ret = vtl_set_vp_registers(args.count, registers);
> +
> +     } else {
> +             ret = mshv_vtl_get_reg(registers);
> +             if (!ret)
> +                     goto copy_args; /* No need of hypercall */
> +             ret = vtl_get_vp_registers(args.count, registers);
> +             if (ret)
> +                     goto free_return;
> +
> +copy_args:
> +             if (copy_to_user((void __user *)args.regs_ptr, registers,
> +                              sizeof(*registers) * args.count))
> +                     ret = -EFAULT;
> +     }
> +
> +free_return:
> +     kfree(registers);
> +     return ret;
> +}
> +

<snip>

> +static int mshv_vtl_hvcall_call(struct mshv_vtl_hvcall_fd *fd,
> +                             struct mshv_vtl_hvcall __user *hvcall_user)
> +{
> +     struct mshv_vtl_hvcall hvcall;
> +     unsigned long flags;
> +     void *in, *out;
> +
> +     if (copy_from_user(&hvcall, hvcall_user, sizeof(struct
> mshv_vtl_hvcall)))
> +             return -EFAULT;
> +     if (hvcall.input_size > HV_HYP_PAGE_SIZE)
> +             return -EINVAL;
> +     if (hvcall.output_size > HV_HYP_PAGE_SIZE)
> +             return -EINVAL;
> +
> +     /*
> +      * By default, all hypercalls are not allowed.
> +      * The user mode code has to set up the allow bitmap once.
> +      */
> +
> +     if (!mshv_vtl_hvcall_is_allowed(fd, hvcall.control & 0xFFFF)) {
> +             dev_err(fd->dev->this_device,
> +                     "Hypercall with control data %#llx isn't allowed\n",
> +                     hvcall.control);
> +             return -EPERM;
> +     }
> +
> +     local_irq_save(flags);
> +     in = *this_cpu_ptr(hyperv_pcpu_input_arg);
> +     out = *this_cpu_ptr(hyperv_pcpu_output_arg);
> +
> +     if (copy_from_user(in, (void __user *)hvcall.input_ptr,
> hvcall.input_size)) {

Here is an issue related to usage of user copy functions when interrupt are 
disabled.
It was reported by Michael K here:
https://github.com/microsoft/OHCL-Linux-Kernel/issues/33

- Saurabh

Reply via email to