1 // SPDX-License-Identifier: GPL-2.0
3 * ACRN Hypervisor Service Module (HSM)
5 * Copyright (C) 2020 Intel Corporation. All rights reserved.
8 * Fengwei Yin <fengwei.yin@intel.com>
9 * Yakui Zhao <yakui.zhao@intel.com>
12 #include <linux/cpu.h>
15 #include <linux/module.h>
16 #include <linux/slab.h>
19 #include <asm/hypervisor.h>
24 * When /dev/acrn_hsm is opened, a 'struct acrn_vm' object is created to
25 * represent a VM instance and continues to be associated with the opened file
26 * descriptor. All ioctl operations on this file descriptor will be targeted to
27 * the VM instance. Release of this file descriptor will destroy the object.
29 static int acrn_dev_open(struct inode *inode, struct file *filp)
33 vm = kzalloc(sizeof(*vm), GFP_KERNEL);
37 vm->vmid = ACRN_INVALID_VMID;
38 filp->private_data = vm;
42 static int pmcmd_ioctl(u64 cmd, void __user *uptr)
44 struct acrn_pstate_data *px_data;
45 struct acrn_cstate_data *cx_data;
49 switch (cmd & PMCMD_TYPE_MASK) {
50 case ACRN_PMCMD_GET_PX_CNT:
51 case ACRN_PMCMD_GET_CX_CNT:
52 pm_info = kmalloc(sizeof(u64), GFP_KERNEL);
56 ret = hcall_get_cpu_state(cmd, virt_to_phys(pm_info));
62 if (copy_to_user(uptr, pm_info, sizeof(u64)))
66 case ACRN_PMCMD_GET_PX_DATA:
67 px_data = kmalloc(sizeof(*px_data), GFP_KERNEL);
71 ret = hcall_get_cpu_state(cmd, virt_to_phys(px_data));
77 if (copy_to_user(uptr, px_data, sizeof(*px_data)))
81 case ACRN_PMCMD_GET_CX_DATA:
82 cx_data = kmalloc(sizeof(*cx_data), GFP_KERNEL);
86 ret = hcall_get_cpu_state(cmd, virt_to_phys(cx_data));
92 if (copy_to_user(uptr, cx_data, sizeof(*cx_data)))
104 * HSM relies on hypercall layer of the ACRN hypervisor to do the
105 * sanity check against the input parameters.
107 static long acrn_dev_ioctl(struct file *filp, unsigned int cmd,
108 unsigned long ioctl_param)
110 struct acrn_vm *vm = filp->private_data;
111 struct acrn_vm_creation *vm_param;
112 struct acrn_vcpu_regs *cpu_regs;
113 struct acrn_ioreq_notify notify;
114 struct acrn_ptdev_irq *irq_info;
115 struct acrn_ioeventfd ioeventfd;
116 struct acrn_vm_memmap memmap;
117 struct acrn_mmiodev *mmiodev;
118 struct acrn_msi_entry *msi;
119 struct acrn_pcidev *pcidev;
120 struct acrn_irqfd irqfd;
121 struct acrn_vdev *vdev;
126 if (vm->vmid == ACRN_INVALID_VMID && cmd != ACRN_IOCTL_CREATE_VM) {
127 dev_dbg(acrn_dev.this_device,
128 "ioctl 0x%x: Invalid VM state!\n", cmd);
133 case ACRN_IOCTL_CREATE_VM:
134 vm_param = memdup_user((void __user *)ioctl_param,
135 sizeof(struct acrn_vm_creation));
136 if (IS_ERR(vm_param))
137 return PTR_ERR(vm_param);
139 if ((vm_param->reserved0 | vm_param->reserved1) != 0) {
144 vm = acrn_vm_create(vm, vm_param);
151 if (copy_to_user((void __user *)ioctl_param, vm_param,
152 sizeof(struct acrn_vm_creation))) {
159 case ACRN_IOCTL_START_VM:
160 ret = hcall_start_vm(vm->vmid);
162 dev_dbg(acrn_dev.this_device,
163 "Failed to start VM %u!\n", vm->vmid);
165 case ACRN_IOCTL_PAUSE_VM:
166 ret = hcall_pause_vm(vm->vmid);
168 dev_dbg(acrn_dev.this_device,
169 "Failed to pause VM %u!\n", vm->vmid);
171 case ACRN_IOCTL_RESET_VM:
172 ret = hcall_reset_vm(vm->vmid);
174 dev_dbg(acrn_dev.this_device,
175 "Failed to restart VM %u!\n", vm->vmid);
177 case ACRN_IOCTL_DESTROY_VM:
178 ret = acrn_vm_destroy(vm);
180 case ACRN_IOCTL_SET_VCPU_REGS:
181 cpu_regs = memdup_user((void __user *)ioctl_param,
182 sizeof(struct acrn_vcpu_regs));
183 if (IS_ERR(cpu_regs))
184 return PTR_ERR(cpu_regs);
186 for (i = 0; i < ARRAY_SIZE(cpu_regs->reserved); i++)
187 if (cpu_regs->reserved[i]) {
192 for (i = 0; i < ARRAY_SIZE(cpu_regs->vcpu_regs.reserved_32); i++)
193 if (cpu_regs->vcpu_regs.reserved_32[i]) {
198 for (i = 0; i < ARRAY_SIZE(cpu_regs->vcpu_regs.reserved_64); i++)
199 if (cpu_regs->vcpu_regs.reserved_64[i]) {
204 for (i = 0; i < ARRAY_SIZE(cpu_regs->vcpu_regs.gdt.reserved); i++)
205 if (cpu_regs->vcpu_regs.gdt.reserved[i] |
206 cpu_regs->vcpu_regs.idt.reserved[i]) {
211 ret = hcall_set_vcpu_regs(vm->vmid, virt_to_phys(cpu_regs));
213 dev_dbg(acrn_dev.this_device,
214 "Failed to set regs state of VM%u!\n",
218 case ACRN_IOCTL_SET_MEMSEG:
219 if (copy_from_user(&memmap, (void __user *)ioctl_param,
223 ret = acrn_vm_memseg_map(vm, &memmap);
225 case ACRN_IOCTL_UNSET_MEMSEG:
226 if (copy_from_user(&memmap, (void __user *)ioctl_param,
230 ret = acrn_vm_memseg_unmap(vm, &memmap);
232 case ACRN_IOCTL_ASSIGN_MMIODEV:
233 mmiodev = memdup_user((void __user *)ioctl_param,
234 sizeof(struct acrn_mmiodev));
236 return PTR_ERR(mmiodev);
238 ret = hcall_assign_mmiodev(vm->vmid, virt_to_phys(mmiodev));
240 dev_dbg(acrn_dev.this_device,
241 "Failed to assign MMIO device!\n");
244 case ACRN_IOCTL_DEASSIGN_MMIODEV:
245 mmiodev = memdup_user((void __user *)ioctl_param,
246 sizeof(struct acrn_mmiodev));
248 return PTR_ERR(mmiodev);
250 ret = hcall_deassign_mmiodev(vm->vmid, virt_to_phys(mmiodev));
252 dev_dbg(acrn_dev.this_device,
253 "Failed to deassign MMIO device!\n");
256 case ACRN_IOCTL_ASSIGN_PCIDEV:
257 pcidev = memdup_user((void __user *)ioctl_param,
258 sizeof(struct acrn_pcidev));
260 return PTR_ERR(pcidev);
262 ret = hcall_assign_pcidev(vm->vmid, virt_to_phys(pcidev));
264 dev_dbg(acrn_dev.this_device,
265 "Failed to assign pci device!\n");
268 case ACRN_IOCTL_DEASSIGN_PCIDEV:
269 pcidev = memdup_user((void __user *)ioctl_param,
270 sizeof(struct acrn_pcidev));
272 return PTR_ERR(pcidev);
274 ret = hcall_deassign_pcidev(vm->vmid, virt_to_phys(pcidev));
276 dev_dbg(acrn_dev.this_device,
277 "Failed to deassign pci device!\n");
280 case ACRN_IOCTL_CREATE_VDEV:
281 vdev = memdup_user((void __user *)ioctl_param,
282 sizeof(struct acrn_vdev));
284 return PTR_ERR(vdev);
286 ret = hcall_create_vdev(vm->vmid, virt_to_phys(vdev));
288 dev_dbg(acrn_dev.this_device,
289 "Failed to create virtual device!\n");
292 case ACRN_IOCTL_DESTROY_VDEV:
293 vdev = memdup_user((void __user *)ioctl_param,
294 sizeof(struct acrn_vdev));
296 return PTR_ERR(vdev);
297 ret = hcall_destroy_vdev(vm->vmid, virt_to_phys(vdev));
299 dev_dbg(acrn_dev.this_device,
300 "Failed to destroy virtual device!\n");
303 case ACRN_IOCTL_SET_PTDEV_INTR:
304 irq_info = memdup_user((void __user *)ioctl_param,
305 sizeof(struct acrn_ptdev_irq));
306 if (IS_ERR(irq_info))
307 return PTR_ERR(irq_info);
309 ret = hcall_set_ptdev_intr(vm->vmid, virt_to_phys(irq_info));
311 dev_dbg(acrn_dev.this_device,
312 "Failed to configure intr for ptdev!\n");
315 case ACRN_IOCTL_RESET_PTDEV_INTR:
316 irq_info = memdup_user((void __user *)ioctl_param,
317 sizeof(struct acrn_ptdev_irq));
318 if (IS_ERR(irq_info))
319 return PTR_ERR(irq_info);
321 ret = hcall_reset_ptdev_intr(vm->vmid, virt_to_phys(irq_info));
323 dev_dbg(acrn_dev.this_device,
324 "Failed to reset intr for ptdev!\n");
327 case ACRN_IOCTL_SET_IRQLINE:
328 ret = hcall_set_irqline(vm->vmid, ioctl_param);
330 dev_dbg(acrn_dev.this_device,
331 "Failed to set interrupt line!\n");
333 case ACRN_IOCTL_INJECT_MSI:
334 msi = memdup_user((void __user *)ioctl_param,
335 sizeof(struct acrn_msi_entry));
339 ret = hcall_inject_msi(vm->vmid, virt_to_phys(msi));
341 dev_dbg(acrn_dev.this_device,
342 "Failed to inject MSI!\n");
345 case ACRN_IOCTL_VM_INTR_MONITOR:
346 ret = pin_user_pages_fast(ioctl_param, 1,
347 FOLL_WRITE | FOLL_LONGTERM, &page);
348 if (unlikely(ret != 1)) {
349 dev_dbg(acrn_dev.this_device,
350 "Failed to pin intr hdr buffer!\n");
354 ret = hcall_vm_intr_monitor(vm->vmid, page_to_phys(page));
356 unpin_user_page(page);
357 dev_dbg(acrn_dev.this_device,
358 "Failed to monitor intr data!\n");
361 if (vm->monitor_page)
362 unpin_user_page(vm->monitor_page);
363 vm->monitor_page = page;
365 case ACRN_IOCTL_CREATE_IOREQ_CLIENT:
366 if (vm->default_client)
368 if (!acrn_ioreq_client_create(vm, NULL, NULL, true, "acrndm"))
371 case ACRN_IOCTL_DESTROY_IOREQ_CLIENT:
372 if (vm->default_client)
373 acrn_ioreq_client_destroy(vm->default_client);
375 case ACRN_IOCTL_ATTACH_IOREQ_CLIENT:
376 if (vm->default_client)
377 ret = acrn_ioreq_client_wait(vm->default_client);
381 case ACRN_IOCTL_NOTIFY_REQUEST_FINISH:
382 if (copy_from_user(¬ify, (void __user *)ioctl_param,
383 sizeof(struct acrn_ioreq_notify)))
386 if (notify.reserved != 0)
389 ret = acrn_ioreq_request_default_complete(vm, notify.vcpu);
391 case ACRN_IOCTL_CLEAR_VM_IOREQ:
392 acrn_ioreq_request_clear(vm);
394 case ACRN_IOCTL_PM_GET_CPU_STATE:
395 if (copy_from_user(&cstate_cmd, (void __user *)ioctl_param,
399 ret = pmcmd_ioctl(cstate_cmd, (void __user *)ioctl_param);
401 case ACRN_IOCTL_IOEVENTFD:
402 if (copy_from_user(&ioeventfd, (void __user *)ioctl_param,
406 if (ioeventfd.reserved != 0)
409 ret = acrn_ioeventfd_config(vm, &ioeventfd);
411 case ACRN_IOCTL_IRQFD:
412 if (copy_from_user(&irqfd, (void __user *)ioctl_param,
415 ret = acrn_irqfd_config(vm, &irqfd);
418 dev_dbg(acrn_dev.this_device, "Unknown IOCTL 0x%x!\n", cmd);
425 static int acrn_dev_release(struct inode *inode, struct file *filp)
427 struct acrn_vm *vm = filp->private_data;
434 static ssize_t remove_cpu_store(struct device *dev,
435 struct device_attribute *attr,
436 const char *buf, size_t count)
441 if (kstrtoull(buf, 0, &cpu) < 0)
444 if (cpu >= num_possible_cpus() || cpu == 0 || !cpu_is_hotpluggable(cpu))
450 lapicid = cpu_data(cpu).apicid;
451 dev_dbg(dev, "Try to remove cpu %lld with lapicid %lld\n", cpu, lapicid);
452 ret = hcall_sos_remove_cpu(lapicid);
454 dev_err(dev, "Failed to remove cpu %lld!\n", cpu);
464 static DEVICE_ATTR_WO(remove_cpu);
466 static umode_t acrn_attr_visible(struct kobject *kobj, struct attribute *a, int n)
468 if (a == &dev_attr_remove_cpu.attr)
469 return IS_ENABLED(CONFIG_HOTPLUG_CPU) ? a->mode : 0;
474 static struct attribute *acrn_attrs[] = {
475 &dev_attr_remove_cpu.attr,
479 static struct attribute_group acrn_attr_group = {
481 .is_visible = acrn_attr_visible,
484 static const struct attribute_group *acrn_attr_groups[] = {
489 static const struct file_operations acrn_fops = {
490 .owner = THIS_MODULE,
491 .open = acrn_dev_open,
492 .release = acrn_dev_release,
493 .unlocked_ioctl = acrn_dev_ioctl,
496 struct miscdevice acrn_dev = {
497 .minor = MISC_DYNAMIC_MINOR,
500 .groups = acrn_attr_groups,
503 static int __init hsm_init(void)
507 if (x86_hyper_type != X86_HYPER_ACRN)
510 if (!(cpuid_eax(ACRN_CPUID_FEATURES) & ACRN_FEATURE_PRIVILEGED_VM))
513 ret = misc_register(&acrn_dev);
515 pr_err("Create misc dev failed!\n");
519 ret = acrn_ioreq_intr_setup();
521 pr_err("Setup I/O request handler failed!\n");
522 misc_deregister(&acrn_dev);
528 static void __exit hsm_exit(void)
530 acrn_ioreq_intr_remove();
531 misc_deregister(&acrn_dev);
533 module_init(hsm_init);
534 module_exit(hsm_exit);
536 MODULE_AUTHOR("Intel Corporation");
537 MODULE_LICENSE("GPL");
538 MODULE_DESCRIPTION("ACRN Hypervisor Service Module (HSM)");