VirtualBox

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

Last change on this file since 9621 was 9621, checked in by vboxsync, 17 years ago

The TSC checks are now fully done in the generic code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.9 KB
Line 
1/* $Rev: 9621 $ */
2/** @file
3 * The VirtualBox Support Driver - Linux hosts.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 * Some lines of code to disable the local APIC on x86_64 machines taken
30 * from a Mandriva patch by Gwenole Beauchesne <[email protected]>.
31 */
32
33/*******************************************************************************
34* Header Files *
35*******************************************************************************/
36#include "SUPDRV.h"
37#include "the-linux-kernel.h"
38#include "version-generated.h"
39
40#include <iprt/assert.h>
41#include <iprt/spinlock.h>
42#include <iprt/semaphore.h>
43#include <iprt/initterm.h>
44#include <iprt/process.h>
45#include <iprt/err.h>
46#include <iprt/mem.h>
47#include <iprt/log.h>
48#include <iprt/mp.h>
49
50#include <linux/sched.h>
51#ifdef CONFIG_DEVFS_FS
52# include <linux/devfs_fs_kernel.h>
53#endif
54#ifdef CONFIG_VBOXDRV_AS_MISC
55# include <linux/miscdevice.h>
56#endif
57#ifdef CONFIG_X86_LOCAL_APIC
58# include <asm/apic.h>
59# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
60# include <asm/nmi.h>
61# endif
62#endif
63
64#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
65# include <asm/pgtable.h>
66# define global_flush_tlb __flush_tlb_global
67#endif
68
69#include <iprt/mem.h>
70
71
72/* devfs defines */
73#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
74# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
75
76# define VBOX_REGISTER_DEVFS() \
77({ \
78 void *rc = NULL; \
79 if (devfs_mk_cdev(MKDEV(DEVICE_MAJOR, 0), \
80 S_IFCHR | S_IRUGO | S_IWUGO, \
81 DEVICE_NAME) == 0) \
82 rc = (void *)' '; /* return not NULL */ \
83 rc; \
84 })
85
86# define VBOX_UNREGISTER_DEVFS(handle) \
87 devfs_remove(DEVICE_NAME);
88
89# else /* < 2.6.0 */
90
91# define VBOX_REGISTER_DEVFS() \
92 devfs_register(NULL, DEVICE_NAME, DEVFS_FL_DEFAULT, \
93 DEVICE_MAJOR, 0, \
94 S_IFCHR | S_IRUGO | S_IWUGO, \
95 &gFileOpsVBoxDrv, NULL)
96
97# define VBOX_UNREGISTER_DEVFS(handle) \
98 if (handle != NULL) \
99 devfs_unregister(handle)
100
101# endif /* < 2.6.0 */
102#endif /* CONFIG_DEV_FS && !CONFIG_VBOXDEV_AS_MISC */
103
104#ifndef CONFIG_VBOXDRV_AS_MISC
105# if defined(CONFIG_DEVFS_FS) && LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 0)
106# define VBOX_REGISTER_DEVICE(a,b,c) devfs_register_chrdev(a,b,c)
107# define VBOX_UNREGISTER_DEVICE(a,b) devfs_unregister_chrdev(a,b)
108# else
109# define VBOX_REGISTER_DEVICE(a,b,c) register_chrdev(a,b,c)
110# define VBOX_UNREGISTER_DEVICE(a,b) unregister_chrdev(a,b)
111# endif
112#endif /* !CONFIG_VBOXDRV_AS_MISC */
113
114
115#ifdef CONFIG_X86_HIGH_ENTRY
116# error "CONFIG_X86_HIGH_ENTRY is not supported by VBoxDrv at this time."
117#endif
118
119/*
120 * This sucks soooo badly on x86! Why don't they export __PAGE_KERNEL_EXEC so PAGE_KERNEL_EXEC would be usable?
121 */
122#if defined(RT_ARCH_AMD64)
123# define MY_PAGE_KERNEL_EXEC PAGE_KERNEL_EXEC
124#elif defined(PAGE_KERNEL_EXEC) && defined(CONFIG_X86_PAE)
125# define MY_PAGE_KERNEL_EXEC __pgprot(cpu_has_pge ? _PAGE_KERNEL_EXEC | _PAGE_GLOBAL : _PAGE_KERNEL_EXEC)
126#else
127# define MY_PAGE_KERNEL_EXEC PAGE_KERNEL
128#endif
129
130/*
131 * The redhat hack section.
132 * - The current hacks are for 2.4.21-15.EL only.
133 */
134#ifndef NO_REDHAT_HACKS
135/* accounting. */
136# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
137# ifdef VM_ACCOUNT
138# define MY_DO_MUNMAP(a,b,c) do_munmap(a, b, c, 0) /* should it be 1 or 0? */
139# endif
140# endif
141
142/* backported remap_page_range. */
143# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
144# include <asm/tlb.h>
145# ifdef tlb_vma /* probably not good enough... */
146# define HAVE_26_STYLE_REMAP_PAGE_RANGE 1
147# endif
148# endif
149
150#endif /* !NO_REDHAT_HACKS */
151
152
153#ifndef MY_DO_MUNMAP
154# define MY_DO_MUNMAP(a,b,c) do_munmap(a, b, c)
155#endif
156
157
158#ifdef CONFIG_X86_LOCAL_APIC
159
160/* If an NMI occurs while we are inside the world switcher the machine will
161 * crash. The Linux NMI watchdog generates periodic NMIs increasing a counter
162 * which is compared with another counter increased in the timer interrupt
163 * handler. We disable the NMI watchdog.
164 *
165 * - Linux >= 2.6.21: The watchdog is disabled by default on i386 and x86_64.
166 * - Linux < 2.6.21: The watchdog is normally enabled by default on x86_64
167 * and disabled on i386.
168 */
169# if defined(RT_ARCH_AMD64)
170# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 21) && !defined(VBOX_REDHAT_KABI)
171# define DO_DISABLE_NMI 1
172# endif
173# endif
174
175# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
176extern int nmi_active;
177# define nmi_atomic_read(P) *(P)
178# define nmi_atomic_set(P, V) *(P) = (V)
179# define nmi_atomic_dec(P) nmi_atomic_set(P, 0)
180# else
181# define nmi_atomic_read(P) atomic_read(P)
182# define nmi_atomic_set(P, V) atomic_set(P, V)
183# define nmi_atomic_dec(P) atomic_dec(P)
184# endif
185
186# ifndef X86_FEATURE_ARCH_PERFMON
187# define X86_FEATURE_ARCH_PERFMON (3*32+9) /* Intel Architectural PerfMon */
188# endif
189# ifndef MSR_ARCH_PERFMON_EVENTSEL0
190# define MSR_ARCH_PERFMON_EVENTSEL0 0x186
191# endif
192# ifndef ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT
193# define ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT (1 << 0)
194# endif
195
196#endif /* CONFIG_X86_LOCAL_APIC */
197
198#define xstr(s) str(s)
199#define str(s) #s
200
201
202/*******************************************************************************
203* Structures and Typedefs *
204*******************************************************************************/
205#ifndef USE_NEW_OS_INTERFACE_FOR_GIP
206# ifdef VBOX_HRTIMER
207typedef enum hrtimer_restart (*PFNVBOXKTIMER)(struct hrtimer *);
208# else
209typedef void (*PFNVBOXKTIMER)(unsigned long);
210# endif
211#endif
212
213
214/*******************************************************************************
215* Global Variables *
216*******************************************************************************/
217/**
218 * Device extention & session data association structure.
219 */
220static SUPDRVDEVEXT g_DevExt;
221
222#ifndef USE_NEW_OS_INTERFACE_FOR_GIP
223/** Timer structure for the GIP update. */
224static VBOXKTIMER g_GipTimer;
225/** Pointer to the page structure for the GIP. */
226struct page *g_pGipPage;
227#endif /* !USE_NEW_OS_INTERFACE_FOR_GIP */
228
229/** Registered devfs device handle. */
230#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
231# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
232static void *g_hDevFsVBoxDrv = NULL;
233# else
234static devfs_handle_t g_hDevFsVBoxDrv = NULL;
235# endif
236#endif
237
238#ifndef CONFIG_VBOXDRV_AS_MISC
239/** Module major number */
240#define DEVICE_MAJOR 234
241/** Saved major device number */
242static int g_iModuleMajor;
243#endif /* !CONFIG_VBOXDRV_AS_MISC */
244
245/** Module parameter.
246 * Not prefixed because the name is used by macros and the end of this file. */
247static int force_async_tsc = 0;
248
249/** The module name. */
250#define DEVICE_NAME "vboxdrv"
251
252#ifdef RT_ARCH_AMD64
253/**
254 * Memory for the executable memory heap (in IPRT).
255 */
256extern uint8_t g_abExecMemory[1572864]; /* 1.5 MB */
257__asm__(".section execmemory, \"awx\", @progbits\n\t"
258 ".align 32\n\t"
259 ".globl g_abExecMemory\n"
260 "g_abExecMemory:\n\t"
261 ".zero 1572864\n\t"
262 ".type g_abExecMemory, @object\n\t"
263 ".size g_abExecMemory, 1572864\n\t"
264 ".text\n\t");
265#endif
266
267
268/*******************************************************************************
269* Internal Functions *
270*******************************************************************************/
271static int VBoxDrvLinuxInit(void);
272static void VBoxDrvLinuxUnload(void);
273static int VBoxDrvLinuxCreate(struct inode *pInode, struct file *pFilp);
274static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp);
275#ifdef HAVE_UNLOCKED_IOCTL
276static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
277#else
278static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
279#endif
280static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg);
281#ifndef USE_NEW_OS_INTERFACE_FOR_GIP
282static int VBoxDrvLinuxInitGip(PSUPDRVDEVEXT pDevExt);
283static int VBoxDrvLinuxTermGip(PSUPDRVDEVEXT pDevExt);
284# ifdef VBOX_HRTIMER
285static enum hrtimer_restart VBoxDrvLinuxGipTimer(struct hrtimer *pTimer);
286# else
287static void VBoxDrvLinuxGipTimer(unsigned long ulUser);
288# endif
289# ifdef CONFIG_SMP
290# ifdef VBOX_HRTIMER
291static enum hrtimer_restart VBoxDrvLinuxGipTimerPerCpu(struct hrtimer *pTimer);
292# else
293static void VBoxDrvLinuxGipTimerPerCpu(unsigned long ulUser);
294# endif
295static void VBoxDrvLinuxGipResumePerCpu(void *pvUser);
296# endif /* CONFIG_SMP */
297#endif /* !USE_NEW_OS_INTERFACE_FOR_GIP */
298static int VBoxDrvLinuxErr2LinuxErr(int);
299
300
301/** The file_operations structure. */
302static struct file_operations gFileOpsVBoxDrv =
303{
304 owner: THIS_MODULE,
305 open: VBoxDrvLinuxCreate,
306 release: VBoxDrvLinuxClose,
307#ifdef HAVE_UNLOCKED_IOCTL
308 unlocked_ioctl: VBoxDrvLinuxIOCtl,
309#else
310 ioctl: VBoxDrvLinuxIOCtl,
311#endif
312};
313
314#ifdef CONFIG_VBOXDRV_AS_MISC
315/** The miscdevice structure. */
316static struct miscdevice gMiscDevice =
317{
318 minor: MISC_DYNAMIC_MINOR,
319 name: DEVICE_NAME,
320 fops: &gFileOpsVBoxDrv,
321# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && \
322 LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17)
323 devfs_name: DEVICE_NAME,
324# endif
325};
326#endif
327
328
329#ifndef USE_NEW_OS_INTERFACE_FOR_GIP
330
331static inline void vbox_ktimer_init(PVBOXKTIMER pTimer, PFNVBOXKTIMER pfnFunction, unsigned long ulData)
332{
333#ifdef VBOX_HRTIMER
334 hrtimer_init(pTimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
335 pTimer->function = pfnFunction;
336#else
337 init_timer(pTimer);
338 pTimer->data = ulData;
339 pTimer->function = pfnFunction;
340 pTimer->expires = jiffies;
341#endif
342}
343
344static inline void vbox_ktimer_start(PVBOXKTIMER pTimer)
345{
346#ifdef VBOX_HRTIMER
347 hrtimer_start(pTimer, ktime_add_ns(ktime_get(), 1000000), HRTIMER_MODE_ABS);
348#else
349 mod_timer(pTimer, jiffies);
350#endif
351}
352
353static inline void vbox_ktimer_stop(PVBOXKTIMER pTimer)
354{
355#ifdef VBOX_HRTIMER
356 hrtimer_cancel(pTimer);
357#else
358 if (timer_pending(pTimer))
359 del_timer_sync(pTimer);
360#endif
361}
362
363#endif /* !USE_NEW_OS_INTERFACE_FOR_GIP */
364
365
366#ifdef CONFIG_X86_LOCAL_APIC
367# ifdef DO_DISABLE_NMI
368
369/** Stop AMD NMI watchdog (x86_64 only). */
370static int stop_k7_watchdog(void)
371{
372 wrmsr(MSR_K7_EVNTSEL0, 0, 0);
373 return 1;
374}
375
376/** Stop Intel P4 NMI watchdog (x86_64 only). */
377static int stop_p4_watchdog(void)
378{
379 wrmsr(MSR_P4_IQ_CCCR0, 0, 0);
380 wrmsr(MSR_P4_IQ_CCCR1, 0, 0);
381 wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
382 return 1;
383}
384
385/** The new method of detecting the event counter */
386static int stop_intel_arch_watchdog(void)
387{
388 unsigned ebx;
389
390 ebx = cpuid_ebx(10);
391 if (!(ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT))
392 wrmsr(MSR_ARCH_PERFMON_EVENTSEL0, 0, 0);
393 return 1;
394}
395
396/** Stop NMI watchdog. */
397static void vbox_stop_apic_nmi_watchdog(void *unused)
398{
399 int stopped = 0;
400
401 /* only support LOCAL and IO APICs for now */
402 if ((nmi_watchdog != NMI_LOCAL_APIC) &&
403 (nmi_watchdog != NMI_IO_APIC))
404 return;
405
406 if (nmi_watchdog == NMI_LOCAL_APIC)
407 {
408 switch (boot_cpu_data.x86_vendor)
409 {
410 case X86_VENDOR_AMD:
411 if (strstr(boot_cpu_data.x86_model_id, "Screwdriver"))
412 return;
413 stopped = stop_k7_watchdog();
414 break;
415 case X86_VENDOR_INTEL:
416 if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON))
417 {
418 stopped = stop_intel_arch_watchdog();
419 break;
420 }
421 stopped = stop_p4_watchdog();
422 break;
423 default:
424 return;
425 }
426 }
427
428 if (stopped)
429 nmi_atomic_dec(&nmi_active);
430}
431
432/** Disable LAPIC NMI watchdog. */
433static void disable_lapic_nmi_watchdog(void)
434{
435 BUG_ON(nmi_watchdog != NMI_LOCAL_APIC);
436
437 if (nmi_atomic_read(&nmi_active) <= 0)
438 return;
439
440 on_each_cpu(vbox_stop_apic_nmi_watchdog, NULL, 1, 1);
441
442 BUG_ON(nmi_atomic_read(&nmi_active) != 0);
443
444 /* tell do_nmi() and others that we're not active any more */
445 nmi_watchdog = NMI_NONE;
446}
447
448/** Shutdown NMI. */
449static void nmi_cpu_shutdown(void * dummy)
450{
451 unsigned int vERR, vPC;
452
453 vPC = apic_read(APIC_LVTPC);
454
455 if ((GET_APIC_DELIVERY_MODE(vPC) == APIC_MODE_NMI) && !(vPC & APIC_LVT_MASKED))
456 {
457 vERR = apic_read(APIC_LVTERR);
458 apic_write(APIC_LVTERR, vERR | APIC_LVT_MASKED);
459 apic_write(APIC_LVTPC, vPC | APIC_LVT_MASKED);
460 apic_write(APIC_LVTERR, vERR);
461 }
462}
463
464static void nmi_shutdown(void)
465{
466 on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1);
467}
468# endif /* DO_DISABLE_NMI */
469#endif /* CONFIG_X86_LOCAL_APIC */
470
471
472/**
473 * Initialize module.
474 *
475 * @returns appropriate status code.
476 */
477static int __init VBoxDrvLinuxInit(void)
478{
479 int rc;
480
481 dprintf(("VBoxDrv::ModuleInit\n"));
482
483#ifdef CONFIG_X86_LOCAL_APIC
484 /*
485 * If an NMI occurs while we are inside the world switcher the macine will crash.
486 * The Linux NMI watchdog generates periodic NMIs increasing a counter which is
487 * compared with another counter increased in the timer interrupt handler. Therefore
488 * we don't allow to setup an NMI watchdog.
489 */
490# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && !defined(VBOX_REDHAT_KABI)
491 /*
492 * First test: NMI actiated? Works only works with Linux 2.6 -- 2.4 does not export
493 * the nmi_watchdog variable.
494 */
495# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) || \
496 (defined CONFIG_X86_64 && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
497# ifdef DO_DISABLE_NMI
498 if (nmi_atomic_read(&nmi_active) > 0)
499 {
500 printk(KERN_DEBUG DEVICE_NAME ": Trying to deactivate the NMI watchdog...\n");
501
502 switch (nmi_watchdog)
503 {
504 case NMI_LOCAL_APIC:
505 disable_lapic_nmi_watchdog();
506 break;
507 case NMI_NONE:
508 nmi_atomic_dec(&nmi_active);
509 break;
510 }
511
512 if (nmi_atomic_read(&nmi_active) == 0)
513 {
514 nmi_shutdown();
515 printk(KERN_DEBUG DEVICE_NAME ": Successfully done.\n");
516 }
517 else
518 printk(KERN_DEBUG DEVICE_NAME ": Failed!\n");
519 }
520# endif /* DO_DISABLE_NMI */
521
522 /*
523 * Permanent IO_APIC mode active? No way to handle this!
524 */
525 if (nmi_watchdog == NMI_IO_APIC)
526 {
527 printk(KERN_ERR DEVICE_NAME
528 ": NMI watchdog in IO_APIC mode active -- refused to load the kernel module!\n"
529 DEVICE_NAME
530 ": Please disable the NMI watchdog by specifying 'nmi_watchdog=0' at kernel\n"
531 DEVICE_NAME
532 ": command line.\n");
533 return -EINVAL;
534 }
535
536 /*
537 * See arch/i386/kernel/nmi.c on >= 2.6.19: -1 means it can never enabled again
538 */
539 nmi_atomic_set(&nmi_active, -1);
540 printk(KERN_DEBUG DEVICE_NAME ": Trying to deactivate the NMI watchdog permanently...\n");
541
542 /*
543 * Now fall through and see if it actually was enabled before. If so, fail
544 * as we cannot deactivate it cleanly from here.
545 */
546# else /* < 2.6.19 */
547 /*
548 * Older 2.6 kernels: nmi_watchdog is not initalized by default
549 */
550 if (nmi_watchdog != NMI_NONE)
551 goto nmi_activated;
552# endif
553# endif /* >= 2.6.0 && !defined(VBOX_REDHAT_KABI) */
554
555 /*
556 * Second test: Interrupt generated by performance counter not masked and can
557 * generate an NMI. Works also with Linux 2.4.
558 */
559 {
560 unsigned int v, ver, maxlvt;
561
562 v = apic_read(APIC_LVR);
563 ver = GET_APIC_VERSION(v);
564 /* 82489DXs do not report # of LVT entries. */
565 maxlvt = APIC_INTEGRATED(ver) ? GET_APIC_MAXLVT(v) : 2;
566 if (maxlvt >= 4)
567 {
568 /* Read status of performance counter IRQ vector */
569 v = apic_read(APIC_LVTPC);
570
571 /* performance counter generates NMI and is not masked? */
572 if ((GET_APIC_DELIVERY_MODE(v) == APIC_MODE_NMI) && !(v & APIC_LVT_MASKED))
573 {
574# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) || \
575 (defined CONFIG_X86_64 && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0))
576 printk(KERN_ERR DEVICE_NAME
577 ": NMI watchdog either active or at least initialized. Please disable the NMI\n"
578 DEVICE_NAME
579 ": watchdog by specifying 'nmi_watchdog=0' at kernel command line.\n");
580 return -EINVAL;
581# else /* < 2.6.19 */
582# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && !defined(VBOX_REDHAT_KABI)
583nmi_activated:
584# endif
585 printk(KERN_ERR DEVICE_NAME
586 ": NMI watchdog active -- refused to load the kernel module! Please disable\n"
587 DEVICE_NAME
588 ": the NMI watchdog by specifying 'nmi_watchdog=0' at kernel command line.\n");
589 return -EINVAL;
590# endif /* >= 2.6.19 */
591 }
592 }
593 }
594# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19)
595 printk(KERN_DEBUG DEVICE_NAME ": Successfully done.\n");
596# endif /* >= 2.6.19 */
597#endif /* CONFIG_X86_LOCAL_APIC */
598
599 /*
600 * Check for synchronous/asynchronous TSC mode.
601 */
602 printk(KERN_DEBUG DEVICE_NAME ": Found %u processor cores.\n", (unsigned)RTMpGetOnlineCount());
603#ifdef CONFIG_VBOXDRV_AS_MISC
604 rc = misc_register(&gMiscDevice);
605 if (rc)
606 {
607 printk(KERN_ERR DEVICE_NAME ": Can't register misc device! rc=%d\n", rc);
608 return rc;
609 }
610#else /* !CONFIG_VBOXDRV_AS_MISC */
611 /*
612 * Register character device.
613 */
614 g_iModuleMajor = DEVICE_MAJOR;
615 rc = VBOX_REGISTER_DEVICE((dev_t)g_iModuleMajor, DEVICE_NAME, &gFileOpsVBoxDrv);
616 if (rc < 0)
617 {
618 dprintf(("VBOX_REGISTER_DEVICE failed with rc=%#x!\n", rc));
619 return rc;
620 }
621
622 /*
623 * Save returned module major number
624 */
625 if (DEVICE_MAJOR != 0)
626 g_iModuleMajor = DEVICE_MAJOR;
627 else
628 g_iModuleMajor = rc;
629 rc = 0;
630
631#ifdef CONFIG_DEVFS_FS
632 /*
633 * Register a device entry
634 */
635 g_hDevFsVBoxDrv = VBOX_REGISTER_DEVFS();
636 if (g_hDevFsVBoxDrv == NULL)
637 {
638 dprintf(("devfs_register failed!\n"));
639 rc = -EINVAL;
640 }
641#endif
642#endif /* !CONFIG_VBOXDRV_AS_MISC */
643 if (!rc)
644 {
645 /*
646 * Initialize the runtime.
647 * On AMD64 we'll have to donate the high rwx memory block to the exec allocator.
648 */
649 rc = RTR0Init(0);
650 if (RT_SUCCESS(rc))
651 {
652#ifdef RT_ARCH_AMD64
653 rc = RTR0MemExecDonate(&g_abExecMemory[0], sizeof(g_abExecMemory));
654#endif
655 /*
656 * Initialize the device extension.
657 */
658 if (RT_SUCCESS(rc))
659 rc = supdrvInitDevExt(&g_DevExt);
660 if (!rc)
661 {
662#ifndef USE_NEW_OS_INTERFACE_FOR_GIP
663 /*
664 * Create the GIP page.
665 */
666 rc = VBoxDrvLinuxInitGip(&g_DevExt);
667 if (!rc)
668#endif /* !USE_NEW_OS_INTERFACE_FOR_GIP */
669 {
670 printk(KERN_INFO DEVICE_NAME ": TSC mode is %s, kernel timer mode is "
671#ifdef VBOX_HRTIMER
672 "'high-res'"
673#else
674 "'normal'"
675#endif
676 ".\n",
677 g_DevExt.pGip->u32Mode == SUPGIPMODE_SYNC_TSC ? "'synchronous'" : "'asynchronous'");
678 LogFlow(("VBoxDrv::ModuleInit returning %#x\n", rc));
679 printk(KERN_DEBUG DEVICE_NAME ": Successfully loaded version "
680 VBOX_VERSION_STRING " (interface " xstr(SUPDRVIOC_VERSION) ").\n");
681 return rc;
682 }
683
684 supdrvDeleteDevExt(&g_DevExt);
685 }
686 else
687 rc = -EINVAL;
688 RTR0Term();
689 }
690 else
691 rc = -EINVAL;
692
693 /*
694 * Failed, cleanup and return the error code.
695 */
696#if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC)
697 VBOX_UNREGISTER_DEVFS(g_hDevFsVBoxDrv);
698#endif
699 }
700#ifdef CONFIG_VBOXDRV_AS_MISC
701 misc_deregister(&gMiscDevice);
702 dprintf(("VBoxDrv::ModuleInit returning %#x (minor:%d)\n", rc, gMiscDevice.minor));
703#else
704 VBOX_UNREGISTER_DEVICE(g_iModuleMajor, DEVICE_NAME);
705 dprintf(("VBoxDrv::ModuleInit returning %#x (major:%d)\n", rc, g_iModuleMajor));
706#endif
707 return rc;
708}
709
710
711/**
712 * Unload the module.
713 */
714static void __exit VBoxDrvLinuxUnload(void)
715{
716 int rc;
717 dprintf(("VBoxDrvLinuxUnload\n"));
718 NOREF(rc);
719
720 /*
721 * I Don't think it's possible to unload a driver which processes have
722 * opened, at least we'll blindly assume that here.
723 */
724#ifdef CONFIG_VBOXDRV_AS_MISC
725 rc = misc_deregister(&gMiscDevice);
726 if (rc < 0)
727 {
728 dprintf(("misc_deregister failed with rc=%#x\n", rc));
729 }
730#else /* !CONFIG_VBOXDRV_AS_MISC */
731# ifdef CONFIG_DEVFS_FS
732 /*
733 * Unregister a device entry
734 */
735 VBOX_UNREGISTER_DEVFS(g_hDevFsVBoxDrv);
736# endif /* devfs */
737 VBOX_UNREGISTER_DEVICE(g_iModuleMajor, DEVICE_NAME);
738#endif /* !CONFIG_VBOXDRV_AS_MISC */
739
740 /*
741 * Destroy GIP, delete the device extension and terminate IPRT.
742 */
743#ifndef USE_NEW_OS_INTERFACE_FOR_GIP
744 VBoxDrvLinuxTermGip(&g_DevExt);
745#endif /* !USE_NEW_OS_INTERFACE_FOR_GIP */
746 supdrvDeleteDevExt(&g_DevExt);
747 RTR0Term();
748}
749
750
751/**
752 * Device open. Called on open /dev/vboxdrv
753 *
754 * @param pInode Pointer to inode info structure.
755 * @param pFilp Associated file pointer.
756 */
757static int VBoxDrvLinuxCreate(struct inode *pInode, struct file *pFilp)
758{
759 int rc;
760 PSUPDRVSESSION pSession;
761 Log(("VBoxDrvLinuxCreate: pFilp=%p pid=%d/%d %s\n", pFilp, RTProcSelf(), current->pid, current->comm));
762
763 /*
764 * Call common code for the rest.
765 */
766 rc = supdrvCreateSession(&g_DevExt, (PSUPDRVSESSION *)&pSession);
767 if (!rc)
768 {
769 pSession->Uid = current->euid;
770 pSession->Gid = current->egid;
771 pSession->Process = RTProcSelf();
772 pSession->R0Process = RTR0ProcHandleSelf();
773 }
774
775 pFilp->private_data = pSession;
776
777 Log(("VBoxDrvLinuxCreate: g_DevExt=%p pSession=%p rc=%d/%d (pid=%d/%d %s)\n",
778 &g_DevExt, pSession, rc, VBoxDrvLinuxErr2LinuxErr(rc),
779 RTProcSelf(), current->pid, current->comm));
780 return VBoxDrvLinuxErr2LinuxErr(rc);
781}
782
783
784/**
785 * Close device.
786 *
787 * @param pInode Pointer to inode info structure.
788 * @param pFilp Associated file pointer.
789 */
790static int VBoxDrvLinuxClose(struct inode *pInode, struct file *pFilp)
791{
792 Log(("VBoxDrvLinuxClose: pFilp=%p pSession=%p pid=%d/%d %s\n",
793 pFilp, pFilp->private_data, RTProcSelf(), current->pid, current->comm));
794 supdrvCloseSession(&g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
795 pFilp->private_data = NULL;
796 return 0;
797}
798
799
800/**
801 * Device I/O Control entry point.
802 *
803 * @param pFilp Associated file pointer.
804 * @param uCmd The function specified to ioctl().
805 * @param ulArg The argument specified to ioctl().
806 */
807#ifdef HAVE_UNLOCKED_IOCTL
808static long VBoxDrvLinuxIOCtl(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
809#else
810static int VBoxDrvLinuxIOCtl(struct inode *pInode, struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
811#endif
812{
813 /*
814 * Deal with the two high-speed IOCtl that takes it's arguments from
815 * the session and iCmd, and only returns a VBox status code.
816 */
817#ifdef HAVE_UNLOCKED_IOCTL
818 if (RT_LIKELY( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
819 || uCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
820 || uCmd == SUP_IOCTL_FAST_DO_NOP))
821 return supdrvIOCtlFast(uCmd, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
822 return VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg);
823
824#else /* !HAVE_UNLOCKED_IOCTL */
825
826 int rc;
827 unlock_kernel();
828 if (RT_LIKELY( uCmd == SUP_IOCTL_FAST_DO_RAW_RUN
829 || uCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
830 || uCmd == SUP_IOCTL_FAST_DO_NOP))
831 rc = supdrvIOCtlFast(uCmd, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data);
832 else
833 rc = VBoxDrvLinuxIOCtlSlow(pFilp, uCmd, ulArg);
834 lock_kernel();
835 return rc;
836#endif /* !HAVE_UNLOCKED_IOCTL */
837}
838
839
840/**
841 * Device I/O Control entry point.
842 *
843 * @param pFilp Associated file pointer.
844 * @param uCmd The function specified to ioctl().
845 * @param ulArg The argument specified to ioctl().
846 */
847static int VBoxDrvLinuxIOCtlSlow(struct file *pFilp, unsigned int uCmd, unsigned long ulArg)
848{
849 int rc;
850 SUPREQHDR Hdr;
851 PSUPREQHDR pHdr;
852 uint32_t cbBuf;
853
854 Log6(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p pid=%d/%d\n", pFilp, uCmd, (void *)ulArg, RTProcSelf(), current->pid));
855
856 /*
857 * Read the header.
858 */
859 if (RT_UNLIKELY(copy_from_user(&Hdr, (void *)ulArg, sizeof(Hdr))))
860 {
861 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x.\n", ulArg, uCmd));
862 return -EFAULT;
863 }
864 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
865 {
866 Log(("VBoxDrvLinuxIOCtl: bad header magic %#x; uCmd=%#x\n", Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, uCmd));
867 return -EINVAL;
868 }
869
870 /*
871 * Buffer the request.
872 */
873 cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
874 if (RT_UNLIKELY(cbBuf > _1M*16))
875 {
876 Log(("VBoxDrvLinuxIOCtl: too big cbBuf=%#x; uCmd=%#x\n", cbBuf, uCmd));
877 return -E2BIG;
878 }
879 if (RT_UNLIKELY(cbBuf != _IOC_SIZE(uCmd) && _IOC_SIZE(uCmd)))
880 {
881 Log(("VBoxDrvLinuxIOCtl: bad ioctl cbBuf=%#x _IOC_SIZE=%#x; uCmd=%#x.\n", cbBuf, _IOC_SIZE(uCmd), uCmd));
882 return -EINVAL;
883 }
884 pHdr = RTMemAlloc(cbBuf);
885 if (RT_UNLIKELY(!pHdr))
886 {
887 OSDBGPRINT(("VBoxDrvLinuxIOCtl: failed to allocate buffer of %d bytes for uCmd=%#x.\n", cbBuf, uCmd));
888 return -ENOMEM;
889 }
890 if (RT_UNLIKELY(copy_from_user(pHdr, (void *)ulArg, Hdr.cbIn)))
891 {
892 Log(("VBoxDrvLinuxIOCtl: copy_from_user(,%#lx, %#x) failed; uCmd=%#x.\n", ulArg, Hdr.cbIn, uCmd));
893 RTMemFree(pHdr);
894 return -EFAULT;
895 }
896
897 /*
898 * Process the IOCtl.
899 */
900 rc = supdrvIOCtl(uCmd, &g_DevExt, (PSUPDRVSESSION)pFilp->private_data, pHdr);
901
902 /*
903 * Copy ioctl data and output buffer back to user space.
904 */
905 if (RT_LIKELY(!rc))
906 {
907 uint32_t cbOut = pHdr->cbOut;
908 if (RT_UNLIKELY(cbOut > cbBuf))
909 {
910 OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n", cbOut, cbBuf, uCmd));
911 cbOut = cbBuf;
912 }
913 if (RT_UNLIKELY(copy_to_user((void *)ulArg, pHdr, cbOut)))
914 {
915 /* this is really bad! */
916 OSDBGPRINT(("VBoxDrvLinuxIOCtl: copy_to_user(%#lx,,%#x); uCmd=%#x!\n", ulArg, cbOut, uCmd));
917 rc = -EFAULT;
918 }
919 }
920 else
921 {
922 Log(("VBoxDrvLinuxIOCtl: pFilp=%p uCmd=%#x ulArg=%p failed, rc=%d\n", pFilp, uCmd, (void *)ulArg, rc));
923 rc = -EINVAL;
924 }
925 RTMemFree(pHdr);
926
927 Log6(("VBoxDrvLinuxIOCtl: returns %d (pid=%d/%d)\n", rc, RTProcSelf(), current->pid));
928 return rc;
929}
930
931
932/**
933 * Initializes any OS specific object creator fields.
934 */
935void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
936{
937 NOREF(pObj);
938 NOREF(pSession);
939}
940
941
942/**
943 * Checks if the session can access the object.
944 *
945 * @returns true if a decision has been made.
946 * @returns false if the default access policy should be applied.
947 *
948 * @param pObj The object in question.
949 * @param pSession The session wanting to access the object.
950 * @param pszObjName The object name, can be NULL.
951 * @param prc Where to store the result when returning true.
952 */
953bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
954{
955 NOREF(pObj);
956 NOREF(pSession);
957 NOREF(pszObjName);
958 NOREF(prc);
959 return false;
960}
961
962
963#ifndef USE_NEW_OS_INTERFACE_FOR_GIP
964
965/**
966 * Initializes the GIP.
967 *
968 * @returns negative errno.
969 * @param pDevExt Instance data. GIP stuff may be updated.
970 */
971static int VBoxDrvLinuxInitGip(PSUPDRVDEVEXT pDevExt)
972{
973 struct page *pPage;
974 dma_addr_t HCPhys;
975 PSUPGLOBALINFOPAGE pGip;
976#ifdef CONFIG_SMP
977 unsigned i;
978#endif
979 LogFlow(("VBoxDrvLinuxInitGip:\n"));
980
981 /*
982 * Allocate the page.
983 */
984 pPage = alloc_pages(GFP_USER, 0);
985 if (!pPage)
986 {
987 Log(("VBoxDrvLinuxInitGip: failed to allocate the GIP page\n"));
988 return -ENOMEM;
989 }
990
991 /*
992 * Lock the page.
993 */
994 SetPageReserved(pPage);
995 g_pGipPage = pPage;
996
997 /*
998 * Call common initialization routine.
999 */
1000 HCPhys = page_to_phys(pPage);
1001 pGip = (PSUPGLOBALINFOPAGE)page_address(pPage);
1002 pDevExt->ulLastJiffies = jiffies;
1003 pDevExt->u64LastMonotime = (uint64_t)pDevExt->ulLastJiffies * TICK_NSEC;
1004 Log(("VBoxDrvInitGIP: TICK_NSEC=%ld HZ=%d jiffies=%ld now=%lld\n",
1005 TICK_NSEC, HZ, pDevExt->ulLastJiffies, pDevExt->u64LastMonotime));
1006 supdrvGipInit(pDevExt, pGip, HCPhys, pDevExt->u64LastMonotime,
1007 HZ <= 1000 ? HZ : 1000);
1008
1009 /*
1010 * Initialize the timer.
1011 */
1012 vbox_ktimer_init(&g_GipTimer, VBoxDrvLinuxGipTimer, (unsigned long)pDevExt);
1013#ifdef CONFIG_SMP
1014 for (i = 0; i < RT_ELEMENTS(pDevExt->aCPUs); i++)
1015 {
1016 pDevExt->aCPUs[i].u64LastMonotime = pDevExt->u64LastMonotime;
1017 pDevExt->aCPUs[i].ulLastJiffies = pDevExt->ulLastJiffies;
1018 pDevExt->aCPUs[i].iSmpProcessorId = -512;
1019 vbox_ktimer_init(&pDevExt->aCPUs[i].Timer, VBoxDrvLinuxGipTimerPerCpu, i);
1020 }
1021#endif
1022
1023 return 0;
1024}
1025
1026
1027/**
1028 * Terminates the GIP.
1029 *
1030 * @returns negative errno.
1031 * @param pDevExt Instance data. GIP stuff may be updated.
1032 */
1033static int VBoxDrvLinuxTermGip(PSUPDRVDEVEXT pDevExt)
1034{
1035 struct page *pPage;
1036 PSUPGLOBALINFOPAGE pGip;
1037#ifdef CONFIG_SMP
1038 unsigned i;
1039#endif
1040 LogFlow(("VBoxDrvLinuxTermGip:\n"));
1041
1042 /*
1043 * Delete the timer if it's pending.
1044 */
1045 vbox_ktimer_stop(&g_GipTimer);
1046#ifdef CONFIG_SMP
1047 for (i = 0; i < RT_ELEMENTS(pDevExt->aCPUs); i++)
1048 vbox_ktimer_stop(&pDevExt->aCPUs[i].Timer);
1049#endif
1050
1051 /*
1052 * Uninitialize the content.
1053 */
1054 pGip = pDevExt->pGip;
1055 pDevExt->pGip = NULL;
1056 if (pGip)
1057 supdrvGipTerm(pGip);
1058
1059 /*
1060 * Free the page.
1061 */
1062 pPage = g_pGipPage;
1063 g_pGipPage = NULL;
1064 if (pPage)
1065 {
1066 ClearPageReserved(pPage);
1067 __free_pages(pPage, 0);
1068 }
1069
1070 return 0;
1071}
1072
1073/**
1074 * Timer callback function.
1075 *
1076 * In ASYNC TSC mode this is called on the primary CPU, and we're
1077 * assuming that the CPU remains online.
1078 *
1079 * @param ulUser The device extension pointer.
1080 */
1081#ifdef VBOX_HRTIMER
1082static enum hrtimer_restart VBoxDrvLinuxGipTimer(struct hrtimer *pTimer)
1083#else
1084static void VBoxDrvLinuxGipTimer(unsigned long ulUser)
1085#endif
1086{
1087 PSUPDRVDEVEXT pDevExt;
1088 PSUPGLOBALINFOPAGE pGip;
1089 unsigned long ulNow;
1090 unsigned long ulDiff;
1091 uint64_t u64Monotime;
1092 unsigned long SavedFlags;
1093#ifdef VBOX_HRTIMER
1094 ktime_t KtNow;
1095#endif
1096
1097 local_irq_save(SavedFlags);
1098
1099 ulNow = jiffies;
1100#ifdef VBOX_HRTIMER
1101 KtNow = ktime_get();
1102 pDevExt = &g_DevExt;
1103#else
1104 pDevExt = (PSUPDRVDEVEXT)ulUser;
1105#endif
1106 pGip = pDevExt->pGip;
1107
1108#ifdef CONFIG_SMP
1109 if (pGip && pGip->u32Mode == SUPGIPMODE_ASYNC_TSC)
1110 {
1111 uint8_t iCPU = ASMGetApicId();
1112 ulDiff = ulNow - pDevExt->aCPUs[iCPU].ulLastJiffies;
1113 pDevExt->aCPUs[iCPU].ulLastJiffies = ulNow;
1114 u64Monotime = pDevExt->aCPUs[iCPU].u64LastMonotime + ulDiff * TICK_NSEC;
1115 pDevExt->aCPUs[iCPU].u64LastMonotime = u64Monotime;
1116 }
1117 else
1118#endif /* CONFIG_SMP */
1119 {
1120 ulDiff = ulNow - pDevExt->ulLastJiffies;
1121 pDevExt->ulLastJiffies = ulNow;
1122 u64Monotime = pDevExt->u64LastMonotime + ulDiff * TICK_NSEC;
1123 pDevExt->u64LastMonotime = u64Monotime;
1124 }
1125 if (RT_LIKELY(pGip))
1126 supdrvGipUpdate(pDevExt->pGip, u64Monotime);
1127 if (RT_LIKELY(!pDevExt->fGIPSuspended))
1128 {
1129#ifdef VBOX_HRTIMER
1130 hrtimer_forward(&g_GipTimer, KtNow, ktime_set(0, 1000000));
1131#else
1132 mod_timer(&g_GipTimer, ulNow + ONE_MSEC_IN_JIFFIES);
1133#endif
1134 }
1135
1136 local_irq_restore(SavedFlags);
1137
1138#ifdef VBOX_HRTIMER
1139 return pDevExt->fGIPSuspended ? HRTIMER_NORESTART : HRTIMER_RESTART;
1140#endif
1141}
1142
1143
1144#ifdef CONFIG_SMP
1145/**
1146 * Timer callback function for the other CPUs.
1147 *
1148 * @param iTimerCPU The APIC ID of this timer.
1149 */
1150#ifdef VBOX_HRTIMER
1151static enum hrtimer_restart VBoxDrvLinuxGipTimerPerCpu(struct hrtimer *pTimer)
1152#else
1153static void VBoxDrvLinuxGipTimerPerCpu(unsigned long iTimerCPU)
1154#endif
1155{
1156 PSUPDRVDEVEXT pDevExt;
1157 PSUPGLOBALINFOPAGE pGip;
1158 uint8_t iCPU;
1159 uint64_t u64Monotime;
1160 unsigned long SavedFlags;
1161 unsigned long ulNow;
1162# ifdef VBOX_HRTIMER
1163 unsigned long iTimerCPU;
1164 ktime_t KtNow;
1165# endif
1166
1167 local_irq_save(SavedFlags);
1168
1169 ulNow = jiffies;
1170 pDevExt = &g_DevExt;
1171 pGip = pDevExt->pGip;
1172 iCPU = ASMGetApicId();
1173# ifdef VBOX_HRTIMER
1174 iTimerCPU = iCPU; /* XXX hrtimer does not support a 'data' field */
1175 KtNow = ktime_get();
1176# endif
1177
1178 if (RT_LIKELY(iCPU < RT_ELEMENTS(pGip->aCPUs)))
1179 {
1180 if (RT_LIKELY(iTimerCPU == iCPU))
1181 {
1182 unsigned long ulDiff = ulNow - pDevExt->aCPUs[iCPU].ulLastJiffies;
1183 pDevExt->aCPUs[iCPU].ulLastJiffies = ulNow;
1184 u64Monotime = pDevExt->aCPUs[iCPU].u64LastMonotime + ulDiff * TICK_NSEC;
1185 pDevExt->aCPUs[iCPU].u64LastMonotime = u64Monotime;
1186 if (RT_LIKELY(pGip))
1187 supdrvGipUpdatePerCpu(pGip, u64Monotime, iCPU);
1188 if (RT_LIKELY(!pDevExt->fGIPSuspended))
1189 {
1190# ifdef VBOX_HRTIMER
1191 hrtimer_forward(&pDevExt->aCPUs[iCPU].Timer, KtNow, ktime_set(0, 1000000));
1192# else
1193 mod_timer(&pDevExt->aCPUs[iCPU].Timer, ulNow + ONE_MSEC_IN_JIFFIES);
1194# endif
1195 }
1196 }
1197 else
1198 printk("vboxdrv: error: GIP CPU update timer executing on the wrong CPU: apicid=%d != timer-apicid=%ld (cpuid=%d !=? timer-cpuid=%d)\n",
1199 iCPU, iTimerCPU, smp_processor_id(), pDevExt->aCPUs[iTimerCPU].iSmpProcessorId);
1200 }
1201 else
1202 printk("vboxdrv: error: APIC ID is bogus (GIP CPU update): apicid=%d max=%lu cpuid=%d\n",
1203 iCPU, (unsigned long)RT_ELEMENTS(pGip->aCPUs), smp_processor_id());
1204
1205 local_irq_restore(SavedFlags);
1206
1207# ifdef VBOX_HRTIMER
1208 return pDevExt->fGIPSuspended ? HRTIMER_NORESTART : HRTIMER_RESTART;
1209# endif
1210}
1211#endif /* CONFIG_SMP */
1212
1213
1214/**
1215 * Maps the GIP into user space.
1216 *
1217 * @returns negative errno.
1218 * @param pDevExt Instance data.
1219 */
1220int VBOXCALL supdrvOSGipMap(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE *ppGip)
1221{
1222 int rc = 0;
1223 unsigned long ulAddr;
1224 unsigned long HCPhys = pDevExt->HCPhysGip;
1225 pgprot_t pgFlags;
1226 pgprot_val(pgFlags) = _PAGE_PRESENT | _PAGE_USER;
1227 LogFlow(("supdrvOSGipMap: ppGip=%p\n", ppGip));
1228
1229 /*
1230 * Allocate user space mapping and put the physical pages into it.
1231 */
1232 down_write(&current->mm->mmap_sem);
1233 ulAddr = do_mmap(NULL, 0, PAGE_SIZE, PROT_READ, MAP_SHARED | MAP_ANONYMOUS, 0);
1234 if (!(ulAddr & ~PAGE_MASK))
1235 {
1236#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) && !defined(HAVE_26_STYLE_REMAP_PAGE_RANGE)
1237 int rc2 = remap_page_range(ulAddr, HCPhys, PAGE_SIZE, pgFlags);
1238#else
1239 int rc2 = 0;
1240 struct vm_area_struct *vma = find_vma(current->mm, ulAddr);
1241 if (vma)
1242#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)
1243 rc2 = remap_page_range(vma, ulAddr, HCPhys, PAGE_SIZE, pgFlags);
1244#else
1245 rc2 = remap_pfn_range(vma, ulAddr, HCPhys >> PAGE_SHIFT, PAGE_SIZE, pgFlags);
1246#endif
1247 else
1248 {
1249 rc = SUPDRV_ERR_NO_MEMORY;
1250 Log(("supdrvOSGipMap: no vma found for ulAddr=%#lx!\n", ulAddr));
1251 }
1252#endif
1253 if (rc2)
1254 {
1255 rc = SUPDRV_ERR_NO_MEMORY;
1256 Log(("supdrvOSGipMap: remap_page_range failed rc2=%d\n", rc2));
1257 }
1258 }
1259 else
1260 {
1261 Log(("supdrvOSGipMap: do_mmap failed ulAddr=%#lx\n", ulAddr));
1262 rc = SUPDRV_ERR_NO_MEMORY;
1263 }
1264 up_write(&current->mm->mmap_sem); /* not quite sure when to give this up. */
1265
1266 /*
1267 * Success?
1268 */
1269 if (!rc)
1270 {
1271 *ppGip = (PSUPGLOBALINFOPAGE)ulAddr;
1272 LogFlow(("supdrvOSGipMap: ppGip=%p\n", *ppGip));
1273 return 0;
1274 }
1275
1276 /*
1277 * Failure, cleanup and be gone.
1278 */
1279 if (ulAddr & ~PAGE_MASK)
1280 {
1281 down_write(&current->mm->mmap_sem);
1282 MY_DO_MUNMAP(current->mm, ulAddr, PAGE_SIZE);
1283 up_write(&current->mm->mmap_sem);
1284 }
1285
1286 LogFlow(("supdrvOSGipMap: returns %d\n", rc));
1287 return rc;
1288}
1289
1290
1291/**
1292 * Maps the GIP into user space.
1293 *
1294 * @returns negative errno.
1295 * @param pDevExt Instance data.
1296 */
1297int VBOXCALL supdrvOSGipUnmap(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip)
1298{
1299 LogFlow(("supdrvOSGipUnmap: pGip=%p\n", pGip));
1300 if (current->mm)
1301 {
1302 down_write(&current->mm->mmap_sem);
1303 MY_DO_MUNMAP(current->mm, (unsigned long)pGip, PAGE_SIZE);
1304 up_write(&current->mm->mmap_sem);
1305 }
1306 LogFlow(("supdrvOSGipUnmap: returns 0\n"));
1307 return 0;
1308}
1309
1310
1311/**
1312 * Resumes the GIP updating.
1313 *
1314 * @param pDevExt Instance data.
1315 */
1316void VBOXCALL supdrvOSGipResume(PSUPDRVDEVEXT pDevExt)
1317{
1318 LogFlow(("supdrvOSGipResume:\n"));
1319 ASMAtomicXchgU8(&pDevExt->fGIPSuspended, false);
1320#ifdef CONFIG_SMP
1321 if (pDevExt->pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
1322 {
1323#endif
1324 vbox_ktimer_start(&g_GipTimer);
1325#ifdef CONFIG_SMP
1326 }
1327 else
1328 {
1329 vbox_ktimer_start(&g_GipTimer);
1330 smp_call_function(VBoxDrvLinuxGipResumePerCpu, pDevExt, 0 /* retry */, 1 /* wait */);
1331 }
1332#endif
1333}
1334
1335
1336#ifdef CONFIG_SMP
1337/**
1338 * Callback for resuming GIP updating on the other CPUs.
1339 *
1340 * This is only used when the GIP is in async tsc mode.
1341 *
1342 * @param pvUser Pointer to the device instance.
1343 */
1344static void VBoxDrvLinuxGipResumePerCpu(void *pvUser)
1345{
1346 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
1347 uint8_t iCPU = ASMGetApicId();
1348
1349 if (RT_UNLIKELY(iCPU >= RT_ELEMENTS(pDevExt->pGip->aCPUs)))
1350 {
1351 printk("vboxdrv: error: apicid=%d max=%lu cpuid=%d\n",
1352 iCPU, (unsigned long)RT_ELEMENTS(pDevExt->pGip->aCPUs), smp_processor_id());
1353 return;
1354 }
1355
1356 pDevExt->aCPUs[iCPU].iSmpProcessorId = smp_processor_id();
1357 vbox_ktimer_start(&pDevExt->aCPUs[iCPU].Timer);
1358}
1359#endif /* CONFIG_SMP */
1360
1361
1362/**
1363 * Suspends the GIP updating.
1364 *
1365 * @param pDevExt Instance data.
1366 */
1367void VBOXCALL supdrvOSGipSuspend(PSUPDRVDEVEXT pDevExt)
1368{
1369#ifdef CONFIG_SMP
1370 unsigned i;
1371#endif
1372 LogFlow(("supdrvOSGipSuspend:\n"));
1373 ASMAtomicXchgU8(&pDevExt->fGIPSuspended, true);
1374
1375 vbox_ktimer_stop(&g_GipTimer);
1376#ifdef CONFIG_SMP
1377 for (i = 0; i < RT_ELEMENTS(pDevExt->aCPUs); i++)
1378 vbox_ktimer_stop(&pDevExt->aCPUs[i].Timer);
1379#endif
1380}
1381
1382#endif /* !USE_NEW_OS_INTERFACE_FOR_GIP */
1383
1384
1385bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
1386{
1387 return force_async_tsc != 0;
1388}
1389
1390
1391/**
1392 * Converts a supdrv error code to an linux error code.
1393 *
1394 * @returns corresponding linux error code.
1395 * @param rc supdrv error code (SUPDRV_ERR_* defines).
1396 */
1397static int VBoxDrvLinuxErr2LinuxErr(int rc)
1398{
1399 switch (rc)
1400 {
1401 case 0: return 0;
1402 case SUPDRV_ERR_GENERAL_FAILURE: return -EACCES;
1403 case SUPDRV_ERR_INVALID_PARAM: return -EINVAL;
1404 case SUPDRV_ERR_INVALID_MAGIC: return -EILSEQ;
1405 case SUPDRV_ERR_INVALID_HANDLE: return -ENXIO;
1406 case SUPDRV_ERR_INVALID_POINTER: return -EFAULT;
1407 case SUPDRV_ERR_LOCK_FAILED: return -ENOLCK;
1408 case SUPDRV_ERR_ALREADY_LOADED: return -EEXIST;
1409 case SUPDRV_ERR_PERMISSION_DENIED: return -EPERM;
1410 case SUPDRV_ERR_VERSION_MISMATCH: return -ENOSYS;
1411 case SUPDRV_ERR_IDT_FAILED: return -1000;
1412 }
1413
1414 return -EPERM;
1415}
1416
1417
1418RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
1419{
1420#if 1
1421 va_list args;
1422 char szMsg[512];
1423
1424 va_start(args, pszFormat);
1425 vsnprintf(szMsg, sizeof(szMsg) - 1, pszFormat, args);
1426 szMsg[sizeof(szMsg) - 1] = '\0';
1427 printk("%s", szMsg);
1428 va_end(args);
1429#else
1430 /* forward to printf - needs some more GCC hacking to fix ebp... */
1431 __asm__ __volatile__ ("mov %0, %esp\n\t"
1432 "jmp %1\n\t",
1433 :: "r" ((uintptr_t)&pszFormat - 4),
1434 "m" (printk));
1435#endif
1436 return 0;
1437}
1438
1439
1440/** Runtime assert implementation for Linux Ring-0. */
1441RTDECL(bool) RTAssertDoBreakpoint(void)
1442{
1443 return true;
1444}
1445
1446
1447/** Runtime assert implementation for Linux Ring-0. */
1448RTDECL(void) AssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
1449{
1450 printk("!!Assertion Failed!!\n"
1451 "Expression: %s\n"
1452 "Location : %s(%d) %s\n",
1453 pszExpr, pszFile, uLine, pszFunction);
1454}
1455
1456
1457/** Runtime assert implementation for Linux Ring-0. */
1458RTDECL(void) AssertMsg2(const char *pszFormat, ...)
1459{ /* forwarder. */
1460 va_list ap;
1461 char msg[256];
1462
1463 va_start(ap, pszFormat);
1464 vsnprintf(msg, sizeof(msg) - 1, pszFormat, ap);
1465 msg[sizeof(msg) - 1] = '\0';
1466 printk("%s", msg);
1467 va_end(ap);
1468}
1469
1470
1471/* GCC C++ hack. (shouldn't be necessary...) */
1472unsigned __gxx_personality_v0 = 0xcccccccc;
1473
1474
1475module_init(VBoxDrvLinuxInit);
1476module_exit(VBoxDrvLinuxUnload);
1477
1478MODULE_AUTHOR("Sun Microsystems, Inc.");
1479MODULE_DESCRIPTION("VirtualBox Support Driver");
1480MODULE_LICENSE("GPL");
1481#ifdef MODULE_VERSION
1482MODULE_VERSION(VBOX_VERSION_STRING " (" xstr(SUPDRVIOC_VERSION) ")");
1483#endif
1484
1485#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
1486module_param(force_async_tsc, int, 0444);
1487#else
1488MODULE_PARM(force_async_tsc, "i");
1489#endif
1490MODULE_PARM_DESC(force_async_tsc, "force the asynchronous TSC mode");
1491
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