Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * ACRN Hypervisor Service Module (HSM)
0004  *
0005  * Copyright (C) 2020 Intel Corporation. All rights reserved.
0006  *
0007  * Authors:
0008  *  Fengwei Yin <fengwei.yin@intel.com>
0009  *  Yakui Zhao <yakui.zhao@intel.com>
0010  */
0011 
0012 #include <linux/cpu.h>
0013 #include <linux/io.h>
0014 #include <linux/mm.h>
0015 #include <linux/module.h>
0016 #include <linux/slab.h>
0017 
0018 #include <asm/acrn.h>
0019 #include <asm/hypervisor.h>
0020 
0021 #include "acrn_drv.h"
0022 
0023 /*
0024  * When /dev/acrn_hsm is opened, a 'struct acrn_vm' object is created to
0025  * represent a VM instance and continues to be associated with the opened file
0026  * descriptor. All ioctl operations on this file descriptor will be targeted to
0027  * the VM instance. Release of this file descriptor will destroy the object.
0028  */
0029 static int acrn_dev_open(struct inode *inode, struct file *filp)
0030 {
0031     struct acrn_vm *vm;
0032 
0033     vm = kzalloc(sizeof(*vm), GFP_KERNEL);
0034     if (!vm)
0035         return -ENOMEM;
0036 
0037     vm->vmid = ACRN_INVALID_VMID;
0038     filp->private_data = vm;
0039     return 0;
0040 }
0041 
0042 static int pmcmd_ioctl(u64 cmd, void __user *uptr)
0043 {
0044     struct acrn_pstate_data *px_data;
0045     struct acrn_cstate_data *cx_data;
0046     u64 *pm_info;
0047     int ret = 0;
0048 
0049     switch (cmd & PMCMD_TYPE_MASK) {
0050     case ACRN_PMCMD_GET_PX_CNT:
0051     case ACRN_PMCMD_GET_CX_CNT:
0052         pm_info = kmalloc(sizeof(u64), GFP_KERNEL);
0053         if (!pm_info)
0054             return -ENOMEM;
0055 
0056         ret = hcall_get_cpu_state(cmd, virt_to_phys(pm_info));
0057         if (ret < 0) {
0058             kfree(pm_info);
0059             break;
0060         }
0061 
0062         if (copy_to_user(uptr, pm_info, sizeof(u64)))
0063             ret = -EFAULT;
0064         kfree(pm_info);
0065         break;
0066     case ACRN_PMCMD_GET_PX_DATA:
0067         px_data = kmalloc(sizeof(*px_data), GFP_KERNEL);
0068         if (!px_data)
0069             return -ENOMEM;
0070 
0071         ret = hcall_get_cpu_state(cmd, virt_to_phys(px_data));
0072         if (ret < 0) {
0073             kfree(px_data);
0074             break;
0075         }
0076 
0077         if (copy_to_user(uptr, px_data, sizeof(*px_data)))
0078             ret = -EFAULT;
0079         kfree(px_data);
0080         break;
0081     case ACRN_PMCMD_GET_CX_DATA:
0082         cx_data = kmalloc(sizeof(*cx_data), GFP_KERNEL);
0083         if (!cx_data)
0084             return -ENOMEM;
0085 
0086         ret = hcall_get_cpu_state(cmd, virt_to_phys(cx_data));
0087         if (ret < 0) {
0088             kfree(cx_data);
0089             break;
0090         }
0091 
0092         if (copy_to_user(uptr, cx_data, sizeof(*cx_data)))
0093             ret = -EFAULT;
0094         kfree(cx_data);
0095         break;
0096     default:
0097         break;
0098     }
0099 
0100     return ret;
0101 }
0102 
0103 /*
0104  * HSM relies on hypercall layer of the ACRN hypervisor to do the
0105  * sanity check against the input parameters.
0106  */
0107 static long acrn_dev_ioctl(struct file *filp, unsigned int cmd,
0108                unsigned long ioctl_param)
0109 {
0110     struct acrn_vm *vm = filp->private_data;
0111     struct acrn_vm_creation *vm_param;
0112     struct acrn_vcpu_regs *cpu_regs;
0113     struct acrn_ioreq_notify notify;
0114     struct acrn_ptdev_irq *irq_info;
0115     struct acrn_ioeventfd ioeventfd;
0116     struct acrn_vm_memmap memmap;
0117     struct acrn_mmiodev *mmiodev;
0118     struct acrn_msi_entry *msi;
0119     struct acrn_pcidev *pcidev;
0120     struct acrn_irqfd irqfd;
0121     struct acrn_vdev *vdev;
0122     struct page *page;
0123     u64 cstate_cmd;
0124     int i, ret = 0;
0125 
0126     if (vm->vmid == ACRN_INVALID_VMID && cmd != ACRN_IOCTL_CREATE_VM) {
0127         dev_dbg(acrn_dev.this_device,
0128             "ioctl 0x%x: Invalid VM state!\n", cmd);
0129         return -EINVAL;
0130     }
0131 
0132     switch (cmd) {
0133     case ACRN_IOCTL_CREATE_VM:
0134         vm_param = memdup_user((void __user *)ioctl_param,
0135                        sizeof(struct acrn_vm_creation));
0136         if (IS_ERR(vm_param))
0137             return PTR_ERR(vm_param);
0138 
0139         if ((vm_param->reserved0 | vm_param->reserved1) != 0) {
0140             kfree(vm_param);
0141             return -EINVAL;
0142         }
0143 
0144         vm = acrn_vm_create(vm, vm_param);
0145         if (!vm) {
0146             ret = -EINVAL;
0147             kfree(vm_param);
0148             break;
0149         }
0150 
0151         if (copy_to_user((void __user *)ioctl_param, vm_param,
0152                  sizeof(struct acrn_vm_creation))) {
0153             acrn_vm_destroy(vm);
0154             ret = -EFAULT;
0155         }
0156 
0157         kfree(vm_param);
0158         break;
0159     case ACRN_IOCTL_START_VM:
0160         ret = hcall_start_vm(vm->vmid);
0161         if (ret < 0)
0162             dev_dbg(acrn_dev.this_device,
0163                 "Failed to start VM %u!\n", vm->vmid);
0164         break;
0165     case ACRN_IOCTL_PAUSE_VM:
0166         ret = hcall_pause_vm(vm->vmid);
0167         if (ret < 0)
0168             dev_dbg(acrn_dev.this_device,
0169                 "Failed to pause VM %u!\n", vm->vmid);
0170         break;
0171     case ACRN_IOCTL_RESET_VM:
0172         ret = hcall_reset_vm(vm->vmid);
0173         if (ret < 0)
0174             dev_dbg(acrn_dev.this_device,
0175                 "Failed to restart VM %u!\n", vm->vmid);
0176         break;
0177     case ACRN_IOCTL_DESTROY_VM:
0178         ret = acrn_vm_destroy(vm);
0179         break;
0180     case ACRN_IOCTL_SET_VCPU_REGS:
0181         cpu_regs = memdup_user((void __user *)ioctl_param,
0182                        sizeof(struct acrn_vcpu_regs));
0183         if (IS_ERR(cpu_regs))
0184             return PTR_ERR(cpu_regs);
0185 
0186         for (i = 0; i < ARRAY_SIZE(cpu_regs->reserved); i++)
0187             if (cpu_regs->reserved[i]) {
0188                 kfree(cpu_regs);
0189                 return -EINVAL;
0190             }
0191 
0192         for (i = 0; i < ARRAY_SIZE(cpu_regs->vcpu_regs.reserved_32); i++)
0193             if (cpu_regs->vcpu_regs.reserved_32[i]) {
0194                 kfree(cpu_regs);
0195                 return -EINVAL;
0196             }
0197 
0198         for (i = 0; i < ARRAY_SIZE(cpu_regs->vcpu_regs.reserved_64); i++)
0199             if (cpu_regs->vcpu_regs.reserved_64[i]) {
0200                 kfree(cpu_regs);
0201                 return -EINVAL;
0202             }
0203 
0204         for (i = 0; i < ARRAY_SIZE(cpu_regs->vcpu_regs.gdt.reserved); i++)
0205             if (cpu_regs->vcpu_regs.gdt.reserved[i] |
0206                 cpu_regs->vcpu_regs.idt.reserved[i]) {
0207                 kfree(cpu_regs);
0208                 return -EINVAL;
0209             }
0210 
0211         ret = hcall_set_vcpu_regs(vm->vmid, virt_to_phys(cpu_regs));
0212         if (ret < 0)
0213             dev_dbg(acrn_dev.this_device,
0214                 "Failed to set regs state of VM%u!\n",
0215                 vm->vmid);
0216         kfree(cpu_regs);
0217         break;
0218     case ACRN_IOCTL_SET_MEMSEG:
0219         if (copy_from_user(&memmap, (void __user *)ioctl_param,
0220                    sizeof(memmap)))
0221             return -EFAULT;
0222 
0223         ret = acrn_vm_memseg_map(vm, &memmap);
0224         break;
0225     case ACRN_IOCTL_UNSET_MEMSEG:
0226         if (copy_from_user(&memmap, (void __user *)ioctl_param,
0227                    sizeof(memmap)))
0228             return -EFAULT;
0229 
0230         ret = acrn_vm_memseg_unmap(vm, &memmap);
0231         break;
0232     case ACRN_IOCTL_ASSIGN_MMIODEV:
0233         mmiodev = memdup_user((void __user *)ioctl_param,
0234                       sizeof(struct acrn_mmiodev));
0235         if (IS_ERR(mmiodev))
0236             return PTR_ERR(mmiodev);
0237 
0238         ret = hcall_assign_mmiodev(vm->vmid, virt_to_phys(mmiodev));
0239         if (ret < 0)
0240             dev_dbg(acrn_dev.this_device,
0241                 "Failed to assign MMIO device!\n");
0242         kfree(mmiodev);
0243         break;
0244     case ACRN_IOCTL_DEASSIGN_MMIODEV:
0245         mmiodev = memdup_user((void __user *)ioctl_param,
0246                       sizeof(struct acrn_mmiodev));
0247         if (IS_ERR(mmiodev))
0248             return PTR_ERR(mmiodev);
0249 
0250         ret = hcall_deassign_mmiodev(vm->vmid, virt_to_phys(mmiodev));
0251         if (ret < 0)
0252             dev_dbg(acrn_dev.this_device,
0253                 "Failed to deassign MMIO device!\n");
0254         kfree(mmiodev);
0255         break;
0256     case ACRN_IOCTL_ASSIGN_PCIDEV:
0257         pcidev = memdup_user((void __user *)ioctl_param,
0258                      sizeof(struct acrn_pcidev));
0259         if (IS_ERR(pcidev))
0260             return PTR_ERR(pcidev);
0261 
0262         ret = hcall_assign_pcidev(vm->vmid, virt_to_phys(pcidev));
0263         if (ret < 0)
0264             dev_dbg(acrn_dev.this_device,
0265                 "Failed to assign pci device!\n");
0266         kfree(pcidev);
0267         break;
0268     case ACRN_IOCTL_DEASSIGN_PCIDEV:
0269         pcidev = memdup_user((void __user *)ioctl_param,
0270                      sizeof(struct acrn_pcidev));
0271         if (IS_ERR(pcidev))
0272             return PTR_ERR(pcidev);
0273 
0274         ret = hcall_deassign_pcidev(vm->vmid, virt_to_phys(pcidev));
0275         if (ret < 0)
0276             dev_dbg(acrn_dev.this_device,
0277                 "Failed to deassign pci device!\n");
0278         kfree(pcidev);
0279         break;
0280     case ACRN_IOCTL_CREATE_VDEV:
0281         vdev = memdup_user((void __user *)ioctl_param,
0282                    sizeof(struct acrn_vdev));
0283         if (IS_ERR(vdev))
0284             return PTR_ERR(vdev);
0285 
0286         ret = hcall_create_vdev(vm->vmid, virt_to_phys(vdev));
0287         if (ret < 0)
0288             dev_dbg(acrn_dev.this_device,
0289                 "Failed to create virtual device!\n");
0290         kfree(vdev);
0291         break;
0292     case ACRN_IOCTL_DESTROY_VDEV:
0293         vdev = memdup_user((void __user *)ioctl_param,
0294                    sizeof(struct acrn_vdev));
0295         if (IS_ERR(vdev))
0296             return PTR_ERR(vdev);
0297         ret = hcall_destroy_vdev(vm->vmid, virt_to_phys(vdev));
0298         if (ret < 0)
0299             dev_dbg(acrn_dev.this_device,
0300                 "Failed to destroy virtual device!\n");
0301         kfree(vdev);
0302         break;
0303     case ACRN_IOCTL_SET_PTDEV_INTR:
0304         irq_info = memdup_user((void __user *)ioctl_param,
0305                        sizeof(struct acrn_ptdev_irq));
0306         if (IS_ERR(irq_info))
0307             return PTR_ERR(irq_info);
0308 
0309         ret = hcall_set_ptdev_intr(vm->vmid, virt_to_phys(irq_info));
0310         if (ret < 0)
0311             dev_dbg(acrn_dev.this_device,
0312                 "Failed to configure intr for ptdev!\n");
0313         kfree(irq_info);
0314         break;
0315     case ACRN_IOCTL_RESET_PTDEV_INTR:
0316         irq_info = memdup_user((void __user *)ioctl_param,
0317                        sizeof(struct acrn_ptdev_irq));
0318         if (IS_ERR(irq_info))
0319             return PTR_ERR(irq_info);
0320 
0321         ret = hcall_reset_ptdev_intr(vm->vmid, virt_to_phys(irq_info));
0322         if (ret < 0)
0323             dev_dbg(acrn_dev.this_device,
0324                 "Failed to reset intr for ptdev!\n");
0325         kfree(irq_info);
0326         break;
0327     case ACRN_IOCTL_SET_IRQLINE:
0328         ret = hcall_set_irqline(vm->vmid, ioctl_param);
0329         if (ret < 0)
0330             dev_dbg(acrn_dev.this_device,
0331                 "Failed to set interrupt line!\n");
0332         break;
0333     case ACRN_IOCTL_INJECT_MSI:
0334         msi = memdup_user((void __user *)ioctl_param,
0335                   sizeof(struct acrn_msi_entry));
0336         if (IS_ERR(msi))
0337             return PTR_ERR(msi);
0338 
0339         ret = hcall_inject_msi(vm->vmid, virt_to_phys(msi));
0340         if (ret < 0)
0341             dev_dbg(acrn_dev.this_device,
0342                 "Failed to inject MSI!\n");
0343         kfree(msi);
0344         break;
0345     case ACRN_IOCTL_VM_INTR_MONITOR:
0346         ret = pin_user_pages_fast(ioctl_param, 1,
0347                       FOLL_WRITE | FOLL_LONGTERM, &page);
0348         if (unlikely(ret != 1)) {
0349             dev_dbg(acrn_dev.this_device,
0350                 "Failed to pin intr hdr buffer!\n");
0351             return -EFAULT;
0352         }
0353 
0354         ret = hcall_vm_intr_monitor(vm->vmid, page_to_phys(page));
0355         if (ret < 0) {
0356             unpin_user_page(page);
0357             dev_dbg(acrn_dev.this_device,
0358                 "Failed to monitor intr data!\n");
0359             return ret;
0360         }
0361         if (vm->monitor_page)
0362             unpin_user_page(vm->monitor_page);
0363         vm->monitor_page = page;
0364         break;
0365     case ACRN_IOCTL_CREATE_IOREQ_CLIENT:
0366         if (vm->default_client)
0367             return -EEXIST;
0368         if (!acrn_ioreq_client_create(vm, NULL, NULL, true, "acrndm"))
0369             ret = -EINVAL;
0370         break;
0371     case ACRN_IOCTL_DESTROY_IOREQ_CLIENT:
0372         if (vm->default_client)
0373             acrn_ioreq_client_destroy(vm->default_client);
0374         break;
0375     case ACRN_IOCTL_ATTACH_IOREQ_CLIENT:
0376         if (vm->default_client)
0377             ret = acrn_ioreq_client_wait(vm->default_client);
0378         else
0379             ret = -ENODEV;
0380         break;
0381     case ACRN_IOCTL_NOTIFY_REQUEST_FINISH:
0382         if (copy_from_user(&notify, (void __user *)ioctl_param,
0383                    sizeof(struct acrn_ioreq_notify)))
0384             return -EFAULT;
0385 
0386         if (notify.reserved != 0)
0387             return -EINVAL;
0388 
0389         ret = acrn_ioreq_request_default_complete(vm, notify.vcpu);
0390         break;
0391     case ACRN_IOCTL_CLEAR_VM_IOREQ:
0392         acrn_ioreq_request_clear(vm);
0393         break;
0394     case ACRN_IOCTL_PM_GET_CPU_STATE:
0395         if (copy_from_user(&cstate_cmd, (void __user *)ioctl_param,
0396                    sizeof(cstate_cmd)))
0397             return -EFAULT;
0398 
0399         ret = pmcmd_ioctl(cstate_cmd, (void __user *)ioctl_param);
0400         break;
0401     case ACRN_IOCTL_IOEVENTFD:
0402         if (copy_from_user(&ioeventfd, (void __user *)ioctl_param,
0403                    sizeof(ioeventfd)))
0404             return -EFAULT;
0405 
0406         if (ioeventfd.reserved != 0)
0407             return -EINVAL;
0408 
0409         ret = acrn_ioeventfd_config(vm, &ioeventfd);
0410         break;
0411     case ACRN_IOCTL_IRQFD:
0412         if (copy_from_user(&irqfd, (void __user *)ioctl_param,
0413                    sizeof(irqfd)))
0414             return -EFAULT;
0415         ret = acrn_irqfd_config(vm, &irqfd);
0416         break;
0417     default:
0418         dev_dbg(acrn_dev.this_device, "Unknown IOCTL 0x%x!\n", cmd);
0419         ret = -ENOTTY;
0420     }
0421 
0422     return ret;
0423 }
0424 
0425 static int acrn_dev_release(struct inode *inode, struct file *filp)
0426 {
0427     struct acrn_vm *vm = filp->private_data;
0428 
0429     acrn_vm_destroy(vm);
0430     kfree(vm);
0431     return 0;
0432 }
0433 
0434 static ssize_t remove_cpu_store(struct device *dev,
0435                 struct device_attribute *attr,
0436                 const char *buf, size_t count)
0437 {
0438     u64 cpu, lapicid;
0439     int ret;
0440 
0441     if (kstrtoull(buf, 0, &cpu) < 0)
0442         return -EINVAL;
0443 
0444     if (cpu >= num_possible_cpus() || cpu == 0 || !cpu_is_hotpluggable(cpu))
0445         return -EINVAL;
0446 
0447     if (cpu_online(cpu))
0448         remove_cpu(cpu);
0449 
0450     lapicid = cpu_data(cpu).apicid;
0451     dev_dbg(dev, "Try to remove cpu %lld with lapicid %lld\n", cpu, lapicid);
0452     ret = hcall_sos_remove_cpu(lapicid);
0453     if (ret < 0) {
0454         dev_err(dev, "Failed to remove cpu %lld!\n", cpu);
0455         goto fail_remove;
0456     }
0457 
0458     return count;
0459 
0460 fail_remove:
0461     add_cpu(cpu);
0462     return ret;
0463 }
0464 static DEVICE_ATTR_WO(remove_cpu);
0465 
0466 static umode_t acrn_attr_visible(struct kobject *kobj, struct attribute *a, int n)
0467 {
0468        if (a == &dev_attr_remove_cpu.attr)
0469                return IS_ENABLED(CONFIG_HOTPLUG_CPU) ? a->mode : 0;
0470 
0471        return a->mode;
0472 }
0473 
0474 static struct attribute *acrn_attrs[] = {
0475     &dev_attr_remove_cpu.attr,
0476     NULL
0477 };
0478 
0479 static struct attribute_group acrn_attr_group = {
0480     .attrs = acrn_attrs,
0481     .is_visible = acrn_attr_visible,
0482 };
0483 
0484 static const struct attribute_group *acrn_attr_groups[] = {
0485     &acrn_attr_group,
0486     NULL
0487 };
0488 
0489 static const struct file_operations acrn_fops = {
0490     .owner      = THIS_MODULE,
0491     .open       = acrn_dev_open,
0492     .release    = acrn_dev_release,
0493     .unlocked_ioctl = acrn_dev_ioctl,
0494 };
0495 
0496 struct miscdevice acrn_dev = {
0497     .minor  = MISC_DYNAMIC_MINOR,
0498     .name   = "acrn_hsm",
0499     .fops   = &acrn_fops,
0500     .groups = acrn_attr_groups,
0501 };
0502 
0503 static int __init hsm_init(void)
0504 {
0505     int ret;
0506 
0507     if (x86_hyper_type != X86_HYPER_ACRN)
0508         return -ENODEV;
0509 
0510     if (!(cpuid_eax(ACRN_CPUID_FEATURES) & ACRN_FEATURE_PRIVILEGED_VM))
0511         return -EPERM;
0512 
0513     ret = misc_register(&acrn_dev);
0514     if (ret) {
0515         pr_err("Create misc dev failed!\n");
0516         return ret;
0517     }
0518 
0519     ret = acrn_ioreq_intr_setup();
0520     if (ret) {
0521         pr_err("Setup I/O request handler failed!\n");
0522         misc_deregister(&acrn_dev);
0523         return ret;
0524     }
0525     return 0;
0526 }
0527 
0528 static void __exit hsm_exit(void)
0529 {
0530     acrn_ioreq_intr_remove();
0531     misc_deregister(&acrn_dev);
0532 }
0533 module_init(hsm_init);
0534 module_exit(hsm_exit);
0535 
0536 MODULE_AUTHOR("Intel Corporation");
0537 MODULE_LICENSE("GPL");
0538 MODULE_DESCRIPTION("ACRN Hypervisor Service Module (HSM)");