From 114894bf69269735e0ac2654084c2f9cabbb6b41 Mon Sep 17 00:00:00 2001 From: Haiwei Li Date: Tue, 28 Nov 2023 13:35:56 +0800 Subject: [PATCH] PM: ACRN: add s3 support for User VM This patchset is introduced to support s3. Three related ioctl and hypercall are added. ACRN_IOCTL_GET_CAPS is used to get capabilities from acrn-hypervisor. ACRN_CAP_RESET_VM_V2 and ACRN_CAP_SET_REG are offered now. ACRN_IOCTL_RESET_VM_V2 is used to reset vm with some options. This feature is available when capability ACRN_CAP_RESET_VM_V2 is offered. ACRN_IOCTL_SET_ONE_REG is used to set one reg of a vcpu from the vm. This feature is available when capability ACRN_CAP_SET_REG is offered. Signed-off-by: Haiwei Li --- arch/x86/include/asm/acrn.h | 4 +++ drivers/virt/acrn/hsm.c | 63 ++++++++++++++++++++++++++++++++++- drivers/virt/acrn/hypercall.h | 42 +++++++++++++++++++++++ include/uapi/linux/acrn.h | 52 +++++++++++++++++++++++++++++ 4 files changed, 160 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/acrn.h b/arch/x86/include/asm/acrn.h index 1dd14381bcb63..601cbcb517f22 100644 --- a/arch/x86/include/asm/acrn.h +++ b/arch/x86/include/asm/acrn.h @@ -19,6 +19,10 @@ */ #define ACRN_CPUID_TIMING_INFO 0x40000010 +/* Select x86 specific features in */ +#define __ACRN_HAVE_RESET_VM_V2 +#define __ACRN_HAVE_SET_REG + void acrn_setup_intr_handler(void (*handler)(void)); void acrn_remove_intr_handler(void); diff --git a/drivers/virt/acrn/hsm.c b/drivers/virt/acrn/hsm.c index 2c1540d6765bb..f3a957524441e 100644 --- a/drivers/virt/acrn/hsm.c +++ b/drivers/virt/acrn/hsm.c @@ -101,6 +101,22 @@ static int pmcmd_ioctl(u64 cmd, void __user *uptr) return ret; } +static bool cmd_without_vm(unsigned int cmd) +{ + const unsigned int cmds[] = { + ACRN_IOCTL_CREATE_VM, + ACRN_IOCTL_GET_CAPS + }; + int i; + + for (i = 0; i < ARRAY_SIZE(cmds); i++) { + if (cmd == cmds[i]) + return true; + } + + return false; +} + /* * HSM relies on hypercall layer of the ACRN hypervisor to do the * sanity check against the input parameters. @@ -109,6 +125,8 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long ioctl_param) { struct acrn_vm *vm = filp->private_data; + struct acrn_vm_reset_state *vm_reset; + struct acrn_cap_bitmap *cap_bitmap; struct acrn_vm_creation *vm_param; struct acrn_vcpu_regs *cpu_regs; struct acrn_ioreq_notify notify; @@ -116,6 +134,7 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd, struct acrn_ioeventfd ioeventfd; struct acrn_vm_memmap memmap; struct acrn_mmiodev *mmiodev; + struct acrn_one_reg *one_reg; struct acrn_msi_entry *msi; struct acrn_pcidev *pcidev; struct acrn_irqfd irqfd; @@ -124,7 +143,7 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd, u64 cstate_cmd; int i, ret = 0; - if (vm->vmid == ACRN_INVALID_VMID && cmd != ACRN_IOCTL_CREATE_VM) { + if (vm->vmid == ACRN_INVALID_VMID && !cmd_without_vm(cmd)) { dev_dbg(acrn_dev.this_device, "ioctl 0x%x: Invalid VM state!\n", cmd); return -EINVAL; @@ -222,6 +241,48 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd, vm->vmid); kfree(cpu_regs); break; + case ACRN_IOCTL_GET_CAPS: + cap_bitmap = memdup_user((void __user *)ioctl_param, + sizeof(struct acrn_cap_bitmap)); + if (IS_ERR(cap_bitmap)) + return PTR_ERR(cap_bitmap); + + ret = hcall_get_caps(virt_to_phys(cap_bitmap)); + if (ret == 0) + ret = copy_to_user((void __user *)ioctl_param, + cap_bitmap, + sizeof(struct acrn_cap_bitmap)); + + if (ret < 0) + dev_dbg(acrn_dev.this_device, "Failed to get CAP\n"); + + kfree(cap_bitmap); + break; + case ACRN_IOCTL_RESET_VM_V2: + vm_reset = memdup_user((void __user *)ioctl_param, + sizeof(struct acrn_vm_reset_state)); + if (IS_ERR(vm_reset)) + return PTR_ERR(vm_reset); + + ret = hcall_reset_vm_v2(vm->vmid, virt_to_phys(vm_reset)); + if (ret < 0) + dev_dbg(acrn_dev.this_device, + "Failed to restart VM %u!\n", vm->vmid); + kfree(vm_reset); + break; + case ACRN_IOCTL_SET_ONE_REG: + one_reg = memdup_user((void __user *)ioctl_param, + sizeof(struct acrn_one_reg)); + if (IS_ERR(one_reg)) + return PTR_ERR(one_reg); + + ret = hcall_set_one_reg(vm->vmid, virt_to_phys(one_reg)); + if (ret < 0) + dev_dbg(acrn_dev.this_device, + "Failed to set one reg from VM%u/VCPU%u!\n", + vm->vmid, one_reg->vcpu_id); + kfree(one_reg); + break; case ACRN_IOCTL_SET_MEMSEG: if (copy_from_user(&memmap, (void __user *)ioctl_param, sizeof(memmap))) diff --git a/drivers/virt/acrn/hypercall.h b/drivers/virt/acrn/hypercall.h index 152ea7baafdaf..a41159a9a39fd 100644 --- a/drivers/virt/acrn/hypercall.h +++ b/drivers/virt/acrn/hypercall.h @@ -15,6 +15,7 @@ #define HC_ID_GEN_BASE 0x0UL #define HC_SOS_REMOVE_CPU _HC_ID(HC_ID, HC_ID_GEN_BASE + 0x01) +#define HC_GET_CAPS _HC_ID(HC_ID, HC_ID_GEN_BASE + 0x03) #define HC_ID_VM_BASE 0x10UL #define HC_CREATE_VM _HC_ID(HC_ID, HC_ID_VM_BASE + 0x00) @@ -23,6 +24,12 @@ #define HC_PAUSE_VM _HC_ID(HC_ID, HC_ID_VM_BASE + 0x03) #define HC_RESET_VM _HC_ID(HC_ID, HC_ID_VM_BASE + 0x05) #define HC_SET_VCPU_REGS _HC_ID(HC_ID, HC_ID_VM_BASE + 0x06) +#ifdef __ACRN_HAVE_RESET_VM_V2 +#define HC_RESET_VM_V2 _HC_ID(HC_ID, HC_ID_VM_BASE + 0x07) +#endif +#ifdef __ACRN_HAVE_SET_REG +#define HC_SET_ONE_REG _HC_ID(HC_ID, HC_ID_VM_BASE + 0x08) +#endif #define HC_ID_IRQ_BASE 0x20UL #define HC_INJECT_MSI _HC_ID(HC_ID, HC_ID_IRQ_BASE + 0x03) @@ -121,6 +128,41 @@ static inline long hcall_reset_vm(u64 vmid) return acrn_hypercall1(HC_RESET_VM, vmid); } +/** + * hcall_reset_vm_v2() - Reset a User VM + * @vmid: User VM ID + * @addr: Service VM GPA of the reset info + * + * Return: 0 on success, <0 on failure + */ +static inline long hcall_reset_vm_v2(u64 vmid, u64 addr) +{ + return acrn_hypercall2(HC_RESET_VM_V2, vmid, addr); +} + +/** + * hcall_get_caps() - Get supported capabilities + * @addr: Service VM GPA of the capability bitmap info + * + * Return: 0 on success, <0 on failure + */ +static inline long hcall_get_caps(u64 addr) +{ + return acrn_hypercall1(HC_GET_CAPS, addr); +} + +/** + * hcall_set_one_reg() - Set one register of a VCPU from User VM + * @vmid: User VM ID + * @addr: Service VM GPA of the one register info + * + * Return: 0 on success, <0 on failure + */ +static inline long hcall_set_one_reg(u64 vmid, u64 addr) +{ + return acrn_hypercall2(HC_SET_ONE_REG, vmid, addr); +} + /** * hcall_set_vcpu_regs() - Set up registers of virtual CPU of a User VM * @vmid: User VM ID diff --git a/include/uapi/linux/acrn.h b/include/uapi/linux/acrn.h index c2e71f174244d..44920bf2d5ca1 100644 --- a/include/uapi/linux/acrn.h +++ b/include/uapi/linux/acrn.h @@ -11,6 +11,7 @@ #ifndef _UAPI_ACRN_H #define _UAPI_ACRN_H +#include #include #include @@ -418,6 +419,39 @@ struct acrn_pcidev { __u32 bar[ACRN_PCI_NUM_BARS]; }; +struct acrn_vm_reset_state { + __u32 vm_reset_mode; + __u32 reserved[7]; +}; + +struct acrn_cap_bitmap { + __u32 index; + __u64 bitmap; +}; + +struct segment_sel { + __u16 selector; + __u64 base; + __u32 limit; + __u32 attr; +}; + +union acrn_reg { + __u16 wval; + __u32 dval; + __u64 qval; + /** for GDTR and IDTR */ + struct acrn_descriptor_ptr dpt; + struct segment_sel seg_sel; +}; + +struct acrn_one_reg { + /** virtual CPU ID for the VCPU */ + __u16 vcpu_id; + __u32 reg; + union acrn_reg value; +}; + /** * struct acrn_mmiodev - Info for assigning or de-assigning a MMIO device * @name: Name of the MMIO device. @@ -665,6 +699,16 @@ struct sbuf_setup_param { /* The ioctl type, documented in ioctl-number.rst */ #define ACRN_IOCTL_TYPE 0xA2 +/* + * Extension capability list. + */ +#ifdef __ACRN_HAVE_RESET_VM_V2 +#define ACRN_CAP_RESET_VM_V2 0 +#endif +#ifdef __ACRN_HAVE_SET_REG +#define ACRN_CAP_SET_REG 1 +#endif + /* * Common IOCTL IDs definition for ACRN userspace */ @@ -680,6 +724,14 @@ struct sbuf_setup_param { _IO(ACRN_IOCTL_TYPE, 0x15) #define ACRN_IOCTL_SET_VCPU_REGS \ _IOW(ACRN_IOCTL_TYPE, 0x16, struct acrn_vcpu_regs) +#define ACRN_IOCTL_GET_CAPS \ + _IOWR(ACRN_IOCTL_TYPE, 0x17, __u64) +/* Available with ACRN_CAP_RESET_VM_V2 */ +#define ACRN_IOCTL_RESET_VM_V2 \ + _IOW(ACRN_IOCTL_TYPE, 0x18, struct acrn_vm_reset_state) +/* Available with ACRN_CAP_SET_REG */ +#define ACRN_IOCTL_SET_ONE_REG \ + _IOW(ACRN_IOCTL_TYPE, 0x19, struct acrn_one_reg) #define ACRN_IOCTL_INJECT_MSI \ _IOW(ACRN_IOCTL_TYPE, 0x23, struct acrn_msi_entry)