VirtualBox

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

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

RT_OS_* and RT_ARCH_* for Runtime/ and Support/

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