VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/drm/vbox_drv.c

Last change on this file was 103788, checked in by vboxsync, 8 weeks ago

Linux Additions: Add possiblity to prevent kernel modules from loading in kernel command line, bugref:8409.

Add to kernel command line either vboxguest.disabled=1 and/or vboxsf.disabled=1
and/or vboxvideo.disabled=1 in order to prevent certain module or all of them
from loading during system boot.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.6 KB
RevLine 
[58129]1/* $Id: vbox_drv.c 103788 2024-03-11 17:50:25Z vboxsync $ */
2/** @file
[48115]3 * VirtualBox Additions Linux kernel video driver
4 */
5
6/*
[98103]7 * Copyright (C) 2013-2023 Oracle and/or its affiliates.
[66544]8 * This file is based on ast_drv.c
[48115]9 * Copyright 2012 Red Hat Inc.
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the
13 * "Software"), to deal in the Software without restriction, including
14 * without limitation the rights to use, copy, modify, merge, publish,
15 * distribute, sub license, and/or sell copies of the Software, and to
16 * permit persons to whom the Software is furnished to do so, subject to
17 * the following conditions:
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
22 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25 * USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * The above copyright notice and this permission notice (including the
28 * next paragraph) shall be included in all copies or substantial portions
29 * of the Software.
30 *
31 * Authors: Dave Airlie <airlied@redhat.com>
[66544]32 * Michael Thayer <michael.thayer@oracle.com,
33 * Hans de Goede <hdegoede@redhat.com>
[48115]34 */
35#include <linux/module.h>
36#include <linux/console.h>
[60104]37#include <linux/vt_kern.h>
[48115]38
[83109]39#include "vbox_drv.h"
40
[48115]41#include <drm/drm_crtc_helper.h>
[85705]42#if RTLNX_VER_MIN(5,1,0) || RTLNX_RHEL_MAJ_PREREQ(8,1)
[85707]43# include <drm/drm_probe_helper.h>
[77850]44#endif
45
[94330]46#if RTLNX_VER_MIN(5,14,0) || RTLNX_RHEL_RANGE(8,6, 8,99)
[90498]47# include <drm/drm_aperture.h>
48#endif
49
[74773]50#include "version-generated.h"
51#include "revision-generated.h"
52
[93416]53/** Detect whether kernel mode setting is OFF. */
54#if defined(CONFIG_VGA_CONSOLE)
[100677]55# if RTLNX_VER_MIN(5,17,0) || RTLNX_RHEL_RANGE(8,7, 8,99) || RTLNX_RHEL_MIN(9,1) || RTLNX_SUSE_MAJ_PREREQ(15,5)
[93416]56# define VBOX_VIDEO_NOMODESET() drm_firmware_drivers_only() && vbox_modeset == -1
57# elif RTLNX_VER_MIN(4,7,0)
58# define VBOX_VIDEO_NOMODESET() vgacon_text_force() && vbox_modeset == -1
59# else /* < 4.7.0 */
60# define VBOX_VIDEO_NOMODESET() 0
61# endif /* < 4.7.0 */
62#else /* !CONFIG_VGA_CONSOLE */
63# define VBOX_VIDEO_NOMODESET() 0
64#endif /* !CONFIG_VGA_CONSOLE */
65
[103788]66#include <VBox/VBoxLnxModInline.h>
67
[74810]68static int vbox_modeset = -1;
[48115]69
70MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
71module_param_named(modeset, vbox_modeset, int, 0400);
72
73static struct drm_driver driver;
74
[67395]75static const struct pci_device_id pciidlist[] = {
76 { 0x80ee, 0xbeef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
77 { 0, 0, 0},
[48115]78};
79MODULE_DEVICE_TABLE(pci, pciidlist);
80
81static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
82{
[86196]83#if RTLNX_VER_MIN(4,19,0) || RTLNX_RHEL_MIN(8,3)
[76976]84 struct drm_device *dev = NULL;
85 int ret = 0;
86
[94330]87# if RTLNX_VER_MIN(5,14,0) || RTLNX_RHEL_RANGE(8,6, 8,99)
[97566]88# if RTLNX_VER_MIN(5,15,0) || RTLNX_RHEL_RANGE(8,7, 8,99) || RTLNX_RHEL_MIN(9,1) || RTLNX_SUSE_MAJ_PREREQ(15,4)
[91233]89 ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &driver);
90# else
[90498]91 ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "vboxvideofb");
[91233]92# endif
[90498]93 if (ret)
94 {
95 printk("unable to remove conflicting framebuffer devices\n");
96 return ret;
97 }
[91233]98# endif /* >= 5.14. */
[90498]99
[76976]100 dev = drm_dev_alloc(&driver, &pdev->dev);
101 if (IS_ERR(dev)) {
102 ret = PTR_ERR(dev);
103 goto err_drv_alloc;
104 }
[94330]105# if RTLNX_VER_MAX(5,14,0) && !RTLNX_RHEL_RANGE(8,6, 8,99)
[76976]106 dev->pdev = pdev;
[90583]107# endif
[76976]108 pci_set_drvdata(pdev, dev);
109
110 ret = vbox_driver_load(dev);
111 if (ret)
112 goto err_vbox_driver_load;
113
114 ret = drm_dev_register(dev, 0);
115 if (ret)
116 goto err_drv_dev_register;
117 return ret;
118
119err_drv_dev_register:
120 vbox_driver_unload(dev);
121err_vbox_driver_load:
122 drm_dev_put(dev);
123err_drv_alloc:
124 return ret;
[86196]125#else /* < 4.19.0 || RHEL < 8.3 */
126 return drm_get_pci_dev(pdev, ent, &driver);
[76976]127#endif
[48115]128}
129
[49518]130static void vbox_pci_remove(struct pci_dev *pdev)
[48115]131{
[67395]132 struct drm_device *dev = pci_get_drvdata(pdev);
[48115]133
[85704]134#if RTLNX_VER_MAX(4,19,0)
[67395]135 drm_put_dev(dev);
[76976]136#else
137 drm_dev_unregister(dev);
138 vbox_driver_unload(dev);
139 drm_dev_put(dev);
140#endif
[48115]141}
142
[85705]143#if RTLNX_VER_MAX(4,9,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4)
[74773]144static void drm_fb_helper_set_suspend_unlocked(struct drm_fb_helper *fb_helper,
145 bool suspend)
146{
147 if (!fb_helper || !fb_helper->fbdev)
148 return;
149
150 console_lock();
151 fb_set_suspend(fb_helper->fbdev, suspend);
152 console_unlock();
153}
154#endif
155
[59526]156static int vbox_drm_freeze(struct drm_device *dev)
157{
[74773]158 struct vbox_private *vbox = dev->dev_private;
159
[67395]160 drm_kms_helper_poll_disable(dev);
[59526]161
[90498]162 pci_save_state(VBOX_DRM_TO_PCI_DEV(dev));
[59526]163
[74773]164 drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, true);
[67395]165
166 return 0;
[59526]167}
168
169static int vbox_drm_thaw(struct drm_device *dev)
170{
[74773]171 struct vbox_private *vbox = dev->dev_private;
172
[67395]173 drm_mode_config_reset(dev);
174 drm_helper_resume_force_mode(dev);
[74773]175 drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, false);
[59526]176
[67395]177 return 0;
[59526]178}
179
180static int vbox_drm_resume(struct drm_device *dev)
181{
[67395]182 int ret;
[59526]183
[90498]184 if (pci_enable_device(VBOX_DRM_TO_PCI_DEV(dev)))
[67395]185 return -EIO;
[59526]186
[67395]187 ret = vbox_drm_thaw(dev);
188 if (ret)
189 return ret;
[59526]190
[67395]191 drm_kms_helper_poll_enable(dev);
192
193 return 0;
[59526]194}
195
196static int vbox_pm_suspend(struct device *dev)
197{
[67395]198 struct pci_dev *pdev = to_pci_dev(dev);
199 struct drm_device *ddev = pci_get_drvdata(pdev);
200 int error;
[59526]201
[67395]202 error = vbox_drm_freeze(ddev);
203 if (error)
204 return error;
[59526]205
[67395]206 pci_disable_device(pdev);
207 pci_set_power_state(pdev, PCI_D3hot);
208
209 return 0;
[59526]210}
211
212static int vbox_pm_resume(struct device *dev)
213{
[67395]214 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
215
216 return vbox_drm_resume(ddev);
[59526]217}
218
219static int vbox_pm_freeze(struct device *dev)
220{
[67395]221 struct pci_dev *pdev = to_pci_dev(dev);
222 struct drm_device *ddev = pci_get_drvdata(pdev);
[59526]223
[67395]224 if (!ddev || !ddev->dev_private)
225 return -ENODEV;
[59526]226
[67395]227 return vbox_drm_freeze(ddev);
[59526]228}
229
230static int vbox_pm_thaw(struct device *dev)
231{
[67395]232 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
233
234 return vbox_drm_thaw(ddev);
[59526]235}
236
237static int vbox_pm_poweroff(struct device *dev)
238{
[67395]239 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
[59526]240
[67395]241 return vbox_drm_freeze(ddev);
[59526]242}
243
244static const struct dev_pm_ops vbox_pm_ops = {
[67395]245 .suspend = vbox_pm_suspend,
246 .resume = vbox_pm_resume,
247 .freeze = vbox_pm_freeze,
248 .thaw = vbox_pm_thaw,
249 .poweroff = vbox_pm_poweroff,
250 .restore = vbox_pm_resume,
[59526]251};
252
[67395]253static struct pci_driver vbox_pci_driver = {
254 .name = DRIVER_NAME,
255 .id_table = pciidlist,
256 .probe = vbox_pci_probe,
257 .remove = vbox_pci_remove,
258 .driver.pm = &vbox_pm_ops,
[48115]259};
260
[85705]261#if RTLNX_VER_MAX(4,7,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4)
[63551]262/* This works around a bug in X servers prior to 1.18.4, which sometimes
263 * submit more dirty rectangles than the kernel is willing to handle and
264 * then disable dirty rectangle handling altogether when they see the
265 * EINVAL error. I do not want the code to hang around forever, which is
266 * why I am limiting it to certain kernel versions. We can increase the
267 * limit if some distributions uses old X servers with new kernels. */
[67395]268long vbox_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
[63551]269{
[67395]270 long rc = drm_ioctl(filp, cmd, arg);
271
272 if (cmd == DRM_IOCTL_MODE_DIRTYFB && rc == -EINVAL)
273 return -EOVERFLOW;
274
275 return rc;
[63551]276}
[85705]277#endif /* RTLNX_VER_MAX(4,7,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4) */
[63551]278
[67395]279static const struct file_operations vbox_fops = {
280 .owner = THIS_MODULE,
281 .open = drm_open,
282 .release = drm_release,
[85705]283#if RTLNX_VER_MAX(4,7,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4)
[67395]284 .unlocked_ioctl = vbox_ioctl,
[63551]285#else
[67395]286 .unlocked_ioctl = drm_ioctl,
[63551]287#endif
[67395]288 .mmap = vbox_mmap,
289 .poll = drm_poll,
[85705]290#if RTLNX_VER_MAX(3,12,0) && !RTLNX_RHEL_MAJ_PREREQ(7,0)
[67395]291 .fasync = drm_fasync,
[52599]292#endif
[48115]293#ifdef CONFIG_COMPAT
[67395]294 .compat_ioctl = drm_compat_ioctl,
[48115]295#endif
[67395]296 .read = drm_read,
[48115]297};
298
[89690]299#if RTLNX_VER_MIN(5,9,0) || RTLNX_RHEL_MIN(8,4) || RTLNX_SUSE_MAJ_PREREQ(15,3)
[86542]300static void
301#else
302static int
303#endif
[86547]304vbox_master_set(struct drm_device *dev,
305 struct drm_file *file_priv, bool from_open)
[60352]306{
[67395]307 struct vbox_private *vbox = dev->dev_private;
308
309 /*
310 * We do not yet know whether the new owner can handle hotplug, so we
311 * do not advertise dynamic modes on the first query and send a
312 * tentative hotplug notification after that to see if they query again.
313 */
314 vbox->initial_mode_queried = false;
315
316 mutex_lock(&vbox->hw_mutex);
[74581]317 /* Start the refresh timer in case the user does not provide dirty
318 * rectangles. */
319 vbox->need_refresh_timer = true;
320 schedule_delayed_work(&vbox->refresh_work, VBOX_REFRESH_PERIOD);
[67395]321 mutex_unlock(&vbox->hw_mutex);
322
[89690]323#if RTLNX_VER_MAX(5,9,0) && !RTLNX_RHEL_MAJ_PREREQ(8,4) && !RTLNX_SUSE_MAJ_PREREQ(15,3)
[67395]324 return 0;
[86542]325#endif
[60352]326}
327
[85705]328#if RTLNX_VER_MAX(4,8,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4)
[60352]329static void vbox_master_drop(struct drm_device *dev,
[67395]330 struct drm_file *file_priv, bool from_release)
[63755]331#else
[67395]332static void vbox_master_drop(struct drm_device *dev, struct drm_file *file_priv)
[63755]333#endif
[60352]334{
[67395]335 struct vbox_private *vbox = dev->dev_private;
336
337 /* See vbox_master_set() */
338 vbox->initial_mode_queried = false;
[74963]339 vbox_report_caps(vbox);
[67395]340
341 mutex_lock(&vbox->hw_mutex);
[74581]342 vbox->need_refresh_timer = false;
[67395]343 mutex_unlock(&vbox->hw_mutex);
[60352]344}
345
[67395]346static struct drm_driver driver = {
[89690]347#if RTLNX_VER_MAX(5,4,0) && !RTLNX_RHEL_MAJ_PREREQ(8,3) && !RTLNX_SUSE_MAJ_PREREQ(15,3)
[86196]348 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ |
[85705]349# if RTLNX_VER_MAX(5,1,0) && !RTLNX_RHEL_MAJ_PREREQ(8,1)
[77850]350 DRIVER_IRQ_SHARED |
[85705]351# endif
[67395]352 DRIVER_PRIME,
[89690]353#else /* >= 5.4.0 && RHEL >= 8.3 && SLES >= 15-SP3 */
[88274]354 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ,
[86174]355#endif /* < 5.4.0 */
[48115]356
[86196]357#if RTLNX_VER_MAX(4,19,0) && !RTLNX_RHEL_MAJ_PREREQ(8,3)
[88274]358 /* Legacy hooks, but still supported. */
[67395]359 .load = vbox_driver_load,
360 .unload = vbox_driver_unload,
[76976]361#endif
[67395]362 .lastclose = vbox_driver_lastclose,
363 .master_set = vbox_master_set,
364 .master_drop = vbox_master_drop,
[85705]365#if RTLNX_VER_MIN(3,18,0) || RTLNX_RHEL_MAJ_PREREQ(7,2)
[85707]366# if RTLNX_VER_MAX(4,14,0) && !RTLNX_RHEL_MAJ_PREREQ(7,5) && !RTLNX_SUSE_MAJ_PREREQ(15,1) && !RTLNX_SUSE_MAJ_PREREQ(12,5)
[67395]367 .set_busid = drm_pci_set_busid,
[69143]368# endif
[59526]369#endif
[48115]370
[67395]371 .fops = &vbox_fops,
[100677]372#if RTLNX_VER_MAX(5,15,0) && !RTLNX_RHEL_RANGE(8,7, 8,99) && !RTLNX_RHEL_MAJ_PREREQ(9,1) && !RTLNX_SUSE_MAJ_PREREQ(15,5)
[67395]373 .irq_handler = vbox_irq_handler,
[91233]374#endif
[67395]375 .name = DRIVER_NAME,
376 .desc = DRIVER_DESC,
377 .date = DRIVER_DATE,
378 .major = DRIVER_MAJOR,
379 .minor = DRIVER_MINOR,
380 .patchlevel = DRIVER_PATCHLEVEL,
[48115]381
[85704]382#if RTLNX_VER_MAX(4,7,0)
[67395]383 .gem_free_object = vbox_gem_free_object,
[76943]384#endif
[67395]385 .dumb_create = vbox_dumb_create,
386 .dumb_map_offset = vbox_dumb_mmap_offset,
[85705]387#if RTLNX_VER_MAX(3,12,0) && !RTLNX_RHEL_MAJ_PREREQ(7,3)
[67395]388 .dumb_destroy = vbox_dumb_destroy,
[90577]389#elif RTLNX_VER_MAX(5,12,0) && !RTLNX_RHEL_MAJ_PREREQ(8,5)
[67395]390 .dumb_destroy = drm_gem_dumb_destroy,
[59568]391#endif
[102874]392#if RTLNX_VER_MAX(6,6,0) && !RTLNX_RHEL_RANGE(9,4, 9,99)
[67395]393 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
394 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
[101079]395#endif
[88207]396 .gem_prime_import = drm_gem_prime_import,
397 .gem_prime_import_sg_table = vbox_gem_prime_import_sg_table,
[102874]398#if RTLNX_VER_MAX(6,6,0) && !RTLNX_RHEL_RANGE(9,4, 9,99)
[88207]399 .gem_prime_mmap = vbox_gem_prime_mmap,
[101079]400#endif
[88207]401
[90577]402#if RTLNX_VER_MAX(5,11,0) && !RTLNX_RHEL_MAJ_PREREQ(8,5)
[88207]403 .dev_priv_size = 0,
[88212]404# if RTLNX_VER_MIN(4,7,0)
[88207]405 .gem_free_object_unlocked = vbox_gem_free_object,
[88212]406# endif
[67395]407 .gem_prime_export = drm_gem_prime_export,
408 .gem_prime_pin = vbox_gem_prime_pin,
409 .gem_prime_unpin = vbox_gem_prime_unpin,
410 .gem_prime_get_sg_table = vbox_gem_prime_get_sg_table,
411 .gem_prime_vmap = vbox_gem_prime_vmap,
412 .gem_prime_vunmap = vbox_gem_prime_vunmap,
[88207]413#endif
[48115]414};
415
416static int __init vbox_init(void)
417{
[103788]418 /* Check if modue loading was disabled. */
419 if (!vbox_mod_should_load())
420 return -EINVAL;
421
[88510]422 printk("vboxvideo: loading version " VBOX_VERSION_STRING " r" __stringify(VBOX_SVN_REV) "\n");
[93416]423 if (VBOX_VIDEO_NOMODESET())
[89689]424 {
425 printk("vboxvideo: kernel is running with *nomodeset* parameter,\n");
426 printk("vboxvideo: please consider either to remove it or load driver\n");
427 printk("vboxvideo: with parameter modeset=1, unloading\n");
[67395]428 return -EINVAL;
[89689]429 }
[48115]430
[67395]431 if (vbox_modeset == 0)
[89689]432 {
433 printk("vboxvideo: driver loaded with modeset=0 parameter, unloading\n");
[67395]434 return -EINVAL;
[89689]435 }
[60104]436
[85705]437#if RTLNX_VER_MIN(3,18,0) || RTLNX_RHEL_MAJ_PREREQ(7,3)
[69143]438 return pci_register_driver(&vbox_pci_driver);
[79690]439#else
440 return drm_pci_init(&driver, &vbox_pci_driver);
441#endif
[48115]442}
[67395]443
[48115]444static void __exit vbox_exit(void)
445{
[85705]446#if RTLNX_VER_MIN(3,18,0) || RTLNX_RHEL_MAJ_PREREQ(7,3)
[69143]447 pci_unregister_driver(&vbox_pci_driver);
[79690]448#else
449 drm_pci_exit(&driver, &vbox_pci_driver);
450#endif
[48115]451}
452
453module_init(vbox_init);
454module_exit(vbox_exit);
455
456MODULE_AUTHOR(DRIVER_AUTHOR);
457MODULE_DESCRIPTION(DRIVER_DESC);
458MODULE_LICENSE("GPL and additional rights");
[60584]459#ifdef MODULE_VERSION
[67177]460MODULE_VERSION(VBOX_VERSION_STRING " r" __stringify(VBOX_SVN_REV));
[60584]461#endif
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use