VirtualBox

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

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

Implemented RTTime for the linux kernel (not used yet).

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