VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 56.5 KB
Line 
1/** @file
2 * The VirtualBox Support Driver - Linux hosts.
3 */
4
5/*
6 * Copyright (C) 2006-2007 innotek GmbH
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License as published by the Free Software Foundation,
12 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
13 * distribution. VirtualBox OSE is distributed in the hope that it will
14 * be useful, but WITHOUT ANY WARRANTY of any kind.
15 * Some lines of code to disable the local APIC on x86_64 machines taken
16 * from a Mandriva patch by Gwenole Beauchesne <[email protected]>.
17 */
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include "SUPDRV.h"
23#include "version-generated.h"
24
25#include <iprt/assert.h>
26#include <iprt/spinlock.h>
27#include <iprt/semaphore.h>
28#include <iprt/initterm.h>
29#include <iprt/process.h>
30#include <iprt/err.h>
31#include <iprt/mem.h>
32
33#include <linux/module.h>
34#include <linux/kernel.h>
35#include <linux/init.h>
36#include <linux/fs.h>
37#include <linux/mm.h>
38#include <linux/pagemap.h>
39#include <linux/sched.h>
40#include <linux/slab.h>
41#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
42# include <linux/jiffies.h>
43#endif
44#include <asm/mman.h>
45#include <asm/io.h>
46#include <asm/uaccess.h>
47#ifdef CONFIG_DEVFS_FS
48# include <linux/devfs_fs_kernel.h>
49#endif
50#ifdef CONFIG_VBOXDRV_AS_MISC
51# include <linux/miscdevice.h>
52#endif
53#ifdef CONFIG_X86_LOCAL_APIC
54# include <asm/apic.h>
55# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
56# include <asm/nmi.h>
57# endif
58#endif
59
60#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
61# ifndef page_to_pfn
62# define page_to_pfn(page) ((page) - mem_map)
63# endif
64# include <asm/pgtable.h>
65# define global_flush_tlb __flush_tlb_global
66#endif
67
68/* devfs defines */
69#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
70# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
71
72# define VBOX_REGISTER_DEVFS() \
73({ \
74 void *rc = NULL; \
75 if (devfs_mk_cdev(MKDEV(DEVICE_MAJOR, 0), \
76 S_IFCHR | S_IRUGO | S_IWUGO, \
77 DEVICE_NAME) == 0) \
78 rc = (void *)' '; /* return not NULL */ \
79 rc; \
80 })
81
82# define VBOX_UNREGISTER_DEVFS(handle) \
83 devfs_remove(DEVICE_NAME);
84
85# else /* < 2.6.0 */
86
87# define VBOX_REGISTER_DEVFS() \
88 devfs_register(NULL, DEVICE_NAME, DEVFS_FL_DEFAULT, \
89 DEVICE_MAJOR, 0, \
90 S_IFCHR | S_IRUGO | S_IWUGO, \
91 &gFileOpsVBoxDrv, NULL)
92
93# define VBOX_UNREGISTER_DEVFS(handle) \
94 if (handle != NULL) \
95 devfs_unregister(handle)
96
97# endif /* < 2.6.0 */
98#endif /* CONFIG_DEV_FS && !CONFIG_VBOXDEV_AS_MISC */
99
100#ifndef CONFIG_VBOXDRV_AS_MISC
101# if defined(CONFIG_DEVFS_FS) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 0)
102# define VBOX_REGISTER_DEVICE(a,b,c) devfs_register_chrdev(a,b,c)
103# define VBOX_UNREGISTER_DEVICE(a,b) devfs_unregister_chrdev(a,b)
104# else
105# define VBOX_REGISTER_DEVICE(a,b,c) register_chrdev(a,b,c)
106# define VBOX_UNREGISTER_DEVICE(a,b) unregister_chrdev(a,b)
107# endif
108#endif /* !CONFIG_VBOXDRV_AS_MISC */
109
110
111#ifdef CONFIG_X86_HIGH_ENTRY
112# error "CONFIG_X86_HIGH_ENTRY is not supported by VBoxDrv at this time."
113#endif
114
115/*
116 * This sucks soooo badly on x86! Why don't they export __PAGE_KERNEL_EXEC so PAGE_KERNEL_EXEC would be usable?
117 */
118#if defined(RT_ARCH_AMD64)
119# define MY_PAGE_KERNEL_EXEC PAGE_KERNEL_EXEC
120#elif defined(PAGE_KERNEL_EXEC) && defined(CONFIG_X86_PAE)
121# define MY_PAGE_KERNEL_EXEC __pgprot(cpu_has_pge ? _PAGE_KERNEL_EXEC | _PAGE_GLOBAL : _PAGE_KERNEL_EXEC)
122#else
123# define MY_PAGE_KERNEL_EXEC PAGE_KERNEL
124#endif
125
126/*
127 * The redhat hack section.
128 * - The current hacks are for 2.4.21-15.EL only.
129 */
130#ifndef NO_REDHAT_HACKS
131/* accounting. */
132# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
133# ifdef VM_ACCOUNT
134# define MY_DO_MUNMAP(a,b,c) do_munmap(a, b, c, 0) /* should it be 1 or 0? */
135# endif
136# endif
137
138/* backported remap_page_range. */
139# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
140# include <asm/tlb.h>
141# ifdef tlb_vma /* probably not good enough... */
142# define HAVE_26_STYLE_REMAP_PAGE_RANGE 1
143# endif
144# endif
145
146# ifndef RT_ARCH_AMD64
147/* In 2.6.9-22.ELsmp we have to call change_page_attr() twice when changing
148 * the page attributes from PAGE_KERNEL to something else, because there appears
149 * to be a bug in one of the many patches that redhat applied.
150 * It should be safe to do this on less buggy linux kernels too. ;-)
151 */
152# define MY_CHANGE_PAGE_ATTR(pPages, cPages, prot) \
153 do { \
154 if (pgprot_val(prot) != pgprot_val(PAGE_KERNEL)) \
155 change_page_attr(pPages, cPages, prot); \
156 change_page_attr(pPages, cPages, prot); \
157 } while (0)
158# endif
159#endif /* !NO_REDHAT_HACKS */
160
161
162#ifndef MY_DO_MUNMAP
163# define MY_DO_MUNMAP(a,b,c) do_munmap(a, b, c)
164#endif
165
166#ifndef MY_CHANGE_PAGE_ATTR
167# ifdef RT_ARCH_AMD64 /** @todo This is a cheap hack, but it'll get around that 'else BUG();' in __change_page_attr(). */
168# define MY_CHANGE_PAGE_ATTR(pPages, cPages, prot) \
169 do { \
170 change_page_attr(pPages, cPages, PAGE_KERNEL_NOCACHE); \
171 change_page_attr(pPages, cPages, prot); \
172 } while (0)
173# else
174# define MY_CHANGE_PAGE_ATTR(pPages, cPages, prot) change_page_attr(pPages, cPages, prot)
175# endif
176#endif
177
178
179/** @def ONE_MSEC_IN_JIFFIES
180 * The number of jiffies that make up 1 millisecond. This is only actually used
181 * when HZ is > 1000. */
182#if HZ <= 1000
183# define ONE_MSEC_IN_JIFFIES 0
184#elif !(HZ % 1000)
185# define ONE_MSEC_IN_JIFFIES (HZ / 1000)
186#else
187# define ONE_MSEC_IN_JIFFIES ((HZ + 999) / 1000)
188# error "HZ is not a multiple of 1000, the GIP stuff won't work right!"
189#endif
190
191#ifdef CONFIG_X86_LOCAL_APIC
192
193/* If an NMI occurs while we are inside the world switcher the machine will
194 * crash. The Linux NMI watchdog generates periodic NMIs increasing a counter
195 * which is compared with another counter increased in the timer interrupt
196 * handler. We disable the NMI watchdog.
197 *
198 * - Linux >= 2.6.21: The watchdog is disabled by default on i386 and x86_64.
199 * - Linux < 2.6.21: The watchdog is normally enabled by default on x86_64
200 * and disabled on i386.
201 */
202# if defined(RT_ARCH_AMD64)
203# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21)
204# define DO_DISABLE_NMI 1
205# endif
206# endif
207
208# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
209extern int nmi_active;
210# define nmi_atomic_read(P) *(P)
211# define nmi_atomic_set(P, V) *(P) = (V)
212# define nmi_atomic_dec(P) nmi_atomic_set(P, 0)
213# else
214# define nmi_atomic_read(P) atomic_read(P)
215# define nmi_atomic_set(P, V) atomic_set(P, V)
216# define nmi_atomic_dec(P) atomic_dec(P)
217# endif
218
219# ifndef X86_FEATURE_ARCH_PERFMON
220# define X86_FEATURE_ARCH_PERFMON (3*32+9) /* Intel Architectural PerfMon */
221# endif
222# ifndef MSR_ARCH_PERFMON_EVENTSEL0
223# define MSR_ARCH_PERFMON_EVENTSEL0 0x186
224# endif
225# ifndef ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT
226# define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT (1 << 0)
227# endif
228
229#endif /* CONFIG_X86_LOCAL_APIC */
230
231
232/*******************************************************************************
233* Defined Constants And Macros *
234*******************************************************************************/
235/**
236 * Device extention & session data association structure.
237 */
238static SUPDRVDEVEXT g_DevExt;
239
240/** Timer structure for the GIP update. */
241static struct timer_list g_GipTimer;
242/** Pointer to the page structure for the GIP. */
243struct page *g_pGipPage;
244
245/** Registered devfs device handle. */
246#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
247# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
248static void *g_hDevFsVBoxDrv = NULL;
249# else
250static devfs_handle_t g_hDevFsVBoxDrv = NULL;
251# endif
252#endif
253
254#ifndef CONFIG_VBOXDRV_AS_MISC
255/** Module major number */
256#define DEVICE_MAJOR 234
257/** Saved major device number */
258static int g_iModuleMajor;
259#endif /* !CONFIG_VBOXDRV_AS_MISC */
260
261/** The module name. */
262#define DEVICE_NAME "vboxdrv"
263
264#ifdef RT_ARCH_AMD64
265/**
266 * Memory for the executable memory heap (in IPRT).
267 */
268extern uint8_t g_abExecMemory[1572864]; /* 1.5 MB */
269__asm__(".section execmemory, \"awx\", @progbits\n\t"
270 ".align 32\n\t"
271 ".globl g_abExecMemory\n"
272 "g_abExecMemory:\n\t"
273 ".zero 1572864\n\t"
274 ".type g_abExecMemory, @object\n\t"
275 ".size g_abExecMemory, 1572864\n\t"
276 ".text\n\t");
277#endif
278
279
280/*******************************************************************************
281* Internal Functions *
282*******************************************************************************/
283static int VBoxSupDrvInit(void);
284static void VBoxSupDrvUnload(void);
285static int VBoxSupDrvCreate(struct inode *pInode, struct file *pFilp);
286static int VBoxSupDrvClose(struct inode *pInode, struct file *pFilp);
287static int VBoxSupDrvDeviceControl(struct inode *pInode, struct file *pFilp,
288 unsigned int IOCmd, unsigned long IOArg);
289static RTR3PTR VBoxSupDrvMapUser(struct page **papPages, unsigned cPages, unsigned fProt, pgprot_t pgFlags);
290static int VBoxSupDrvInitGip(PSUPDRVDEVEXT pDevExt);
291static int VBoxSupDrvTermGip(PSUPDRVDEVEXT pDevExt);
292static void VBoxSupGipTimer(unsigned long ulUser);
293#ifdef CONFIG_SMP
294static void VBoxSupGipTimerPerCpu(unsigned long ulUser);
295static void VBoxSupGipResumePerCpu(void *pvUser);
296#endif
297static int VBoxSupDrvOrder(unsigned long size);
298static int VBoxSupDrvErr2LinuxErr(int);
299
300
301/** The file_operations structure. */
302static struct file_operations gFileOpsVBoxDrv =
303{
304 owner: THIS_MODULE,
305 open: VBoxSupDrvCreate,
306 release: VBoxSupDrvClose,
307 ioctl: VBoxSupDrvDeviceControl,
308};
309
310#ifdef CONFIG_VBOXDRV_AS_MISC
311/** The miscdevice structure. */
312static struct miscdevice gMiscDevice =
313{
314 minor: MISC_DYNAMIC_MINOR,
315 name: DEVICE_NAME,
316 fops: &gFileOpsVBoxDrv,
317# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && \
318 LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
319 devfs_name: DEVICE_NAME,
320# endif
321};
322#endif
323
324#ifdef CONFIG_X86_LOCAL_APIC
325# ifdef DO_DISABLE_NMI
326
327/** Stop AMD NMI watchdog (x86_64 only). */
328static int stop_k7_watchdog(void)
329{
330 wrmsr(MSR_K7_EVNTSEL0, 0, 0);
331 return 1;
332}
333
334/** Stop Intel P4 NMI watchdog (x86_64 only). */
335static int stop_p4_watchdog(void)
336{
337 wrmsr(MSR_P4_IQ_CCCR0, 0, 0);
338 wrmsr(MSR_P4_IQ_CCCR1, 0, 0);
339 wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
340 return 1;
341}
342
343/** The new method of detecting the event counter */
344static int stop_intel_arch_watchdog(void)
345{
346 unsigned ebx;
347
348 ebx = cpuid_ebx(10);
349 if (!(ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
350 wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, 0, 0);
351 return 1;
352}
353
354/** Stop NMI watchdog. */
355static void vbox_stop_apic_nmi_watchdog(void *unused)
356{
357 int stopped = 0;
358
359 /* only support LOCAL and IO APICs for now */
360 if ((nmi_watchdog != NMI_LOCAL_APIC) &&
361 (nmi_watchdog != NMI_IO_APIC))
362 return;
363
364 if (nmi_watchdog == NMI_LOCAL_APIC)
365 {
366 switch (boot_cpu_data.x86_vendor)
367 {
368 case X86_VENDOR_AMD:
369 if (strstr(boot_cpu_data.x86_model_id, "Screwdriver"))
370 return;
371 stopped = stop_k7_watchdog();
372 break;
373 case X86_VENDOR_INTEL:
374 if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
375 {
376 stopped = stop_intel_arch_watchdog();
377 break;
378 }
379 stopped = stop_p4_watchdog();
380 break;
381 default:
382 return;
383 }
384 }
385
386 if (stopped)
387 nmi_atomic_dec(&nmi_active);
388}
389
390/** Disable LAPIC NMI watchdog. */
391static void disable_lapic_nmi_watchdog(void)
392{
393 BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
394
395 if (nmi_atomic_read(&nmi_active) <= 0)
396 return;
397
398 on_each_cpu(vbox_stop_apic_nmi_watchdog, NULL, 1, 1);
399
400 BUG_ON(nmi_atomic_read(&nmi_active) != 0);
401
402 /* tell do_nmi() and others that we're not active any more */
403 nmi_watchdog = NMI_NONE;
404}
405
406/** Shutdown NMI. */
407static void nmi_cpu_shutdown(void * dummy)
408{
409 unsigned int vERR, vPC;
410
411 vPC = apic_read(APIC_LVTPC);
412
413 if ((GET_APIC_DELIVERY_MODE(vPC) == APIC_MODE_NMI) && !(vPC & APIC_LVT_MASKED))
414 {
415 vERR = apic_read(APIC_LVTERR);
416 apic_write(APIC_LVTERR, vERR | APIC_LVT_MASKED);
417 apic_write(APIC_LVTPC, vPC | APIC_LVT_MASKED);
418 apic_write(APIC_LVTERR, vERR);
419 }
420}
421
422static void nmi_shutdown(void)
423{
424 on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1);
425}
426# endif /* DO_DISABLE_NMI */
427#endif /* CONFIG_X86_LOCAL_APIC */
428
429/**
430 * Initialize module.
431 *
432 * @returns appropriate status code.
433 */
434static int __init VBoxSupDrvInit(void)
435{
436 int rc;
437
438 dprintf(("VBoxDrv::ModuleInit\n"));
439
440#ifdef CONFIG_X86_LOCAL_APIC
441 /*
442 * If an NMI occurs while we are inside the world switcher the macine will crash.
443 * The Linux NMI watchdog generates periodic NMIs increasing a counter which is
444 * compared with another counter increased in the timer interrupt handler. Therefore
445 * we don't allow to setup an NMI watchdog.
446 */
447# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
448 /*
449 * First test: NMI actiated? Works only works with Linux 2.6 -- 2.4 does not export
450 * the nmi_watchdog variable.
451 */
452# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) || \
453 (defined CONFIG_X86_64 && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
454# ifdef DO_DISABLE_NMI
455 if (nmi_atomic_read(&nmi_active) > 0)
456 {
457 printk(KERN_INFO DEVICE_NAME ": Trying to deactivate the NMI watchdog...\n");
458
459 switch (nmi_watchdog)
460 {
461 case NMI_LOCAL_APIC:
462 disable_lapic_nmi_watchdog();
463 break;
464 case NMI_NONE:
465 nmi_atomic_dec(&nmi_active);
466 break;
467 }
468
469 if (nmi_atomic_read(&nmi_active) == 0)
470 {
471 nmi_shutdown();
472 printk(KERN_INFO DEVICE_NAME ": Successfully done.\n");
473 }
474 else
475 printk(KERN_INFO DEVICE_NAME ": Failed!\n");
476 }
477# endif /* DO_DISABLE_NMI */
478
479 /*
480 * Permanent IO_APIC mode active? No way to handle this!
481 */
482 if (nmi_watchdog == NMI_IO_APIC)
483 {
484 printk(KERN_ERR DEVICE_NAME
485 ": NMI watchdog in IO_APIC mode active -- refused to load the kernel module!\n"
486 DEVICE_NAME
487 ": Please disable the NMI watchdog by specifying 'nmi_watchdog=0' at kernel\n"
488 DEVICE_NAME
489 ": command line.\n");
490 return -EINVAL;
491 }
492
493 /*
494 * See arch/i386/kernel/nmi.c on >= 2.6.19: -1 means it can never enabled again
495 */
496 nmi_atomic_set(&nmi_active, -1);
497 printk(KERN_INFO DEVICE_NAME ": Trying to deactivate the NMI watchdog permanently...\n");
498
499 /*
500 * Now fall through and see if it actually was enabled before. If so, fail
501 * as we cannot deactivate it cleanly from here.
502 */
503# else /* < 2.6.19 */
504 /*
505 * Older 2.6 kernels: nmi_watchdog is not initalized by default
506 */
507 if (nmi_watchdog != NMI_NONE)
508 goto nmi_activated;
509# endif
510# endif /* >= 2.6.0 */
511
512 /*
513 * Second test: Interrupt generated by performance counter not masked and can
514 * generate an NMI. Works also with Linux 2.4.
515 */
516 {
517 unsigned int v, ver, maxlvt;
518
519 v = apic_read(APIC_LVR);
520 ver = GET_APIC_VERSION(v);
521 /* 82489DXs do not report # of LVT entries. */
522 maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2;
523 if (maxlvt >= 4)
524 {
525 /* Read status of performance counter IRQ vector */
526 v = apic_read(APIC_LVTPC);
527
528 /* performance counter generates NMI and is not masked? */
529 if ((GET_APIC_DELIVERY_MODE(v) == APIC_MODE_NMI) && !(v & APIC_LVT_MASKED))
530 {
531# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) || \
532 (defined CONFIG_X86_64 && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
533 printk(KERN_ERR DEVICE_NAME
534 ": NMI watchdog either active or at least initialized. Please disable the NMI\n"
535 DEVICE_NAME
536 ": watchdog by specifying 'nmi_watchdog=0' at kernel command line.\n");
537 return -EINVAL;
538# else /* < 2.6.19 */
539# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
540nmi_activated:
541# endif
542 printk(KERN_ERR DEVICE_NAME
543 ": NMI watchdog active -- refused to load the kernel module! Please disable\n"
544 DEVICE_NAME
545 ": the NMI watchdog by specifying 'nmi_watchdog=0' at kernel command line.\n");
546 return -EINVAL;
547# endif /* >= 2.6.19 */
548 }
549 }
550 }
551# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
552 printk(KERN_INFO DEVICE_NAME ": Successfully done.\n");
553# endif /* >= 2.6.19 */
554#endif /* CONFIG_X86_LOCAL_APIC */
555
556#ifdef CONFIG_VBOXDRV_AS_MISC
557 rc = misc_register(&gMiscDevice);
558 if (rc)
559 {
560 printk(KERN_ERR DEVICE_NAME ": Can't register misc device! rc=%d\n", rc);
561 return rc;
562 }
563#else /* !CONFIG_VBOXDRV_AS_MISC */
564 /*
565 * Register character device.
566 */
567 g_iModuleMajor = DEVICE_MAJOR;
568 rc = VBOX_REGISTER_DEVICE((dev_t)g_iModuleMajor, DEVICE_NAME, &gFileOpsVBoxDrv);
569 if (rc < 0)
570 {
571 dprintf(("VBOX_REGISTER_DEVICE failed with rc=%#x!\n", rc));
572 return rc;
573 }
574
575 /*
576 * Save returned module major number
577 */
578 if (DEVICE_MAJOR != 0)
579 g_iModuleMajor = DEVICE_MAJOR;
580 else
581 g_iModuleMajor = rc;
582 rc = 0;
583
584#ifdef CONFIG_DEVFS_FS
585 /*
586 * Register a device entry
587 */
588 g_hDevFsVBoxDrv = VBOX_REGISTER_DEVFS();
589 if (g_hDevFsVBoxDrv == NULL)
590 {
591 dprintf(("devfs_register failed!\n"));
592 rc = -EINVAL;
593 }
594#endif
595#endif /* !CONFIG_VBOXDRV_AS_MISC */
596 if (!rc)
597 {
598 /*
599 * Initialize the runtime.
600 * On AMD64 we'll have to donate the high rwx memory block to the exec allocator.
601 */
602 rc = RTR0Init(0);
603 if (RT_SUCCESS(rc))
604 {
605#ifdef RT_ARCH_AMD64
606 rc = RTR0MemExecDonate(&g_abExecMemory[0], sizeof(g_abExecMemory));
607#endif
608 /*
609 * Initialize the device extension.
610 */
611 if (RT_SUCCESS(rc))
612 rc = supdrvInitDevExt(&g_DevExt);
613 if (!rc)
614 {
615 /*
616 * Create the GIP page.
617 */
618 rc = VBoxSupDrvInitGip(&g_DevExt);
619 if (!rc)
620 {
621 dprintf(("VBoxDrv::ModuleInit returning %#x\n", rc));
622 return rc;
623 }
624
625 supdrvDeleteDevExt(&g_DevExt);
626 }
627 else
628 rc = -EINVAL;
629 RTR0Term();
630 }
631 else
632 rc = -EINVAL;
633
634 /*
635 * Failed, cleanup and return the error code.
636 */
637#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
638 VBOX_UNREGISTER_DEVFS(g_hDevFsVBoxDrv);
639#endif
640 }
641#ifdef CONFIG_VBOXDRV_AS_MISC
642 misc_deregister(&gMiscDevice);
643 dprintf(("VBoxDrv::ModuleInit returning %#x (minor:%d)\n", rc, gMiscDevice.minor));
644#else
645 VBOX_UNREGISTER_DEVICE(g_iModuleMajor, DEVICE_NAME);
646 dprintf(("VBoxDrv::ModuleInit returning %#x (major:%d)\n", rc, g_iModuleMajor));
647#endif
648 return rc;
649}
650
651
652/**
653 * Unload the module.
654 */
655static void __exit VBoxSupDrvUnload(void)
656{
657 int rc;
658 dprintf(("VBoxSupDrvUnload\n"));
659
660 /*
661 * I Don't think it's possible to unload a driver which processes have
662 * opened, at least we'll blindly assume that here.
663 */
664#ifdef CONFIG_VBOXDRV_AS_MISC
665 rc = misc_deregister(&gMiscDevice);
666 if (rc < 0)
667 {
668 dprintf(("misc_deregister failed with rc=%#x\n", rc));
669 }
670#else /* !CONFIG_VBOXDRV_AS_MISC */
671#ifdef CONFIG_DEVFS_FS
672 /*
673 * Unregister a device entry
674 */
675 VBOX_UNREGISTER_DEVFS(g_hDevFsVBoxDrv);
676#endif // devfs
677 rc = VBOX_UNREGISTER_DEVICE(g_iModuleMajor, DEVICE_NAME);
678 if (rc < 0)
679 {
680 dprintf(("unregister_chrdev failed with rc=%#x (major:%d)\n", rc, g_iModuleMajor));
681 }
682#endif /* !CONFIG_VBOXDRV_AS_MISC */
683
684 /*
685 * Destroy GIP, delete the device extension and terminate IPRT.
686 */
687 VBoxSupDrvTermGip(&g_DevExt);
688 supdrvDeleteDevExt(&g_DevExt);
689 RTR0Term();
690}
691
692
693/**
694 * Device open. Called on open /dev/vboxdrv
695 *
696 * @param pInode Pointer to inode info structure.
697 * @param pFilp Associated file pointer.
698 */
699static int VBoxSupDrvCreate(struct inode *pInode, struct file *pFilp)
700{
701 int rc;
702 PSUPDRVSESSION pSession;
703 dprintf(("VBoxSupDrvCreate: pFilp=%p\n", pFilp));
704
705 /*
706 * Call common code for the rest.
707 */
708 rc = supdrvCreateSession(&g_DevExt, (PSUPDRVSESSION *)&pSession);
709 if (!rc)
710 {
711 pSession->Uid = current->euid;
712 pSession->Gid = current->egid;
713 pSession->Process = RTProcSelf();
714 pSession->R0Process = RTR0ProcHandleSelf();
715 }
716
717 dprintf(("VBoxSupDrvCreate: g_DevExt=%p pSession=%p rc=%d\n", &g_DevExt, pSession, rc));
718 pFilp->private_data = pSession;
719
720 return VBoxSupDrvErr2LinuxErr(rc);
721}
722
723
724/**
725 * Close device.
726 *
727 * @param pInode Pointer to inode info structure.
728 * @param pFilp Associated file pointer.
729 */
730static int VBoxSupDrvClose(struct inode *pInode, struct file *pFilp)
731{
732 dprintf(("VBoxSupDrvClose: pFilp=%p private_data=%p\n", pFilp, pFilp->private_data));
733 supdrvCloseSession(&g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
734 pFilp->private_data = NULL;
735 return 0;
736}
737
738
739/**
740 * Device I/O Control entry point.
741 *
742 * @param pInode Pointer to inode info structure.
743 * @param pFilp Associated file pointer.
744 * @param IOCmd The function specified to ioctl().
745 * @param IOArg The argument specified to ioctl().
746 */
747static int VBoxSupDrvDeviceControl(struct inode *pInode, struct file *pFilp,
748 unsigned int IOCmd, unsigned long IOArg)
749{
750 int rc;
751 SUPDRVIOCTLDATA Args;
752 void *pvBuf = NULL;
753 int cbBuf = 0;
754 unsigned cbOut = 0;
755
756 dprintf2(("VBoxSupDrvDeviceControl: pFilp=%p IOCmd=%x IOArg=%p\n", pFilp, IOCmd, (void *)IOArg));
757
758 /*
759 * Copy ioctl data structure from user space.
760 */
761 if (_IOC_SIZE(IOCmd) != sizeof(SUPDRVIOCTLDATA))
762 {
763 dprintf(("VBoxSupDrvDeviceControl: incorrect input length! cbArgs=%d\n", _IOC_SIZE(IOCmd)));
764 return -EINVAL;
765 }
766 if (copy_from_user(&Args, (void *)IOArg, _IOC_SIZE(IOCmd)))
767 {
768 dprintf(("VBoxSupDrvDeviceControl: copy_from_user(&Args) failed.\n"));
769 return -EFAULT;
770 }
771
772 /*
773 * Allocate and copy user space input data buffer to kernel space.
774 */
775 if (Args.cbIn > 0 || Args.cbOut > 0)
776 {
777 cbBuf = max(Args.cbIn, Args.cbOut);
778 pvBuf = vmalloc(cbBuf);
779 if (pvBuf == NULL)
780 {
781 dprintf(("VBoxSupDrvDeviceControl: failed to allocate buffer of %d bytes.\n", cbBuf));
782 return -ENOMEM;
783 }
784
785 if (copy_from_user(pvBuf, (void *)Args.pvIn, Args.cbIn))
786 {
787 dprintf(("VBoxSupDrvDeviceControl: copy_from_user(pvBuf) failed.\n"));
788 vfree(pvBuf);
789 return -EFAULT;
790 }
791 }
792
793 /*
794 * Process the IOCtl.
795 */
796 rc = supdrvIOCtl(IOCmd, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data,
797 pvBuf, Args.cbIn, pvBuf, Args.cbOut, &cbOut);
798
799 /*
800 * Copy ioctl data and output buffer back to user space.
801 */
802 if (rc)
803 {
804 dprintf(("VBoxSupDrvDeviceControl: pFilp=%p IOCmd=%x IOArg=%p failed, rc=%d (linux rc=%d)\n",
805 pFilp, IOCmd, (void *)IOArg, rc, VBoxSupDrvErr2LinuxErr(rc)));
806 rc = VBoxSupDrvErr2LinuxErr(rc);
807 }
808 else if (cbOut > 0)
809 {
810 if (pvBuf != NULL && cbOut <= cbBuf)
811 {
812 if (copy_to_user((void *)Args.pvOut, pvBuf, cbOut))
813 {
814 dprintf(("copy_to_user failed.\n"));
815 rc = -EFAULT;
816 }
817 }
818 else
819 {
820 dprintf(("WHAT!?! supdrvIOCtl messed up! cbOut=%d cbBuf=%d pvBuf=%p\n", cbOut, cbBuf, pvBuf));
821 rc = -EPERM;
822 }
823 }
824
825 if (pvBuf)
826 vfree(pvBuf);
827
828 dprintf2(("VBoxSupDrvDeviceControl: returns %d\n", rc));
829 return rc;
830}
831
832
833/**
834 * Initializes any OS specific object creator fields.
835 */
836void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
837{
838 NOREF(pObj);
839 NOREF(pSession);
840}
841
842
843/**
844 * Checks if the session can access the object.
845 *
846 * @returns true if a decision has been made.
847 * @returns false if the default access policy should be applied.
848 *
849 * @param pObj The object in question.
850 * @param pSession The session wanting to access the object.
851 * @param pszObjName The object name, can be NULL.
852 * @param prc Where to store the result when returning true.
853 */
854bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
855{
856 NOREF(pObj);
857 NOREF(pSession);
858 NOREF(pszObjName);
859 NOREF(prc);
860 return false;
861}
862
863
864/**
865 * Compute order. Some functions allocate 2^order pages.
866 *
867 * @returns order.
868 * @param cPages Number of pages.
869 */
870static int VBoxSupDrvOrder(unsigned long cPages)
871{
872 int iOrder;
873 unsigned long cTmp;
874
875 for (iOrder = 0, cTmp = cPages; cTmp >>= 1; ++iOrder)
876 ;
877 if (cPages & ~(1 << iOrder))
878 ++iOrder;
879
880 return iOrder;
881}
882
883
884/**
885 * OS Specific code for locking down memory.
886 *
887 * @returns 0 on success.
888 * @returns SUPDRV_ERR_* on failure.
889 * @param pMem Pointer to memory.
890 * This is not linked in anywhere.
891 * @param paPages Array which should be filled with the address of the physical pages.
892 *
893 * @remark See sgl_map_user_pages() for an example of an similar function.
894 */
895int VBOXCALL supdrvOSLockMemOne(PSUPDRVMEMREF pMem, PSUPPAGE paPages)
896{
897 int rc;
898 struct page **papPages;
899 unsigned iPage;
900 unsigned cPages = pMem->cb >> PAGE_SHIFT;
901 unsigned long pv = (unsigned long)pMem->pvR3;
902 struct vm_area_struct **papVMAs;
903
904 /*
905 * Allocate page pointer array.
906 */
907 papPages = vmalloc(cPages * sizeof(*papPages));
908 if (!papPages)
909 return SUPDRV_ERR_NO_MEMORY;
910
911 /*
912 * Allocate the VMA pointer array.
913 */
914 papVMAs = vmalloc(cPages * sizeof(*papVMAs));
915 if (!papVMAs)
916 return SUPDRV_ERR_NO_MEMORY;
917
918 /*
919 * Get user pages.
920 */
921 down_read(&current->mm->mmap_sem);
922 rc = get_user_pages(current, /* Task for fault acounting. */
923 current->mm, /* Whose pages. */
924 (unsigned long)pv, /* Where from. */
925 cPages, /* How many pages. */
926 1, /* Write to memory. */
927 0, /* force. */
928 papPages, /* Page array. */
929 papVMAs); /* vmas */
930 if (rc != cPages)
931 {
932 up_read(&current->mm->mmap_sem);
933 dprintf(("supdrvOSLockMemOne: get_user_pages failed. rc=%d\n", rc));
934 return SUPDRV_ERR_LOCK_FAILED;
935 }
936
937 for (iPage = 0; iPage < cPages; iPage++)
938 flush_dcache_page(papPages[iPage]);
939 up_read(&current->mm->mmap_sem);
940
941 pMem->u.locked.papPages = papPages;
942 pMem->u.locked.cPages = cPages;
943
944 /*
945 * Get addresses, protect against fork()
946 */
947 for (iPage = 0; iPage < cPages; iPage++)
948 {
949 paPages[iPage].Phys = page_to_phys(papPages[iPage]);
950 paPages[iPage].uReserved = 0;
951 papVMAs[iPage]->vm_flags |= VM_DONTCOPY;
952 }
953
954 vfree(papVMAs);
955
956 dprintf2(("supdrvOSLockMemOne: pvR3=%p cb=%d papPages=%p\n",
957 pMem->pvR3, pMem->cb, pMem->u.locked.papPages));
958 return 0;
959}
960
961
962/**
963 * Unlocks the memory pointed to by pv.
964 *
965 * @param pMem Pointer to memory to unlock.
966 *
967 * @remark See sgl_unmap_user_pages() for an example of an similar function.
968 */
969void VBOXCALL supdrvOSUnlockMemOne(PSUPDRVMEMREF pMem)
970{
971 unsigned iPage;
972 dprintf2(("supdrvOSUnlockMemOne: pvR3=%p cb=%d papPages=%p\n",
973 pMem->pvR3, pMem->cb, pMem->u.locked.papPages));
974
975 /*
976 * Loop thru the pages and release them.
977 */
978 for (iPage = 0; iPage < pMem->u.locked.cPages; iPage++)
979 {
980 if (!PageReserved(pMem->u.locked.papPages[iPage]))
981 SetPageDirty(pMem->u.locked.papPages[iPage]);
982 page_cache_release(pMem->u.locked.papPages[iPage]);
983 }
984
985 /* free the page array */
986 vfree(pMem->u.locked.papPages);
987 pMem->u.locked.cPages = 0;
988}
989
990
991/**
992 * OS Specific code for allocating page aligned memory with continuous fixed
993 * physical paged backing.
994 *
995 * @returns 0 on success.
996 * @returns SUPDRV_ERR_* on failure.
997 * @param pMem Memory reference record of the memory to be allocated.
998 * (This is not linked in anywhere.)
999 * @param ppvR0 Where to store the virtual address of the ring-0 mapping. (optional)
1000 * @param ppvR3 Where to store the virtual address of the ring-3 mapping.
1001 * @param pHCPhys Where to store the physical address.
1002 */
1003int VBOXCALL supdrvOSContAllocOne(PSUPDRVMEMREF pMem, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS pHCPhys)
1004{
1005 struct page *paPages;
1006 unsigned iPage;
1007 unsigned cbAligned = RT_ALIGN(pMem->cb, PAGE_SIZE);
1008 unsigned cPages = cbAligned >> PAGE_SHIFT;
1009 unsigned cOrder = VBoxSupDrvOrder(cPages);
1010 unsigned long ulAddr;
1011 dma_addr_t HCPhys;
1012 int rc = 0;
1013 pgprot_t pgFlags;
1014 pgprot_val(pgFlags) = _PAGE_PRESENT | _PAGE_RW | _PAGE_USER;
1015
1016 Assert(ppvR3);
1017 Assert(pHCPhys);
1018
1019 /*
1020 * Allocate page pointer array.
1021 */
1022#ifdef RT_ARCH_AMD64 /** @todo check out if there is a correct way of getting memory below 4GB (physically). */
1023 paPages = alloc_pages(GFP_DMA, cOrder);
1024#else
1025 paPages = alloc_pages(GFP_USER, cOrder);
1026#endif
1027 if (!paPages)
1028 return SUPDRV_ERR_NO_MEMORY;
1029
1030 /*
1031 * Lock the pages.
1032 */
1033 for (iPage = 0; iPage < cPages; iPage++)
1034 {
1035 SetPageReserved(&paPages[iPage]);
1036 if (!PageHighMem(&paPages[iPage]) && pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL))
1037 MY_CHANGE_PAGE_ATTR(&paPages[iPage], 1, MY_PAGE_KERNEL_EXEC);
1038#ifdef DEBUG
1039 if (iPage + 1 < cPages && (page_to_phys((&paPages[iPage])) + 0x1000) != page_to_phys((&paPages[iPage + 1])))
1040 {
1041 dprintf(("supdrvOSContAllocOne: Pages are not continuous!!!! iPage=%d phys=%llx physnext=%llx\n",
1042 iPage, (long long)page_to_phys((&paPages[iPage])), (long long)page_to_phys((&paPages[iPage + 1]))));
1043 BUG();
1044 }
1045#endif
1046 }
1047 HCPhys = page_to_phys(paPages);
1048
1049 /*
1050 * Allocate user space mapping and put the physical pages into it.
1051 */
1052 down_write(&current->mm->mmap_sem);
1053 ulAddr = do_mmap(NULL, 0, cbAligned, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_ANONYMOUS, 0);
1054 if (!(ulAddr & ~PAGE_MASK))
1055 {
1056#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(HAVE_26_STYLE_REMAP_PAGE_RANGE)
1057 int rc2 = remap_page_range(ulAddr, HCPhys, cbAligned, pgFlags);
1058#else
1059 int rc2 = 0;
1060 struct vm_area_struct *vma = find_vma(current->mm, ulAddr);
1061 if (vma)
1062#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
1063 rc2 = remap_page_range(vma, ulAddr, HCPhys, cbAligned, pgFlags);
1064#else
1065 rc2 = remap_pfn_range(vma, ulAddr, HCPhys >> PAGE_SHIFT, cbAligned, pgFlags);
1066#endif
1067 else
1068 {
1069 rc = SUPDRV_ERR_NO_MEMORY;
1070 dprintf(("supdrvOSContAllocOne: no vma found for ulAddr=%#lx!\n", ulAddr));
1071 }
1072#endif
1073 if (rc2)
1074 {
1075 rc = SUPDRV_ERR_NO_MEMORY;
1076 dprintf(("supdrvOSContAllocOne: remap_page_range failed rc2=%d\n", rc2));
1077 }
1078 }
1079 else
1080 {
1081 dprintf(("supdrvOSContAllocOne: do_mmap failed ulAddr=%#lx\n", ulAddr));
1082 rc = SUPDRV_ERR_NO_MEMORY;
1083 }
1084 up_write(&current->mm->mmap_sem); /* not quite sure when to give this up. */
1085
1086 /*
1087 * Success?
1088 */
1089 if (!rc)
1090 {
1091 *pHCPhys = HCPhys;
1092 *ppvR3 = ulAddr;
1093 if (ppvR0)
1094 *ppvR0 = (void *)ulAddr;
1095 pMem->pvR3 = ulAddr;
1096 pMem->pvR0 = NULL;
1097 pMem->u.cont.paPages = paPages;
1098 pMem->u.cont.cPages = cPages;
1099 pMem->cb = cbAligned;
1100
1101 dprintf2(("supdrvOSContAllocOne: pvR0=%p pvR3=%p cb=%d paPages=%p *pHCPhys=%lx *ppvR0=*ppvR3=%p\n",
1102 pMem->pvR0, pMem->pvR3, pMem->cb, paPages, (unsigned long)*pHCPhys, *ppvR3));
1103 global_flush_tlb();
1104 return 0;
1105 }
1106
1107 /*
1108 * Failure, cleanup and be gone.
1109 */
1110 down_write(&current->mm->mmap_sem);
1111 if (ulAddr & ~PAGE_MASK)
1112 MY_DO_MUNMAP(current->mm, ulAddr, pMem->cb);
1113 for (iPage = 0; iPage < cPages; iPage++)
1114 {
1115 ClearPageReserved(&paPages[iPage]);
1116 if (!PageHighMem(&paPages[iPage]) && pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL))
1117 MY_CHANGE_PAGE_ATTR(&paPages[iPage], 1, PAGE_KERNEL);
1118 }
1119 up_write(&current->mm->mmap_sem); /* check when we can leave this. */
1120 __free_pages(paPages, cOrder);
1121
1122 global_flush_tlb();
1123 return rc;
1124}
1125
1126
1127/**
1128 * Frees contiguous memory.
1129 *
1130 * @param pMem Memory reference record of the memory to be freed.
1131 */
1132void VBOXCALL supdrvOSContFreeOne(PSUPDRVMEMREF pMem)
1133{
1134 unsigned iPage;
1135
1136 dprintf2(("supdrvOSContFreeOne: pvR0=%p pvR3=%p cb=%d paPages=%p\n",
1137 pMem->pvR0, pMem->pvR3, pMem->cb, pMem->u.cont.paPages));
1138
1139 /*
1140 * do_exit() destroys the mm before closing files.
1141 * I really hope it cleans up our stuff properly...
1142 */
1143 if (current->mm)
1144 {
1145 down_write(&current->mm->mmap_sem);
1146 MY_DO_MUNMAP(current->mm, (unsigned long)pMem->pvR3, pMem->cb);
1147 up_write(&current->mm->mmap_sem); /* check when we can leave this. */
1148 }
1149
1150 /*
1151 * Change page attributes freeing the pages.
1152 */
1153 for (iPage = 0; iPage < pMem->u.cont.cPages; iPage++)
1154 {
1155 ClearPageReserved(&pMem->u.cont.paPages[iPage]);
1156 if (!PageHighMem(&pMem->u.cont.paPages[iPage]) && pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL))
1157 MY_CHANGE_PAGE_ATTR(&pMem->u.cont.paPages[iPage], 1, PAGE_KERNEL);
1158 }
1159 __free_pages(pMem->u.cont.paPages, VBoxSupDrvOrder(pMem->u.cont.cPages));
1160
1161 pMem->u.cont.cPages = 0;
1162}
1163
1164
1165/**
1166 * Allocates memory which mapped into both kernel and user space.
1167 * The returned memory is page aligned and so is the allocation.
1168 *
1169 * @returns 0 on success.
1170 * @returns SUPDRV_ERR_* on failure.
1171 * @param pMem Memory reference record of the memory to be allocated.
1172 * (This is not linked in anywhere.)
1173 * @param ppvR0 Where to store the address of the Ring-0 mapping.
1174 * @param ppvR3 Where to store the address of the Ring-3 mapping.
1175 */
1176int VBOXCALL supdrvOSMemAllocOne(PSUPDRVMEMREF pMem, PRTR0PTR ppvR0, PRTR3PTR ppvR3)
1177{
1178 const unsigned cbAligned = RT_ALIGN(pMem->cb, PAGE_SIZE);
1179 const unsigned cPages = cbAligned >> PAGE_SHIFT;
1180#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 22)
1181 unsigned cOrder = VBoxSupDrvOrder(cPages);
1182 struct page *paPages;
1183#endif
1184 struct page **papPages;
1185 unsigned iPage;
1186 pgprot_t pgFlags;
1187 pgprot_val(pgFlags) = _PAGE_PRESENT | _PAGE_RW | _PAGE_USER;
1188
1189 /*
1190 * Allocate array with page pointers.
1191 */
1192 pMem->u.mem.cPages = 0;
1193 pMem->u.mem.papPages = papPages = kmalloc(sizeof(papPages[0]) * cPages, GFP_KERNEL);
1194 if (!papPages)
1195 return SUPDRV_ERR_NO_MEMORY;
1196
1197 /*
1198 * Allocate the pages.
1199 */
1200#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
1201 for (iPage = 0; iPage < cPages; iPage++)
1202 {
1203 papPages[iPage] = alloc_page(GFP_HIGHUSER);
1204 if (!papPages[iPage])
1205 {
1206 pMem->u.mem.cPages = iPage;
1207 supdrvOSMemFreeOne(pMem);
1208 return SUPDRV_ERR_NO_MEMORY;
1209 }
1210 }
1211
1212#else /* < 2.4.22 */
1213 paPages = alloc_pages(GFP_USER, cOrder);
1214 if (!paPages)
1215 {
1216 supdrvOSMemFreeOne(pMem);
1217 return SUPDRV_ERR_NO_MEMORY;
1218 }
1219 for (iPage = 0; iPage < cPages; iPage++)
1220 {
1221 papPages[iPage] = &paPages[iPage];
1222 if (pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL))
1223 MY_CHANGE_PAGE_ATTR(papPages[iPage], 1, MY_PAGE_KERNEL_EXEC);
1224 if (PageHighMem(papPages[iPage]))
1225 BUG();
1226 }
1227#endif
1228 pMem->u.mem.cPages = cPages;
1229
1230 /*
1231 * Reserve the pages.
1232 */
1233 for (iPage = 0; iPage < cPages; iPage++)
1234 SetPageReserved(papPages[iPage]);
1235
1236 /*
1237 * Create the Ring-0 mapping.
1238 */
1239 if (ppvR0)
1240 {
1241#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
1242# ifdef VM_MAP
1243 *ppvR0 = pMem->pvR0 = vmap(papPages, cPages, VM_MAP, pgFlags);
1244# else
1245 *ppvR0 = pMem->pvR0 = vmap(papPages, cPages, VM_ALLOC, pgFlags);
1246# endif
1247#else
1248 *ppvR0 = pMem->pvR0 = phys_to_virt(page_to_phys(papPages[0]));
1249#endif
1250 }
1251 if (pMem->pvR0 || !ppvR0)
1252 {
1253 /*
1254 * Create the ring3 mapping.
1255 */
1256 if (ppvR3)
1257 *ppvR3 = pMem->pvR3 = VBoxSupDrvMapUser(papPages, cPages, PROT_READ | PROT_WRITE | PROT_EXEC, pgFlags);
1258 if (pMem->pvR3 || !ppvR3)
1259 return 0;
1260 dprintf(("supdrvOSMemAllocOne: failed to map into r3! cPages=%u\n", cPages));
1261 }
1262 else
1263 dprintf(("supdrvOSMemAllocOne: failed to map into r0! cPages=%u\n", cPages));
1264
1265 supdrvOSMemFreeOne(pMem);
1266 return SUPDRV_ERR_NO_MEMORY;
1267}
1268
1269
1270/**
1271 * Get the physical addresses of the pages in the allocation.
1272 * This is called while inside bundle the spinlock.
1273 *
1274 * @param pMem Memory reference record of the memory.
1275 * @param paPages Where to store the page addresses.
1276 */
1277void VBOXCALL supdrvOSMemGetPages(PSUPDRVMEMREF pMem, PSUPPAGE paPages)
1278{
1279 unsigned iPage;
1280 for (iPage = 0; iPage < pMem->u.mem.cPages; iPage++)
1281 {
1282 paPages[iPage].Phys = page_to_phys(pMem->u.mem.papPages[iPage]);
1283 paPages[iPage].uReserved = 0;
1284 }
1285}
1286
1287
1288/**
1289 * Frees memory allocated by supdrvOSMemAllocOne().
1290 *
1291 * @param pMem Memory reference record of the memory to be free.
1292 */
1293void VBOXCALL supdrvOSMemFreeOne(PSUPDRVMEMREF pMem)
1294{
1295 dprintf2(("supdrvOSMemFreeOne: pvR0=%p pvR3=%p cb=%d cPages=%d papPages=%p\n",
1296 pMem->pvR0, pMem->pvR3, pMem->cb, pMem->u.mem.cPages, pMem->u.mem.papPages));
1297
1298 /*
1299 * Unmap the user mapping (if any).
1300 * do_exit() destroys the mm before closing files.
1301 */
1302 if (pMem->pvR3 && current->mm)
1303 {
1304 down_write(&current->mm->mmap_sem);
1305 MY_DO_MUNMAP(current->mm, (unsigned long)pMem->pvR3, RT_ALIGN(pMem->cb, PAGE_SIZE));
1306 up_write(&current->mm->mmap_sem); /* check when we can leave this. */
1307 }
1308 pMem->pvR3 = NIL_RTR3PTR;
1309
1310 /*
1311 * Unmap the kernel mapping (if any).
1312 */
1313 if (pMem->pvR0)
1314 {
1315#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
1316 vunmap(pMem->pvR0);
1317#endif
1318 pMem->pvR0 = NULL;
1319 }
1320
1321 /*
1322 * Free the physical pages.
1323 */
1324 if (pMem->u.mem.papPages)
1325 {
1326 struct page **papPages = pMem->u.mem.papPages;
1327 const unsigned cPages = pMem->u.mem.cPages;
1328 unsigned iPage;
1329
1330 /* Restore the page flags. */
1331 for (iPage = 0; iPage < cPages; iPage++)
1332 {
1333 ClearPageReserved(papPages[iPage]);
1334#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 22)
1335 if (pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL))
1336 MY_CHANGE_PAGE_ATTR(papPages[iPage], 1, PAGE_KERNEL);
1337#endif
1338 }
1339
1340 /* Free the pages. */
1341#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 22)
1342 for (iPage = 0; iPage < pMem->u.cont.cPages; iPage++)
1343 __free_page(papPages[iPage]);
1344#else
1345 if (cPages > 0)
1346 __free_pages(papPages[0], VBoxSupDrvOrder(cPages));
1347#endif
1348 /* Free the page pointer array. */
1349 kfree(papPages);
1350 pMem->u.mem.papPages = NULL;
1351 }
1352 pMem->u.mem.cPages = 0;
1353}
1354
1355
1356/**
1357 * Maps a range of pages into user space.
1358 *
1359 * @returns Pointer to the user space mapping on success.
1360 * @returns NULL on failure.
1361 * @param papPages Array of the pages to map.
1362 * @param cPages Number of pages to map.
1363 * @param fProt The mapping protection.
1364 * @param pgFlags The page level protection.
1365 */
1366static RTR3PTR VBoxSupDrvMapUser(struct page **papPages, unsigned cPages, unsigned fProt, pgprot_t pgFlags)
1367{
1368 int rc = SUPDRV_ERR_NO_MEMORY;
1369 unsigned long ulAddr;
1370
1371 /*
1372 * Allocate user space mapping.
1373 */
1374 down_write(&current->mm->mmap_sem);
1375 ulAddr = do_mmap(NULL, 0, cPages * PAGE_SIZE, fProt, MAP_SHARED | MAP_ANONYMOUS, 0);
1376 if (!(ulAddr & ~PAGE_MASK))
1377 {
1378 /*
1379 * Map page by page into the mmap area.
1380 * This is generic, paranoid and not very efficient.
1381 */
1382 int rc = 0;
1383 unsigned long ulAddrCur = ulAddr;
1384 unsigned iPage;
1385 for (iPage = 0; iPage < cPages; iPage++, ulAddrCur += PAGE_SIZE)
1386 {
1387#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) || defined(HAVE_26_STYLE_REMAP_PAGE_RANGE)
1388 struct vm_area_struct *vma = find_vma(current->mm, ulAddrCur);
1389 if (!vma)
1390 break;
1391#endif
1392
1393#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 11)
1394 rc = remap_pfn_range(vma, ulAddrCur, page_to_pfn(papPages[iPage]), PAGE_SIZE, pgFlags);
1395#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) || defined(HAVE_26_STYLE_REMAP_PAGE_RANGE)
1396 rc = remap_page_range(vma, ulAddrCur, page_to_phys(papPages[iPage]), PAGE_SIZE, pgFlags);
1397#else /* 2.4 */
1398 rc = remap_page_range(ulAddrCur, page_to_phys(papPages[iPage]), PAGE_SIZE, pgFlags);
1399#endif
1400 if (rc)
1401 break;
1402 }
1403
1404 /*
1405 * Successful?
1406 */
1407 if (iPage >= cPages)
1408 {
1409 up_write(&current->mm->mmap_sem);
1410 return ulAddr;
1411 }
1412
1413 /* no, cleanup! */
1414 if (rc)
1415 dprintf(("VBoxSupDrvMapUser: remap_[page|pfn]_range failed! rc=%d\n", rc));
1416 else
1417 dprintf(("VBoxSupDrvMapUser: find_vma failed!\n"));
1418
1419 MY_DO_MUNMAP(current->mm, ulAddr, cPages << PAGE_SHIFT);
1420 }
1421 else
1422 {
1423 dprintf(("supdrvOSContAllocOne: do_mmap failed ulAddr=%#lx\n", ulAddr));
1424 rc = SUPDRV_ERR_NO_MEMORY;
1425 }
1426 up_write(&current->mm->mmap_sem);
1427
1428 return NIL_RTR3PTR;
1429}
1430
1431
1432/**
1433 * Initializes the GIP.
1434 *
1435 * @returns negative errno.
1436 * @param pDevExt Instance data. GIP stuff may be updated.
1437 */
1438static int VBoxSupDrvInitGip(PSUPDRVDEVEXT pDevExt)
1439{
1440 struct page *pPage;
1441 dma_addr_t HCPhys;
1442 PSUPGLOBALINFOPAGE pGip;
1443#ifdef CONFIG_SMP
1444 unsigned i;
1445#endif
1446 dprintf(("VBoxSupDrvInitGip:\n"));
1447
1448 /*
1449 * Allocate the page.
1450 */
1451 pPage = alloc_pages(GFP_USER, 0);
1452 if (!pPage)
1453 {
1454 dprintf(("VBoxSupDrvInitGip: failed to allocate the GIP page\n"));
1455 return -ENOMEM;
1456 }
1457
1458 /*
1459 * Lock the page.
1460 */
1461 SetPageReserved(pPage);
1462 g_pGipPage = pPage;
1463
1464 /*
1465 * Call common initialization routine.
1466 */
1467 HCPhys = page_to_phys(pPage);
1468 pGip = (PSUPGLOBALINFOPAGE)page_address(pPage);
1469 pDevExt->ulLastJiffies = jiffies;
1470#ifdef TICK_NSEC
1471 pDevExt->u64LastMonotime = (uint64_t)pDevExt->ulLastJiffies * TICK_NSEC;
1472 dprintf(("VBoxSupDrvInitGIP: TICK_NSEC=%ld HZ=%d jiffies=%ld now=%lld\n",
1473 TICK_NSEC, HZ, pDevExt->ulLastJiffies, pDevExt->u64LastMonotime));
1474#else
1475 pDevExt->u64LastMonotime = (uint64_t)pDevExt->ulLastJiffies * (1000000 / HZ);
1476 dprintf(("VBoxSupDrvInitGIP: TICK_NSEC=%d HZ=%d jiffies=%ld now=%lld\n",
1477 (int)(1000000 / HZ), HZ, pDevExt->ulLastJiffies, pDevExt->u64LastMonotime));
1478#endif
1479 supdrvGipInit(pDevExt, pGip, HCPhys, pDevExt->u64LastMonotime,
1480 HZ <= 1000 ? HZ : 1000);
1481
1482 /*
1483 * Initialize the timer.
1484 */
1485 init_timer(&g_GipTimer);
1486 g_GipTimer.data = (unsigned long)pDevExt;
1487 g_GipTimer.function = VBoxSupGipTimer;
1488 g_GipTimer.expires = jiffies;
1489#ifdef CONFIG_SMP
1490 for (i = 0; i < RT_ELEMENTS(pDevExt->aCPUs); i++)
1491 {
1492 pDevExt->aCPUs[i].u64LastMonotime = pDevExt->u64LastMonotime;
1493 pDevExt->aCPUs[i].ulLastJiffies = pDevExt->ulLastJiffies;
1494 pDevExt->aCPUs[i].iSmpProcessorId = -512;
1495 init_timer(&pDevExt->aCPUs[i].Timer);
1496 pDevExt->aCPUs[i].Timer.data = i;
1497 pDevExt->aCPUs[i].Timer.function = VBoxSupGipTimerPerCpu;
1498 pDevExt->aCPUs[i].Timer.expires = jiffies;
1499 }
1500#endif
1501
1502 return 0;
1503}
1504
1505
1506/**
1507 * Terminates the GIP.
1508 *
1509 * @returns negative errno.
1510 * @param pDevExt Instance data. GIP stuff may be updated.
1511 */
1512static int VBoxSupDrvTermGip(PSUPDRVDEVEXT pDevExt)
1513{
1514 struct page *pPage;
1515 PSUPGLOBALINFOPAGE pGip;
1516#ifdef CONFIG_SMP
1517 unsigned i;
1518#endif
1519 dprintf(("VBoxSupDrvTermGip:\n"));
1520
1521 /*
1522 * Delete the timer if it's pending.
1523 */
1524 if (timer_pending(&g_GipTimer))
1525 del_timer_sync(&g_GipTimer);
1526#ifdef CONFIG_SMP
1527 for (i = 0; i < RT_ELEMENTS(pDevExt->aCPUs); i++)
1528 if (timer_pending(&pDevExt->aCPUs[i].Timer))
1529 del_timer_sync(&pDevExt->aCPUs[i].Timer);
1530#endif
1531
1532 /*
1533 * Uninitialize the content.
1534 */
1535 pGip = pDevExt->pGip;
1536 pDevExt->pGip = NULL;
1537 if (pGip)
1538 supdrvGipTerm(pGip);
1539
1540 /*
1541 * Free the page.
1542 */
1543 pPage = g_pGipPage;
1544 g_pGipPage = NULL;
1545 if (pPage)
1546 {
1547 ClearPageReserved(pPage);
1548 __free_pages(pPage, 0);
1549 }
1550
1551 return 0;
1552}
1553
1554/**
1555 * Timer callback function.
1556 *
1557 * In ASYNC TSC mode this is called on the primary CPU, and we're
1558 * assuming that the CPU remains online.
1559 *
1560 * @param ulUser The device extension pointer.
1561 */
1562static void VBoxSupGipTimer(unsigned long ulUser)
1563{
1564 PSUPDRVDEVEXT pDevExt;
1565 PSUPGLOBALINFOPAGE pGip;
1566 unsigned long ulNow;
1567 unsigned long ulDiff;
1568 uint64_t u64Monotime;
1569 unsigned long SavedFlags;
1570
1571 local_irq_save(SavedFlags);
1572
1573 pDevExt = (PSUPDRVDEVEXT)ulUser;
1574 pGip = pDevExt->pGip;
1575 ulNow = jiffies;
1576
1577#ifdef CONFIG_SMP
1578 if (pGip && pGip->u32Mode == SUPGIPMODE_ASYNC_TSC)
1579 {
1580 uint8_t iCPU = ASMGetApicId();
1581 ulDiff = ulNow - pDevExt->aCPUs[iCPU].ulLastJiffies;
1582 pDevExt->aCPUs[iCPU].ulLastJiffies = ulNow;
1583#ifdef TICK_NSEC
1584 u64Monotime = pDevExt->aCPUs[iCPU].u64LastMonotime + ulDiff * TICK_NSEC;
1585#else
1586 u64Monotime = pDevExt->aCPUs[iCPU].u64LastMonotime + ulDiff * (1000000 / HZ);
1587#endif
1588 pDevExt->aCPUs[iCPU].u64LastMonotime = u64Monotime;
1589 }
1590 else
1591#endif /* CONFIG_SMP */
1592 {
1593 ulDiff = ulNow - pDevExt->ulLastJiffies;
1594 pDevExt->ulLastJiffies = ulNow;
1595#ifdef TICK_NSEC
1596 u64Monotime = pDevExt->u64LastMonotime + ulDiff * TICK_NSEC;
1597#else
1598 u64Monotime = pDevExt->u64LastMonotime + ulDiff * (1000000 / HZ);
1599#endif
1600 pDevExt->u64LastMonotime = u64Monotime;
1601 }
1602 if (RT_LIKELY(pGip))
1603 supdrvGipUpdate(pDevExt->pGip, u64Monotime);
1604 if (RT_LIKELY(!pDevExt->fGIPSuspended))
1605 mod_timer(&g_GipTimer, ulNow + (HZ <= 1000 ? 0 : ONE_MSEC_IN_JIFFIES));
1606
1607 local_irq_restore(SavedFlags);
1608}
1609
1610
1611#ifdef CONFIG_SMP
1612/**
1613 * Timer callback function for the other CPUs.
1614 *
1615 * @param iTimerCPU The APIC ID of this timer.
1616 */
1617static void VBoxSupGipTimerPerCpu(unsigned long iTimerCPU)
1618{
1619 PSUPDRVDEVEXT pDevExt;
1620 PSUPGLOBALINFOPAGE pGip;
1621 uint8_t iCPU;
1622 uint64_t u64Monotime;
1623 unsigned long SavedFlags;
1624
1625 local_irq_save(SavedFlags);
1626
1627 pDevExt = &g_DevExt;
1628 pGip = pDevExt->pGip;
1629 iCPU = ASMGetApicId();
1630
1631 if (RT_LIKELY(iCPU < RT_ELEMENTS(pGip->aCPUs)))
1632 {
1633 if (RT_LIKELY(iTimerCPU == iCPU))
1634 {
1635 unsigned long ulNow = jiffies;
1636 unsigned long ulDiff = ulNow - pDevExt->aCPUs[iCPU].ulLastJiffies;
1637 pDevExt->aCPUs[iCPU].ulLastJiffies = ulNow;
1638#ifdef TICK_NSEC
1639 u64Monotime = pDevExt->aCPUs[iCPU].u64LastMonotime + ulDiff * TICK_NSEC;
1640#else
1641 u64Monotime = pDevExt->aCPUs[iCPU].u64LastMonotime + ulDiff * (1000000 / HZ);
1642#endif
1643 pDevExt->aCPUs[iCPU].u64LastMonotime = u64Monotime;
1644 if (RT_LIKELY(pGip))
1645 supdrvGipUpdatePerCpu(pGip, u64Monotime, iCPU);
1646 if (RT_LIKELY(!pDevExt->fGIPSuspended))
1647 mod_timer(&pDevExt->aCPUs[iCPU].Timer, ulNow + (HZ <= 1000 ? 0 : ONE_MSEC_IN_JIFFIES));
1648 }
1649 else
1650 printk("vboxdrv: error: GIP CPU update timer executing on the wrong CPU: apicid=%d != timer-apicid=%ld (cpuid=%d !=? timer-cpuid=%d)\n",
1651 iCPU, iTimerCPU, smp_processor_id(), pDevExt->aCPUs[iTimerCPU].iSmpProcessorId);
1652 }
1653 else
1654 printk("vboxdrv: error: APIC ID is bogus (GIP CPU update): apicid=%d max=%lu cpuid=%d\n",
1655 iCPU, (unsigned long)RT_ELEMENTS(pGip->aCPUs), smp_processor_id());
1656
1657 local_irq_restore(SavedFlags);
1658}
1659#endif /* CONFIG_SMP */
1660
1661
1662/**
1663 * Maps the GIP into user space.
1664 *
1665 * @returns negative errno.
1666 * @param pDevExt Instance data.
1667 */
1668int VBOXCALL supdrvOSGipMap(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE *ppGip)
1669{
1670 int rc = 0;
1671 unsigned long ulAddr;
1672 unsigned long HCPhys = pDevExt->HCPhysGip;
1673 pgprot_t pgFlags;
1674 pgprot_val(pgFlags) = _PAGE_PRESENT | _PAGE_USER;
1675 dprintf2(("supdrvOSGipMap: ppGip=%p\n", ppGip));
1676
1677 /*
1678 * Allocate user space mapping and put the physical pages into it.
1679 */
1680 down_write(&current->mm->mmap_sem);
1681 ulAddr = do_mmap(NULL, 0, PAGE_SIZE, PROT_READ, MAP_SHARED | MAP_ANONYMOUS, 0);
1682 if (!(ulAddr & ~PAGE_MASK))
1683 {
1684#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(HAVE_26_STYLE_REMAP_PAGE_RANGE)
1685 int rc2 = remap_page_range(ulAddr, HCPhys, PAGE_SIZE, pgFlags);
1686#else
1687 int rc2 = 0;
1688 struct vm_area_struct *vma = find_vma(current->mm, ulAddr);
1689 if (vma)
1690#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
1691 rc2 = remap_page_range(vma, ulAddr, HCPhys, PAGE_SIZE, pgFlags);
1692#else
1693 rc2 = remap_pfn_range(vma, ulAddr, HCPhys >> PAGE_SHIFT, PAGE_SIZE, pgFlags);
1694#endif
1695 else
1696 {
1697 rc = SUPDRV_ERR_NO_MEMORY;
1698 dprintf(("supdrvOSGipMap: no vma found for ulAddr=%#lx!\n", ulAddr));
1699 }
1700#endif
1701 if (rc2)
1702 {
1703 rc = SUPDRV_ERR_NO_MEMORY;
1704 dprintf(("supdrvOSGipMap: remap_page_range failed rc2=%d\n", rc2));
1705 }
1706 }
1707 else
1708 {
1709 dprintf(("supdrvOSGipMap: do_mmap failed ulAddr=%#lx\n", ulAddr));
1710 rc = SUPDRV_ERR_NO_MEMORY;
1711 }
1712 up_write(&current->mm->mmap_sem); /* not quite sure when to give this up. */
1713
1714 /*
1715 * Success?
1716 */
1717 if (!rc)
1718 {
1719 *ppGip = (PSUPGLOBALINFOPAGE)ulAddr;
1720 dprintf2(("supdrvOSGipMap: ppGip=%p\n", *ppGip));
1721 return 0;
1722 }
1723
1724 /*
1725 * Failure, cleanup and be gone.
1726 */
1727 if (ulAddr & ~PAGE_MASK)
1728 {
1729 down_write(&current->mm->mmap_sem);
1730 MY_DO_MUNMAP(current->mm, ulAddr, PAGE_SIZE);
1731 up_write(&current->mm->mmap_sem);
1732 }
1733
1734 dprintf2(("supdrvOSGipMap: returns %d\n", rc));
1735 return rc;
1736}
1737
1738
1739/**
1740 * Maps the GIP into user space.
1741 *
1742 * @returns negative errno.
1743 * @param pDevExt Instance data.
1744 */
1745int VBOXCALL supdrvOSGipUnmap(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip)
1746{
1747 dprintf2(("supdrvOSGipUnmap: pGip=%p\n", pGip));
1748 if (current->mm)
1749 {
1750 down_write(&current->mm->mmap_sem);
1751 MY_DO_MUNMAP(current->mm, (unsigned long)pGip, PAGE_SIZE);
1752 up_write(&current->mm->mmap_sem);
1753 }
1754 dprintf2(("supdrvOSGipUnmap: returns 0\n"));
1755 return 0;
1756}
1757
1758
1759/**
1760 * Resumes the GIP updating.
1761 *
1762 * @param pDevExt Instance data.
1763 */
1764void VBOXCALL supdrvOSGipResume(PSUPDRVDEVEXT pDevExt)
1765{
1766 dprintf2(("supdrvOSGipResume:\n"));
1767 ASMAtomicXchgU8(&pDevExt->fGIPSuspended, false);
1768#ifdef CONFIG_SMP
1769 if (pDevExt->pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
1770#endif
1771 mod_timer(&g_GipTimer, jiffies);
1772#ifdef CONFIG_SMP
1773 else
1774 {
1775 mod_timer(&g_GipTimer, jiffies);
1776 smp_call_function(VBoxSupGipResumePerCpu, pDevExt, 0 /* retry */, 1 /* wait */);
1777 }
1778#endif
1779}
1780
1781
1782#ifdef CONFIG_SMP
1783/**
1784 * Callback for resuming GIP updating on the other CPUs.
1785 *
1786 * This is only used when the GIP is in async tsc mode.
1787 *
1788 * @param pvUser Pointer to the device instance.
1789 */
1790static void VBoxSupGipResumePerCpu(void *pvUser)
1791{
1792 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
1793 uint8_t iCPU = ASMGetApicId();
1794
1795 if (RT_UNLIKELY(iCPU >= RT_ELEMENTS(pDevExt->pGip->aCPUs)))
1796 {
1797 printk("vboxdrv: error: apicid=%d max=%lu cpuid=%d\n",
1798 iCPU, (unsigned long)RT_ELEMENTS(pDevExt->pGip->aCPUs), smp_processor_id());
1799 return;
1800 }
1801
1802 pDevExt->aCPUs[iCPU].iSmpProcessorId = smp_processor_id();
1803 mod_timer(&pDevExt->aCPUs[iCPU].Timer, jiffies);
1804}
1805#endif /* CONFIG_SMP */
1806
1807
1808/**
1809 * Suspends the GIP updating.
1810 *
1811 * @param pDevExt Instance data.
1812 */
1813void VBOXCALL supdrvOSGipSuspend(PSUPDRVDEVEXT pDevExt)
1814{
1815#ifdef CONFIG_SMP
1816 unsigned i;
1817#endif
1818 dprintf2(("supdrvOSGipSuspend:\n"));
1819 ASMAtomicXchgU8(&pDevExt->fGIPSuspended, true);
1820
1821 if (timer_pending(&g_GipTimer))
1822 del_timer_sync(&g_GipTimer);
1823#ifdef CONFIG_SMP
1824 for (i = 0; i < RT_ELEMENTS(pDevExt->aCPUs); i++)
1825 if (timer_pending(&pDevExt->aCPUs[i].Timer))
1826 del_timer_sync(&pDevExt->aCPUs[i].Timer);
1827#endif
1828}
1829
1830
1831/**
1832 * Get the current CPU count.
1833 * @returns Number of cpus.
1834 */
1835unsigned VBOXCALL supdrvOSGetCPUCount(void)
1836{
1837#ifdef CONFIG_SMP
1838# ifdef num_present_cpus
1839 return num_present_cpus();
1840# else
1841 return smp_num_cpus;
1842# endif
1843#else
1844 return 1;
1845#endif
1846}
1847
1848/**
1849 * Force async tsc mode.
1850 * @todo add a module argument for this.
1851 */
1852bool VBOXCALL supdrvOSGetForcedAsyncTscMode(void)
1853{
1854 return false;
1855}
1856
1857
1858/**
1859 * Converts a supdrv error code to an linux error code.
1860 *
1861 * @returns corresponding linux error code.
1862 * @param rc supdrv error code (SUPDRV_ERR_* defines).
1863 */
1864static int VBoxSupDrvErr2LinuxErr(int rc)
1865{
1866 switch (rc)
1867 {
1868 case 0: return 0;
1869 case SUPDRV_ERR_GENERAL_FAILURE: return -EACCES;
1870 case SUPDRV_ERR_INVALID_PARAM: return -EINVAL;
1871 case SUPDRV_ERR_INVALID_MAGIC: return -EILSEQ;
1872 case SUPDRV_ERR_INVALID_HANDLE: return -ENXIO;
1873 case SUPDRV_ERR_INVALID_POINTER: return -EFAULT;
1874 case SUPDRV_ERR_LOCK_FAILED: return -ENOLCK;
1875 case SUPDRV_ERR_ALREADY_LOADED: return -EEXIST;
1876 case SUPDRV_ERR_PERMISSION_DENIED: return -EPERM;
1877 case SUPDRV_ERR_VERSION_MISMATCH: return -ENOSYS;
1878 case SUPDRV_ERR_IDT_FAILED: return -1000;
1879 }
1880
1881 return -EPERM;
1882}
1883
1884
1885RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
1886{
1887#if 1
1888 va_list args;
1889 char szMsg[512];
1890
1891 va_start(args, pszFormat);
1892 vsnprintf(szMsg, sizeof(szMsg) - 1, pszFormat, args);
1893 szMsg[sizeof(szMsg) - 1] = '\0';
1894 printk("%s", szMsg);
1895 va_end(args);
1896#else
1897 /* forward to printf - needs some more GCC hacking to fix ebp... */
1898 __asm__ __volatile__ ("mov %0, %esp\n\t"
1899 "jmp %1\n\t",
1900 :: "r" ((uintptr_t)&pszFormat - 4),
1901 "m" (printk));
1902#endif
1903 return 0;
1904}
1905
1906
1907/** Runtime assert implementation for Linux Ring-0. */
1908RTDECL(void) AssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
1909{
1910 printk("!!Assertion Failed!!\n"
1911 "Expression: %s\n"
1912 "Location : %s(%d) %s\n",
1913 pszExpr, pszFile, uLine, pszFunction);
1914}
1915
1916
1917/** Runtime assert implementation for Linux Ring-0. */
1918RTDECL(void) AssertMsg2(const char *pszFormat, ...)
1919{ /* forwarder. */
1920 va_list ap;
1921 char msg[256];
1922
1923 va_start(ap, pszFormat);
1924 vsnprintf(msg, sizeof(msg) - 1, pszFormat, ap);
1925 msg[sizeof(msg) - 1] = '\0';
1926 printk("%s", msg);
1927 va_end(ap);
1928}
1929
1930
1931/* GCC C++ hack. */
1932unsigned __gxx_personality_v0 = 0xcccccccc;
1933
1934
1935module_init(VBoxSupDrvInit);
1936module_exit(VBoxSupDrvUnload);
1937
1938MODULE_AUTHOR("innotek GmbH");
1939MODULE_DESCRIPTION("VirtualBox Support Driver");
1940MODULE_LICENSE("GPL");
1941#ifdef MODULE_VERSION
1942#define xstr(s) str(s)
1943#define str(s) #s
1944MODULE_VERSION(VBOX_VERSION_STRING " (" xstr(SUPDRVIOC_VERSION) ")");
1945#endif
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