cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hsm.c (13287B)


      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 */
     29static 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
     42static 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 */
    107static 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
    425static 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
    434static 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).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
    460fail_remove:
    461	add_cpu(cpu);
    462	return ret;
    463}
    464static DEVICE_ATTR_WO(remove_cpu);
    465
    466static 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
    474static struct attribute *acrn_attrs[] = {
    475	&dev_attr_remove_cpu.attr,
    476	NULL
    477};
    478
    479static struct attribute_group acrn_attr_group = {
    480	.attrs = acrn_attrs,
    481	.is_visible = acrn_attr_visible,
    482};
    483
    484static const struct attribute_group *acrn_attr_groups[] = {
    485	&acrn_attr_group,
    486	NULL
    487};
    488
    489static 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
    496struct miscdevice acrn_dev = {
    497	.minor	= MISC_DYNAMIC_MINOR,
    498	.name	= "acrn_hsm",
    499	.fops	= &acrn_fops,
    500	.groups	= acrn_attr_groups,
    501};
    502
    503static 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
    528static void __exit hsm_exit(void)
    529{
    530	acrn_ioreq_intr_remove();
    531	misc_deregister(&acrn_dev);
    532}
    533module_init(hsm_init);
    534module_exit(hsm_exit);
    535
    536MODULE_AUTHOR("Intel Corporation");
    537MODULE_LICENSE("GPL");
    538MODULE_DESCRIPTION("ACRN Hypervisor Service Module (HSM)");