virt: acrn: Introduce an ioctl to set vCPU registers state
A virtual CPU of User VM has different context due to the different registers state. ACRN userspace needs to set the virtual CPU registers state (e.g. giving a initial registers state to a virtual BSP of a User VM). HSM provides an ioctl ACRN_IOCTL_SET_VCPU_REGS to do the virtual CPU registers state setting. The ioctl passes the registers state from ACRN userspace to the hypervisor directly. Cc: Zhi Wang <zhi.a.wang@intel.com> Cc: Zhenyu Wang <zhenyuw@linux.intel.com> Cc: Yu Wang <yu1.wang@intel.com> Cc: Reinette Chatre <reinette.chatre@intel.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reviewed-by: Zhi Wang <zhi.a.wang@intel.com> Reviewed-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: Shuo Liu <shuo.a.liu@intel.com> Link: https://lore.kernel.org/r/20210207031040.49576-8-shuo.a.liu@intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
9c5137aedd
commit
2ad2aaee1b
3 changed files with 165 additions and 1 deletions
|
@ -9,6 +9,7 @@
|
||||||
* Yakui Zhao <yakui.zhao@intel.com>
|
* Yakui Zhao <yakui.zhao@intel.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/io.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
@ -46,7 +47,8 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd,
|
||||||
{
|
{
|
||||||
struct acrn_vm *vm = filp->private_data;
|
struct acrn_vm *vm = filp->private_data;
|
||||||
struct acrn_vm_creation *vm_param;
|
struct acrn_vm_creation *vm_param;
|
||||||
int ret = 0;
|
struct acrn_vcpu_regs *cpu_regs;
|
||||||
|
int i, ret = 0;
|
||||||
|
|
||||||
if (vm->vmid == ACRN_INVALID_VMID && cmd != ACRN_IOCTL_CREATE_VM) {
|
if (vm->vmid == ACRN_INVALID_VMID && cmd != ACRN_IOCTL_CREATE_VM) {
|
||||||
dev_dbg(acrn_dev.this_device,
|
dev_dbg(acrn_dev.this_device,
|
||||||
|
@ -100,6 +102,36 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd,
|
||||||
case ACRN_IOCTL_DESTROY_VM:
|
case ACRN_IOCTL_DESTROY_VM:
|
||||||
ret = acrn_vm_destroy(vm);
|
ret = acrn_vm_destroy(vm);
|
||||||
break;
|
break;
|
||||||
|
case ACRN_IOCTL_SET_VCPU_REGS:
|
||||||
|
cpu_regs = memdup_user((void __user *)ioctl_param,
|
||||||
|
sizeof(struct acrn_vcpu_regs));
|
||||||
|
if (IS_ERR(cpu_regs))
|
||||||
|
return PTR_ERR(cpu_regs);
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(cpu_regs->reserved); i++)
|
||||||
|
if (cpu_regs->reserved[i])
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(cpu_regs->vcpu_regs.reserved_32); i++)
|
||||||
|
if (cpu_regs->vcpu_regs.reserved_32[i])
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(cpu_regs->vcpu_regs.reserved_64); i++)
|
||||||
|
if (cpu_regs->vcpu_regs.reserved_64[i])
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(cpu_regs->vcpu_regs.gdt.reserved); i++)
|
||||||
|
if (cpu_regs->vcpu_regs.gdt.reserved[i] |
|
||||||
|
cpu_regs->vcpu_regs.idt.reserved[i])
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ret = hcall_set_vcpu_regs(vm->vmid, virt_to_phys(cpu_regs));
|
||||||
|
if (ret < 0)
|
||||||
|
dev_dbg(acrn_dev.this_device,
|
||||||
|
"Failed to set regs state of VM%u!\n",
|
||||||
|
vm->vmid);
|
||||||
|
kfree(cpu_regs);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
dev_dbg(acrn_dev.this_device, "Unknown IOCTL 0x%x!\n", cmd);
|
dev_dbg(acrn_dev.this_device, "Unknown IOCTL 0x%x!\n", cmd);
|
||||||
ret = -ENOTTY;
|
ret = -ENOTTY;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#define HC_START_VM _HC_ID(HC_ID, HC_ID_VM_BASE + 0x02)
|
#define HC_START_VM _HC_ID(HC_ID, HC_ID_VM_BASE + 0x02)
|
||||||
#define HC_PAUSE_VM _HC_ID(HC_ID, HC_ID_VM_BASE + 0x03)
|
#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_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)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hcall_create_vm() - Create a User VM
|
* hcall_create_vm() - Create a User VM
|
||||||
|
@ -75,4 +76,16 @@ static inline long hcall_reset_vm(u64 vmid)
|
||||||
return acrn_hypercall1(HC_RESET_VM, vmid);
|
return acrn_hypercall1(HC_RESET_VM, vmid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hcall_set_vcpu_regs() - Set up registers of virtual CPU of a User VM
|
||||||
|
* @vmid: User VM ID
|
||||||
|
* @regs_state: Service VM GPA of registers state
|
||||||
|
*
|
||||||
|
* Return: 0 on success, <0 on failure
|
||||||
|
*/
|
||||||
|
static inline long hcall_set_vcpu_regs(u64 vmid, u64 regs_state)
|
||||||
|
{
|
||||||
|
return acrn_hypercall2(HC_SET_VCPU_REGS, vmid, regs_state);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __ACRN_HSM_HYPERCALL_H */
|
#endif /* __ACRN_HSM_HYPERCALL_H */
|
||||||
|
|
|
@ -38,6 +38,123 @@ struct acrn_vm_creation {
|
||||||
__u64 cpu_affinity;
|
__u64 cpu_affinity;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct acrn_gp_regs - General registers of a User VM
|
||||||
|
* @rax: Value of register RAX
|
||||||
|
* @rcx: Value of register RCX
|
||||||
|
* @rdx: Value of register RDX
|
||||||
|
* @rbx: Value of register RBX
|
||||||
|
* @rsp: Value of register RSP
|
||||||
|
* @rbp: Value of register RBP
|
||||||
|
* @rsi: Value of register RSI
|
||||||
|
* @rdi: Value of register RDI
|
||||||
|
* @r8: Value of register R8
|
||||||
|
* @r9: Value of register R9
|
||||||
|
* @r10: Value of register R10
|
||||||
|
* @r11: Value of register R11
|
||||||
|
* @r12: Value of register R12
|
||||||
|
* @r13: Value of register R13
|
||||||
|
* @r14: Value of register R14
|
||||||
|
* @r15: Value of register R15
|
||||||
|
*/
|
||||||
|
struct acrn_gp_regs {
|
||||||
|
__le64 rax;
|
||||||
|
__le64 rcx;
|
||||||
|
__le64 rdx;
|
||||||
|
__le64 rbx;
|
||||||
|
__le64 rsp;
|
||||||
|
__le64 rbp;
|
||||||
|
__le64 rsi;
|
||||||
|
__le64 rdi;
|
||||||
|
__le64 r8;
|
||||||
|
__le64 r9;
|
||||||
|
__le64 r10;
|
||||||
|
__le64 r11;
|
||||||
|
__le64 r12;
|
||||||
|
__le64 r13;
|
||||||
|
__le64 r14;
|
||||||
|
__le64 r15;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct acrn_descriptor_ptr - Segment descriptor table of a User VM.
|
||||||
|
* @limit: Limit field.
|
||||||
|
* @base: Base field.
|
||||||
|
* @reserved: Reserved and must be 0.
|
||||||
|
*/
|
||||||
|
struct acrn_descriptor_ptr {
|
||||||
|
__le16 limit;
|
||||||
|
__le64 base;
|
||||||
|
__le16 reserved[3];
|
||||||
|
} __attribute__ ((__packed__));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct acrn_regs - Registers structure of a User VM
|
||||||
|
* @gprs: General registers
|
||||||
|
* @gdt: Global Descriptor Table
|
||||||
|
* @idt: Interrupt Descriptor Table
|
||||||
|
* @rip: Value of register RIP
|
||||||
|
* @cs_base: Base of code segment selector
|
||||||
|
* @cr0: Value of register CR0
|
||||||
|
* @cr4: Value of register CR4
|
||||||
|
* @cr3: Value of register CR3
|
||||||
|
* @ia32_efer: Value of IA32_EFER MSR
|
||||||
|
* @rflags: Value of regsiter RFLAGS
|
||||||
|
* @reserved_64: Reserved and must be 0
|
||||||
|
* @cs_ar: Attribute field of code segment selector
|
||||||
|
* @cs_limit: Limit field of code segment selector
|
||||||
|
* @reserved_32: Reserved and must be 0
|
||||||
|
* @cs_sel: Value of code segment selector
|
||||||
|
* @ss_sel: Value of stack segment selector
|
||||||
|
* @ds_sel: Value of data segment selector
|
||||||
|
* @es_sel: Value of extra segment selector
|
||||||
|
* @fs_sel: Value of FS selector
|
||||||
|
* @gs_sel: Value of GS selector
|
||||||
|
* @ldt_sel: Value of LDT descriptor selector
|
||||||
|
* @tr_sel: Value of TSS descriptor selector
|
||||||
|
*/
|
||||||
|
struct acrn_regs {
|
||||||
|
struct acrn_gp_regs gprs;
|
||||||
|
struct acrn_descriptor_ptr gdt;
|
||||||
|
struct acrn_descriptor_ptr idt;
|
||||||
|
|
||||||
|
__le64 rip;
|
||||||
|
__le64 cs_base;
|
||||||
|
__le64 cr0;
|
||||||
|
__le64 cr4;
|
||||||
|
__le64 cr3;
|
||||||
|
__le64 ia32_efer;
|
||||||
|
__le64 rflags;
|
||||||
|
__le64 reserved_64[4];
|
||||||
|
|
||||||
|
__le32 cs_ar;
|
||||||
|
__le32 cs_limit;
|
||||||
|
__le32 reserved_32[3];
|
||||||
|
|
||||||
|
__le16 cs_sel;
|
||||||
|
__le16 ss_sel;
|
||||||
|
__le16 ds_sel;
|
||||||
|
__le16 es_sel;
|
||||||
|
__le16 fs_sel;
|
||||||
|
__le16 gs_sel;
|
||||||
|
__le16 ldt_sel;
|
||||||
|
__le16 tr_sel;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct acrn_vcpu_regs - Info of vCPU registers state
|
||||||
|
* @vcpu_id: vCPU ID
|
||||||
|
* @reserved: Reserved and must be 0
|
||||||
|
* @vcpu_regs: vCPU registers state
|
||||||
|
*
|
||||||
|
* This structure will be passed to hypervisor directly.
|
||||||
|
*/
|
||||||
|
struct acrn_vcpu_regs {
|
||||||
|
__u16 vcpu_id;
|
||||||
|
__u16 reserved[3];
|
||||||
|
struct acrn_regs vcpu_regs;
|
||||||
|
};
|
||||||
|
|
||||||
/* The ioctl type, documented in ioctl-number.rst */
|
/* The ioctl type, documented in ioctl-number.rst */
|
||||||
#define ACRN_IOCTL_TYPE 0xA2
|
#define ACRN_IOCTL_TYPE 0xA2
|
||||||
|
|
||||||
|
@ -54,5 +171,7 @@ struct acrn_vm_creation {
|
||||||
_IO(ACRN_IOCTL_TYPE, 0x13)
|
_IO(ACRN_IOCTL_TYPE, 0x13)
|
||||||
#define ACRN_IOCTL_RESET_VM \
|
#define ACRN_IOCTL_RESET_VM \
|
||||||
_IO(ACRN_IOCTL_TYPE, 0x15)
|
_IO(ACRN_IOCTL_TYPE, 0x15)
|
||||||
|
#define ACRN_IOCTL_SET_VCPU_REGS \
|
||||||
|
_IOW(ACRN_IOCTL_TYPE, 0x16, struct acrn_vcpu_regs)
|
||||||
|
|
||||||
#endif /* _UAPI_ACRN_H */
|
#endif /* _UAPI_ACRN_H */
|
||||||
|
|
Loading…
Add table
Reference in a new issue