VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/linux/SUPDrv-linux.c@ 84

Last change on this file since 84 was 82, checked in by vboxsync, 18 years ago

small cosmetical fix to get my syntax checker back on line

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.2 KB
Line 
1/** @file
2 *
3 * VBox host drivers - Ring-0 support drivers - Linux host:
4 * Linux host driver code
5 */
6
7/*
8 * Copyright (C) 2006 InnoTek Systemberatung GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#include "SUPDRV.h"
27#include <iprt/assert.h>
28#include <iprt/spinlock.h>
29#include <iprt/semaphore.h>
30
31#include <linux/module.h>
32#include <linux/kernel.h>
33#include <linux/init.h>
34#include <linux/fs.h>
35#include <linux/mm.h>
36#include <linux/pagemap.h>
37#include <linux/slab.h>
38#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
39# include <linux/jiffies.h>
40#endif
41#include <asm/mman.h>
42#include <asm/io.h>
43#include <asm/uaccess.h>
44#ifdef CONFIG_DEVFS_FS
45# include <linux/devfs_fs_kernel.h>
46#endif
47#ifdef CONFIG_VBOXDRV_AS_MISC
48# include <linux/miscdevice.h>
49#endif
50#ifdef CONFIG_X86_LOCAL_APIC
51# include <asm/apic.h>
52# include <asm/nmi.h>
53#endif
54
55#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(page_to_pfn)
56# define page_to_pfn(page) ((page) - mem_map)
57#endif
58
59/* devfs defines */
60#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
61# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
62
63# define VBOX_REGISTER_DEVFS() \
64({ \
65 void *rc = NULL; \
66 if (devfs_mk_cdev(MKDEV(DEVICE_MAJOR, 0), \
67 S_IFCHR | S_IRUGO | S_IWUGO, \
68 DEVICE_NAME) == 0) \
69 rc = (void *)' '; /* return not NULL */ \
70 rc; \
71 })
72
73# define VBOX_UNREGISTER_DEVFS(handle) \
74 devfs_remove(DEVICE_NAME);
75
76# else /* < 2.6.0 */
77
78# define VBOX_REGISTER_DEVFS() \
79 devfs_register(NULL, DEVICE_NAME, DEVFS_FL_DEFAULT, \
80 DEVICE_MAJOR, 0, \
81 S_IFCHR | S_IRUGO | S_IWUGO, \
82 &gFileOpsVBoxDrv, NULL)
83
84# define VBOX_UNREGISTER_DEVFS(handle) \
85 if (handle != NULL) \
86 devfs_unregister(handle)
87
88# endif /* < 2.6.0 */
89#endif /* CONFIG_DEV_FS && !CONFIG_VBOXDEV_AS_MISC */
90
91#ifndef CONFIG_VBOXDRV_AS_MISC
92# if defined(CONFIG_DEVFS_FS) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 0)
93# define VBOX_REGISTER_DEVICE(a,b,c) devfs_register_chrdev(a,b,c)
94# define VBOX_UNREGISTER_DEVICE(a,b) devfs_unregister_chrdev(a,b)
95# else
96# define VBOX_REGISTER_DEVICE(a,b,c) register_chrdev(a,b,c)
97# define VBOX_UNREGISTER_DEVICE(a,b) unregister_chrdev(a,b)
98# endif
99#endif /* !CONFIG_VBOXDRV_AS_MISC */
100
101
102#ifdef CONFIG_X86_HIGH_ENTRY
103# error "CONFIG_X86_HIGH_ENTRY is not supported by VBoxDrv at this time."
104#endif
105
106/*
107 * This sucks soooo badly on x86! Why don't they export __PAGE_KERNEL_EXEC so PAGE_KERNEL_EXEC would be usable?
108 */
109#if defined(__AMD64__)
110# define MY_PAGE_KERNEL_EXEC PAGE_KERNEL_EXEC
111#elif defined(PAGE_KERNEL_EXEC) && defined(CONFIG_X86_PAE)
112# define MY_PAGE_KERNEL_EXEC __pgprot(cpu_has_pge ? _PAGE_KERNEL_EXEC | _PAGE_GLOBAL : _PAGE_KERNEL_EXEC)
113#else
114# define MY_PAGE_KERNEL_EXEC PAGE_KERNEL
115#endif
116
117/*
118 * The redhat hack section.
119 * - The current hacks are for 2.4.21-15.EL only.
120 */
121#ifndef NO_REDHAT_HACKS
122/* accounting. */
123# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
124# ifdef VM_ACCOUNT
125# define MY_DO_MUNMAP(a,b,c) do_munmap(a, b, c, 0) /* should it be 1 or 0? */
126# endif
127# endif
128
129/* backported remap_page_range. */
130# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
131# include <asm/tlb.h>
132# ifdef tlb_vma /* probably not good enough... */
133# define HAVE_26_STYLE_REMAP_PAGE_RANGE 1
134# endif
135# endif
136
137# ifndef __AMD64__
138/* In 2.6.9-22.ELsmp we have to call change_page_attr() twice when changing
139 * the page attributes from PAGE_KERNEL to something else, because there appears
140 * to be a bug in one of the many patches that redhat applied.
141 * It should be safe to do this on less buggy linux kernels too. ;-)
142 */
143# define MY_CHANGE_PAGE_ATTR(pPages, cPages, prot) \
144 do { \
145 if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) \
146 change_page_attr(pPages, cPages, prot); \
147 change_page_attr(pPages, cPages, prot); \
148 } while (0)
149# endif
150#endif /* !NO_REDHAT_HACKS */
151
152
153#ifndef MY_DO_MUNMAP
154# define MY_DO_MUNMAP(a,b,c) do_munmap(a, b, c)
155#endif
156
157#ifndef MY_CHANGE_PAGE_ATTR
158# ifdef __AMD64__ /** @todo This is a cheap hack, but it'll get around that 'else BUG();' in __change_page_attr(). */
159# define MY_CHANGE_PAGE_ATTR(pPages, cPages, prot) \
160 do { \
161 change_page_attr(pPages, cPages, PAGE_KERNEL_NOCACHE); \
162 change_page_attr(pPages, cPages, prot); \
163 } while (0)
164# else
165# define MY_CHANGE_PAGE_ATTR(pPages, cPages, prot) change_page_attr(pPages, cPages, prot)
166# endif
167#endif
168
169
170/** @def ONE_MSEC_IN_JIFFIES
171 * The number of jiffies that make up 1 millisecond. This is only actually used
172 * when HZ is > 1000. */
173#if HZ <= 1000
174# define ONE_MSEC_IN_JIFFIES 0
175#elif !(HZ % 1000)
176# define ONE_MSEC_IN_JIFFIES (HZ / 1000)
177#else
178# define ONE_MSEC_IN_JIFFIES ((HZ + 999) / 1000)
179# error "HZ is not a multiple of 1000, the GIP stuff won't work right!"
180#endif
181
182
183/*******************************************************************************
184* Defined Constants And Macros *
185*******************************************************************************/
186/**
187 * Device extention & session data association structure.
188 */
189static SUPDRVDEVEXT g_DevExt;
190
191/** Timer structure for the GIP update. */
192static struct timer_list g_GipTimer;
193/** Pointer to the page structure for the GIP. */
194struct page *g_pGipPage;
195
196/** Registered devfs device handle. */
197#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
198# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
199static void *g_hDevFsVBoxDrv = NULL;
200# else
201static devfs_handle_t g_hDevFsVBoxDrv = NULL;
202# endif
203#endif
204
205#ifndef CONFIG_VBOXDRV_AS_MISC
206/** Module major number */
207#define DEVICE_MAJOR 234
208/** Saved major device number */
209static int g_iModuleMajor;
210#endif /* !CONFIG_VBOXDRV_AS_MISC */
211
212/** The module name. */
213#define DEVICE_NAME "vboxdrv"
214
215
216
217
218/*******************************************************************************
219* Internal Functions *
220*******************************************************************************/
221static int VBoxSupDrvInit(void);
222static void VBoxSupDrvUnload(void);
223static int VBoxSupDrvCreate(struct inode *pInode, struct file *pFilp);
224static int VBoxSupDrvClose(struct inode *pInode, struct file *pFilp);
225static int VBoxSupDrvDeviceControl(struct inode *pInode, struct file *pFilp,
226 unsigned int IOCmd, unsigned long IOArg);
227static void *VBoxSupDrvMapUser(struct page **papPages, unsigned cPages, unsigned fProt, pgprot_t pgFlags);
228static int VBoxSupDrvInitGip(PSUPDRVDEVEXT pDevExt);
229static int VBoxSupDrvTermGip(PSUPDRVDEVEXT pDevExt);
230static void VBoxSupGipTimer(unsigned long ulUser);
231static int VBoxSupDrvOrder(unsigned long size);
232static int VBoxSupDrvErr2LinuxErr(int);
233
234
235/** The file_operations structure. */
236static struct file_operations gFileOpsVBoxDrv =
237{
238 owner: THIS_MODULE,
239 open: VBoxSupDrvCreate,
240 release: VBoxSupDrvClose,
241 ioctl: VBoxSupDrvDeviceControl,
242};
243
244#ifdef CONFIG_VBOXDRV_AS_MISC
245/** The miscdevice structure. */
246static struct miscdevice gMiscDevice =
247{
248 minor: MISC_DYNAMIC_MINOR,
249 name: DEVICE_NAME,
250 fops: &gFileOpsVBoxDrv,
251# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && \
252 LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
253 devfs_name: DEVICE_NAME,
254# endif
255};
256#endif
257
258
259/**
260 * Initialize module.
261 *
262 * @returns appropritate status code.
263 */
264static int __init VBoxSupDrvInit(void)
265{
266 int rc;
267
268 dprintf(("VBoxDrv::ModuleInit\n"));
269
270#ifdef CONFIG_X86_LOCAL_APIC
271 /*
272 * If an NMI occurs while we are inside the world switcher the macine will crash.
273 * The Linux NMI watchdog generates periodic NMIs increasing a counter which is
274 * compared with another counter increased in the timer interrupt handler. Therefore
275 * we don't allow to setup an NMI watchdog.
276 */
277# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
278 /*
279 * First test: NMI actiated? Works only works with Linux 2.6 -- 2.4 does not export
280 * the nmi_watchdog variable.
281 */
282 if (nmi_watchdog != NMI_NONE)
283 goto nmi_activated;
284# endif
285
286 /*
287 * Second test: Interrupt generated by performance counter not masked and can
288 * generate an NMI. Works also with Linux 2.4.
289 */
290 {
291 unsigned int v, ver, maxlvt;
292
293 v = apic_read(APIC_LVR);
294 ver = GET_APIC_VERSION(v);
295 /* 82489DXs do not report # of LVT entries. */
296 maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2;
297 if (maxlvt >= 4)
298 {
299 /* Read status of performance counter IRQ vector */
300 v = apic_read(APIC_LVTPC);
301
302 /* performance counter generates NMI and is not masked? */
303 if ((GET_APIC_DELIVERY_MODE(v) == APIC_MODE_NMI) && !(v & APIC_LVT_MASKED))
304 {
305nmi_activated:
306 printk(KERN_ERR DEVICE_NAME ": NMI watchdog active -- refused to load the kernel module! Please disable\n"
307 DEVICE_NAME ": the NMI watchdog by specifying 'nmi_watchdog=0' at kernel command line.\n");
308 return -EINVAL;
309 }
310 }
311 }
312#endif
313
314#ifdef CONFIG_VBOXDRV_AS_MISC
315 rc = misc_register(&gMiscDevice);
316 if (rc)
317 {
318 printk(KERN_ERR DEVICE_NAME ": Can't register misc device! rc=%d\n", rc);
319 return rc;
320 }
321#else /* !CONFIG_VBOXDRV_AS_MISC */
322 /*
323 * Register character device.
324 */
325 g_iModuleMajor = DEVICE_MAJOR;
326 rc = VBOX_REGISTER_DEVICE((dev_t)g_iModuleMajor, DEVICE_NAME, &gFileOpsVBoxDrv);
327 if (rc < 0)
328 {
329 dprintf(("VBOX_REGISTER_DEVICE failed with rc=%#x!\n", rc));
330 return rc;
331 }
332
333 /*
334 * Save returned module major number
335 */
336 if (DEVICE_MAJOR != 0)
337 g_iModuleMajor = DEVICE_MAJOR;
338 else
339 g_iModuleMajor = rc;
340 rc = 0;
341
342#ifdef CONFIG_DEVFS_FS
343 /*
344 * Register a device entry
345 */
346 g_hDevFsVBoxDrv = VBOX_REGISTER_DEVFS();
347 if (g_hDevFsVBoxDrv == NULL)
348 {
349 dprintf(("devfs_register failed!\n"));
350 rc = -EINVAL;
351 }
352#endif
353#endif /* !CONFIG_VBOXDRV_AS_MISC */
354 if (!rc)
355 {
356 /*
357 * Initialize the device extension.
358 */
359 rc = supdrvInitDevExt(&g_DevExt);
360 if (!rc)
361 {
362 /*
363 * Create the GIP page.
364 */
365 rc = VBoxSupDrvInitGip(&g_DevExt);
366 if (!rc)
367 {
368 dprintf(("VBoxDrv::ModuleInit returning %#x\n", rc));
369 return rc;
370 }
371 supdrvDeleteDevExt(&g_DevExt);
372 }
373 else
374 rc = -EINVAL;
375
376 /*
377 * Failed, cleanup and return the error code.
378 */
379#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
380 VBOX_UNREGISTER_DEVFS(g_hDevFsVBoxDrv);
381#endif
382 }
383#ifdef CONFIG_VBOXDRV_AS_MISC
384 misc_deregister(&gMiscDevice);
385 dprintf(("VBoxDrv::ModuleInit returning %#x (minor:%d)\n", rc, gMiscDevice.minor));
386#else
387 VBOX_UNREGISTER_DEVICE(g_iModuleMajor, DEVICE_NAME);
388 dprintf(("VBoxDrv::ModuleInit returning %#x (major:%d)\n", rc, g_iModuleMajor));
389#endif
390 return rc;
391}
392
393
394/**
395 * Unload the module.
396 */
397static void __exit VBoxSupDrvUnload(void)
398{
399 int rc;
400 dprintf(("VBoxSupDrvUnload\n"));
401
402 /*
403 * I Don't think it's possible to unload a driver which processes have
404 * opened, at least we'll blindly assume that here.
405 */
406#ifdef CONFIG_VBOXDRV_AS_MISC
407 rc = misc_deregister(&gMiscDevice);
408 if (rc < 0)
409 {
410 dprintf(("misc_deregister failed with rc=%#x\n", rc));
411 }
412#else /* !CONFIG_VBOXDRV_AS_MISC */
413#ifdef CONFIG_DEVFS_FS
414 /*
415 * Unregister a device entry
416 */
417 VBOX_UNREGISTER_DEVFS(g_hDevFsVBoxDrv);
418#endif // devfs
419 rc = VBOX_UNREGISTER_DEVICE(g_iModuleMajor, DEVICE_NAME);
420 if (rc < 0)
421 {
422 dprintf(("unregister_chrdev failed with rc=%#x (major:%d)\n", rc, g_iModuleMajor));
423 }
424#endif /* !CONFIG_VBOXDRV_AS_MISC */
425
426 /*
427 * Destroy GIP and delete the device extension.
428 */
429 VBoxSupDrvTermGip(&g_DevExt);
430 supdrvDeleteDevExt(&g_DevExt);
431}
432
433
434/**
435 * Device open. Called on open /dev/vboxdrv
436 *
437 * @param pInode Pointer to inode info structure.
438 * @param pFilp Associated file pointer.
439 */
440static int VBoxSupDrvCreate(struct inode *pInode, struct file *pFilp)
441{
442 int rc;
443 PSUPDRVSESSION pSession;
444 dprintf(("VBoxSupDrvCreate: pFilp=%p\n", pFilp));
445
446 /*
447 * Call common code for the rest.
448 */
449 rc = supdrvCreateSession(&g_DevExt, (PSUPDRVSESSION *)&pSession);
450 if (!rc)
451 {
452 pSession->Uid = current->euid;
453 pSession->Gid = current->egid;
454 pSession->Process = (RTPROCESS)current->tgid;
455 }
456
457 dprintf(("VBoxSupDrvCreate: g_DevExt=%p pSession=%p rc=%d\n", &g_DevExt, pSession, rc));
458 pFilp->private_data = pSession;
459
460 return VBoxSupDrvErr2LinuxErr(rc);
461}
462
463
464/**
465 * Close device.
466 *
467 * @param pInode Pointer to inode info structure.
468 * @param pFilp Associated file pointer.
469 */
470static int VBoxSupDrvClose(struct inode *pInode, struct file *pFilp)
471{
472 dprintf(("VBoxSupDrvClose: pFilp=%p private_data=%p\n", pFilp, pFilp->private_data));
473 supdrvCloseSession(&g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
474 pFilp->private_data = NULL;
475 return 0;
476}
477
478
479/**
480 * Device I/O Control entry point.
481 *
482 * @param pInode Pointer to inode info structure.
483 * @param pFilp Associated file pointer.
484 * @param IOCmd The function specified to ioctl().
485 * @param IOArg The argument specified to ioctl().
486 */
487static int VBoxSupDrvDeviceControl(struct inode *pInode, struct file *pFilp,
488 unsigned int IOCmd, unsigned long IOArg)
489{
490 int rc;
491 SUPDRVIOCTLDATA Args;
492 void *pvBuf = NULL;
493 int cbBuf = 0;
494 unsigned cbOut = 0;
495
496 dprintf2(("VBoxSupDrvDeviceControl: pFilp=%p IOCmd=%x IOArg=%p\n", pFilp, IOCmd, (void *)IOArg));
497
498 /*
499 * Copy ioctl data structure from user space.
500 */
501 if (_IOC_SIZE(IOCmd) != sizeof(SUPDRVIOCTLDATA))
502 {
503 dprintf(("VBoxSupDrvDeviceControl: incorrect input length! cbArgs=%d\n", _IOC_SIZE(IOCmd)));
504 return -EINVAL;
505 }
506 if (copy_from_user(&Args, (void *)IOArg, _IOC_SIZE(IOCmd)))
507 {
508 dprintf(("VBoxSupDrvDeviceControl: copy_from_user(&Args) failed.\n"));
509 return -EFAULT;
510 }
511
512 /*
513 * Allocate and copy user space input data buffer to kernel space.
514 */
515 if (Args.cbIn > 0 || Args.cbOut > 0)
516 {
517 cbBuf = max(Args.cbIn, Args.cbOut);
518 pvBuf = vmalloc(cbBuf);
519 if (pvBuf == NULL)
520 {
521 dprintf(("VBoxSupDrvDeviceControl: failed to allocate buffer of %d bytes.\n", cbBuf));
522 return -ENOMEM;
523 }
524
525 if (copy_from_user(pvBuf, (void *)Args.pvIn, Args.cbIn))
526 {
527 dprintf(("VBoxSupDrvDeviceControl: copy_from_user(pvBuf) failed.\n"));
528 vfree(pvBuf);
529 return -EFAULT;
530 }
531 }
532
533 /*
534 * Process the IOCtl.
535 */
536 rc = supdrvIOCtl(IOCmd, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data,
537 pvBuf, Args.cbIn, pvBuf, Args.cbOut, &cbOut);
538
539 /*
540 * Copy ioctl data and output buffer back to user space.
541 */
542 if (rc)
543 {
544 dprintf(("VBoxSupDrvDeviceControl: pFilp=%p IOCmd=%x IOArg=%p failed, rc=%d (linux rc=%d)\n",
545 pFilp, IOCmd, (void *)IOArg, rc, VBoxSupDrvErr2LinuxErr(rc)));
546 rc = VBoxSupDrvErr2LinuxErr(rc);
547 }
548 else if (cbOut > 0)
549 {
550 if (pvBuf != NULL && cbOut <= cbBuf)
551 {
552 if (copy_to_user((void *)Args.pvOut, pvBuf, cbOut))
553 {
554 dprintf(("copy_to_user failed.\n"));
555 rc = -EFAULT;
556 }
557 }
558 else
559 {
560 dprintf(("WHAT!?! supdrvIOCtl messed up! cbOut=%d cbBuf=%d pvBuf=%p\n", cbOut, cbBuf, pvBuf));
561 rc = -EPERM;
562 }
563 }
564
565 if (pvBuf)
566 vfree(pvBuf);
567
568 dprintf2(("VBoxSupDrvDeviceControl: returns %d\n", rc));
569 return rc;
570}
571
572
573/**
574 * Initializes any OS specific object creator fields.
575 */
576void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
577{
578 NOREF(pObj);
579 NOREF(pSession);
580}
581
582
583/**
584 * Checks if the session can access the object.
585 *
586 * @returns true if a decision has been made.
587 * @returns false if the default access policy should be applied.
588 *
589 * @param pObj The object in question.
590 * @param pSession The session wanting to access the object.
591 * @param pszObjName The object name, can be NULL.
592 * @param prc Where to store the result when returning true.
593 */
594bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
595{
596 NOREF(pObj);
597 NOREF(pSession);
598 NOREF(pszObjName);
599 NOREF(prc);
600 return false;
601}
602
603
604/**
605 * Compute order. Some functions allocate 2^order pages.
606 *
607 * @returns order.
608 * @param cPages Number of pages.
609 */
610static int VBoxSupDrvOrder(unsigned long cPages)
611{
612 int iOrder;
613 unsigned long cTmp;
614
615 for (iOrder = 0, cTmp = cPages; cTmp >>= 1; ++iOrder)
616 ;
617 if (cPages & ~(1 << iOrder))
618 ++iOrder;
619
620 return iOrder;
621}
622
623
624/**
625 * OS Specific code for locking down memory.
626 *
627 * @returns 0 on success.
628 * @returns SUPDRV_ERR_* on failure.
629 * @param pMem Pointer to memory.
630 * This is not linked in anywhere.
631 * @param paPages Array which should be filled with the address of the physical pages.
632 *
633 * @remark See sgl_map_user_pages() for an example of an similar function.
634 */
635int VBOXCALL supdrvOSLockMemOne(PSUPDRVMEMREF pMem, PSUPPAGE paPages)
636{
637 int rc;
638 struct page **papPages;
639 unsigned iPage;
640 unsigned cPages = pMem->cb >> PAGE_SHIFT;
641 unsigned long pv = (unsigned long)pMem->pvR3;
642
643 /*
644 * Allocate page pointer array.
645 */
646 papPages = vmalloc(cPages * sizeof(*papPages));
647 if (!papPages)
648 return SUPDRV_ERR_NO_MEMORY;
649
650 /*
651 * Get user pages.
652 */
653 down_read(&current->mm->mmap_sem);
654 rc = get_user_pages(current, /* Task for fault acounting. */
655 current->mm, /* Whose pages. */
656 (unsigned long)pv, /* Where from. */
657 cPages, /* How many pages. */
658 1, /* Write to memory. */
659 0, /* force. */
660 papPages, /* Page array. */
661 NULL); /* vmas */
662 if (rc != cPages)
663 {
664 up_read(&current->mm->mmap_sem);
665 dprintf(("supdrvOSLockMemOne: get_user_pages failed. rc=%d\n", rc));
666 return SUPDRV_ERR_LOCK_FAILED;
667 }
668
669 for (iPage = 0; iPage < cPages; iPage++)
670 flush_dcache_page(papPages[iPage]);
671 up_read(&current->mm->mmap_sem);
672
673 pMem->u.locked.papPages = papPages;
674 pMem->u.locked.cPages = cPages;
675
676 /*
677 * Get addresses.
678 */
679 for (iPage = 0; iPage < cPages; iPage++)
680 {
681 paPages[iPage].Phys = page_to_phys(papPages[iPage]);
682 paPages[iPage].uReserved = 0;
683 }
684
685 dprintf2(("supdrvOSLockMemOne: pvR3=%p cb=%d papPages=%p\n",
686 pMem->pvR3, pMem->cb, pMem->u.locked.papPages));
687 return 0;
688}
689
690
691/**
692 * Unlocks the memory pointed to by pv.
693 *
694 * @param pv Memory to unlock.
695 * @param cb Size of the memory (debug).
696 *
697 * @remark See sgl_unmap_user_pages() for an example of an similar function.
698 */
699void VBOXCALL supdrvOSUnlockMemOne(PSUPDRVMEMREF pMem)
700{
701 unsigned iPage;
702 dprintf2(("supdrvOSUnlockMemOne: pvR3=%p cb=%d papPages=%p\n",
703 pMem->pvR3, pMem->cb, pMem->u.locked.papPages));
704
705 /*
706 * Loop thru the pages and release them.
707 */
708 for (iPage = 0; iPage < pMem->u.locked.cPages; iPage++)
709 {
710 if (!PageReserved(pMem->u.locked.papPages[iPage]))
711 SetPageDirty(pMem->u.locked.papPages[iPage]);
712 page_cache_release(pMem->u.locked.papPages[iPage]);
713 }
714
715 /* free the page array */
716 vfree(pMem->u.locked.papPages);
717 pMem->u.locked.cPages = 0;
718}
719
720
721/**
722 * OS Specific code for allocating page aligned memory with continuous fixed
723 * physical paged backing.
724 *
725 * @returns 0 on success.
726 * @returns SUPDRV_ERR_* on failure.
727 * @param pMem Memory reference record of the memory to be allocated.
728 * (This is not linked in anywhere.)
729 * @param ppvR0 Where to store the virtual address of the ring-0 mapping. (optional)
730 * @param ppvR3 Where to store the virtual address of the ring-3 mapping.
731 * @param pHCPhys Where to store the physical address.
732 */
733int VBOXCALL supdrvOSContAllocOne(PSUPDRVMEMREF pMem, void **ppvR0, void **ppvR3, PRTHCPHYS pHCPhys)
734{
735 struct page *paPages;
736 unsigned iPage;
737 unsigned cbAligned = RT_ALIGN(pMem->cb, PAGE_SIZE);
738 unsigned cPages = cbAligned >> PAGE_SHIFT;
739 unsigned cOrder = VBoxSupDrvOrder(cPages);
740 unsigned long ulAddr;
741 dma_addr_t HCPhys;
742 int rc = 0;
743 pgprot_t pgFlags;
744 pgprot_val(pgFlags) = _PAGE_PRESENT | _PAGE_RW | _PAGE_USER;
745
746 Assert(ppvR3);
747 Assert(pHCPhys);
748
749 /*
750 * Allocate page pointer array.
751 */
752#ifdef __AMD64__ /** @todo check out if there is a correct way of getting memory below 4GB (physically). */
753 paPages = alloc_pages(GFP_DMA, cOrder);
754#else
755 paPages = alloc_pages(GFP_USER, cOrder);
756#endif
757 if (!paPages)
758 return SUPDRV_ERR_NO_MEMORY;
759
760 /*
761 * Lock the pages.
762 */
763 for (iPage = 0; iPage < cPages; iPage++)
764 {
765 SetPageReserved(&paPages[iPage]);
766 if (!PageHighMem(&paPages[iPage]) && pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL))
767 MY_CHANGE_PAGE_ATTR(&paPages[iPage], 1, MY_PAGE_KERNEL_EXEC);
768#ifdef DEBUG
769 if (iPage + 1 < cPages && (page_to_phys((&paPages[iPage])) + 0x1000) != page_to_phys((&paPages[iPage + 1])))
770 {
771 dprintf(("supdrvOSContAllocOne: Pages are not continuous!!!! iPage=%d phys=%llx physnext=%llx\n",
772 iPage, (long long)page_to_phys((&paPages[iPage])), (long long)page_to_phys((&paPages[iPage + 1]))));
773 BUG();
774 }
775#endif
776 }
777 HCPhys = page_to_phys(paPages);
778
779 /*
780 * Allocate user space mapping and put the physical pages into it.
781 */
782 down_write(&current->mm->mmap_sem);
783 ulAddr = do_mmap(NULL, 0, cbAligned, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_ANONYMOUS, 0);
784 if (!(ulAddr & ~PAGE_MASK))
785 {
786#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(HAVE_26_STYLE_REMAP_PAGE_RANGE)
787 int rc2 = remap_page_range(ulAddr, HCPhys, cbAligned, pgFlags);
788#else
789 int rc2 = 0;
790 struct vm_area_struct *vma = find_vma(current->mm, ulAddr);
791 if (vma)
792#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
793 rc2 = remap_page_range(vma, ulAddr, HCPhys, cbAligned, pgFlags);
794#else
795 rc2 = remap_pfn_range(vma, ulAddr, HCPhys >> PAGE_SHIFT, cbAligned, pgFlags);
796#endif
797 else
798 {
799 rc = SUPDRV_ERR_NO_MEMORY;
800 dprintf(("supdrvOSContAllocOne: no vma found for ulAddr=%#lx!\n", ulAddr));
801 }
802#endif
803 if (rc2)
804 {
805 rc = SUPDRV_ERR_NO_MEMORY;
806 dprintf(("supdrvOSContAllocOne: remap_page_range failed rc2=%d\n", rc2));
807 }
808 }
809 else
810 {
811 dprintf(("supdrvOSContAllocOne: do_mmap failed ulAddr=%#lx\n", ulAddr));
812 rc = SUPDRV_ERR_NO_MEMORY;
813 }
814 up_write(&current->mm->mmap_sem); /* not quite sure when to give this up. */
815
816 /*
817 * Success?
818 */
819 if (!rc)
820 {
821 *pHCPhys = HCPhys;
822 *ppvR3 = (void *)ulAddr;
823 if (ppvR0)
824 *ppvR0 = (void *)ulAddr;
825 pMem->pvR3 = (void *)ulAddr;
826 pMem->pvR0 = NULL;
827 pMem->u.cont.paPages = paPages;
828 pMem->u.cont.cPages = cPages;
829 pMem->cb = cbAligned;
830
831 dprintf2(("supdrvOSContAllocOne: pvR0=%p pvR3=%p cb=%d paPages=%p *pHCPhys=%lx *ppvR0=*ppvR3=%p\n",
832 pMem->pvR0, pMem->pvR3, pMem->cb, paPages, (unsigned long)*pHCPhys, *ppvR3));
833 global_flush_tlb();
834 return 0;
835 }
836
837 /*
838 * Failure, cleanup and be gone.
839 */
840 down_write(&current->mm->mmap_sem);
841 if (ulAddr & ~PAGE_MASK)
842 MY_DO_MUNMAP(current->mm, ulAddr, pMem->cb);
843 for (iPage = 0; iPage < cPages; iPage++)
844 {
845 ClearPageReserved(&paPages[iPage]);
846 if (!PageHighMem(&paPages[iPage]) && pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL))
847 MY_CHANGE_PAGE_ATTR(&paPages[iPage], 1, PAGE_KERNEL);
848 }
849 up_write(&current->mm->mmap_sem); /* check when we can leave this. */
850 __free_pages(paPages, cOrder);
851
852 global_flush_tlb();
853 return rc;
854}
855
856
857/**
858 * Frees contiguous memory.
859 *
860 * @param pMem Memory reference record of the memory to be freed.
861 */
862void VBOXCALL supdrvOSContFreeOne(PSUPDRVMEMREF pMem)
863{
864 unsigned iPage;
865
866 dprintf2(("supdrvOSContFreeOne: pvR0=%p pvR3=%p cb=%d paPages=%p\n",
867 pMem->pvR0, pMem->pvR3, pMem->cb, pMem->u.cont.paPages));
868
869 /*
870 * do_exit() destroys the mm before closing files.
871 * I really hope it cleans up our stuff properly...
872 */
873 if (current->mm)
874 {
875 down_write(&current->mm->mmap_sem);
876 MY_DO_MUNMAP(current->mm, (unsigned long)pMem->pvR3, pMem->cb);
877 up_write(&current->mm->mmap_sem); /* check when we can leave this. */
878 }
879
880 /*
881 * Change page attributes freeing the pages.
882 */
883 for (iPage = 0; iPage < pMem->u.cont.cPages; iPage++)
884 {
885 ClearPageReserved(&pMem->u.cont.paPages[iPage]);
886 if (!PageHighMem(&pMem->u.cont.paPages[iPage]) && pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL))
887 MY_CHANGE_PAGE_ATTR(&pMem->u.cont.paPages[iPage], 1, PAGE_KERNEL);
888 }
889 __free_pages(pMem->u.cont.paPages, VBoxSupDrvOrder(pMem->u.cont.cPages));
890
891 pMem->u.cont.cPages = 0;
892}
893
894
895/**
896 * Allocates memory which mapped into both kernel and user space.
897 * The returned memory is page aligned and so is the allocation.
898 *
899 * @returns 0 on success.
900 * @returns SUPDRV_ERR_* on failure.
901 * @param pMem Memory reference record of the memory to be allocated.
902 * (This is not linked in anywhere.)
903 * @param ppvR0 Where to store the address of the Ring-0 mapping.
904 * @param ppvR3 Where to store the address of the Ring-3 mapping.
905 */
906int VBOXCALL supdrvOSMemAllocOne(PSUPDRVMEMREF pMem, void **ppvR0, void **ppvR3)
907{
908 const unsigned cbAligned = RT_ALIGN(pMem->cb, PAGE_SIZE);
909 const unsigned cPages = cbAligned >> PAGE_SHIFT;
910#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 22)
911 unsigned cOrder = VBoxSupDrvOrder(cPages);
912 struct page *paPages;
913#endif
914 struct page **papPages;
915 unsigned iPage;
916 pgprot_t pgFlags;
917 pgprot_val(pgFlags) = _PAGE_PRESENT | _PAGE_RW | _PAGE_USER;
918
919 /*
920 * Allocate array with page pointers.
921 */
922 pMem->u.mem.cPages = 0;
923 pMem->u.mem.papPages = papPages = kmalloc(sizeof(papPages[0]) * cPages, GFP_KERNEL);
924 if (!papPages)
925 return SUPDRV_ERR_NO_MEMORY;
926
927 /*
928 * Allocate the pages.
929 */
930#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
931 for (iPage = 0; iPage < cPages; iPage++)
932 {
933 papPages[iPage] = alloc_page(GFP_HIGHUSER);
934 if (!papPages[iPage])
935 {
936 pMem->u.mem.cPages = iPage;
937 supdrvOSMemFreeOne(pMem);
938 return SUPDRV_ERR_NO_MEMORY;
939 }
940 }
941
942#else /* < 2.4.22 */
943 paPages = alloc_pages(GFP_USER, cOrder);
944 if (!paPages)
945 {
946 supdrvOSMemFreeOne(pMem);
947 return SUPDRV_ERR_NO_MEMORY;
948 }
949 for (iPage = 0; iPage < cPages; iPage++)
950 {
951 papPages[iPage] = &paPages[iPage];
952 if (pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL))
953 MY_CHANGE_PAGE_ATTR(papPages[iPage], 1, MY_PAGE_KERNEL_EXEC);
954 if (PageHighMem(papPages[iPage]))
955 BUG();
956 }
957#endif
958 pMem->u.mem.cPages = cPages;
959
960 /*
961 * Reserve the pages.
962 */
963 for (iPage = 0; iPage < cPages; iPage++)
964 SetPageReserved(papPages[iPage]);
965
966 /*
967 * Create the Ring-0 mapping.
968 */
969 if (ppvR0)
970 {
971#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
972# ifdef VM_MAP
973 *ppvR0 = pMem->pvR0 = vmap(papPages, cPages, VM_MAP, pgFlags);
974# else
975 *ppvR0 = pMem->pvR0 = vmap(papPages, cPages, VM_ALLOC, pgFlags);
976# endif
977#else
978 *ppvR0 = pMem->pvR0 = phys_to_virt(page_to_phys(papPages[0]));
979#endif
980 }
981 if (pMem->pvR0 || !ppvR0)
982 {
983 /*
984 * Create the ring3 mapping.
985 */
986 if (ppvR3)
987 *ppvR3 = pMem->pvR3 = VBoxSupDrvMapUser(papPages, cPages, PROT_READ | PROT_WRITE | PROT_EXEC, pgFlags);
988 if (pMem->pvR3 || !ppvR3)
989 return 0;
990 dprintf(("supdrvOSMemAllocOne: failed to map into r3! cPages=%u\n", cPages));
991 }
992 else
993 dprintf(("supdrvOSMemAllocOne: failed to map into r0! cPages=%u\n", cPages));
994
995 supdrvOSMemFreeOne(pMem);
996 return SUPDRV_ERR_NO_MEMORY;
997}
998
999
1000/**
1001 * Get the physical addresses of the pages in the allocation.
1002 * This is called while inside bundle the spinlock.
1003 *
1004 * @param pMem Memory reference record of the memory.
1005 * @param paPages Where to store the page addresses.
1006 */
1007void VBOXCALL supdrvOSMemGetPages(PSUPDRVMEMREF pMem, PSUPPAGE paPages)
1008{
1009 unsigned iPage;
1010 for (iPage = 0; iPage < pMem->u.mem.cPages; iPage++)
1011 {
1012 paPages[iPage].Phys = page_to_phys(pMem->u.mem.papPages[iPage]);
1013 paPages[iPage].uReserved = 0;
1014 }
1015}
1016
1017
1018/**
1019 * Frees memory allocated by supdrvOSMemAllocOne().
1020 *
1021 * @param pMem Memory reference record of the memory to be free.
1022 */
1023void VBOXCALL supdrvOSMemFreeOne(PSUPDRVMEMREF pMem)
1024{
1025 dprintf2(("supdrvOSMemFreeOne: pvR0=%p pvR3=%p cb=%d cPages=%d papPages=%p\n",
1026 pMem->pvR0, pMem->pvR3, pMem->cb, pMem->u.mem.cPages, pMem->u.mem.papPages));
1027
1028 /*
1029 * Unmap the user mapping (if any).
1030 * do_exit() destroys the mm before closing files.
1031 */
1032 if (pMem->pvR3 && current->mm)
1033 {
1034 down_write(&current->mm->mmap_sem);
1035 MY_DO_MUNMAP(current->mm, (unsigned long)pMem->pvR3, RT_ALIGN(pMem->cb, PAGE_SIZE));
1036 up_write(&current->mm->mmap_sem); /* check when we can leave this. */
1037 }
1038 pMem->pvR3 = NULL;
1039
1040 /*
1041 * Unmap the kernel mapping (if any).
1042 */
1043 if (pMem->pvR0)
1044 {
1045#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
1046 vunmap(pMem->pvR0);
1047#endif
1048 pMem->pvR0 = NULL;
1049 }
1050
1051 /*
1052 * Free the physical pages.
1053 */
1054 if (pMem->u.mem.papPages)
1055 {
1056 struct page **papPages = pMem->u.mem.papPages;
1057 const unsigned cPages = pMem->u.mem.cPages;
1058 unsigned iPage;
1059
1060 /* Restore the page flags. */
1061 for (iPage = 0; iPage < cPages; iPage++)
1062 {
1063 ClearPageReserved(papPages[iPage]);
1064#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 22)
1065 if (pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL))
1066 MY_CHANGE_PAGE_ATTR(papPages[iPage], 1, PAGE_KERNEL);
1067#endif
1068 }
1069
1070 /* Free the pages. */
1071#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
1072 for (iPage = 0; iPage < pMem->u.cont.cPages; iPage++)
1073 __free_page(papPages[iPage]);
1074#else
1075 if (cPages > 0)
1076 __free_pages(papPages[0], VBoxSupDrvOrder(cPages));
1077#endif
1078 /* Free the page pointer array. */
1079 kfree(papPages);
1080 pMem->u.mem.papPages = NULL;
1081 }
1082 pMem->u.mem.cPages = 0;
1083}
1084
1085
1086/**
1087 * Maps a range of pages into user space.
1088 *
1089 * @returns Pointer to the user space mapping on success.
1090 * @returns NULL on failure.
1091 * @param papPages Array of the pages to map.
1092 * @param cPages Number of pages to map.
1093 * @param fProt The mapping protection.
1094 * @param pgFlags The page level protection.
1095 */
1096static void *VBoxSupDrvMapUser(struct page **papPages, unsigned cPages, unsigned fProt, pgprot_t pgFlags)
1097{
1098 int rc = SUPDRV_ERR_NO_MEMORY;
1099 unsigned long ulAddr;
1100
1101 /*
1102 * Allocate user space mapping.
1103 */
1104 down_write(&current->mm->mmap_sem);
1105 ulAddr = do_mmap(NULL, 0, cPages * PAGE_SIZE, fProt, MAP_SHARED | MAP_ANONYMOUS, 0);
1106 if (!(ulAddr & ~PAGE_MASK))
1107 {
1108 /*
1109 * Map page by page into the mmap area.
1110 * This is generic, paranoid and not very efficient.
1111 */
1112 int rc = 0;
1113 unsigned long ulAddrCur = ulAddr;
1114 unsigned iPage;
1115 for (iPage = 0; iPage < cPages; iPage++, ulAddrCur += PAGE_SIZE)
1116 {
1117#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) || defined(HAVE_26_STYLE_REMAP_PAGE_RANGE)
1118 struct vm_area_struct *vma = find_vma(current->mm, ulAddrCur);
1119 if (!vma)
1120 break;
1121#endif
1122
1123#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
1124 rc = remap_pfn_range(vma, ulAddrCur, page_to_pfn(papPages[iPage]), PAGE_SIZE, pgFlags);
1125#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) || defined(HAVE_26_STYLE_REMAP_PAGE_RANGE)
1126 rc = remap_page_range(vma, ulAddrCur, page_to_phys(papPages[iPage]), PAGE_SIZE, pgFlags);
1127#else /* 2.4 */
1128 rc = remap_page_range(ulAddrCur, page_to_phys(papPages[iPage]), PAGE_SIZE, pgFlags);
1129#endif
1130 if (rc)
1131 break;
1132 }
1133
1134 /*
1135 * Successful?
1136 */
1137 if (iPage >= cPages)
1138 {
1139 up_write(&current->mm->mmap_sem);
1140 return (void *)ulAddr;
1141 }
1142
1143 /* no, cleanup! */
1144 if (rc)
1145 dprintf(("VBoxSupDrvMapUser: remap_[page|pfn]_range failed! rc=%d\n", rc));
1146 else
1147 dprintf(("VBoxSupDrvMapUser: find_vma failed!\n"));
1148
1149 MY_DO_MUNMAP(current->mm, ulAddr, cPages * PAGE_SIZE);
1150 }
1151 else
1152 {
1153 dprintf(("supdrvOSContAllocOne: do_mmap failed ulAddr=%#lx\n", ulAddr));
1154 rc = SUPDRV_ERR_NO_MEMORY;
1155 }
1156 up_write(&current->mm->mmap_sem);
1157
1158 return NULL;
1159}
1160
1161
1162/**
1163 * Initializes the GIP.
1164 *
1165 * @returns negative errno.
1166 * @param pDevExt Instance data. GIP stuff may be updated.
1167 */
1168static int VBoxSupDrvInitGip(PSUPDRVDEVEXT pDevExt)
1169{
1170 struct page *pPage;
1171 dma_addr_t HCPhys;
1172 PSUPGLOBALINFOPAGE pGip;
1173 dprintf(("VBoxSupDrvInitGip:\n"));
1174
1175 /*
1176 * Allocate the page.
1177 */
1178 pPage = alloc_pages(GFP_USER, 0);
1179 if (!pPage)
1180 {
1181 dprintf(("VBoxSupDrvInitGip: failed to allocate the GIP page\n"));
1182 return -ENOMEM;
1183 }
1184
1185 /*
1186 * Lock the page.
1187 */
1188 SetPageReserved(pPage);
1189 g_pGipPage = pPage;
1190
1191 /*
1192 * Call common initialization routine.
1193 */
1194 HCPhys = page_to_phys(pPage);
1195 pGip = (PSUPGLOBALINFOPAGE)page_address(pPage);
1196 pDevExt->ulLastJiffies = jiffies;
1197#ifdef TICK_NSEC
1198 pDevExt->u64LastMonotime = (uint64_t)pDevExt->ulLastJiffies * TICK_NSEC;
1199 dprintf(("VBoxSupDrvInitGIP: TICK_NSEC=%ld HZ=%d jiffies=%ld now=%lld\n",
1200 TICK_NSEC, HZ, pDevExt->ulLastJiffies, pDevExt->u64LastMonotime));
1201#else
1202 pDevExt->u64LastMonotime = (uint64_t)pDevExt->ulLastJiffies * (1000000 / HZ);
1203 dprintf(("VBoxSupDrvInitGIP: TICK_NSEC=%d HZ=%d jiffies=%ld now=%lld\n",
1204 (int)(1000000 / HZ), HZ, pDevExt->ulLastJiffies, pDevExt->u64LastMonotime));
1205#endif
1206 supdrvGipInit(pDevExt, pGip, HCPhys, pDevExt->u64LastMonotime,
1207 HZ <= 1000 ? HZ : 1000);
1208
1209 /*
1210 * Initialize the timer.
1211 */
1212 init_timer(&g_GipTimer);
1213 g_GipTimer.data = (unsigned long)pDevExt;
1214 g_GipTimer.function = VBoxSupGipTimer;
1215 g_GipTimer.expires = jiffies;
1216
1217 return 0;
1218}
1219
1220
1221/**
1222 * Terminates the GIP.
1223 *
1224 * @returns negative errno.
1225 * @param pDevExt Instance data. GIP stuff may be updated.
1226 */
1227static int VBoxSupDrvTermGip(PSUPDRVDEVEXT pDevExt)
1228{
1229 struct page *pPage;
1230 PSUPGLOBALINFOPAGE pGip;
1231 dprintf(("VBoxSupDrvTermGip:\n"));
1232
1233 /*
1234 * Delete the timer if it's pending.
1235 */
1236 if (timer_pending(&g_GipTimer))
1237 del_timer(&g_GipTimer);
1238
1239 /*
1240 * Uninitialize the content.
1241 */
1242 pGip = pDevExt->pGip;
1243 pDevExt->pGip = NULL;
1244 if (pGip)
1245 supdrvGipTerm(pGip);
1246
1247 /*
1248 * Free the page.
1249 */
1250 pPage = g_pGipPage;
1251 g_pGipPage = NULL;
1252 if (pPage)
1253 {
1254 ClearPageReserved(pPage);
1255 __free_pages(pPage, 0);
1256 }
1257
1258 return 0;
1259}
1260
1261/**
1262 * Timer callback function.
1263 * The ulUser parameter is the device extension pointer.
1264 */
1265static void VBoxSupGipTimer(unsigned long ulUser)
1266{
1267 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)ulUser;
1268 unsigned long ulNow = jiffies;
1269 unsigned long ulDiff = ulNow - pDevExt->ulLastJiffies;
1270 pDevExt->ulLastJiffies = ulNow;
1271#ifdef TICK_NSEC
1272 pDevExt->u64LastMonotime += ulDiff * TICK_NSEC;
1273#else
1274 pDevExt->u64LastMonotime += ulDiff * (1000000 / HZ);
1275#endif
1276 supdrvGipUpdate(pDevExt->pGip, pDevExt->u64LastMonotime);
1277 mod_timer(&g_GipTimer, jiffies + (HZ <= 1000 ? 0 : ONE_MSEC_IN_JIFFIES));
1278}
1279
1280
1281/**
1282 * Maps the GIP into user space.
1283 *
1284 * @returns negative errno.
1285 * @param pDevExt Instance data.
1286 */
1287int VBOXCALL supdrvOSGipMap(PSUPDRVDEVEXT pDevExt, PCSUPGLOBALINFOPAGE *ppGip)
1288{
1289 int rc = 0;
1290 unsigned long ulAddr;
1291 unsigned long HCPhys = pDevExt->HCPhysGip;
1292 pgprot_t pgFlags;
1293 pgprot_val(pgFlags) = _PAGE_PRESENT | _PAGE_USER;
1294 dprintf2(("supdrvOSGipMap: ppGip=%p\n", ppGip));
1295
1296 /*
1297 * Allocate user space mapping and put the physical pages into it.
1298 */
1299 down_write(&current->mm->mmap_sem);
1300 ulAddr = do_mmap(NULL, 0, PAGE_SIZE, PROT_READ, MAP_SHARED | MAP_ANONYMOUS, 0);
1301 if (!(ulAddr & ~PAGE_MASK))
1302 {
1303#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(HAVE_26_STYLE_REMAP_PAGE_RANGE)
1304 int rc2 = remap_page_range(ulAddr, HCPhys, PAGE_SIZE, pgFlags);
1305#else
1306 int rc2 = 0;
1307 struct vm_area_struct *vma = find_vma(current->mm, ulAddr);
1308 if (vma)
1309#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
1310 rc2 = remap_page_range(vma, ulAddr, HCPhys, PAGE_SIZE, pgFlags);
1311#else
1312 rc2 = remap_pfn_range(vma, ulAddr, HCPhys >> PAGE_SHIFT, PAGE_SIZE, pgFlags);
1313#endif
1314 else
1315 {
1316 rc = SUPDRV_ERR_NO_MEMORY;
1317 dprintf(("supdrvOSGipMap: no vma found for ulAddr=%#lx!\n", ulAddr));
1318 }
1319#endif
1320 if (rc2)
1321 {
1322 rc = SUPDRV_ERR_NO_MEMORY;
1323 dprintf(("supdrvOSGipMap: remap_page_range failed rc2=%d\n", rc2));
1324 }
1325 }
1326 else
1327 {
1328 dprintf(("supdrvOSGipMap: do_mmap failed ulAddr=%#lx\n", ulAddr));
1329 rc = SUPDRV_ERR_NO_MEMORY;
1330 }
1331 up_write(&current->mm->mmap_sem); /* not quite sure when to give this up. */
1332
1333 /*
1334 * Success?
1335 */
1336 if (!rc)
1337 {
1338 *ppGip = (PCSUPGLOBALINFOPAGE)ulAddr;
1339 dprintf2(("supdrvOSGipMap: ppGip=%p\n", *ppGip));
1340 return 0;
1341 }
1342
1343 /*
1344 * Failure, cleanup and be gone.
1345 */
1346 if (ulAddr & ~PAGE_MASK)
1347 {
1348 down_write(&current->mm->mmap_sem);
1349 MY_DO_MUNMAP(current->mm, ulAddr, PAGE_SIZE);
1350 up_write(&current->mm->mmap_sem);
1351 }
1352
1353 dprintf2(("supdrvOSGipMap: returns %d\n", rc));
1354 return rc;
1355}
1356
1357
1358/**
1359 * Maps the GIP into user space.
1360 *
1361 * @returns negative errno.
1362 * @param pDevExt Instance data.
1363 */
1364int VBOXCALL supdrvOSGipUnmap(PSUPDRVDEVEXT pDevExt, PCSUPGLOBALINFOPAGE pGip)
1365{
1366 dprintf2(("supdrvOSGipUnmap: pGip=%p\n", pGip));
1367 if (current->mm)
1368 {
1369 down_write(&current->mm->mmap_sem);
1370 MY_DO_MUNMAP(current->mm, (unsigned long)pGip, PAGE_SIZE);
1371 up_write(&current->mm->mmap_sem);
1372 }
1373 dprintf2(("supdrvOSGipUnmap: returns 0\n"));
1374 return 0;
1375}
1376
1377
1378/**
1379 * Resumes the GIP updating.
1380 *
1381 * @param pDevExt Instance data.
1382 */
1383void VBOXCALL supdrvOSGipResume(PSUPDRVDEVEXT pDevExt)
1384{
1385 dprintf2(("supdrvOSGipResume:\n"));
1386 mod_timer(&g_GipTimer, jiffies);
1387}
1388
1389
1390/**
1391 * Suspends the GIP updating.
1392 *
1393 * @param pDevExt Instance data.
1394 */
1395void VBOXCALL supdrvOSGipSuspend(PSUPDRVDEVEXT pDevExt)
1396{
1397 dprintf2(("supdrvOSGipSuspend:\n"));
1398 if (timer_pending(&g_GipTimer))
1399 del_timer(&g_GipTimer);
1400}
1401
1402
1403/**
1404 * Converts a supdrv error code to an linux error code.
1405 *
1406 * @returns corresponding linux error code.
1407 * @param rc supdrv error code (SUPDRV_ERR_* defines).
1408 */
1409static int VBoxSupDrvErr2LinuxErr(int rc)
1410{
1411 switch (rc)
1412 {
1413 case 0: return 0;
1414 case SUPDRV_ERR_GENERAL_FAILURE: return -EACCES;
1415 case SUPDRV_ERR_INVALID_PARAM: return -EINVAL;
1416 case SUPDRV_ERR_INVALID_MAGIC: return -EILSEQ;
1417 case SUPDRV_ERR_INVALID_HANDLE: return -ENXIO;
1418 case SUPDRV_ERR_INVALID_POINTER: return -EFAULT;
1419 case SUPDRV_ERR_LOCK_FAILED: return -ENOLCK;
1420 case SUPDRV_ERR_ALREADY_LOADED: return -EEXIST;
1421 case SUPDRV_ERR_PERMISSION_DENIED: return -EPERM;
1422 case SUPDRV_ERR_VERSION_MISMATCH: return -ENOSYS;
1423 }
1424
1425 return -EPERM;
1426}
1427
1428
1429RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
1430{
1431#if 1
1432 va_list args;
1433 char szMsg[512];
1434
1435 va_start(args, pszFormat);
1436 vsnprintf(szMsg, sizeof(szMsg) - 1, pszFormat, args);
1437 szMsg[sizeof(szMsg) - 1] = '\0';
1438 printk("%s", szMsg);
1439 va_end(args);
1440#else
1441 /* forward to printf - needs some more GCC hacking to fix ebp... */
1442 __asm__ __volatile__ ("mov %0, %esp\n\t"
1443 "jmp %1\n\t",
1444 :: "r" ((uintptr_t)&pszFormat - 4),
1445 "m" (printk));
1446#endif
1447 return 0;
1448}
1449
1450
1451/** Runtime assert implementation for Linux Ring-0. */
1452RTDECL(void) AssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
1453{
1454 printk("!!Assertion Failed!!\n"
1455 "Expression: %s\n"
1456 "Location : %s(%d) %s\n",
1457 pszExpr, pszFile, uLine, pszFunction);
1458}
1459
1460
1461/** Runtime assert implementation for Linux Ring-0. */
1462RTDECL(void) AssertMsg2(const char *pszFormat, ...)
1463{ /* forwarder. */
1464 va_list ap;
1465 char msg[256];
1466
1467 va_start(ap, pszFormat);
1468 vsnprintf(msg, sizeof(msg) - 1, pszFormat, ap);
1469 msg[sizeof(msg) - 1] = '\0';
1470 printk("%s", msg);
1471 va_end(ap);
1472}
1473
1474
1475/* GCC C++ hack. */
1476unsigned __gxx_personality_v0 = 0xcccccccc;
1477
1478
1479module_init(VBoxSupDrvInit);
1480module_exit(VBoxSupDrvUnload);
1481
1482MODULE_AUTHOR("InnoTek Systemberatung GmbH");
1483MODULE_DESCRIPTION("VirtualBox Support Driver");
1484MODULE_LICENSE("GPL");
Note: See TracBrowser for help on using the repository browser.

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