VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp@ 4800

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

Redid the supdrv interface. works on windows and linux while the other OSes still needs some adjusting/testing. internal networking is temporarily broken as the SUPCallVMMR0Ex interface is being reworked (this is what all this is really about).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.2 KB
Line 
1/* $Id: SUPDrv-win.cpp 4800 2007-09-14 14:59:15Z vboxsync $ */
2/** @file
3 * VirtualBox Support Driver - Windows NT specific parts.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#include "SUPDRV.h"
24#include <excpt.h>
25#include <iprt/assert.h>
26#include <iprt/process.h>
27
28
29/*******************************************************************************
30* Defined Constants And Macros *
31*******************************************************************************/
32/** The support service name. */
33#define SERVICE_NAME "VBoxDrv"
34/** Win32 Device name. */
35#define DEVICE_NAME "\\\\.\\VBoxDrv"
36/** NT Device name. */
37#define DEVICE_NAME_NT L"\\Device\\VBoxDrv"
38/** Win Symlink name. */
39#define DEVICE_NAME_DOS L"\\DosDevices\\VBoxDrv"
40/** The Pool tag (VBox). */
41#define SUPDRV_NT_POOL_TAG 'xoBV'
42
43
44/*******************************************************************************
45* Structures and Typedefs *
46*******************************************************************************/
47#if 0 //def RT_ARCH_AMD64
48typedef struct SUPDRVEXECMEM
49{
50 PMDL pMdl;
51 void *pvMapping;
52 void *pvAllocation;
53} SUPDRVEXECMEM, *PSUPDRVEXECMEM;
54#endif
55
56
57/*******************************************************************************
58* Internal Functions *
59*******************************************************************************/
60static void _stdcall VBoxDrvNtUnload(PDRIVER_OBJECT pDrvObj);
61static NTSTATUS _stdcall VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
62static NTSTATUS _stdcall VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
63static NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
64static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack);
65static NTSTATUS _stdcall VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
66static NTSTATUS VBoxDrvNtErr2NtStatus(int rc);
67static NTSTATUS VBoxDrvNtGipInit(PSUPDRVDEVEXT pDevExt);
68static void VBoxDrvNtGipTerm(PSUPDRVDEVEXT pDevExt);
69static void _stdcall VBoxDrvNtGipTimer(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2);
70static void _stdcall VBoxDrvNtGipPerCpuDpc(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2);
71
72
73/*******************************************************************************
74* Exported Functions *
75*******************************************************************************/
76__BEGIN_DECLS
77ULONG _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath);
78__END_DECLS
79
80
81/**
82 * Driver entry point.
83 *
84 * @returns appropriate status code.
85 * @param pDrvObj Pointer to driver object.
86 * @param pRegPath Registry base path.
87 */
88ULONG _stdcall DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
89{
90 NTSTATUS rc;
91 dprintf(("VBoxDrv::DriverEntry\n"));
92
93 /*
94 * Create device.
95 * (That means creating a device object and a symbolic link so the DOS
96 * subsystems (OS/2, win32, ++) can access the device.)
97 */
98 UNICODE_STRING DevName;
99 RtlInitUnicodeString(&DevName, DEVICE_NAME_NT);
100 PDEVICE_OBJECT pDevObj;
101 rc = IoCreateDevice(pDrvObj, sizeof(SUPDRVDEVEXT), &DevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDevObj);
102 if (NT_SUCCESS(rc))
103 {
104 UNICODE_STRING DosName;
105 RtlInitUnicodeString(&DosName, DEVICE_NAME_DOS);
106 rc = IoCreateSymbolicLink(&DosName, &DevName);
107 if (NT_SUCCESS(rc))
108 {
109 /*
110 * Initialize the device extension.
111 */
112 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
113 memset(pDevExt, 0, sizeof(*pDevExt));
114 int vrc = supdrvInitDevExt(pDevExt);
115 if (!vrc)
116 {
117 /*
118 * Inititalize the GIP.
119 */
120 rc = VBoxDrvNtGipInit(pDevExt);
121 if (NT_SUCCESS(rc))
122 {
123 /*
124 * Setup the driver entry points in pDrvObj.
125 */
126 pDrvObj->DriverUnload = VBoxDrvNtUnload;
127 pDrvObj->MajorFunction[IRP_MJ_CREATE] = VBoxDrvNtCreate;
128 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = VBoxDrvNtClose;
129 pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxDrvNtDeviceControl;
130 pDrvObj->MajorFunction[IRP_MJ_READ] = VBoxDrvNtNotSupportedStub;
131 pDrvObj->MajorFunction[IRP_MJ_WRITE] = VBoxDrvNtNotSupportedStub;
132 /* more? */
133 dprintf(("VBoxDrv::DriverEntry returning STATUS_SUCCESS\n"));
134 return STATUS_SUCCESS;
135 }
136 dprintf(("VBoxDrvNtGipInit failed with rc=%#x!\n", rc));
137
138 supdrvDeleteDevExt(pDevExt);
139 }
140 else
141 {
142 dprintf(("supdrvInitDevExit failed with vrc=%d!\n", vrc));
143 rc = VBoxDrvNtErr2NtStatus(vrc);
144 }
145
146 IoDeleteSymbolicLink(&DosName);
147 }
148 else
149 dprintf(("IoCreateSymbolicLink failed with rc=%#x!\n", rc));
150
151 IoDeleteDevice(pDevObj);
152 }
153 else
154 dprintf(("IoCreateDevice failed with rc=%#x!\n", rc));
155
156 if (NT_SUCCESS(rc))
157 rc = STATUS_INVALID_PARAMETER;
158 dprintf(("VBoxDrv::DriverEntry returning %#x\n", rc));
159 return rc;
160}
161
162
163/**
164 * Unload the driver.
165 *
166 * @param pDrvObj Driver object.
167 */
168void _stdcall VBoxDrvNtUnload(PDRIVER_OBJECT pDrvObj)
169{
170 dprintf(("VBoxDrvNtUnload\n"));
171 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDrvObj->DeviceObject->DeviceExtension;
172
173 /*
174 * We ASSUME that it's not possible to unload a driver with open handles.
175 * Start by deleting the symbolic link
176 */
177 UNICODE_STRING DosName;
178 RtlInitUnicodeString(&DosName, DEVICE_NAME_DOS);
179 NTSTATUS rc = IoDeleteSymbolicLink(&DosName);
180
181 /*
182 * Terminate the GIP page and delete the device extension.
183 */
184 VBoxDrvNtGipTerm(pDevExt);
185 supdrvDeleteDevExt(pDevExt);
186 IoDeleteDevice(pDrvObj->DeviceObject);
187}
188
189
190/**
191 * Create (i.e. Open) file entry point.
192 *
193 * @param pDevObj Device object.
194 * @param pIrp Request packet.
195 */
196NTSTATUS _stdcall VBoxDrvNtCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
197{
198 dprintf(("VBoxDrvNtCreate\n"));
199 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
200 PFILE_OBJECT pFileObj = pStack->FileObject;
201 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
202
203 /*
204 * We are not remotely similar to a directory...
205 * (But this is possible.)
206 */
207 if (pStack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
208 {
209 pIrp->IoStatus.Status = STATUS_NOT_A_DIRECTORY;
210 pIrp->IoStatus.Information = 0;
211 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
212 return STATUS_NOT_A_DIRECTORY;
213 }
214
215 /*
216 * Call common code for the rest.
217 */
218 pFileObj->FsContext = NULL;
219 PSUPDRVSESSION pSession;
220 int rc = supdrvCreateSession(pDevExt, &pSession);
221 if (!rc)
222 {
223 pSession->Uid = NIL_RTUID;
224 pSession->Gid = NIL_RTGID;
225 pSession->Process = RTProcSelf();
226 pSession->R0Process = RTR0ProcHandleSelf();
227 pFileObj->FsContext = pSession;
228 }
229
230 NTSTATUS rcNt = pIrp->IoStatus.Status = VBoxDrvNtErr2NtStatus(rc);
231 pIrp->IoStatus.Information = 0;
232 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
233
234 return rcNt;
235}
236
237
238/**
239 * Close file entry point.
240 *
241 * @param pDevObj Device object.
242 * @param pIrp Request packet.
243 */
244NTSTATUS _stdcall VBoxDrvNtClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
245{
246 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
247 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
248 PFILE_OBJECT pFileObj = pStack->FileObject;
249 dprintf(("VBoxDrvNtClose: pDevExt=%p pFileObj=%p pSession=%p\n",
250 pDevExt, pFileObj, pFileObj->FsContext));
251 supdrvCloseSession(pDevExt, (PSUPDRVSESSION)pFileObj->FsContext);
252 pFileObj->FsContext = NULL;
253 pIrp->IoStatus.Information = 0;
254 pIrp->IoStatus.Status = STATUS_SUCCESS;
255 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
256
257 return STATUS_SUCCESS;
258}
259
260
261/**
262 * Device I/O Control entry point.
263 *
264 * @param pDevObj Device object.
265 * @param pIrp Request packet.
266 */
267NTSTATUS _stdcall VBoxDrvNtDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
268{
269 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
270 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
271 PSUPDRVSESSION pSession = (PSUPDRVSESSION)pStack->FileObject->FsContext;
272
273#ifdef VBOX_WITHOUT_IDT_PATCHING
274 /*
275 * Deal with the two high-speed IOCtl that takes it's arguments from
276 * the session and iCmd, and only returns a VBox status code.
277 */
278 ULONG ulCmd = pStack->Parameters.DeviceIoControl.IoControlCode;
279 if ( ulCmd == SUP_IOCTL_FAST_DO_RAW_RUN
280 || ulCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
281 || ulCmd == SUP_IOCTL_FAST_DO_NOP)
282 {
283 int rc = supdrvIOCtlFast(ulCmd, pDevExt, pSession);
284
285 /* Complete the I/O request. */
286 NTSTATUS rcNt = pIrp->IoStatus.Status = STATUS_SUCCESS;
287 pIrp->IoStatus.Information = sizeof(rc);
288 __try
289 {
290 *(int *)pIrp->UserBuffer = rc;
291 }
292 __except(EXCEPTION_EXECUTE_HANDLER)
293 {
294 rcNt = pIrp->IoStatus.Status = GetExceptionCode();
295 dprintf(("VBoxSupDrvDeviceContorl: Exception Code %#x\n", rcNt));
296 }
297 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
298 return rcNt;
299 }
300#endif /* VBOX_WITHOUT_IDT_PATCHING */
301
302 return VBoxDrvNtDeviceControlSlow(pDevExt, pSession, pIrp, pStack);
303}
304
305
306/**
307 * Worker for VBoxDrvNtDeviceControl that takes the slow IOCtl functions.
308 *
309 * @returns NT status code.
310 *
311 * @param pDevObj Device object.
312 * @param pSession The session.
313 * @param pIrp Request packet.
314 * @param pStack The stack location containing the DeviceControl parameters.
315 */
316static int VBoxDrvNtDeviceControlSlow(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PIRP pIrp, PIO_STACK_LOCATION pStack)
317{
318 NTSTATUS rcNt;
319 unsigned cbOut = 0;
320 int rc = 0;
321 dprintf2(("VBoxDrvNtDeviceControlSlow(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
322 pDevExt, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
323 pIrp->AssociatedIrp.SystemBuffer, pStack->Parameters.DeviceIoControl.InputBufferLength,
324 pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
325
326#ifdef RT_ARCH_AMD64
327 /* Don't allow 32-bit processes to do any I/O controls. */
328 if (!IoIs32bitProcess(pIrp))
329#endif
330 {
331 /* Verify that it's a buffered CTL. */
332 if ((pStack->Parameters.DeviceIoControl.IoControlCode & 0x3) == METHOD_BUFFERED)
333 {
334 /* Verify that the sizes in the request header are correct. */
335 PSUPREQHDR pHdr = (PSUPREQHDR)pIrp->AssociatedIrp.SystemBuffer;
336 if ( pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr)
337 && pStack->Parameters.DeviceIoControl.InputBufferLength == pHdr->cbIn
338 && pStack->Parameters.DeviceIoControl.OutputBufferLength == pHdr->cbOut)
339 {
340 /*
341 * Do the job.
342 */
343 rc = supdrvIOCtl(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession, pHdr);
344 if (!rc)
345 {
346 rcNt = STATUS_SUCCESS;
347 cbOut = pHdr->cbOut;
348 if (cbOut > pStack->Parameters.DeviceIoControl.OutputBufferLength)
349 {
350 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
351 OSDBGPRINT(("VBoxDrvLinuxIOCtl: too much output! %#x > %#x; uCmd=%#x!\n",
352 pHdr->cbOut, cbOut, pStack->Parameters.DeviceIoControl.IoControlCode));
353 }
354 }
355 else
356 rcNt = STATUS_INVALID_PARAMETER;
357 dprintf2(("VBoxDrvNtDeviceControlSlow: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc));
358 }
359 else
360 {
361 dprintf(("VBoxDrvNtDeviceControlSlow: Mismatching sizes (%#x) - Hdr=%#lx/%#lx Irp=%#lx/%#lx!\n",
362 pStack->Parameters.DeviceIoControl.IoControlCode,
363 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbIn : 0,
364 pStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(*pHdr) ? pHdr->cbOut : 0,
365 pStack->Parameters.DeviceIoControl.InputBufferLength,
366 pStack->Parameters.DeviceIoControl.OutputBufferLength));
367 rcNt = STATUS_INVALID_PARAMETER;
368 }
369 }
370 else
371 {
372 dprintf(("VBoxDrvNtDeviceControlSlow: not buffered request (%#x) - not supported\n",
373 pStack->Parameters.DeviceIoControl.IoControlCode));
374 rcNt = STATUS_NOT_SUPPORTED;
375 }
376 }
377#ifdef RT_ARCH_AMD64
378 else
379 {
380 dprintf(("VBoxDrvNtDeviceControlSlow: WOW64 req - not supported\n"));
381 rcNt = STATUS_NOT_SUPPORTED;
382 }
383#endif
384
385 /* complete the request. */
386 pIrp->IoStatus.Status = rcNt;
387 pIrp->IoStatus.Information = cbOut;
388 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
389 return rcNt;
390}
391
392
393/**
394 * Stub function for functions we don't implemented.
395 *
396 * @returns STATUS_NOT_SUPPORTED
397 * @param pDevObj Device object.
398 * @param pIrp IRP.
399 */
400NTSTATUS _stdcall VBoxDrvNtNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
401{
402 dprintf(("VBoxDrvNtNotSupportedStub\n"));
403 pDevObj = pDevObj;
404
405 pIrp->IoStatus.Information = 0;
406 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
407 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
408
409 return STATUS_NOT_SUPPORTED;
410}
411
412
413/**
414 * Initializes any OS specific object creator fields.
415 */
416void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
417{
418 NOREF(pObj);
419 NOREF(pSession);
420}
421
422
423/**
424 * Checks if the session can access the object.
425 *
426 * @returns true if a decision has been made.
427 * @returns false if the default access policy should be applied.
428 *
429 * @param pObj The object in question.
430 * @param pSession The session wanting to access the object.
431 * @param pszObjName The object name, can be NULL.
432 * @param prc Where to store the result when returning true.
433 */
434bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
435{
436 NOREF(pObj);
437 NOREF(pSession);
438 NOREF(pszObjName);
439 NOREF(prc);
440 return false;
441}
442
443
444#ifndef USE_NEW_OS_INTERFACE_FOR_MM
445
446/**
447 * OS Specific code for locking down memory.
448 *
449 * @returns 0 on success.
450 * @returns SUPDRV_ERR_* on failure.
451 * @param pMem Pointer to memory.
452 * This is not linked in anywhere.
453 * @param paPages Array which should be filled with the address of the physical pages.
454 */
455int VBOXCALL supdrvOSLockMemOne(PSUPDRVMEMREF pMem, PSUPPAGE paPages)
456{
457 /* paranoia */
458 if (!pMem->cb)
459 {
460 AssertMsgFailed(("Fool! No memory to lock!\n"));
461 return SUPDRV_ERR_INVALID_PARAM;
462 }
463 Assert(RT_ALIGN(pMem->cb, PAGE_SIZE) == pMem->cb);
464
465 /*
466 * Calc the number of MDLs we need to allocate.
467 */
468 unsigned cMdls = pMem->cb / MAX_LOCK_MEM_SIZE;
469 if ((pMem->cb % MAX_LOCK_MEM_SIZE) > 0)
470 cMdls++;
471
472 /*
473 * Allocate memory for the MDL pointer array.
474 */
475 pMem->u.locked.papMdl = (PMDL *)ExAllocatePoolWithTag(NonPagedPool, sizeof(*pMem->u.locked.papMdl) * cMdls, SUPDRV_NT_POOL_TAG);
476 if (!pMem->u.locked.papMdl)
477 {
478 AssertMsgFailed(("shit, couldn't allocated %d bytes for the mdl pointer array!\n", sizeof(*pMem->u.locked.papMdl) * cMdls));
479 return SUPDRV_ERR_NO_MEMORY;
480 }
481
482 /*
483 * Loop locking down the sub parts of the memory.
484 */
485 PSUPPAGE pPage = paPages;
486 unsigned cbTotal = 0;
487 uint8_t *pu8 = (uint8_t *)pMem->pvR3;
488 for (unsigned i = 0; i < cMdls; i++)
489 {
490 /*
491 * Calc the number of bytes to lock this time.
492 */
493 unsigned cbCur = pMem->cb - cbTotal;
494 if (cbCur > MAX_LOCK_MEM_SIZE)
495 cbCur = MAX_LOCK_MEM_SIZE;
496
497 if (cbCur == 0)
498 AssertMsgFailed(("cbCur: 0!\n"));
499
500 /*
501 * Allocate pMdl.
502 */
503 PMDL pMdl = IoAllocateMdl(pu8, cbCur, FALSE, FALSE, NULL);
504 if (!pMdl)
505 {
506 AssertMsgFailed(("Ops! IoAllocateMdl failed for pu8=%p and cb=%d\n", pu8, cbCur));
507 return SUPDRV_ERR_NO_MEMORY;
508 }
509
510 /*
511 * Lock the pages.
512 */
513 NTSTATUS rc = STATUS_SUCCESS;
514 __try
515 {
516 MmProbeAndLockPages(pMdl, UserMode, IoModifyAccess);
517 }
518 __except(EXCEPTION_EXECUTE_HANDLER)
519 {
520 rc = GetExceptionCode();
521 dprintf(("supdrvOSLockMemOne: Exception Code %#x\n", rc));
522 }
523
524 if (!NT_SUCCESS(rc))
525 {
526 /*
527 * Cleanup and fail.
528 */
529 IoFreeMdl(pMdl);
530 while (i-- > 0)
531 {
532 MmUnlockPages(pMem->u.locked.papMdl[i]);
533 IoFreeMdl(pMem->u.locked.papMdl[i]);
534 }
535 ExFreePool(pMem->u.locked.papMdl);
536 pMem->u.locked.papMdl = NULL;
537 return SUPDRV_ERR_LOCK_FAILED;
538 }
539
540 /*
541 * Add MDL to array and update the pages.
542 */
543 pMem->u.locked.papMdl[i] = pMdl;
544
545 const uintptr_t *pauPFNs = (uintptr_t *)(pMdl + 1); /* ASSUMES ULONG_PTR == uintptr_t, NTDDK4 doesn't have ULONG_PTR. */
546 for (unsigned iPage = 0, cPages = cbCur >> PAGE_SHIFT; iPage < cPages; iPage++)
547 {
548 pPage->Phys = (RTHCPHYS)pauPFNs[iPage] << PAGE_SHIFT;
549 pPage->uReserved = 0;
550 pPage++;
551 }
552
553 /* next */
554 cbTotal += cbCur;
555 pu8 += cbCur;
556 }
557
558 /*
559 * Finish structure and return succesfully.
560 */
561 pMem->u.locked.cMdls = cMdls;
562
563 dprintf2(("supdrvOSLockMemOne: pvR3=%p cb=%d cMdls=%d\n",
564 pMem->pvR3, pMem->cb, cMdls));
565 return 0;
566}
567
568
569/**
570 * Unlocks the memory pointed to by pv.
571 *
572 * @param pv Memory to unlock.
573 * @param cb Size of the memory (debug).
574 */
575void VBOXCALL supdrvOSUnlockMemOne(PSUPDRVMEMREF pMem)
576{
577 dprintf2(("supdrvOSUnlockMemOne: pvR3=%p cb=%d cMdl=%p papMdl=%p\n",
578 pMem->pvR3, pMem->cb, pMem->u.locked.cMdls, pMem->u.locked.papMdl));
579
580 for (unsigned i = 0; i < pMem->u.locked.cMdls; i++)
581 {
582 MmUnlockPages(pMem->u.locked.papMdl[i]);
583 IoFreeMdl(pMem->u.locked.papMdl[i]);
584 }
585
586 ExFreePool(pMem->u.locked.papMdl);
587 pMem->u.locked.papMdl = NULL;
588}
589
590
591/**
592 * OS Specific code for allocating page aligned memory with continuous fixed
593 * physical paged backing.
594 *
595 * @returns 0 on success.
596 * @returns SUPDRV_ERR_* on failure.
597 * @param pMem Memory reference record of the memory to be allocated.
598 * (This is not linked in anywhere.)
599 * @param ppvR0 Where to store the virtual address of the ring-0 mapping. (optional)
600 * @param ppvR3 Where to store the virtual address of the ring-3 mapping.
601 * @param pHCPhys Where to store the physical address.
602 */
603int VBOXCALL supdrvOSContAllocOne(PSUPDRVMEMREF pMem, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS pHCPhys)
604{
605 Assert(ppvR3);
606 Assert(pHCPhys);
607
608 /*
609 * Try allocate the memory.
610 */
611 PHYSICAL_ADDRESS Phys;
612 Phys.HighPart = 0;
613 Phys.LowPart = ~0;
614 unsigned cbAligned = RT_ALIGN(pMem->cb, PAGE_SIZE);
615 pMem->pvR0 = MmAllocateContiguousMemory(cbAligned, Phys);
616 if (!pMem->pvR0)
617 return SUPDRV_ERR_NO_MEMORY;
618
619 /*
620 * Map into user space.
621 */
622 int rc = SUPDRV_ERR_NO_MEMORY;
623 pMem->u.cont.pMdl = IoAllocateMdl(pMem->pvR0, cbAligned, FALSE, FALSE, NULL);
624 if (pMem->u.cont.pMdl)
625 {
626 MmBuildMdlForNonPagedPool(pMem->u.cont.pMdl);
627 __try
628 {
629 pMem->pvR3 = (RTR3PTR)MmMapLockedPagesSpecifyCache(pMem->u.cont.pMdl, UserMode, MmCached, NULL, FALSE, NormalPagePriority);
630 if (pMem->pvR3)
631 {
632 /*
633 * Done, setup pMem and return values.
634 */
635#ifdef RT_ARCH_AMD64
636 MmProtectMdlSystemAddress(pMem->u.cont.pMdl, PAGE_EXECUTE_READWRITE);
637#endif
638 *ppvR3 = pMem->pvR3;
639 if (ppvR0)
640 *ppvR0 = pMem->pvR0;
641 const uintptr_t *pauPFNs = (const uintptr_t *)(pMem->u.cont.pMdl + 1); /* ASSUMES ULONG_PTR == uintptr_t, NTDDK4 doesn't have ULONG_PTR. */
642 *pHCPhys = (RTHCPHYS)pauPFNs[0] << PAGE_SHIFT;
643 dprintf2(("supdrvOSContAllocOne: pvR0=%p pvR3=%p cb=%d pMdl=%p *pHCPhys=%VHp\n",
644 pMem->pvR0, pMem->pvR3, pMem->cb, pMem->u.mem.pMdl, *pHCPhys));
645 return 0;
646 }
647 }
648 __except(EXCEPTION_EXECUTE_HANDLER)
649 {
650 NTSTATUS rc = GetExceptionCode();
651 dprintf(("supdrvOSContAllocOne: Exception Code %#x\n", rc));
652 }
653 IoFreeMdl(pMem->u.cont.pMdl);
654 rc = SUPDRV_ERR_LOCK_FAILED;
655 }
656 MmFreeContiguousMemory(pMem->pvR0);
657 pMem->pvR0 = NULL;
658 return rc;
659}
660
661
662/**
663 * Frees contiguous memory.
664 *
665 * @param pMem Memory reference record of the memory to be freed.
666 */
667void VBOXCALL supdrvOSContFreeOne(PSUPDRVMEMREF pMem)
668{
669 __try
670 {
671 dprintf2(("supdrvOSContFreeOne: pvR0=%p pvR3=%p cb=%d pMdl=%p\n",
672 pMem->pvR0, pMem->pvR3, pMem->cb, pMem->u.cont.pMdl));
673 if (pMem->pvR3)
674 {
675 MmUnmapLockedPages((void *)pMem->pvR3, pMem->u.cont.pMdl);
676 dprintf2(("MmUnmapLockedPages ok!\n"));
677 pMem->pvR3 = NULL;
678 }
679
680 IoFreeMdl(pMem->u.cont.pMdl);
681 dprintf2(("IoFreeMdl ok!\n"));
682 pMem->u.cont.pMdl = NULL;
683
684 MmFreeContiguousMemory(pMem->pvR0);
685 dprintf2(("MmFreeContiguousMemory ok!\n"));
686 pMem->pvR0 = NULL;
687 }
688 __except(EXCEPTION_EXECUTE_HANDLER)
689 {
690 NTSTATUS rc = GetExceptionCode();
691 dprintf(("supdrvOSContFreeOne: Exception Code %#x\n", rc));
692 }
693}
694
695
696/**
697 * Allocates memory which mapped into both kernel and user space.
698 * The returned memory is page aligned and so is the allocation.
699 *
700 * @returns 0 on success.
701 * @returns SUPDRV_ERR_* on failure.
702 * @param pMem Memory reference record of the memory to be allocated.
703 * (This is not linked in anywhere.)
704 * @param ppvR0 Where to store the address of the Ring-0 mapping.
705 * @param ppvR3 Where to store the address of the Ring-3 mapping.
706 */
707int VBOXCALL supdrvOSMemAllocOne(PSUPDRVMEMREF pMem, PRTR0PTR ppvR0, PRTR3PTR ppvR3)
708{
709 Assert(ppvR0);
710 Assert(ppvR3);
711
712 /*
713 * Try allocate the memory.
714 */
715 unsigned cbAligned = RT_ALIGN(RT_MAX(pMem->cb, PAGE_SIZE * 2), PAGE_SIZE);
716 pMem->pvR0 = ExAllocatePoolWithTag(NonPagedPool, cbAligned, SUPDRV_NT_POOL_TAG);
717 if (!pMem->pvR0)
718 return SUPDRV_ERR_NO_MEMORY;
719
720 /*
721 * Map into user space.
722 */
723 int rc = SUPDRV_ERR_NO_MEMORY;
724 pMem->u.mem.pMdl = IoAllocateMdl(pMem->pvR0, cbAligned, FALSE, FALSE, NULL);
725 if (pMem->u.mem.pMdl)
726 {
727 MmBuildMdlForNonPagedPool(pMem->u.mem.pMdl);
728 __try
729 {
730 pMem->pvR3 = (RTR3PTR)MmMapLockedPagesSpecifyCache(pMem->u.mem.pMdl, UserMode, MmCached, NULL, FALSE, NormalPagePriority);
731 if (pMem->pvR3)
732 {
733 /*
734 * Done, setup pMem and return values.
735 */
736 *ppvR3 = pMem->pvR3;
737 *ppvR0 = pMem->pvR0;
738 dprintf2(("supdrvOSContAllocOne: pvR0=%p pvR3=%p cb=%d pMdl=%p\n",
739 pMem->pvR0, pMem->pvR3, pMem->cb, pMem->u.mem.pMdl));
740 return 0;
741 }
742 }
743 __except(EXCEPTION_EXECUTE_HANDLER)
744 {
745 NTSTATUS rc = GetExceptionCode();
746 dprintf(("supdrvOSContAllocOne: Exception Code %#x\n", rc));
747 }
748 rc = SUPDRV_ERR_LOCK_FAILED;
749
750 IoFreeMdl(pMem->u.mem.pMdl);
751 pMem->u.mem.pMdl = NULL;
752 pMem->pvR3 = NULL;
753 }
754
755 MmFreeContiguousMemory(pMem->pvR0);
756 pMem->pvR0 = NULL;
757 return rc;
758}
759
760
761/**
762 * Get the physical addresses of the pages in the allocation.
763 * This is called while inside bundle the spinlock.
764 *
765 * @param pMem Memory reference record of the memory.
766 * @param paPages Where to store the page addresses.
767 */
768void VBOXCALL supdrvOSMemGetPages(PSUPDRVMEMREF pMem, PSUPPAGE paPages)
769{
770 const unsigned cPages = RT_ALIGN(pMem->cb, PAGE_SIZE) >> PAGE_SHIFT;
771 const uintptr_t *pauPFNs = (const uintptr_t *)(pMem->u.mem.pMdl + 1); /* ASSUMES ULONG_PTR == uintptr_t, NTDDK doesn't have ULONG_PTR. */
772 for (unsigned iPage = 0; iPage < cPages; iPage++)
773 {
774 paPages[iPage].Phys = (RTHCPHYS)pauPFNs[iPage] << PAGE_SHIFT;
775 paPages[iPage].uReserved = 0;
776 }
777}
778
779
780/**
781 * Frees memory allocated by supdrvOSMemAllocOne().
782 *
783 * @param pMem Memory reference record of the memory to be free.
784 */
785void VBOXCALL supdrvOSMemFreeOne(PSUPDRVMEMREF pMem)
786{
787 __try
788 {
789 dprintf2(("supdrvOSContFreeOne: pvR0=%p pvR3=%p cb=%d pMdl=%p\n",
790 pMem->pvR0, pMem->pvR3, pMem->cb, pMem->u.mem.pMdl));
791 if (pMem->pvR3)
792 {
793 MmUnmapLockedPages((void *)pMem->pvR3, pMem->u.mem.pMdl);
794 pMem->pvR3 = NULL;
795 dprintf2(("MmUnmapLockedPages ok!\n"));
796 }
797
798 IoFreeMdl(pMem->u.mem.pMdl);
799 pMem->u.mem.pMdl = NULL;
800 dprintf2(("IoFreeMdl ok!\n"));
801
802 ExFreePool(pMem->pvR0);
803 pMem->pvR0 = NULL;
804 dprintf2(("MmFreeContiguousMemory ok!\n"));
805 }
806 __except(EXCEPTION_EXECUTE_HANDLER)
807 {
808 NTSTATUS rc = GetExceptionCode();
809 dprintf(("supdrvOSContFreeOne: Exception Code %#x\n", rc));
810 }
811}
812
813#endif /* !USE_NEW_OS_INTERFACE_FOR_MM */
814
815
816/**
817 * Gets the monotone timestamp (nano seconds).
818 * @returns NanoTS.
819 */
820static inline uint64_t supdrvOSMonotime(void)
821{
822 return (uint64_t)KeQueryInterruptTime() * 100;
823}
824
825
826/**
827 * Initializes the GIP.
828 *
829 * @returns NT status code.
830 * @param pDevExt Instance data. GIP stuff may be updated.
831 */
832static NTSTATUS VBoxDrvNtGipInit(PSUPDRVDEVEXT pDevExt)
833{
834 dprintf2(("VBoxSupDrvTermGip:\n"));
835
836 /*
837 * Try allocate the memory.
838 * Make sure it's below 4GB for 32-bit GC support
839 */
840 NTSTATUS rc;
841 PHYSICAL_ADDRESS Phys;
842 Phys.HighPart = 0;
843 Phys.LowPart = ~0;
844 PSUPGLOBALINFOPAGE pGip = (PSUPGLOBALINFOPAGE)MmAllocateContiguousMemory(PAGE_SIZE, Phys);
845 if (pGip)
846 {
847 if (!((uintptr_t)pGip & (PAGE_SIZE - 1)))
848 {
849 pDevExt->pGipMdl = IoAllocateMdl(pGip, PAGE_SIZE, FALSE, FALSE, NULL);
850 if (pDevExt->pGipMdl)
851 {
852 MmBuildMdlForNonPagedPool(pDevExt->pGipMdl);
853
854 /*
855 * Figure the timer interval and frequency.
856 * It turns out trying 1023Hz doesn't work. So, we'll set the max Hz at 128 for now.
857 */
858 ExSetTimerResolution(156250, TRUE);
859 ULONG ulClockIntervalActual = ExSetTimerResolution(0, FALSE);
860 ULONG ulClockInterval = RT_MAX(ulClockIntervalActual, 78125); /* 1/128 */
861 ULONG ulClockFreq = 10000000 / ulClockInterval;
862 pDevExt->ulGipTimerInterval = ulClockInterval / 10000; /* ms */
863
864 /*
865 * Call common initialization routine.
866 */
867 Phys = MmGetPhysicalAddress(pGip); /* could perhaps use the Mdl, not that it looks much better */
868 supdrvGipInit(pDevExt, pGip, (RTHCPHYS)Phys.QuadPart, supdrvOSMonotime(), ulClockFreq);
869
870 /*
871 * Initialize the timer.
872 */
873 KeInitializeTimerEx(&pDevExt->GipTimer, SynchronizationTimer);
874 KeInitializeDpc(&pDevExt->GipDpc, VBoxDrvNtGipTimer, pDevExt);
875
876 /*
877 * Initialize the DPCs we're using to update the per-cpu GIP data.
878 * (Not sure if we need to be this careful with KeSetTargetProcessorDpc...)
879 */
880 UNICODE_STRING RoutineName;
881 RtlInitUnicodeString(&RoutineName, L"KeSetTargetProcessorDpc");
882 VOID (*pfnKeSetTargetProcessorDpc)(IN PRKDPC, IN CCHAR) = (VOID (*)(IN PRKDPC, IN CCHAR))MmGetSystemRoutineAddress(&RoutineName);
883
884 for (unsigned i = 0; i < RT_ELEMENTS(pDevExt->aGipCpuDpcs); i++)
885 {
886 KeInitializeDpc(&pDevExt->aGipCpuDpcs[i], VBoxDrvNtGipPerCpuDpc, pGip);
887 KeSetImportanceDpc(&pDevExt->aGipCpuDpcs[i], HighImportance);
888 if (pfnKeSetTargetProcessorDpc)
889 pfnKeSetTargetProcessorDpc(&pDevExt->aGipCpuDpcs[i], i);
890 }
891
892 dprintf(("VBoxDrvNtGipInit: ulClockFreq=%ld ulClockInterval=%ld ulClockIntervalActual=%ld Phys=%x%08x\n",
893 ulClockFreq, ulClockInterval, ulClockIntervalActual, Phys.HighPart, Phys.LowPart));
894 return STATUS_SUCCESS;
895 }
896
897 dprintf(("VBoxSupDrvInitGip: IoAllocateMdl failed for %p/PAGE_SIZE\n", pGip));
898 rc = STATUS_NO_MEMORY;
899 }
900 else
901 {
902 dprintf(("VBoxSupDrvInitGip: GIP memory is not page aligned! pGip=%p\n", pGip));
903 rc = STATUS_INVALID_ADDRESS;
904 }
905 MmFreeContiguousMemory(pGip);
906 }
907 else
908 {
909 dprintf(("VBoxSupDrvInitGip: no cont memory.\n"));
910 rc = STATUS_NO_MEMORY;
911 }
912 return rc;
913}
914
915
916/**
917 * Terminates the GIP.
918 *
919 * @returns negative errno.
920 * @param pDevExt Instance data. GIP stuff may be updated.
921 */
922static void VBoxDrvNtGipTerm(PSUPDRVDEVEXT pDevExt)
923{
924 dprintf(("VBoxSupDrvTermGip:\n"));
925 PSUPGLOBALINFOPAGE pGip;
926
927 /*
928 * Cancel the timer and wait on DPCs if it was still pending.
929 */
930 if (KeCancelTimer(&pDevExt->GipTimer))
931 {
932 UNICODE_STRING RoutineName;
933 RtlInitUnicodeString(&RoutineName, L"KeFlushQueuedDpcs");
934 VOID (*pfnKeFlushQueuedDpcs)(VOID) = (VOID (*)(VOID))MmGetSystemRoutineAddress(&RoutineName);
935 if (pfnKeFlushQueuedDpcs)
936 pfnKeFlushQueuedDpcs();
937 }
938
939 /*
940 * Uninitialize the content.
941 */
942 pGip = pDevExt->pGip;
943 pDevExt->pGip = NULL;
944 if (pGip)
945 {
946 supdrvGipTerm(pGip);
947
948 /*
949 * Free the page.
950 */
951 if (pDevExt->pGipMdl)
952 {
953 IoFreeMdl(pDevExt->pGipMdl);
954 pDevExt->pGipMdl = NULL;
955 }
956 MmFreeContiguousMemory(pGip);
957 }
958}
959
960
961/**
962 * Timer callback function.
963 * The pvUser parameter is the pDevExt pointer.
964 */
965static void _stdcall VBoxDrvNtGipTimer(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
966{
967 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
968 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
969 if (pGip)
970 {
971 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
972 supdrvGipUpdate(pGip, supdrvOSMonotime());
973 else
974 {
975 RTCCUINTREG xFL = ASMGetFlags();
976 ASMIntDisable();
977
978 /*
979 * We cannot do other than assume a 1:1 relation ship between the
980 * affinity mask and the process despite the warnings in the docs.
981 * If someone knows a better way to get this done, please let bird know.
982 */
983 unsigned iSelf = KeGetCurrentProcessorNumber();
984 KAFFINITY Mask = KeQueryActiveProcessors();
985
986 for (unsigned i = 0; i < RT_ELEMENTS(pDevExt->aGipCpuDpcs); i++)
987 {
988 if ( i != iSelf
989 && (Mask & RT_BIT_64(i)))
990 KeInsertQueueDpc(&pDevExt->aGipCpuDpcs[i], 0, 0);
991 }
992
993 /* Run the normal update. */
994 supdrvGipUpdate(pGip, supdrvOSMonotime());
995
996 ASMSetFlags(xFL);
997 }
998 }
999}
1000
1001
1002/**
1003 * Per cpu callback callback function.
1004 * The pvUser parameter is the pGip pointer.
1005 */
1006static void _stdcall VBoxDrvNtGipPerCpuDpc(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
1007{
1008 PSUPGLOBALINFOPAGE pGip = (PSUPGLOBALINFOPAGE)pvUser;
1009 supdrvGipUpdatePerCpu(pGip, supdrvOSMonotime(), ASMGetApicId());
1010}
1011
1012
1013/**
1014 * Maps the GIP into user space.
1015 *
1016 * @returns negative errno.
1017 * @param pDevExt Instance data.
1018 */
1019int VBOXCALL supdrvOSGipMap(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE *ppGip)
1020{
1021 dprintf2(("supdrvOSGipMap: ppGip=%p (pDevExt->pGipMdl=%p)\n", ppGip, pDevExt->pGipMdl));
1022
1023 /*
1024 * Map into user space.
1025 */
1026 int rc = 0;
1027 void *pv = NULL;
1028 __try
1029 {
1030 *ppGip = (PSUPGLOBALINFOPAGE)MmMapLockedPagesSpecifyCache(pDevExt->pGipMdl, UserMode, MmCached, NULL, FALSE, NormalPagePriority);
1031 }
1032 __except(EXCEPTION_EXECUTE_HANDLER)
1033 {
1034 NTSTATUS rcNt = GetExceptionCode();
1035 dprintf(("supdrvOsGipMap: Exception Code %#x\n", rcNt));
1036 rc = SUPDRV_ERR_LOCK_FAILED;
1037 }
1038
1039 dprintf2(("supdrvOSGipMap: returns %d, *ppGip=%p\n", rc, *ppGip));
1040 return 0;
1041}
1042
1043
1044/**
1045 * Maps the GIP into user space.
1046 *
1047 * @returns negative errno.
1048 * @param pDevExt Instance data.
1049 */
1050int VBOXCALL supdrvOSGipUnmap(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip)
1051{
1052 dprintf2(("supdrvOSGipUnmap: pGip=%p (pGipMdl=%p)\n", pGip, pDevExt->pGipMdl));
1053
1054 int rc = 0;
1055 __try
1056 {
1057 MmUnmapLockedPages((void *)pGip, pDevExt->pGipMdl);
1058 }
1059 __except(EXCEPTION_EXECUTE_HANDLER)
1060 {
1061 NTSTATUS rcNt = GetExceptionCode();
1062 dprintf(("supdrvOSGipUnmap: Exception Code %#x\n", rcNt));
1063 rc = SUPDRV_ERR_GENERAL_FAILURE;
1064 }
1065 dprintf2(("supdrvOSGipUnmap: returns %d\n", rc));
1066 return rc;
1067}
1068
1069
1070/**
1071 * Resumes the GIP updating.
1072 *
1073 * @param pDevExt Instance data.
1074 */
1075void VBOXCALL supdrvOSGipResume(PSUPDRVDEVEXT pDevExt)
1076{
1077 dprintf2(("supdrvOSGipResume:\n"));
1078 LARGE_INTEGER DueTime;
1079 DueTime.QuadPart = -10000; /* 1ms, relative */
1080 KeSetTimerEx(&pDevExt->GipTimer, DueTime, pDevExt->ulGipTimerInterval, &pDevExt->GipDpc);
1081}
1082
1083
1084/**
1085 * Suspends the GIP updating.
1086 *
1087 * @param pDevExt Instance data.
1088 */
1089void VBOXCALL supdrvOSGipSuspend(PSUPDRVDEVEXT pDevExt)
1090{
1091 dprintf2(("supdrvOSGipSuspend:\n"));
1092 KeCancelTimer(&pDevExt->GipTimer);
1093#ifdef RT_ARCH_AMD64
1094 ExSetTimerResolution(0, FALSE);
1095#endif
1096}
1097
1098
1099#ifndef USE_NEW_OS_INTERFACE_FOR_MM
1100
1101/**
1102 * Allocate small amounts of memory which is does not have the NX bit set.
1103 *
1104 * @returns Pointer to the allocated memory
1105 * @returns NULL if out of memory.
1106 * @param cb Size of the memory block.
1107 */
1108void *VBOXCALL supdrvOSExecAlloc(size_t cb)
1109{
1110#if 0 //def RT_ARCH_AMD64
1111 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
1112 void *pv = ExAllocatePoolWithTag(NonPagedPool, cb, SUPDRV_NT_POOL_TAG);
1113 if (pv)
1114 {
1115 /*
1116 * Create a kernel mapping which we make PAGE_EXECUTE_READWRITE using
1117 * the MmProtectMdlSystemAddress API.
1118 */
1119 int rc = SUPDRV_ERR_NO_MEMORY;
1120 PMDL pMdl = IoAllocateMdl(pv, cb, FALSE, FALSE, NULL);
1121 if (pMdl)
1122 {
1123 MmBuildMdlForNonPagedPool(pMdl);
1124 __try
1125 {
1126 void *pvMapping = MmMapLockedPagesSpecifyCache(pMdl, KernelMode, MmCached, NULL, FALSE, NormalPagePriority);
1127 if (pvMapping)
1128 {
1129 NTSTATUS rc = MmProtectMdlSystemAddress(pMdl, PAGE_EXECUTE_READWRITE);
1130 if (NT_SUCCESS(rc))
1131 {
1132 /*
1133 * Create tracking structure and insert it into the list.
1134 */
1135
1136
1137 return pvMapping;
1138 }
1139
1140 MmUnmapLockedPages(pvMapping, pMdl);
1141 }
1142 }
1143 __except(EXCEPTION_EXECUTE_HANDLER)
1144 {
1145 NTSTATUS rc = GetExceptionCode();
1146 dprintf(("supdrvOSExecAlloc: Exception Code %#x\n", rc));
1147 }
1148 IoFreeMdl(pMem->u.mem.pMdl);
1149 }
1150 ExFreePool(pv);
1151 }
1152 dprintf2(("supdrvOSExecAlloc(%d): returns NULL\n", cb));
1153 return NULL;
1154#else
1155 void *pv = ExAllocatePoolWithTag(NonPagedPool, cb, SUPDRV_NT_POOL_TAG);
1156 dprintf2(("supdrvOSExecAlloc(%d): returns %p\n", cb, pv));
1157 return pv;
1158#endif
1159}
1160
1161#endif /* !USE_NEW_OS_INTERFACE_FOR_MM */
1162
1163
1164/**
1165 * Get the current CPU count.
1166 * @returns Number of cpus.
1167 */
1168unsigned VBOXCALL supdrvOSGetCPUCount(void)
1169{
1170 KAFFINITY Mask = KeQueryActiveProcessors();
1171 unsigned cCpus = 0;
1172 unsigned iBit;
1173 for (iBit = 0; iBit < sizeof(Mask) * 8; iBit++)
1174 if (Mask & RT_BIT_64(iBit))
1175 cCpus++;
1176 if (cCpus == 0) /* paranoia */
1177 cCpus = 1;
1178 return cCpus;
1179}
1180
1181
1182/**
1183 * Force async tsc mode (stub).
1184 */
1185bool VBOXCALL supdrvOSGetForcedAsyncTscMode(void)
1186{
1187 return false;
1188}
1189
1190
1191/**
1192 * Converts a supdrv error code to an nt status code.
1193 *
1194 * @returns corresponding nt status code.
1195 * @param rc supdrv error code (SUPDRV_ERR_* defines).
1196 */
1197static NTSTATUS VBoxDrvNtErr2NtStatus(int rc)
1198{
1199 switch (rc)
1200 {
1201 case 0: return STATUS_SUCCESS;
1202 case SUPDRV_ERR_GENERAL_FAILURE: return STATUS_NOT_SUPPORTED;
1203 case SUPDRV_ERR_INVALID_PARAM: return STATUS_INVALID_PARAMETER;
1204 case SUPDRV_ERR_INVALID_MAGIC: return STATUS_UNKNOWN_REVISION;
1205 case SUPDRV_ERR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;
1206 case SUPDRV_ERR_INVALID_POINTER: return STATUS_INVALID_ADDRESS;
1207 case SUPDRV_ERR_LOCK_FAILED: return STATUS_NOT_LOCKED;
1208 case SUPDRV_ERR_ALREADY_LOADED: return STATUS_IMAGE_ALREADY_LOADED;
1209 case SUPDRV_ERR_PERMISSION_DENIED: return STATUS_ACCESS_DENIED;
1210 case SUPDRV_ERR_VERSION_MISMATCH: return STATUS_REVISION_MISMATCH;
1211 }
1212
1213 return STATUS_UNSUCCESSFUL;
1214}
1215
1216
1217/** Runtime assert implementation for Native Win32 Ring-0. */
1218RTDECL(void) AssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
1219{
1220 DbgPrint("\n!!Assertion Failed!!\n"
1221 "Expression: %s\n"
1222 "Location : %s(%d) %s\n",
1223 pszExpr, pszFile, uLine, pszFunction);
1224}
1225
1226int VBOXCALL mymemcmp(const void *pv1, const void *pv2, size_t cb)
1227{
1228 const uint8_t *pb1 = (const uint8_t *)pv1;
1229 const uint8_t *pb2 = (const uint8_t *)pv2;
1230 for (; cb > 0; cb--, pb1++, pb2++)
1231 if (*pb1 != *pb2)
1232 return *pb1 - *pb2;
1233 return 0;
1234}
1235
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