From: Yingshiuan Pan <yingshiuan.pan@xxxxxxxxxxxx> The VM component is responsible for setting up the capability and memory management for the protected VMs. The capability is mainly about the lifecycle control and boot context initialization. Signed-off-by: Yingshiuan Pan <yingshiuan.pan@xxxxxxxxxxxx> Co-developed-by: Jerry Wang <ze-yu.wang@xxxxxxxxxxxx> Signed-off-by: Jerry Wang <ze-yu.wang@xxxxxxxxxxxx> Signed-off-by: Yi-De Wu <yi-de.wu@xxxxxxxxxxxx> Signed-off-by: Liju Chen <liju-clr.chen@xxxxxxxxxxxx> --- MAINTAINERS | 1 + arch/arm64/geniezone/gzvm_arch_common.h | 4 ++ arch/arm64/geniezone/vm.c | 27 +++++++ drivers/virt/geniezone/Makefile | 2 +- drivers/virt/geniezone/gzvm_main.c | 15 ++++ drivers/virt/geniezone/gzvm_vm.c | 93 +++++++++++++++++++++++++ include/linux/soc/mediatek/gzvm_drv.h | 29 ++++++++ include/uapi/linux/gzvm.h | 25 +++++++ 8 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 drivers/virt/geniezone/gzvm_vm.c create mode 100644 include/uapi/linux/gzvm.h diff --git a/MAINTAINERS b/MAINTAINERS index 708c13103ec5..e7fd6f6a4350 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9680,6 +9680,7 @@ F: Documentation/virt/geniezone/ F: arch/arm64/geniezone/ F: drivers/virt/geniezone/ F: include/linux/soc/mediatek/gzvm_drv.h +F: include/uapi/linux/gzvm.h GENWQE (IBM Generic Workqueue Card) M: Frank Haverkamp <haver@xxxxxxxxxxxxx> diff --git a/arch/arm64/geniezone/gzvm_arch_common.h b/arch/arm64/geniezone/gzvm_arch_common.h index 660c7cf3fc18..60ee5ed2b39f 100644 --- a/arch/arm64/geniezone/gzvm_arch_common.h +++ b/arch/arm64/geniezone/gzvm_arch_common.h @@ -9,6 +9,8 @@ #include <linux/arm-smccc.h> enum { + GZVM_FUNC_CREATE_VM = 0, + GZVM_FUNC_DESTROY_VM = 1, GZVM_FUNC_PROBE = 12, NR_GZVM_FUNC, }; @@ -19,6 +21,8 @@ enum { ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \ SMC_ENTITY_MTK, (GZVM_FUNCID_START + (func))) +#define MT_HVC_GZVM_CREATE_VM GZVM_HCALL_ID(GZVM_FUNC_CREATE_VM) +#define MT_HVC_GZVM_DESTROY_VM GZVM_HCALL_ID(GZVM_FUNC_DESTROY_VM) #define MT_HVC_GZVM_PROBE GZVM_HCALL_ID(GZVM_FUNC_PROBE) /** diff --git a/arch/arm64/geniezone/vm.c b/arch/arm64/geniezone/vm.c index daad21b28f6f..8e3c9f872bb1 100644 --- a/arch/arm64/geniezone/vm.c +++ b/arch/arm64/geniezone/vm.c @@ -7,6 +7,7 @@ #include <linux/err.h> #include <linux/uaccess.h> +#include <linux/gzvm.h> #include <linux/soc/mediatek/gzvm_drv.h> #include "gzvm_arch_common.h" @@ -70,3 +71,29 @@ int gzvm_arch_probe(struct gzvm_version drv_version, return 0; } + +/** + * gzvm_arch_create_vm() - create vm + * @vm_type: VM type. Only supports Linux VM now. + * + * Return: + * * positive value - VM ID + * * -ENOMEM - Memory not enough for storing VM data + */ +int gzvm_arch_create_vm(unsigned long vm_type) +{ + struct arm_smccc_res res; + int ret; + + ret = gzvm_hypcall_wrapper(MT_HVC_GZVM_CREATE_VM, vm_type, 0, 0, 0, 0, + 0, 0, &res); + return ret ? ret : res.a1; +} + +int gzvm_arch_destroy_vm(u16 vm_id) +{ + struct arm_smccc_res res; + + return gzvm_hypcall_wrapper(MT_HVC_GZVM_DESTROY_VM, vm_id, 0, 0, 0, 0, + 0, 0, &res); +} diff --git a/drivers/virt/geniezone/Makefile b/drivers/virt/geniezone/Makefile index 3a82e5fddf90..25614ea3dea2 100644 --- a/drivers/virt/geniezone/Makefile +++ b/drivers/virt/geniezone/Makefile @@ -6,4 +6,4 @@ GZVM_DIR ?= ../../../drivers/virt/geniezone -gzvm-y := $(GZVM_DIR)/gzvm_main.o +gzvm-y := $(GZVM_DIR)/gzvm_main.o $(GZVM_DIR)/gzvm_vm.o diff --git a/drivers/virt/geniezone/gzvm_main.c b/drivers/virt/geniezone/gzvm_main.c index dc91fd61ba75..02dec63ce48f 100644 --- a/drivers/virt/geniezone/gzvm_main.c +++ b/drivers/virt/geniezone/gzvm_main.c @@ -4,6 +4,7 @@ */ #include <linux/device.h> +#include <linux/file.h> #include <linux/kdev_t.h> #include <linux/miscdevice.h> #include <linux/module.h> @@ -48,6 +49,19 @@ int gzvm_err_to_errno(unsigned long err) return -EINVAL; } +static long gzvm_dev_ioctl(struct file *filp, unsigned int cmd, + unsigned long user_args) +{ + switch (cmd) { + case GZVM_CREATE_VM: + return gzvm_dev_ioctl_create_vm(&gzvm_drv, user_args); + default: + break; + } + + return -ENOTTY; +} + static int gzvm_dev_open(struct inode *inode, struct file *file) { /* @@ -65,6 +79,7 @@ static int gzvm_dev_release(struct inode *inode, struct file *file) } static const struct file_operations gzvm_chardev_ops = { + .unlocked_ioctl = gzvm_dev_ioctl, .llseek = noop_llseek, .open = gzvm_dev_open, .release = gzvm_dev_release, diff --git a/drivers/virt/geniezone/gzvm_vm.c b/drivers/virt/geniezone/gzvm_vm.c new file mode 100644 index 000000000000..500bc8276d60 --- /dev/null +++ b/drivers/virt/geniezone/gzvm_vm.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +#include <linux/anon_inodes.h> +#include <linux/file.h> +#include <linux/kdev_t.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/soc/mediatek/gzvm_drv.h> + +static DEFINE_MUTEX(gzvm_list_lock); +static LIST_HEAD(gzvm_list); + +static void gzvm_destroy_vm(struct gzvm *gzvm) +{ + pr_debug("VM-%u is going to be destroyed\n", gzvm->vm_id); + + mutex_lock(&gzvm->lock); + + gzvm_arch_destroy_vm(gzvm->vm_id); + + mutex_lock(&gzvm_list_lock); + list_del(&gzvm->vm_list); + mutex_unlock(&gzvm_list_lock); + + mutex_unlock(&gzvm->lock); + + kfree(gzvm); +} + +static int gzvm_vm_release(struct inode *inode, struct file *filp) +{ + struct gzvm *gzvm = filp->private_data; + + gzvm_destroy_vm(gzvm); + return 0; +} + +static const struct file_operations gzvm_vm_fops = { + .release = gzvm_vm_release, +}; + +static struct gzvm *gzvm_create_vm(struct gzvm_driver *drv, unsigned long vm_type) +{ + int ret; + struct gzvm *gzvm; + + gzvm = kzalloc(sizeof(*gzvm), GFP_KERNEL); + if (!gzvm) + return ERR_PTR(-ENOMEM); + + ret = gzvm_arch_create_vm(vm_type); + if (ret < 0) { + kfree(gzvm); + return ERR_PTR(ret); + } + + gzvm->gzvm_drv = drv; + gzvm->vm_id = ret; + gzvm->mm = current->mm; + mutex_init(&gzvm->lock); + + mutex_lock(&gzvm_list_lock); + list_add(&gzvm->vm_list, &gzvm_list); + mutex_unlock(&gzvm_list_lock); + + pr_debug("VM-%u is created\n", gzvm->vm_id); + + return gzvm; +} + +/** + * gzvm_dev_ioctl_create_vm - Create vm fd + * @vm_type: VM type. Only supports Linux VM now + * @drv: GenieZone driver info to be stored in struct gzvm for future usage + * + * Return: fd of vm, negative if error + */ +int gzvm_dev_ioctl_create_vm(struct gzvm_driver *drv, unsigned long vm_type) +{ + struct gzvm *gzvm; + + gzvm = gzvm_create_vm(drv, vm_type); + if (IS_ERR(gzvm)) + return PTR_ERR(gzvm); + + return anon_inode_getfd("gzvm-vm", &gzvm_vm_fops, gzvm, + O_RDWR | O_CLOEXEC); +} diff --git a/include/linux/soc/mediatek/gzvm_drv.h b/include/linux/soc/mediatek/gzvm_drv.h index 495bf5b8b8e0..70008afaaf61 100644 --- a/include/linux/soc/mediatek/gzvm_drv.h +++ b/include/linux/soc/mediatek/gzvm_drv.h @@ -6,6 +6,10 @@ #ifndef __GZVM_DRV_H__ #define __GZVM_DRV_H__ +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/gzvm.h> + /* GZVM version encode */ #define GZVM_DRV_MAJOR_VERSION 16 #define GZVM_DRV_MINOR_VERSION 0 @@ -21,6 +25,8 @@ struct gzvm_driver { struct gzvm_version drv_version; }; +#define INVALID_VM_ID 0xffff + /* * These are the definitions of APIs between GenieZone hypervisor and driver, * there's no need to be visible to uapi. Furthermore, we need GenieZone @@ -32,10 +38,33 @@ struct gzvm_driver { #define ERR_NOT_IMPLEMENTED (-27) #define ERR_FAULT (-40) +/** + * struct gzvm: the following data structures are for data transferring between + * driver and hypervisor, and they're aligned with hypervisor definitions. + * @gzvm_drv: the data structure is used to keep driver's information + * @mm: userspace tied to this vm + * @lock: lock for list_add + * @vm_list: list head for vm list + * @vm_id: vm id + */ +struct gzvm { + struct gzvm_driver *gzvm_drv; + struct mm_struct *mm; + struct mutex lock; + struct list_head vm_list; + u16 vm_id; +}; + +int gzvm_dev_ioctl_create_vm(struct gzvm_driver *drv, unsigned long vm_type); + int gzvm_err_to_errno(unsigned long err); +void gzvm_destroy_all_vms(void); + /* arch-dependant functions */ int gzvm_arch_probe(struct gzvm_version drv_version, struct gzvm_version *hyp_version); +int gzvm_arch_create_vm(unsigned long vm_type); +int gzvm_arch_destroy_vm(u16 vm_id); #endif /* __GZVM_DRV_H__ */ diff --git a/include/uapi/linux/gzvm.h b/include/uapi/linux/gzvm.h new file mode 100644 index 000000000000..c26c7720fab7 --- /dev/null +++ b/include/uapi/linux/gzvm.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (c) 2023 MediaTek Inc. + */ + +/** + * DOC: UAPI of GenieZone Hypervisor + * + * This file declares common data structure shared among user space, + * kernel space, and GenieZone hypervisor. + */ +#ifndef __GZVM_H__ +#define __GZVM_H__ + +#include <linux/const.h> +#include <linux/types.h> +#include <linux/ioctl.h> + +/* GZVM ioctls */ +#define GZVM_IOC_MAGIC 0x92 /* gz */ + +/* ioctls for /dev/gzvm fds */ +#define GZVM_CREATE_VM _IO(GZVM_IOC_MAGIC, 0x01) /* Returns a Geniezone VM fd */ + +#endif /* __GZVM_H__ */ -- 2.18.0