VirtualBox

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

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

attempt to disable the local APIC on x86_64 systems

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