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).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
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)");
539