0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/cred.h>
0009 #include <linux/input.h>
0010 #include <linux/kernel.h>
0011 #include <linux/miscdevice.h>
0012 #include <linux/module.h>
0013 #include <linux/pci.h>
0014 #include <linux/poll.h>
0015 #include <linux/vbox_utils.h>
0016 #include "vboxguest_core.h"
0017
0018
0019 #define DEVICE_NAME "vboxguest"
0020
0021 #define DEVICE_NAME_USER "vboxuser"
0022
0023 #define VBOX_VENDORID 0x80ee
0024
0025 #define VMMDEV_DEVICEID 0xcafe
0026
0027
0028 static DEFINE_MUTEX(vbg_gdev_mutex);
0029
0030 static struct vbg_dev *vbg_gdev;
0031
0032 static u32 vbg_misc_device_requestor(struct inode *inode)
0033 {
0034 u32 requestor = VMMDEV_REQUESTOR_USERMODE |
0035 VMMDEV_REQUESTOR_CON_DONT_KNOW |
0036 VMMDEV_REQUESTOR_TRUST_NOT_GIVEN;
0037
0038 if (from_kuid(current_user_ns(), current_uid()) == 0)
0039 requestor |= VMMDEV_REQUESTOR_USR_ROOT;
0040 else
0041 requestor |= VMMDEV_REQUESTOR_USR_USER;
0042
0043 if (in_egroup_p(inode->i_gid))
0044 requestor |= VMMDEV_REQUESTOR_GRP_VBOX;
0045
0046 return requestor;
0047 }
0048
0049 static int vbg_misc_device_open(struct inode *inode, struct file *filp)
0050 {
0051 struct vbg_session *session;
0052 struct vbg_dev *gdev;
0053
0054
0055 gdev = container_of(filp->private_data, struct vbg_dev, misc_device);
0056
0057 session = vbg_core_open_session(gdev, vbg_misc_device_requestor(inode));
0058 if (IS_ERR(session))
0059 return PTR_ERR(session);
0060
0061 filp->private_data = session;
0062 return 0;
0063 }
0064
0065 static int vbg_misc_device_user_open(struct inode *inode, struct file *filp)
0066 {
0067 struct vbg_session *session;
0068 struct vbg_dev *gdev;
0069
0070
0071 gdev = container_of(filp->private_data, struct vbg_dev,
0072 misc_device_user);
0073
0074 session = vbg_core_open_session(gdev, vbg_misc_device_requestor(inode) |
0075 VMMDEV_REQUESTOR_USER_DEVICE);
0076 if (IS_ERR(session))
0077 return PTR_ERR(session);
0078
0079 filp->private_data = session;
0080 return 0;
0081 }
0082
0083
0084
0085
0086
0087
0088
0089 static int vbg_misc_device_close(struct inode *inode, struct file *filp)
0090 {
0091 vbg_core_close_session(filp->private_data);
0092 filp->private_data = NULL;
0093 return 0;
0094 }
0095
0096
0097
0098
0099
0100
0101
0102
0103 static long vbg_misc_device_ioctl(struct file *filp, unsigned int req,
0104 unsigned long arg)
0105 {
0106 struct vbg_session *session = filp->private_data;
0107 size_t returned_size, size;
0108 struct vbg_ioctl_hdr hdr;
0109 bool is_vmmdev_req;
0110 int ret = 0;
0111 void *buf;
0112
0113 if (copy_from_user(&hdr, (void *)arg, sizeof(hdr)))
0114 return -EFAULT;
0115
0116 if (hdr.version != VBG_IOCTL_HDR_VERSION)
0117 return -EINVAL;
0118
0119 if (hdr.size_in < sizeof(hdr) ||
0120 (hdr.size_out && hdr.size_out < sizeof(hdr)))
0121 return -EINVAL;
0122
0123 size = max(hdr.size_in, hdr.size_out);
0124 if (_IOC_SIZE(req) && _IOC_SIZE(req) != size)
0125 return -EINVAL;
0126 if (size > SZ_16M)
0127 return -E2BIG;
0128
0129
0130
0131
0132
0133 is_vmmdev_req = (req & ~IOCSIZE_MASK) == VBG_IOCTL_VMMDEV_REQUEST(0) ||
0134 req == VBG_IOCTL_VMMDEV_REQUEST_BIG ||
0135 req == VBG_IOCTL_VMMDEV_REQUEST_BIG_ALT;
0136
0137 if (is_vmmdev_req)
0138 buf = vbg_req_alloc(size, VBG_IOCTL_HDR_TYPE_DEFAULT,
0139 session->requestor);
0140 else
0141 buf = kmalloc(size, GFP_KERNEL);
0142 if (!buf)
0143 return -ENOMEM;
0144
0145 *((struct vbg_ioctl_hdr *)buf) = hdr;
0146 if (copy_from_user(buf + sizeof(hdr), (void *)arg + sizeof(hdr),
0147 hdr.size_in - sizeof(hdr))) {
0148 ret = -EFAULT;
0149 goto out;
0150 }
0151 if (hdr.size_in < size)
0152 memset(buf + hdr.size_in, 0, size - hdr.size_in);
0153
0154 ret = vbg_core_ioctl(session, req, buf);
0155 if (ret)
0156 goto out;
0157
0158 returned_size = ((struct vbg_ioctl_hdr *)buf)->size_out;
0159 if (returned_size > size) {
0160 vbg_debug("%s: too much output data %zu > %zu\n",
0161 __func__, returned_size, size);
0162 returned_size = size;
0163 }
0164 if (copy_to_user((void *)arg, buf, returned_size) != 0)
0165 ret = -EFAULT;
0166
0167 out:
0168 if (is_vmmdev_req)
0169 vbg_req_free(buf, size);
0170 else
0171 kfree(buf);
0172
0173 return ret;
0174 }
0175
0176
0177 static const struct file_operations vbg_misc_device_fops = {
0178 .owner = THIS_MODULE,
0179 .open = vbg_misc_device_open,
0180 .release = vbg_misc_device_close,
0181 .unlocked_ioctl = vbg_misc_device_ioctl,
0182 #ifdef CONFIG_COMPAT
0183 .compat_ioctl = vbg_misc_device_ioctl,
0184 #endif
0185 };
0186 static const struct file_operations vbg_misc_device_user_fops = {
0187 .owner = THIS_MODULE,
0188 .open = vbg_misc_device_user_open,
0189 .release = vbg_misc_device_close,
0190 .unlocked_ioctl = vbg_misc_device_ioctl,
0191 #ifdef CONFIG_COMPAT
0192 .compat_ioctl = vbg_misc_device_ioctl,
0193 #endif
0194 };
0195
0196
0197
0198
0199
0200
0201 static int vbg_input_open(struct input_dev *input)
0202 {
0203 struct vbg_dev *gdev = input_get_drvdata(input);
0204 u32 feat = VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE | VMMDEV_MOUSE_NEW_PROTOCOL;
0205
0206 return vbg_core_set_mouse_status(gdev, feat);
0207 }
0208
0209
0210
0211
0212
0213
0214 static void vbg_input_close(struct input_dev *input)
0215 {
0216 struct vbg_dev *gdev = input_get_drvdata(input);
0217
0218 vbg_core_set_mouse_status(gdev, 0);
0219 }
0220
0221
0222
0223
0224
0225
0226 static int vbg_create_input_device(struct vbg_dev *gdev)
0227 {
0228 struct input_dev *input;
0229
0230 input = devm_input_allocate_device(gdev->dev);
0231 if (!input)
0232 return -ENOMEM;
0233
0234 input->id.bustype = BUS_PCI;
0235 input->id.vendor = VBOX_VENDORID;
0236 input->id.product = VMMDEV_DEVICEID;
0237 input->open = vbg_input_open;
0238 input->close = vbg_input_close;
0239 input->dev.parent = gdev->dev;
0240 input->name = "VirtualBox mouse integration";
0241
0242 input_set_abs_params(input, ABS_X, VMMDEV_MOUSE_RANGE_MIN,
0243 VMMDEV_MOUSE_RANGE_MAX, 0, 0);
0244 input_set_abs_params(input, ABS_Y, VMMDEV_MOUSE_RANGE_MIN,
0245 VMMDEV_MOUSE_RANGE_MAX, 0, 0);
0246 input_set_capability(input, EV_KEY, BTN_MOUSE);
0247 input_set_drvdata(input, gdev);
0248
0249 gdev->input = input;
0250
0251 return input_register_device(gdev->input);
0252 }
0253
0254 static ssize_t host_version_show(struct device *dev,
0255 struct device_attribute *attr, char *buf)
0256 {
0257 struct vbg_dev *gdev = dev_get_drvdata(dev);
0258
0259 return sprintf(buf, "%s\n", gdev->host_version);
0260 }
0261
0262 static ssize_t host_features_show(struct device *dev,
0263 struct device_attribute *attr, char *buf)
0264 {
0265 struct vbg_dev *gdev = dev_get_drvdata(dev);
0266
0267 return sprintf(buf, "%#x\n", gdev->host_features);
0268 }
0269
0270 static DEVICE_ATTR_RO(host_version);
0271 static DEVICE_ATTR_RO(host_features);
0272
0273
0274
0275
0276
0277
0278 static int vbg_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
0279 {
0280 struct device *dev = &pci->dev;
0281 resource_size_t io, io_len, mmio, mmio_len;
0282 struct vmmdev_memory *vmmdev;
0283 struct vbg_dev *gdev;
0284 int ret;
0285
0286 gdev = devm_kzalloc(dev, sizeof(*gdev), GFP_KERNEL);
0287 if (!gdev)
0288 return -ENOMEM;
0289
0290 ret = pci_enable_device(pci);
0291 if (ret != 0) {
0292 vbg_err("vboxguest: Error enabling device: %d\n", ret);
0293 return ret;
0294 }
0295
0296 ret = -ENODEV;
0297
0298 io = pci_resource_start(pci, 0);
0299 io_len = pci_resource_len(pci, 0);
0300 if (!io || !io_len) {
0301 vbg_err("vboxguest: Error IO-port resource (0) is missing\n");
0302 goto err_disable_pcidev;
0303 }
0304 if (devm_request_region(dev, io, io_len, DEVICE_NAME) == NULL) {
0305 vbg_err("vboxguest: Error could not claim IO resource\n");
0306 ret = -EBUSY;
0307 goto err_disable_pcidev;
0308 }
0309
0310 mmio = pci_resource_start(pci, 1);
0311 mmio_len = pci_resource_len(pci, 1);
0312 if (!mmio || !mmio_len) {
0313 vbg_err("vboxguest: Error MMIO resource (1) is missing\n");
0314 goto err_disable_pcidev;
0315 }
0316
0317 if (devm_request_mem_region(dev, mmio, mmio_len, DEVICE_NAME) == NULL) {
0318 vbg_err("vboxguest: Error could not claim MMIO resource\n");
0319 ret = -EBUSY;
0320 goto err_disable_pcidev;
0321 }
0322
0323 vmmdev = devm_ioremap(dev, mmio, mmio_len);
0324 if (!vmmdev) {
0325 vbg_err("vboxguest: Error ioremap failed; MMIO addr=%pap size=%pap\n",
0326 &mmio, &mmio_len);
0327 goto err_disable_pcidev;
0328 }
0329
0330
0331 if (vmmdev->version != VMMDEV_MEMORY_VERSION ||
0332 vmmdev->size < 32 || vmmdev->size > mmio_len) {
0333 vbg_err("vboxguest: Bogus VMMDev memory; version=%08x (expected %08x) size=%d (expected <= %d)\n",
0334 vmmdev->version, VMMDEV_MEMORY_VERSION,
0335 vmmdev->size, (int)mmio_len);
0336 goto err_disable_pcidev;
0337 }
0338
0339 gdev->io_port = io;
0340 gdev->mmio = vmmdev;
0341 gdev->dev = dev;
0342 gdev->misc_device.minor = MISC_DYNAMIC_MINOR;
0343 gdev->misc_device.name = DEVICE_NAME;
0344 gdev->misc_device.fops = &vbg_misc_device_fops;
0345 gdev->misc_device_user.minor = MISC_DYNAMIC_MINOR;
0346 gdev->misc_device_user.name = DEVICE_NAME_USER;
0347 gdev->misc_device_user.fops = &vbg_misc_device_user_fops;
0348
0349 ret = vbg_core_init(gdev, VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
0350 if (ret)
0351 goto err_disable_pcidev;
0352
0353 ret = vbg_create_input_device(gdev);
0354 if (ret) {
0355 vbg_err("vboxguest: Error creating input device: %d\n", ret);
0356 goto err_vbg_core_exit;
0357 }
0358
0359 ret = request_irq(pci->irq, vbg_core_isr, IRQF_SHARED, DEVICE_NAME,
0360 gdev);
0361 if (ret) {
0362 vbg_err("vboxguest: Error requesting irq: %d\n", ret);
0363 goto err_vbg_core_exit;
0364 }
0365
0366 ret = misc_register(&gdev->misc_device);
0367 if (ret) {
0368 vbg_err("vboxguest: Error misc_register %s failed: %d\n",
0369 DEVICE_NAME, ret);
0370 goto err_free_irq;
0371 }
0372
0373 ret = misc_register(&gdev->misc_device_user);
0374 if (ret) {
0375 vbg_err("vboxguest: Error misc_register %s failed: %d\n",
0376 DEVICE_NAME_USER, ret);
0377 goto err_unregister_misc_device;
0378 }
0379
0380 mutex_lock(&vbg_gdev_mutex);
0381 if (!vbg_gdev)
0382 vbg_gdev = gdev;
0383 else
0384 ret = -EBUSY;
0385 mutex_unlock(&vbg_gdev_mutex);
0386
0387 if (ret) {
0388 vbg_err("vboxguest: Error more then 1 vbox guest pci device\n");
0389 goto err_unregister_misc_device_user;
0390 }
0391
0392 pci_set_drvdata(pci, gdev);
0393 device_create_file(dev, &dev_attr_host_version);
0394 device_create_file(dev, &dev_attr_host_features);
0395
0396 vbg_info("vboxguest: misc device minor %d, IRQ %d, I/O port %x, MMIO at %pap (size %pap)\n",
0397 gdev->misc_device.minor, pci->irq, gdev->io_port,
0398 &mmio, &mmio_len);
0399
0400 return 0;
0401
0402 err_unregister_misc_device_user:
0403 misc_deregister(&gdev->misc_device_user);
0404 err_unregister_misc_device:
0405 misc_deregister(&gdev->misc_device);
0406 err_free_irq:
0407 free_irq(pci->irq, gdev);
0408 err_vbg_core_exit:
0409 vbg_core_exit(gdev);
0410 err_disable_pcidev:
0411 pci_disable_device(pci);
0412
0413 return ret;
0414 }
0415
0416 static void vbg_pci_remove(struct pci_dev *pci)
0417 {
0418 struct vbg_dev *gdev = pci_get_drvdata(pci);
0419
0420 mutex_lock(&vbg_gdev_mutex);
0421 vbg_gdev = NULL;
0422 mutex_unlock(&vbg_gdev_mutex);
0423
0424 free_irq(pci->irq, gdev);
0425 device_remove_file(gdev->dev, &dev_attr_host_features);
0426 device_remove_file(gdev->dev, &dev_attr_host_version);
0427 misc_deregister(&gdev->misc_device_user);
0428 misc_deregister(&gdev->misc_device);
0429 vbg_core_exit(gdev);
0430 pci_disable_device(pci);
0431 }
0432
0433 struct vbg_dev *vbg_get_gdev(void)
0434 {
0435 mutex_lock(&vbg_gdev_mutex);
0436
0437
0438
0439
0440
0441
0442 if (vbg_gdev)
0443 return vbg_gdev;
0444
0445 mutex_unlock(&vbg_gdev_mutex);
0446 return ERR_PTR(-ENODEV);
0447 }
0448 EXPORT_SYMBOL(vbg_get_gdev);
0449
0450 void vbg_put_gdev(struct vbg_dev *gdev)
0451 {
0452 WARN_ON(gdev != vbg_gdev);
0453 mutex_unlock(&vbg_gdev_mutex);
0454 }
0455 EXPORT_SYMBOL(vbg_put_gdev);
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465 void vbg_linux_mouse_event(struct vbg_dev *gdev)
0466 {
0467 int rc;
0468
0469
0470 gdev->mouse_status_req->mouse_features = 0;
0471 gdev->mouse_status_req->pointer_pos_x = 0;
0472 gdev->mouse_status_req->pointer_pos_y = 0;
0473 rc = vbg_req_perform(gdev, gdev->mouse_status_req);
0474 if (rc >= 0) {
0475 input_report_abs(gdev->input, ABS_X,
0476 gdev->mouse_status_req->pointer_pos_x);
0477 input_report_abs(gdev->input, ABS_Y,
0478 gdev->mouse_status_req->pointer_pos_y);
0479 input_sync(gdev->input);
0480 }
0481 }
0482
0483 static const struct pci_device_id vbg_pci_ids[] = {
0484 { .vendor = VBOX_VENDORID, .device = VMMDEV_DEVICEID },
0485 {}
0486 };
0487 MODULE_DEVICE_TABLE(pci, vbg_pci_ids);
0488
0489 static struct pci_driver vbg_pci_driver = {
0490 .name = DEVICE_NAME,
0491 .id_table = vbg_pci_ids,
0492 .probe = vbg_pci_probe,
0493 .remove = vbg_pci_remove,
0494 };
0495
0496 module_pci_driver(vbg_pci_driver);
0497
0498 MODULE_AUTHOR("Oracle Corporation");
0499 MODULE_DESCRIPTION("Oracle VM VirtualBox Guest Additions for Linux Module");
0500 MODULE_LICENSE("GPL");