mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-01 02:33:57 +00:00
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
@ -9,6 +9,7 @@
|
||||
* Yakui Zhao <yakui.zhao@intel.com>
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.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_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) {
|
||||
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:
|
||||
ret = acrn_vm_destroy(vm);
|
||||
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:
|
||||
dev_dbg(acrn_dev.this_device, "Unknown IOCTL 0x%x!\n", cmd);
|
||||
ret = -ENOTTY;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#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_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
|
||||
@ -75,4 +76,16 @@ static inline long hcall_reset_vm(u64 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 */
|
||||
|
@ -38,6 +38,123 @@ struct acrn_vm_creation {
|
||||
__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 */
|
||||
#define ACRN_IOCTL_TYPE 0xA2
|
||||
|
||||
@ -54,5 +171,7 @@ struct acrn_vm_creation {
|
||||
_IO(ACRN_IOCTL_TYPE, 0x13)
|
||||
#define ACRN_IOCTL_RESET_VM \
|
||||
_IO(ACRN_IOCTL_TYPE, 0x15)
|
||||
#define ACRN_IOCTL_SET_VCPU_REGS \
|
||||
_IOW(ACRN_IOCTL_TYPE, 0x16, struct acrn_vcpu_regs)
|
||||
|
||||
#endif /* _UAPI_ACRN_H */
|
||||
|
Loading…
Reference in New Issue
Block a user