VirtualBox

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

Last change on this file was 103788, checked in by vboxsync, 7 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
Line 
1/* $Id: vbox_drv.c 103788 2024-03-11 17:50:25Z vboxsync $ */
2/** @file
3 * VirtualBox Additions Linux kernel video driver
4 */
5
6/*
7 * Copyright (C) 2013-2023 Oracle and/or its affiliates.
8 * This file is based on ast_drv.c
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>
32 * Michael Thayer <michael.thayer@oracle.com,
33 * Hans de Goede <hdegoede@redhat.com>
34 */
35#include <linux/module.h>
36#include <linux/console.h>
37#include <linux/vt_kern.h>
38
39#include "vbox_drv.h"
40
41#include <drm/drm_crtc_helper.h>
42#if RTLNX_VER_MIN(5,1,0) || RTLNX_RHEL_MAJ_PREREQ(8,1)
43# include <drm/drm_probe_helper.h>
44#endif
45
46#if RTLNX_VER_MIN(5,14,0) || RTLNX_RHEL_RANGE(8,6, 8,99)
47# include <drm/drm_aperture.h>
48#endif
49
50#include "version-generated.h"
51#include "revision-generated.h"
52
53/** Detect whether kernel mode setting is OFF. */
54#if defined(CONFIG_VGA_CONSOLE)
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)
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
66#include <VBox/VBoxLnxModInline.h>
67
68static int vbox_modeset = -1;
69
70MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
71module_param_named(modeset, vbox_modeset, int, 0400);
72
73static struct drm_driver driver;
74
75static const struct pci_device_id pciidlist[] = {
76 { 0x80ee, 0xbeef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
77 { 0, 0, 0},
78};
79MODULE_DEVICE_TABLE(pci, pciidlist);
80
81static int vbox_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
82{
83#if RTLNX_VER_MIN(4,19,0) || RTLNX_RHEL_MIN(8,3)
84 struct drm_device *dev = NULL;
85 int ret = 0;
86
87# if RTLNX_VER_MIN(5,14,0) || RTLNX_RHEL_RANGE(8,6, 8,99)
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)
89 ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, &driver);
90# else
91 ret = drm_aperture_remove_conflicting_pci_framebuffers(pdev, "vboxvideofb");
92# endif
93 if (ret)
94 {
95 printk("unable to remove conflicting framebuffer devices\n");
96 return ret;
97 }
98# endif /* >= 5.14. */
99
100 dev = drm_dev_alloc(&driver, &pdev->dev);
101 if (IS_ERR(dev)) {
102 ret = PTR_ERR(dev);
103 goto err_drv_alloc;
104 }
105# if RTLNX_VER_MAX(5,14,0) && !RTLNX_RHEL_RANGE(8,6, 8,99)
106 dev->pdev = pdev;
107# endif
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;
125#else /* < 4.19.0 || RHEL < 8.3 */
126 return drm_get_pci_dev(pdev, ent, &driver);
127#endif
128}
129
130static void vbox_pci_remove(struct pci_dev *pdev)
131{
132 struct drm_device *dev = pci_get_drvdata(pdev);
133
134#if RTLNX_VER_MAX(4,19,0)
135 drm_put_dev(dev);
136#else
137 drm_dev_unregister(dev);
138 vbox_driver_unload(dev);
139 drm_dev_put(dev);
140#endif
141}
142
143#if RTLNX_VER_MAX(4,9,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4)
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
156static int vbox_drm_freeze(struct drm_device *dev)
157{
158 struct vbox_private *vbox = dev->dev_private;
159
160 drm_kms_helper_poll_disable(dev);
161
162 pci_save_state(VBOX_DRM_TO_PCI_DEV(dev));
163
164 drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, true);
165
166 return 0;
167}
168
169static int vbox_drm_thaw(struct drm_device *dev)
170{
171 struct vbox_private *vbox = dev->dev_private;
172
173 drm_mode_config_reset(dev);
174 drm_helper_resume_force_mode(dev);
175 drm_fb_helper_set_suspend_unlocked(&vbox->fbdev->helper, false);
176
177 return 0;
178}
179
180static int vbox_drm_resume(struct drm_device *dev)
181{
182 int ret;
183
184 if (pci_enable_device(VBOX_DRM_TO_PCI_DEV(dev)))
185 return -EIO;
186
187 ret = vbox_drm_thaw(dev);
188 if (ret)
189 return ret;
190
191 drm_kms_helper_poll_enable(dev);
192
193 return 0;
194}
195
196static int vbox_pm_suspend(struct device *dev)
197{
198 struct pci_dev *pdev = to_pci_dev(dev);
199 struct drm_device *ddev = pci_get_drvdata(pdev);
200 int error;
201
202 error = vbox_drm_freeze(ddev);
203 if (error)
204 return error;
205
206 pci_disable_device(pdev);
207 pci_set_power_state(pdev, PCI_D3hot);
208
209 return 0;
210}
211
212static int vbox_pm_resume(struct device *dev)
213{
214 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
215
216 return vbox_drm_resume(ddev);
217}
218
219static int vbox_pm_freeze(struct device *dev)
220{
221 struct pci_dev *pdev = to_pci_dev(dev);
222 struct drm_device *ddev = pci_get_drvdata(pdev);
223
224 if (!ddev || !ddev->dev_private)
225 return -ENODEV;
226
227 return vbox_drm_freeze(ddev);
228}
229
230static int vbox_pm_thaw(struct device *dev)
231{
232 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
233
234 return vbox_drm_thaw(ddev);
235}
236
237static int vbox_pm_poweroff(struct device *dev)
238{
239 struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
240
241 return vbox_drm_freeze(ddev);
242}
243
244static const struct dev_pm_ops vbox_pm_ops = {
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,
251};
252
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,
259};
260
261#if RTLNX_VER_MAX(4,7,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4)
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. */
268long vbox_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
269{
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;
276}
277#endif /* RTLNX_VER_MAX(4,7,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4) */
278
279static const struct file_operations vbox_fops = {
280 .owner = THIS_MODULE,
281 .open = drm_open,
282 .release = drm_release,
283#if RTLNX_VER_MAX(4,7,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4)
284 .unlocked_ioctl = vbox_ioctl,
285#else
286 .unlocked_ioctl = drm_ioctl,
287#endif
288 .mmap = vbox_mmap,
289 .poll = drm_poll,
290#if RTLNX_VER_MAX(3,12,0) && !RTLNX_RHEL_MAJ_PREREQ(7,0)
291 .fasync = drm_fasync,
292#endif
293#ifdef CONFIG_COMPAT
294 .compat_ioctl = drm_compat_ioctl,
295#endif
296 .read = drm_read,
297};
298
299#if RTLNX_VER_MIN(5,9,0) || RTLNX_RHEL_MIN(8,4) || RTLNX_SUSE_MAJ_PREREQ(15,3)
300static void
301#else
302static int
303#endif
304vbox_master_set(struct drm_device *dev,
305 struct drm_file *file_priv, bool from_open)
306{
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);
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);
321 mutex_unlock(&vbox->hw_mutex);
322
323#if RTLNX_VER_MAX(5,9,0) && !RTLNX_RHEL_MAJ_PREREQ(8,4) && !RTLNX_SUSE_MAJ_PREREQ(15,3)
324 return 0;
325#endif
326}
327
328#if RTLNX_VER_MAX(4,8,0) && !RTLNX_RHEL_MAJ_PREREQ(7,4)
329static void vbox_master_drop(struct drm_device *dev,
330 struct drm_file *file_priv, bool from_release)
331#else
332static void vbox_master_drop(struct drm_device *dev, struct drm_file *file_priv)
333#endif
334{
335 struct vbox_private *vbox = dev->dev_private;
336
337 /* See vbox_master_set() */
338 vbox->initial_mode_queried = false;
339 vbox_report_caps(vbox);
340
341 mutex_lock(&vbox->hw_mutex);
342 vbox->need_refresh_timer = false;
343 mutex_unlock(&vbox->hw_mutex);
344}
345
346static struct drm_driver driver = {
347#if RTLNX_VER_MAX(5,4,0) && !RTLNX_RHEL_MAJ_PREREQ(8,3) && !RTLNX_SUSE_MAJ_PREREQ(15,3)
348 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ |
349# if RTLNX_VER_MAX(5,1,0) && !RTLNX_RHEL_MAJ_PREREQ(8,1)
350 DRIVER_IRQ_SHARED |
351# endif
352 DRIVER_PRIME,
353#else /* >= 5.4.0 && RHEL >= 8.3 && SLES >= 15-SP3 */
354 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_HAVE_IRQ,
355#endif /* < 5.4.0 */
356
357#if RTLNX_VER_MAX(4,19,0) && !RTLNX_RHEL_MAJ_PREREQ(8,3)
358 /* Legacy hooks, but still supported. */
359 .load = vbox_driver_load,
360 .unload = vbox_driver_unload,
361#endif
362 .lastclose = vbox_driver_lastclose,
363 .master_set = vbox_master_set,
364 .master_drop = vbox_master_drop,
365#if RTLNX_VER_MIN(3,18,0) || RTLNX_RHEL_MAJ_PREREQ(7,2)
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)
367 .set_busid = drm_pci_set_busid,
368# endif
369#endif
370
371 .fops = &vbox_fops,
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)
373 .irq_handler = vbox_irq_handler,
374#endif
375 .name = DRIVER_NAME,
376 .desc = DRIVER_DESC,
377 .date = DRIVER_DATE,
378 .major = DRIVER_MAJOR,
379 .minor = DRIVER_MINOR,
380 .patchlevel = DRIVER_PATCHLEVEL,
381
382#if RTLNX_VER_MAX(4,7,0)
383 .gem_free_object = vbox_gem_free_object,
384#endif
385 .dumb_create = vbox_dumb_create,
386 .dumb_map_offset = vbox_dumb_mmap_offset,
387#if RTLNX_VER_MAX(3,12,0) && !RTLNX_RHEL_MAJ_PREREQ(7,3)
388 .dumb_destroy = vbox_dumb_destroy,
389#elif RTLNX_VER_MAX(5,12,0) && !RTLNX_RHEL_MAJ_PREREQ(8,5)
390 .dumb_destroy = drm_gem_dumb_destroy,
391#endif
392#if RTLNX_VER_MAX(6,6,0) && !RTLNX_RHEL_RANGE(9,4, 9,99)
393 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
394 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
395#endif
396 .gem_prime_import = drm_gem_prime_import,
397 .gem_prime_import_sg_table = vbox_gem_prime_import_sg_table,
398#if RTLNX_VER_MAX(6,6,0) && !RTLNX_RHEL_RANGE(9,4, 9,99)
399 .gem_prime_mmap = vbox_gem_prime_mmap,
400#endif
401
402#if RTLNX_VER_MAX(5,11,0) && !RTLNX_RHEL_MAJ_PREREQ(8,5)
403 .dev_priv_size = 0,
404# if RTLNX_VER_MIN(4,7,0)
405 .gem_free_object_unlocked = vbox_gem_free_object,
406# endif
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,
413#endif
414};
415
416static int __init vbox_init(void)
417{
418 /* Check if modue loading was disabled. */
419 if (!vbox_mod_should_load())
420 return -EINVAL;
421
422 printk("vboxvideo: loading version " VBOX_VERSION_STRING " r" __stringify(VBOX_SVN_REV) "\n");
423 if (VBOX_VIDEO_NOMODESET())
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");
428 return -EINVAL;
429 }
430
431 if (vbox_modeset == 0)
432 {
433 printk("vboxvideo: driver loaded with modeset=0 parameter, unloading\n");
434 return -EINVAL;
435 }
436
437#if RTLNX_VER_MIN(3,18,0) || RTLNX_RHEL_MAJ_PREREQ(7,3)
438 return pci_register_driver(&vbox_pci_driver);
439#else
440 return drm_pci_init(&driver, &vbox_pci_driver);
441#endif
442}
443
444static void __exit vbox_exit(void)
445{
446#if RTLNX_VER_MIN(3,18,0) || RTLNX_RHEL_MAJ_PREREQ(7,3)
447 pci_unregister_driver(&vbox_pci_driver);
448#else
449 drm_pci_exit(&driver, &vbox_pci_driver);
450#endif
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");
459#ifdef MODULE_VERSION
460MODULE_VERSION(VBOX_VERSION_STRING " r" __stringify(VBOX_SVN_REV));
461#endif
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use