GNU Linux-libre 6.7.9-gnu
[releases.git] / drivers / virt / acrn / hsm.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * ACRN Hypervisor Service Module (HSM)
4  *
5  * Copyright (C) 2020 Intel Corporation. All rights reserved.
6  *
7  * Authors:
8  *      Fengwei Yin <fengwei.yin@intel.com>
9  *      Yakui Zhao <yakui.zhao@intel.com>
10  */
11
12 #include <linux/cpu.h>
13 #include <linux/io.h>
14 #include <linux/mm.h>
15 #include <linux/module.h>
16 #include <linux/slab.h>
17
18 #include <asm/acrn.h>
19 #include <asm/hypervisor.h>
20
21 #include "acrn_drv.h"
22
23 /*
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.
28  */
29 static int acrn_dev_open(struct inode *inode, struct file *filp)
30 {
31         struct acrn_vm *vm;
32
33         vm = kzalloc(sizeof(*vm), GFP_KERNEL);
34         if (!vm)
35                 return -ENOMEM;
36
37         vm->vmid = ACRN_INVALID_VMID;
38         filp->private_data = vm;
39         return 0;
40 }
41
42 static int pmcmd_ioctl(u64 cmd, void __user *uptr)
43 {
44         struct acrn_pstate_data *px_data;
45         struct acrn_cstate_data *cx_data;
46         u64 *pm_info;
47         int ret = 0;
48
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);
53                 if (!pm_info)
54                         return -ENOMEM;
55
56                 ret = hcall_get_cpu_state(cmd, virt_to_phys(pm_info));
57                 if (ret < 0) {
58                         kfree(pm_info);
59                         break;
60                 }
61
62                 if (copy_to_user(uptr, pm_info, sizeof(u64)))
63                         ret = -EFAULT;
64                 kfree(pm_info);
65                 break;
66         case ACRN_PMCMD_GET_PX_DATA:
67                 px_data = kmalloc(sizeof(*px_data), GFP_KERNEL);
68                 if (!px_data)
69                         return -ENOMEM;
70
71                 ret = hcall_get_cpu_state(cmd, virt_to_phys(px_data));
72                 if (ret < 0) {
73                         kfree(px_data);
74                         break;
75                 }
76
77                 if (copy_to_user(uptr, px_data, sizeof(*px_data)))
78                         ret = -EFAULT;
79                 kfree(px_data);
80                 break;
81         case ACRN_PMCMD_GET_CX_DATA:
82                 cx_data = kmalloc(sizeof(*cx_data), GFP_KERNEL);
83                 if (!cx_data)
84                         return -ENOMEM;
85
86                 ret = hcall_get_cpu_state(cmd, virt_to_phys(cx_data));
87                 if (ret < 0) {
88                         kfree(cx_data);
89                         break;
90                 }
91
92                 if (copy_to_user(uptr, cx_data, sizeof(*cx_data)))
93                         ret = -EFAULT;
94                 kfree(cx_data);
95                 break;
96         default:
97                 break;
98         }
99
100         return ret;
101 }
102
103 /*
104  * HSM relies on hypercall layer of the ACRN hypervisor to do the
105  * sanity check against the input parameters.
106  */
107 static long acrn_dev_ioctl(struct file *filp, unsigned int cmd,
108                            unsigned long ioctl_param)
109 {
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;
122         struct page *page;
123         u64 cstate_cmd;
124         int i, ret = 0;
125
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);
129                 return -EINVAL;
130         }
131
132         switch (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);
138
139                 if ((vm_param->reserved0 | vm_param->reserved1) != 0) {
140                         kfree(vm_param);
141                         return -EINVAL;
142                 }
143
144                 vm = acrn_vm_create(vm, vm_param);
145                 if (!vm) {
146                         ret = -EINVAL;
147                         kfree(vm_param);
148                         break;
149                 }
150
151                 if (copy_to_user((void __user *)ioctl_param, vm_param,
152                                  sizeof(struct acrn_vm_creation))) {
153                         acrn_vm_destroy(vm);
154                         ret = -EFAULT;
155                 }
156
157                 kfree(vm_param);
158                 break;
159         case ACRN_IOCTL_START_VM:
160                 ret = hcall_start_vm(vm->vmid);
161                 if (ret < 0)
162                         dev_dbg(acrn_dev.this_device,
163                                 "Failed to start VM %u!\n", vm->vmid);
164                 break;
165         case ACRN_IOCTL_PAUSE_VM:
166                 ret = hcall_pause_vm(vm->vmid);
167                 if (ret < 0)
168                         dev_dbg(acrn_dev.this_device,
169                                 "Failed to pause VM %u!\n", vm->vmid);
170                 break;
171         case ACRN_IOCTL_RESET_VM:
172                 ret = hcall_reset_vm(vm->vmid);
173                 if (ret < 0)
174                         dev_dbg(acrn_dev.this_device,
175                                 "Failed to restart VM %u!\n", vm->vmid);
176                 break;
177         case ACRN_IOCTL_DESTROY_VM:
178                 ret = acrn_vm_destroy(vm);
179                 break;
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);
185
186                 for (i = 0; i < ARRAY_SIZE(cpu_regs->reserved); i++)
187                         if (cpu_regs->reserved[i]) {
188                                 kfree(cpu_regs);
189                                 return -EINVAL;
190                         }
191
192                 for (i = 0; i < ARRAY_SIZE(cpu_regs->vcpu_regs.reserved_32); i++)
193                         if (cpu_regs->vcpu_regs.reserved_32[i]) {
194                                 kfree(cpu_regs);
195                                 return -EINVAL;
196                         }
197
198                 for (i = 0; i < ARRAY_SIZE(cpu_regs->vcpu_regs.reserved_64); i++)
199                         if (cpu_regs->vcpu_regs.reserved_64[i]) {
200                                 kfree(cpu_regs);
201                                 return -EINVAL;
202                         }
203
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]) {
207                                 kfree(cpu_regs);
208                                 return -EINVAL;
209                         }
210
211                 ret = hcall_set_vcpu_regs(vm->vmid, virt_to_phys(cpu_regs));
212                 if (ret < 0)
213                         dev_dbg(acrn_dev.this_device,
214                                 "Failed to set regs state of VM%u!\n",
215                                 vm->vmid);
216                 kfree(cpu_regs);
217                 break;
218         case ACRN_IOCTL_SET_MEMSEG:
219                 if (copy_from_user(&memmap, (void __user *)ioctl_param,
220                                    sizeof(memmap)))
221                         return -EFAULT;
222
223                 ret = acrn_vm_memseg_map(vm, &memmap);
224                 break;
225         case ACRN_IOCTL_UNSET_MEMSEG:
226                 if (copy_from_user(&memmap, (void __user *)ioctl_param,
227                                    sizeof(memmap)))
228                         return -EFAULT;
229
230                 ret = acrn_vm_memseg_unmap(vm, &memmap);
231                 break;
232         case ACRN_IOCTL_ASSIGN_MMIODEV:
233                 mmiodev = memdup_user((void __user *)ioctl_param,
234                                       sizeof(struct acrn_mmiodev));
235                 if (IS_ERR(mmiodev))
236                         return PTR_ERR(mmiodev);
237
238                 ret = hcall_assign_mmiodev(vm->vmid, virt_to_phys(mmiodev));
239                 if (ret < 0)
240                         dev_dbg(acrn_dev.this_device,
241                                 "Failed to assign MMIO device!\n");
242                 kfree(mmiodev);
243                 break;
244         case ACRN_IOCTL_DEASSIGN_MMIODEV:
245                 mmiodev = memdup_user((void __user *)ioctl_param,
246                                       sizeof(struct acrn_mmiodev));
247                 if (IS_ERR(mmiodev))
248                         return PTR_ERR(mmiodev);
249
250                 ret = hcall_deassign_mmiodev(vm->vmid, virt_to_phys(mmiodev));
251                 if (ret < 0)
252                         dev_dbg(acrn_dev.this_device,
253                                 "Failed to deassign MMIO device!\n");
254                 kfree(mmiodev);
255                 break;
256         case ACRN_IOCTL_ASSIGN_PCIDEV:
257                 pcidev = memdup_user((void __user *)ioctl_param,
258                                      sizeof(struct acrn_pcidev));
259                 if (IS_ERR(pcidev))
260                         return PTR_ERR(pcidev);
261
262                 ret = hcall_assign_pcidev(vm->vmid, virt_to_phys(pcidev));
263                 if (ret < 0)
264                         dev_dbg(acrn_dev.this_device,
265                                 "Failed to assign pci device!\n");
266                 kfree(pcidev);
267                 break;
268         case ACRN_IOCTL_DEASSIGN_PCIDEV:
269                 pcidev = memdup_user((void __user *)ioctl_param,
270                                      sizeof(struct acrn_pcidev));
271                 if (IS_ERR(pcidev))
272                         return PTR_ERR(pcidev);
273
274                 ret = hcall_deassign_pcidev(vm->vmid, virt_to_phys(pcidev));
275                 if (ret < 0)
276                         dev_dbg(acrn_dev.this_device,
277                                 "Failed to deassign pci device!\n");
278                 kfree(pcidev);
279                 break;
280         case ACRN_IOCTL_CREATE_VDEV:
281                 vdev = memdup_user((void __user *)ioctl_param,
282                                    sizeof(struct acrn_vdev));
283                 if (IS_ERR(vdev))
284                         return PTR_ERR(vdev);
285
286                 ret = hcall_create_vdev(vm->vmid, virt_to_phys(vdev));
287                 if (ret < 0)
288                         dev_dbg(acrn_dev.this_device,
289                                 "Failed to create virtual device!\n");
290                 kfree(vdev);
291                 break;
292         case ACRN_IOCTL_DESTROY_VDEV:
293                 vdev = memdup_user((void __user *)ioctl_param,
294                                    sizeof(struct acrn_vdev));
295                 if (IS_ERR(vdev))
296                         return PTR_ERR(vdev);
297                 ret = hcall_destroy_vdev(vm->vmid, virt_to_phys(vdev));
298                 if (ret < 0)
299                         dev_dbg(acrn_dev.this_device,
300                                 "Failed to destroy virtual device!\n");
301                 kfree(vdev);
302                 break;
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);
308
309                 ret = hcall_set_ptdev_intr(vm->vmid, virt_to_phys(irq_info));
310                 if (ret < 0)
311                         dev_dbg(acrn_dev.this_device,
312                                 "Failed to configure intr for ptdev!\n");
313                 kfree(irq_info);
314                 break;
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);
320
321                 ret = hcall_reset_ptdev_intr(vm->vmid, virt_to_phys(irq_info));
322                 if (ret < 0)
323                         dev_dbg(acrn_dev.this_device,
324                                 "Failed to reset intr for ptdev!\n");
325                 kfree(irq_info);
326                 break;
327         case ACRN_IOCTL_SET_IRQLINE:
328                 ret = hcall_set_irqline(vm->vmid, ioctl_param);
329                 if (ret < 0)
330                         dev_dbg(acrn_dev.this_device,
331                                 "Failed to set interrupt line!\n");
332                 break;
333         case ACRN_IOCTL_INJECT_MSI:
334                 msi = memdup_user((void __user *)ioctl_param,
335                                   sizeof(struct acrn_msi_entry));
336                 if (IS_ERR(msi))
337                         return PTR_ERR(msi);
338
339                 ret = hcall_inject_msi(vm->vmid, virt_to_phys(msi));
340                 if (ret < 0)
341                         dev_dbg(acrn_dev.this_device,
342                                 "Failed to inject MSI!\n");
343                 kfree(msi);
344                 break;
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");
351                         return -EFAULT;
352                 }
353
354                 ret = hcall_vm_intr_monitor(vm->vmid, page_to_phys(page));
355                 if (ret < 0) {
356                         unpin_user_page(page);
357                         dev_dbg(acrn_dev.this_device,
358                                 "Failed to monitor intr data!\n");
359                         return ret;
360                 }
361                 if (vm->monitor_page)
362                         unpin_user_page(vm->monitor_page);
363                 vm->monitor_page = page;
364                 break;
365         case ACRN_IOCTL_CREATE_IOREQ_CLIENT:
366                 if (vm->default_client)
367                         return -EEXIST;
368                 if (!acrn_ioreq_client_create(vm, NULL, NULL, true, "acrndm"))
369                         ret = -EINVAL;
370                 break;
371         case ACRN_IOCTL_DESTROY_IOREQ_CLIENT:
372                 if (vm->default_client)
373                         acrn_ioreq_client_destroy(vm->default_client);
374                 break;
375         case ACRN_IOCTL_ATTACH_IOREQ_CLIENT:
376                 if (vm->default_client)
377                         ret = acrn_ioreq_client_wait(vm->default_client);
378                 else
379                         ret = -ENODEV;
380                 break;
381         case ACRN_IOCTL_NOTIFY_REQUEST_FINISH:
382                 if (copy_from_user(&notify, (void __user *)ioctl_param,
383                                    sizeof(struct acrn_ioreq_notify)))
384                         return -EFAULT;
385
386                 if (notify.reserved != 0)
387                         return -EINVAL;
388
389                 ret = acrn_ioreq_request_default_complete(vm, notify.vcpu);
390                 break;
391         case ACRN_IOCTL_CLEAR_VM_IOREQ:
392                 acrn_ioreq_request_clear(vm);
393                 break;
394         case ACRN_IOCTL_PM_GET_CPU_STATE:
395                 if (copy_from_user(&cstate_cmd, (void __user *)ioctl_param,
396                                    sizeof(cstate_cmd)))
397                         return -EFAULT;
398
399                 ret = pmcmd_ioctl(cstate_cmd, (void __user *)ioctl_param);
400                 break;
401         case ACRN_IOCTL_IOEVENTFD:
402                 if (copy_from_user(&ioeventfd, (void __user *)ioctl_param,
403                                    sizeof(ioeventfd)))
404                         return -EFAULT;
405
406                 if (ioeventfd.reserved != 0)
407                         return -EINVAL;
408
409                 ret = acrn_ioeventfd_config(vm, &ioeventfd);
410                 break;
411         case ACRN_IOCTL_IRQFD:
412                 if (copy_from_user(&irqfd, (void __user *)ioctl_param,
413                                    sizeof(irqfd)))
414                         return -EFAULT;
415                 ret = acrn_irqfd_config(vm, &irqfd);
416                 break;
417         default:
418                 dev_dbg(acrn_dev.this_device, "Unknown IOCTL 0x%x!\n", cmd);
419                 ret = -ENOTTY;
420         }
421
422         return ret;
423 }
424
425 static int acrn_dev_release(struct inode *inode, struct file *filp)
426 {
427         struct acrn_vm *vm = filp->private_data;
428
429         acrn_vm_destroy(vm);
430         kfree(vm);
431         return 0;
432 }
433
434 static ssize_t remove_cpu_store(struct device *dev,
435                                 struct device_attribute *attr,
436                                 const char *buf, size_t count)
437 {
438         u64 cpu, lapicid;
439         int ret;
440
441         if (kstrtoull(buf, 0, &cpu) < 0)
442                 return -EINVAL;
443
444         if (cpu >= num_possible_cpus() || cpu == 0 || !cpu_is_hotpluggable(cpu))
445                 return -EINVAL;
446
447         if (cpu_online(cpu))
448                 remove_cpu(cpu);
449
450         lapicid = cpu_data(cpu).topo.apicid;
451         dev_dbg(dev, "Try to remove cpu %lld with lapicid %lld\n", cpu, lapicid);
452         ret = hcall_sos_remove_cpu(lapicid);
453         if (ret < 0) {
454                 dev_err(dev, "Failed to remove cpu %lld!\n", cpu);
455                 goto fail_remove;
456         }
457
458         return count;
459
460 fail_remove:
461         add_cpu(cpu);
462         return ret;
463 }
464 static DEVICE_ATTR_WO(remove_cpu);
465
466 static umode_t acrn_attr_visible(struct kobject *kobj, struct attribute *a, int n)
467 {
468        if (a == &dev_attr_remove_cpu.attr)
469                return IS_ENABLED(CONFIG_HOTPLUG_CPU) ? a->mode : 0;
470
471        return a->mode;
472 }
473
474 static struct attribute *acrn_attrs[] = {
475         &dev_attr_remove_cpu.attr,
476         NULL
477 };
478
479 static struct attribute_group acrn_attr_group = {
480         .attrs = acrn_attrs,
481         .is_visible = acrn_attr_visible,
482 };
483
484 static const struct attribute_group *acrn_attr_groups[] = {
485         &acrn_attr_group,
486         NULL
487 };
488
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,
494 };
495
496 struct miscdevice acrn_dev = {
497         .minor  = MISC_DYNAMIC_MINOR,
498         .name   = "acrn_hsm",
499         .fops   = &acrn_fops,
500         .groups = acrn_attr_groups,
501 };
502
503 static int __init hsm_init(void)
504 {
505         int ret;
506
507         if (x86_hyper_type != X86_HYPER_ACRN)
508                 return -ENODEV;
509
510         if (!(cpuid_eax(ACRN_CPUID_FEATURES) & ACRN_FEATURE_PRIVILEGED_VM))
511                 return -EPERM;
512
513         ret = misc_register(&acrn_dev);
514         if (ret) {
515                 pr_err("Create misc dev failed!\n");
516                 return ret;
517         }
518
519         ret = acrn_ioreq_intr_setup();
520         if (ret) {
521                 pr_err("Setup I/O request handler failed!\n");
522                 misc_deregister(&acrn_dev);
523                 return ret;
524         }
525         return 0;
526 }
527
528 static void __exit hsm_exit(void)
529 {
530         acrn_ioreq_intr_remove();
531         misc_deregister(&acrn_dev);
532 }
533 module_init(hsm_init);
534 module_exit(hsm_exit);
535
536 MODULE_AUTHOR("Intel Corporation");
537 MODULE_LICENSE("GPL");
538 MODULE_DESCRIPTION("ACRN Hypervisor Service Module (HSM)");