VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/drm/vbox_main.c@ 59573

Last change on this file since 59573 was 59573, checked in by vboxsync, 9 years ago

bugref:8087: Additions/x11: support non-root X server: fix a (correct) use of uninitialised variable warning in an error path.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.4 KB
Line 
1/* $Id: vbox_main.c 59573 2016-02-03 17:53:51Z vboxsync $ */
2/** @file
3 * VirtualBox Additions Linux kernel video driver
4 */
5
6/*
7 * Copyright (C) 2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 * --------------------------------------------------------------------
17 *
18 * This code is based on
19 * ast_main.c
20 * with the following copyright and permission notice:
21 *
22 * Copyright 2012 Red Hat Inc.
23 *
24 * Permission is hereby granted, free of charge, to any person obtaining a
25 * copy of this software and associated documentation files (the
26 * "Software"), to deal in the Software without restriction, including
27 * without limitation the rights to use, copy, modify, merge, publish,
28 * distribute, sub license, and/or sell copies of the Software, and to
29 * permit persons to whom the Software is furnished to do so, subject to
30 * the following conditions:
31 *
32 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
35 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
36 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
37 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
38 * USE OR OTHER DEALINGS IN THE SOFTWARE.
39 *
40 * The above copyright notice and this permission notice (including the
41 * next paragraph) shall be included in all copies or substantial portions
42 * of the Software.
43 *
44 */
45/*
46 * Authors: Dave Airlie <[email protected]>
47 */
48#include "vbox_drv.h"
49
50#include <VBox/VBoxVideoGuest.h>
51#include <VBox/VBoxVideo.h>
52
53#include <drm/drm_fb_helper.h>
54#include <drm/drm_crtc_helper.h>
55
56static void vbox_user_framebuffer_destroy(struct drm_framebuffer *fb)
57{
58 struct vbox_framebuffer *vbox_fb = to_vbox_framebuffer(fb);
59 if (vbox_fb->obj)
60 drm_gem_object_unreference_unlocked(vbox_fb->obj);
61
62 LogFunc(("vboxvideo: %d: vbox_fb=%p, vbox_fb->obj=%p\n", __LINE__,
63 vbox_fb, vbox_fb->obj));
64 drm_framebuffer_cleanup(fb);
65 kfree(fb);
66}
67
68/** Send information about dirty rectangles to VBVA. If necessary we enable
69 * VBVA first, as this is normally disabled after a mode set in case a user
70 * takes over the console that is not aware of VBVA (i.e. the VESA BIOS). */
71void vbox_framebuffer_dirty_rectangles(struct drm_framebuffer *fb,
72 struct drm_clip_rect *rects,
73 unsigned num_rects)
74{
75 struct vbox_private *vbox = fb->dev->dev_private;
76 unsigned i;
77 unsigned long flags;
78
79 LogFunc(("vboxvideo: %d: fb=%p, num_rects=%u, vbox=%p\n", __LINE__, fb,
80 num_rects, vbox));
81 spin_lock_irqsave(&vbox->dev_lock, flags);
82 for (i = 0; i < num_rects; ++i)
83 {
84 struct drm_crtc *crtc;
85 list_for_each_entry(crtc, &fb->dev->mode_config.crtc_list, head)
86 {
87 unsigned crtc_id = to_vbox_crtc(crtc)->crtc_id;
88 struct VBVABUFFER *pVBVA = vbox->vbva_info[crtc_id].pVBVA;
89 VBVACMDHDR cmdHdr;
90
91 if (!pVBVA)
92 {
93 LogFunc(("vboxvideo: enabling VBVA.\n"));
94 pVBVA = (struct VBVABUFFER *) ( ((uint8_t *)vbox->vram)
95 + vbox->vram_size
96 + crtc_id * VBVA_MIN_BUFFER_SIZE);
97 if (!VBoxVBVAEnable(&vbox->vbva_info[crtc_id], &vbox->submit_info, pVBVA, crtc_id))
98 AssertReleaseMsgFailed(("VBoxVBVAEnable failed - heap allocation error, very old host or driver error.\n"));
99 /* Assume that if the user knows to send dirty rectangle information
100 * they can also handle hot-plug events. */
101 VBoxHGSMISendCapsInfo(&vbox->submit_info, VBVACAPS_VIDEO_MODE_HINTS | VBVACAPS_DISABLE_CURSOR_INTEGRATION);
102 }
103 if ( CRTC_FB(crtc) != fb
104 || rects[i].x1 > crtc->x
105 + crtc->hwmode.hdisplay
106 || rects[i].y1 > crtc->y
107 + crtc->hwmode.vdisplay
108 || rects[i].x2 < crtc->x
109 || rects[i].y2 < crtc->y)
110 continue;
111 cmdHdr.x = (int16_t)rects[i].x1;
112 cmdHdr.y = (int16_t)rects[i].y1;
113 cmdHdr.w = (uint16_t)rects[i].x2 - rects[i].x1;
114 cmdHdr.h = (uint16_t)rects[i].y2 - rects[i].y1;
115 if (VBoxVBVABufferBeginUpdate(&vbox->vbva_info[crtc_id],
116 &vbox->submit_info))
117 {
118 VBoxVBVAWrite(&vbox->vbva_info[crtc_id], &vbox->submit_info, &cmdHdr,
119 sizeof(cmdHdr));
120 VBoxVBVABufferEndUpdate(&vbox->vbva_info[crtc_id]);
121 }
122 }
123 }
124 spin_unlock_irqrestore(&vbox->dev_lock, flags);
125 LogFunc(("vboxvideo: %d\n", __LINE__));
126}
127
128static int vbox_user_framebuffer_dirty(struct drm_framebuffer *fb,
129 struct drm_file *file_priv,
130 unsigned flags, unsigned color,
131 struct drm_clip_rect *rects,
132 unsigned num_rects)
133{
134 LogFunc(("vboxvideo: %d, flags=%u\n", __LINE__, flags));
135 vbox_framebuffer_dirty_rectangles(fb, rects, num_rects);
136 return 0;
137}
138
139static const struct drm_framebuffer_funcs vbox_fb_funcs = {
140 .destroy = vbox_user_framebuffer_destroy,
141 .dirty = vbox_user_framebuffer_dirty,
142};
143
144
145int vbox_framebuffer_init(struct drm_device *dev,
146 struct vbox_framebuffer *vbox_fb,
147 struct DRM_MODE_FB_CMD *mode_cmd,
148 struct drm_gem_object *obj)
149{
150 int ret;
151
152 LogFunc(("vboxvideo: %d: dev=%p, vbox_fb=%p, obj=%p\n", __LINE__, dev,
153 vbox_fb, obj));
154 drm_helper_mode_fill_fb_struct(&vbox_fb->base, mode_cmd);
155 vbox_fb->obj = obj;
156 ret = drm_framebuffer_init(dev, &vbox_fb->base, &vbox_fb_funcs);
157 if (ret) {
158 DRM_ERROR("framebuffer init failed %d\n", ret);
159 LogFunc(("vboxvideo: %d\n", __LINE__));
160 return ret;
161 }
162 LogFunc(("vboxvideo: %d\n", __LINE__));
163 return 0;
164}
165
166static struct drm_framebuffer *
167vbox_user_framebuffer_create(struct drm_device *dev,
168 struct drm_file *filp,
169 struct drm_mode_fb_cmd2 *mode_cmd)
170{
171 struct drm_gem_object *obj;
172 struct vbox_framebuffer *vbox_fb;
173 int ret;
174
175 LogFunc(("vboxvideo: %d\n", __LINE__));
176 obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]);
177 if (obj == NULL)
178 return ERR_PTR(-ENOENT);
179
180 vbox_fb = kzalloc(sizeof(*vbox_fb), GFP_KERNEL);
181 if (!vbox_fb) {
182 drm_gem_object_unreference_unlocked(obj);
183 return ERR_PTR(-ENOMEM);
184 }
185
186 ret = vbox_framebuffer_init(dev, vbox_fb, mode_cmd, obj);
187 if (ret) {
188 drm_gem_object_unreference_unlocked(obj);
189 kfree(vbox_fb);
190 return ERR_PTR(ret);
191 }
192 LogFunc(("vboxvideo: %d\n", __LINE__));
193 return &vbox_fb->base;
194}
195
196static const struct drm_mode_config_funcs vbox_mode_funcs = {
197 .fb_create = vbox_user_framebuffer_create,
198};
199
200static void disableVBVA(struct vbox_private *pVBox)
201{
202 unsigned i;
203
204 if (pVBox->vbva_info)
205 {
206 for (i = 0; i < pVBox->num_crtcs; ++i)
207 VBoxVBVADisable(&pVBox->vbva_info[i], &pVBox->submit_info, i);
208 kfree(pVBox->vbva_info);
209 pVBox->vbva_info = NULL;
210 }
211}
212
213static int vbox_vbva_init(struct vbox_private *vbox)
214{
215 unsigned i;
216 bool fRC = true;
217 LogFunc(("vboxvideo: %d: vbox=%p, vbox->num_crtcs=%u, vbox->vbva_info=%p\n",
218 __LINE__, vbox, (unsigned)vbox->num_crtcs, vbox->vbva_info));
219 if (!vbox->vbva_info)
220 {
221 vbox->vbva_info = kzalloc( sizeof(struct VBVABUFFERCONTEXT)
222 * vbox->num_crtcs,
223 GFP_KERNEL);
224 if (!vbox->vbva_info)
225 return -ENOMEM;
226 }
227 /* Take a command buffer for each screen from the end of usable VRAM. */
228 vbox->vram_size -= vbox->num_crtcs * VBVA_MIN_BUFFER_SIZE;
229 for (i = 0; i < vbox->num_crtcs; ++i)
230 VBoxVBVASetupBufferContext(&vbox->vbva_info[i],
231 vbox->vram_size + i * VBVA_MIN_BUFFER_SIZE,
232 VBVA_MIN_BUFFER_SIZE);
233 LogFunc(("vboxvideo: %d: vbox->vbva_info=%p, vbox->vram_size=%u\n",
234 __LINE__, vbox->vbva_info, (unsigned)vbox->vram_size));
235 return 0;
236}
237
238
239/** Allocation function for the HGSMI heap and data. */
240static DECLCALLBACK(void *) hgsmiEnvAlloc(void *pvEnv, HGSMISIZE cb)
241{
242 NOREF(pvEnv);
243 return kmalloc(cb, GFP_KERNEL);
244}
245
246
247/** Free function for the HGSMI heap and data. */
248static DECLCALLBACK(void) hgsmiEnvFree(void *pvEnv, void *pv)
249{
250 NOREF(pvEnv);
251 kfree(pv);
252}
253
254
255/** Pointers to the HGSMI heap and data manipulation functions. */
256static HGSMIENV g_hgsmiEnv =
257{
258 NULL,
259 hgsmiEnvAlloc,
260 hgsmiEnvFree
261};
262
263
264/** Do we support the 4.3 plus mode hint reporting interface? */
265static bool haveHGSMImode_hintAndCursorReportingInterface(struct vbox_private *pVBox)
266{
267 uint32_t fmode_hintReporting, fCursorReporting;
268
269 return RT_SUCCESS(VBoxQueryConfHGSMI(&pVBox->submit_info, VBOX_VBVA_CONF32_MODE_HINT_REPORTING, &fmode_hintReporting))
270 && RT_SUCCESS(VBoxQueryConfHGSMI(&pVBox->submit_info, VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING, &fCursorReporting))
271 && fmode_hintReporting == VINF_SUCCESS
272 && fCursorReporting == VINF_SUCCESS;
273}
274
275
276/** Set up our heaps and data exchange buffers in VRAM before handing the rest
277 * to the memory manager. */
278static int setupAcceleration(struct vbox_private *pVBox)
279{
280 uint32_t offBase, offGuestHeap, cbGuestHeap, host_flags_offset;
281 void *pvGuestHeap;
282
283 VBoxHGSMIGetBaseMappingInfo(pVBox->full_vram_size, &offBase, NULL,
284 &offGuestHeap, &cbGuestHeap, &host_flags_offset);
285 pvGuestHeap = ((uint8_t *)pVBox->vram) + offBase + offGuestHeap;
286 pVBox->host_flags_offset = offBase + host_flags_offset;
287 if (RT_FAILURE(VBoxHGSMISetupGuestContext(&pVBox->submit_info, pvGuestHeap,
288 cbGuestHeap,
289 offBase + offGuestHeap,
290 &g_hgsmiEnv)))
291 return -ENOMEM;
292 /* Reduce available VRAM size to reflect the guest heap. */
293 pVBox->vram_size = offBase;
294 /* Linux drm represents monitors as a 32-bit array. */
295 pVBox->num_crtcs = RT_MIN(VBoxHGSMIGetMonitorCount(&pVBox->submit_info), 32);
296 if (!haveHGSMImode_hintAndCursorReportingInterface(pVBox))
297 return -ENOTSUPP;
298 pVBox->last_mode_hints = kzalloc(sizeof(VBVAMODEHINT) * pVBox->num_crtcs, GFP_KERNEL);
299 if (!pVBox->last_mode_hints)
300 return -ENOMEM;
301 return vbox_vbva_init(pVBox);
302}
303
304
305int vbox_driver_load(struct drm_device *dev, unsigned long flags)
306{
307 struct vbox_private *vbox;
308 int ret = 0;
309
310 LogFunc(("vboxvideo: %d: dev=%p\n", __LINE__, dev));
311 if (!VBoxHGSMIIsSupported())
312 return -ENODEV;
313 vbox = kzalloc(sizeof(struct vbox_private), GFP_KERNEL);
314 if (!vbox)
315 return -ENOMEM;
316
317 dev->dev_private = vbox;
318 vbox->dev = dev;
319
320 spin_lock_init(&vbox->dev_lock);
321 /* I hope this won't interfere with the memory manager. */
322 vbox->vram = pci_iomap(dev->pdev, 0, 0);
323 if (!vbox->vram) {
324 ret = -EIO;
325 goto out_free;
326 }
327 vbox->full_vram_size = VBoxVideoGetVRAMSize();
328 vbox->any_pitch = VBoxVideoAnyWidthAllowed();
329 DRM_INFO("VRAM %08x\n", vbox->full_vram_size);
330
331 ret = setupAcceleration(vbox);
332 if (ret)
333 goto out_free;
334
335 ret = vbox_mm_init(vbox);
336 if (ret)
337 goto out_free;
338
339 drm_mode_config_init(dev);
340
341 dev->mode_config.funcs = (void *)&vbox_mode_funcs;
342 dev->mode_config.min_width = 64;
343 dev->mode_config.min_height = 64;
344 dev->mode_config.preferred_depth = 24;
345 dev->mode_config.max_width = VBE_DISPI_MAX_XRES;
346 dev->mode_config.max_height = VBE_DISPI_MAX_YRES;
347
348 ret = vbox_mode_init(dev);
349 if (ret)
350 goto out_free;
351
352 ret = vbox_fbdev_init(dev);
353 if (ret)
354 goto out_free;
355 LogFunc(("vboxvideo: %d: vbox=%p, vbox->vram=%p, vbox->full_vram_size=%u\n",
356 __LINE__, vbox, vbox->vram, (unsigned)vbox->full_vram_size));
357 return 0;
358out_free:
359 if (vbox->vram)
360 pci_iounmap(dev->pdev, vbox->vram);
361 kfree(vbox);
362 dev->dev_private = NULL;
363 LogFunc(("vboxvideo: %d: ret=%d\n", __LINE__, ret));
364 return ret;
365}
366
367int vbox_driver_unload(struct drm_device *dev)
368{
369 struct vbox_private *vbox = dev->dev_private;
370
371 LogFunc(("vboxvideo: %d\n", __LINE__));
372 vbox_mode_fini(dev);
373 vbox_fbdev_fini(dev);
374 drm_mode_config_cleanup(dev);
375
376 disableVBVA(vbox);
377 vbox_mm_fini(vbox);
378 pci_iounmap(dev->pdev, vbox->vram);
379 kfree(vbox);
380 LogFunc(("vboxvideo: %d\n", __LINE__));
381 return 0;
382}
383
384int vbox_gem_create(struct drm_device *dev,
385 u32 size, bool iskernel,
386 struct drm_gem_object **obj)
387{
388 struct vbox_bo *vboxbo;
389 int ret;
390
391 LogFunc(("vboxvideo: %d: dev=%p, size=%u, iskernel=%u\n", __LINE__,
392 dev, (unsigned)size, (unsigned)iskernel));
393 *obj = NULL;
394
395 size = roundup(size, PAGE_SIZE);
396 if (size == 0)
397 return -EINVAL;
398
399 ret = vbox_bo_create(dev, size, 0, 0, &vboxbo);
400 if (ret) {
401 if (ret != -ERESTARTSYS)
402 DRM_ERROR("failed to allocate GEM object\n");
403 return ret;
404 }
405 *obj = &vboxbo->gem;
406 LogFunc(("vboxvideo: %d: obj=%p\n", __LINE__, obj));
407 return 0;
408}
409
410int vbox_dumb_create(struct drm_file *file,
411 struct drm_device *dev,
412 struct drm_mode_create_dumb *args)
413{
414 int ret;
415 struct drm_gem_object *gobj;
416 u32 handle;
417
418 LogFunc(("vboxvideo: %d: args->width=%u, args->height=%u, args->bpp=%u\n",
419 __LINE__, (unsigned)args->width, (unsigned)args->height,
420 (unsigned)args->bpp));
421 args->pitch = args->width * ((args->bpp + 7) / 8);
422 args->size = args->pitch * args->height;
423
424 ret = vbox_gem_create(dev, args->size, false,
425 &gobj);
426 if (ret)
427 return ret;
428
429 ret = drm_gem_handle_create(file, gobj, &handle);
430 drm_gem_object_unreference_unlocked(gobj);
431 if (ret)
432 return ret;
433
434 args->handle = handle;
435 LogFunc(("vboxvideo: %d: args->handle=%u\n", __LINE__,
436 (unsigned)args->handle));
437 return 0;
438}
439
440#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0)
441int vbox_dumb_destroy(struct drm_file *file,
442 struct drm_device *dev,
443 uint32_t handle)
444{
445 LogFunc(("vboxvideo: %d: dev=%p, handle=%u\n", __LINE__, dev,
446 (unsigned)handle));
447 return drm_gem_handle_delete(file, handle);
448}
449#endif
450
451static void vbox_bo_unref(struct vbox_bo **bo)
452{
453 struct ttm_buffer_object *tbo;
454
455 if ((*bo) == NULL)
456 return;
457
458 LogFunc(("vboxvideo: %d: bo=%p\n", __LINE__, bo));
459 tbo = &((*bo)->bo);
460 ttm_bo_unref(&tbo);
461 if (tbo == NULL)
462 *bo = NULL;
463
464}
465void vbox_gem_free_object(struct drm_gem_object *obj)
466{
467 struct vbox_bo *vbox_bo = gem_to_vbox_bo(obj);
468
469 LogFunc(("vboxvideo: %d: vbox_bo=%p\n", __LINE__, vbox_bo));
470 vbox_bo_unref(&vbox_bo);
471}
472
473
474static inline u64 vbox_bo_mmap_offset(struct vbox_bo *bo)
475{
476#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 12, 0)
477 return bo->bo.addr_space_offset;
478#else
479 return drm_vma_node_offset_addr(&bo->bo.vma_node);
480#endif
481}
482int
483vbox_dumb_mmap_offset(struct drm_file *file,
484 struct drm_device *dev,
485 uint32_t handle,
486 uint64_t *offset)
487{
488 struct drm_gem_object *obj;
489 int ret;
490 struct vbox_bo *bo;
491
492 LogFunc(("vboxvideo: %d: dev=%p, handle=%u\n", __LINE__,
493 dev, (unsigned)handle));
494 mutex_lock(&dev->struct_mutex);
495 obj = drm_gem_object_lookup(dev, file, handle);
496 if (obj == NULL) {
497 ret = -ENOENT;
498 goto out_unlock;
499 }
500
501 bo = gem_to_vbox_bo(obj);
502 *offset = vbox_bo_mmap_offset(bo);
503
504 drm_gem_object_unreference(obj);
505 ret = 0;
506 LogFunc(("vboxvideo: %d: bo=%p, *offset=%llu\n", __LINE__,
507 bo, (unsigned long long)*offset));
508out_unlock:
509 mutex_unlock(&dev->struct_mutex);
510 return ret;
511
512}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette