VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/win32/SUPDrv-win32.cpp@ 382

Last change on this file since 382 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.0 KB
Line 
1/** @file
2 *
3 * VBox host drivers - Ring-0 support drivers - Win32 host:
4 * Win32 host driver code
5 */
6
7/*
8 * Copyright (C) 2006 InnoTek Systemberatung GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23
24
25/*******************************************************************************
26* Header Files *
27*******************************************************************************/
28#include "SUPDRV.h"
29#include <excpt.h>
30#include <iprt/assert.h>
31
32
33/*******************************************************************************
34* Defined Constants And Macros *
35*******************************************************************************/
36/** The support service name. */
37#define SERVICE_NAME "VBoxDrv"
38/** Win32 Device name. */
39#define DEVICE_NAME "\\\\.\\VBoxDrv"
40/** NT Device name. */
41#define DEVICE_NAME_NT L"\\Device\\VBoxDrv"
42/** Win32 Symlink name. */
43#define DEVICE_NAME_DOS L"\\DosDevices\\VBoxDrv"
44
45
46/*******************************************************************************
47* Structures and Typedefs *
48*******************************************************************************/
49#if 0 //def __AMD64__
50typedef struct SUPDRVEXECMEM
51{
52 PMDL pMdl;
53 void *pvMapping;
54 void *pvAllocation;
55} SUPDRVEXECMEM, *PSUPDRVEXECMEM;
56#endif
57
58
59/*******************************************************************************
60* Internal Functions *
61*******************************************************************************/
62static void _stdcall VBoxSupDrvUnload(PDRIVER_OBJECT pDrvObj);
63static NTSTATUS _stdcall VBoxSupDrvCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
64static NTSTATUS _stdcall VBoxSupDrvClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
65static NTSTATUS _stdcall VBoxSupDrvDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp);
66static NTSTATUS _stdcall VBoxSupDrvNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp);
67static NTSTATUS VBoxSupDrvErr2NtStatus(int rc);
68static NTSTATUS VBoxSupDrvGipInit(PSUPDRVDEVEXT pDevExt);
69static void VBoxSupDrvGipTerm(PSUPDRVDEVEXT pDevExt);
70static void _stdcall VBoxSupDrvGipTimer(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 appropritate 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 = VBoxSupDrvGipInit(pDevExt);
121 if (NT_SUCCESS(rc))
122 {
123 /*
124 * Setup the driver entry points in pDrvObj.
125 */
126 pDrvObj->DriverUnload = VBoxSupDrvUnload;
127 pDrvObj->MajorFunction[IRP_MJ_CREATE] = VBoxSupDrvCreate;
128 pDrvObj->MajorFunction[IRP_MJ_CLOSE] = VBoxSupDrvClose;
129 pDrvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VBoxSupDrvDeviceControl;
130 pDrvObj->MajorFunction[IRP_MJ_READ] = VBoxSupDrvNotSupportedStub;
131 pDrvObj->MajorFunction[IRP_MJ_WRITE] = VBoxSupDrvNotSupportedStub;
132 /* more? */
133 dprintf(("VBoxDrv::DriverEntry returning STATUS_SUCCESS\n"));
134 return STATUS_SUCCESS;
135 }
136 else
137 dprintf(("VBoxSupDrvGipInit failed with rc=%#x!\n", rc));
138 supdrvDeleteDevExt(pDevExt);
139 }
140 else
141 {
142 dprintf(("supdrvInitDevExit failed with vrc=%d!\n", vrc));
143 rc = VBoxSupDrvErr2NtStatus(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 VBoxSupDrvUnload(PDRIVER_OBJECT pDrvObj)
169{
170 dprintf(("VBoxSupDrvUnload\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 VBoxSupDrvGipTerm(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 VBoxSupDrvCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
197{
198 dprintf(("VBoxSupDrvCreate\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 = NIL_RTPROCESS;
226 pFileObj->FsContext = pSession;
227 }
228
229 NTSTATUS rcNt = pIrp->IoStatus.Status = VBoxSupDrvErr2NtStatus(rc);
230 pIrp->IoStatus.Information = 0;
231 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
232
233 return rcNt;
234}
235
236
237/**
238 * Close file entry point.
239 *
240 * @param pDevObj Device object.
241 * @param pIrp Request packet.
242 */
243NTSTATUS _stdcall VBoxSupDrvClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
244{
245 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
246 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
247 PFILE_OBJECT pFileObj = pStack->FileObject;
248 dprintf(("VBoxSupDrvClose: pDevExt=%p pFileObj=%p pSession=%p\n",
249 pDevExt, pFileObj, pFileObj->FsContext));
250 supdrvCloseSession(pDevExt, (PSUPDRVSESSION)pFileObj->FsContext);
251 pFileObj->FsContext = NULL;
252 pIrp->IoStatus.Information = 0;
253 pIrp->IoStatus.Status = STATUS_SUCCESS;
254 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
255
256 return STATUS_SUCCESS;
257}
258
259
260/**
261 * Device I/O Control entry point.
262 *
263 * @param pDevObj Device object.
264 * @param pIrp Request packet.
265 */
266NTSTATUS _stdcall VBoxSupDrvDeviceControl(PDEVICE_OBJECT pDevObj, PIRP pIrp)
267{
268 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pDevObj->DeviceExtension;
269 PIO_STACK_LOCATION pStack = IoGetCurrentIrpStackLocation(pIrp);
270 PSUPDRVSESSION pSession = (PSUPDRVSESSION)pStack->FileObject->FsContext;
271 char *pBuf = (char *)pIrp->AssociatedIrp.SystemBuffer; /* all requests are buffered. */
272 unsigned cbOut = 0;
273 dprintf2(("VBoxSupDrvDeviceControl(%p,%p): ioctl=%#x pBuf=%p cbIn=%#x cbOut=%#x pSession=%p\n",
274 pDevObj, pIrp, pStack->Parameters.DeviceIoControl.IoControlCode,
275 pBuf, pStack->Parameters.DeviceIoControl.InputBufferLength,
276 pStack->Parameters.DeviceIoControl.OutputBufferLength, pSession));
277
278#ifdef __WIN64__
279 /*
280 * Don't allow 32-bit processes to do any I/O controls.
281 */
282 if (IoIs32bitProcess(pIrp))
283 {
284 dprintf(("VBoxSupDrvDeviceControl: returns STATUS_NOT_SUPPORTED - WOW64 req\n"));
285 return STATUS_NOT_SUPPORTED;
286 }
287#endif
288
289 int rc = supdrvIOCtl(pStack->Parameters.DeviceIoControl.IoControlCode, pDevExt, pSession,
290 pBuf, pStack->Parameters.DeviceIoControl.InputBufferLength,
291 pBuf, pStack->Parameters.DeviceIoControl.OutputBufferLength,
292 &cbOut);
293
294 /* sanity check. */
295 AssertMsg(cbOut <= pStack->Parameters.DeviceIoControl.OutputBufferLength,
296 ("cbOut is too large! cbOut=%d max=%d! ioctl=%#x\n",
297 cbOut, pStack->Parameters.DeviceIoControl.OutputBufferLength,
298 pStack->Parameters.DeviceIoControl.IoControlCode));
299 if (cbOut > pStack->Parameters.DeviceIoControl.OutputBufferLength)
300 cbOut = pStack->Parameters.DeviceIoControl.OutputBufferLength;
301
302 /* complete the request. */
303 NTSTATUS rcNt = pIrp->IoStatus.Status = VBoxSupDrvErr2NtStatus(rc);
304 pIrp->IoStatus.Information = NT_SUCCESS(rcNt) ? cbOut : rc;
305 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
306
307 dprintf2(("VBoxSupDrvDeviceControl: returns %#x cbOut=%d rc=%#x\n", rcNt, cbOut, rc));
308 return rcNt;
309}
310
311
312/**
313 * Stub function for functions we don't implemented.
314 *
315 * @returns STATUS_NOT_SUPPORTED
316 * @param pDevObj Device object.
317 * @param pIrp IRP.
318 */
319NTSTATUS _stdcall VBoxSupDrvNotSupportedStub(PDEVICE_OBJECT pDevObj, PIRP pIrp)
320{
321 dprintf(("VBoxSupDrvNotSupportedStub\n"));
322 pDevObj = pDevObj;
323
324 pIrp->IoStatus.Information = 0;
325 pIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
326 IoCompleteRequest(pIrp, IO_NO_INCREMENT);
327
328 return STATUS_NOT_SUPPORTED;
329}
330
331
332/**
333 * Initializes any OS specific object creator fields.
334 */
335void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
336{
337 NOREF(pObj);
338 NOREF(pSession);
339}
340
341
342/**
343 * Checks if the session can access the object.
344 *
345 * @returns true if a decision has been made.
346 * @returns false if the default access policy should be applied.
347 *
348 * @param pObj The object in question.
349 * @param pSession The session wanting to access the object.
350 * @param pszObjName The object name, can be NULL.
351 * @param prc Where to store the result when returning true.
352 */
353bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
354{
355 NOREF(pObj);
356 NOREF(pSession);
357 NOREF(pszObjName);
358 NOREF(prc);
359 return false;
360}
361
362
363/**
364 * OS Specific code for locking down memory.
365 *
366 * @returns 0 on success.
367 * @returns SUPDRV_ERR_* on failure.
368 * @param pMem Pointer to memory.
369 * This is not linked in anywhere.
370 * @param paPages Array which should be filled with the address of the physical pages.
371 */
372int VBOXCALL supdrvOSLockMemOne(PSUPDRVMEMREF pMem, PSUPPAGE paPages)
373{
374 /* paranoia */
375 if (!pMem->cb)
376 {
377 AssertMsgFailed(("Fool! No memory to lock!\n"));
378 return SUPDRV_ERR_INVALID_PARAM;
379 }
380 Assert(RT_ALIGN(pMem->cb, PAGE_SIZE) == pMem->cb);
381
382 /*
383 * Calc the number of MDLs we need to allocate.
384 */
385 unsigned cMdls = pMem->cb / MAX_LOCK_MEM_SIZE;
386 if ((pMem->cb % MAX_LOCK_MEM_SIZE) > 0)
387 cMdls++;
388
389 /*
390 * Allocate memory for the MDL pointer array.
391 */
392 pMem->u.locked.papMdl = (PMDL *)ExAllocatePoolWithTag(NonPagedPool, sizeof(*pMem->u.locked.papMdl) * cMdls, 'vbox');
393 if (!pMem->u.locked.papMdl)
394 {
395 AssertMsgFailed(("shit, couldn't allocated %d bytes for the mdl pointer array!\n", sizeof(*pMem->u.locked.papMdl) * cMdls));
396 return SUPDRV_ERR_NO_MEMORY;
397 }
398
399 /*
400 * Loop locking down the sub parts of the memory.
401 */
402 PSUPPAGE pPage = paPages;
403 unsigned cbTotal = 0;
404 uint8_t *pu8 = (uint8_t *)pMem->pvR3;
405 for (unsigned i = 0; i < cMdls; i++)
406 {
407 /*
408 * Calc the number of bytes to lock this time.
409 */
410 unsigned cbCur = pMem->cb - cbTotal;
411 if (cbCur > MAX_LOCK_MEM_SIZE)
412 cbCur = MAX_LOCK_MEM_SIZE;
413
414 if (cbCur == 0)
415 AssertMsgFailed(("cbCur: 0!\n"));
416
417 /*
418 * Allocate pMdl.
419 */
420 PMDL pMdl = IoAllocateMdl(pu8, cbCur, FALSE, FALSE, NULL);
421 if (!pMdl)
422 {
423 AssertMsgFailed(("Ops! IoAllocateMdl failed for pu8=%p and cb=%d\n", pu8, cbCur));
424 return SUPDRV_ERR_NO_MEMORY;
425 }
426
427 /*
428 * Lock the pages.
429 */
430 NTSTATUS rc = STATUS_SUCCESS;
431 __try
432 {
433 MmProbeAndLockPages(pMdl, UserMode, IoModifyAccess);
434 }
435 __except(EXCEPTION_EXECUTE_HANDLER)
436 {
437 rc = GetExceptionCode();
438 dprintf(("supdrvOSLockMemOne: Exception Code %#x\n", rc));
439 }
440
441 if (!NT_SUCCESS(rc))
442 {
443 /*
444 * Cleanup and fail.
445 */
446 IoFreeMdl(pMdl);
447 while (i-- > 0)
448 {
449 MmUnlockPages(pMem->u.locked.papMdl[i]);
450 IoFreeMdl(pMem->u.locked.papMdl[i]);
451 }
452 ExFreePool(pMem->u.locked.papMdl);
453 pMem->u.locked.papMdl = NULL;
454 return SUPDRV_ERR_LOCK_FAILED;
455 }
456
457 /*
458 * Add MDL to array and update the pages.
459 */
460 pMem->u.locked.papMdl[i] = pMdl;
461
462 const uintptr_t *pauPFNs = (uintptr_t *)(pMdl + 1); /* ASSUMES ULONG_PTR == uintptr_t, NTDDK4 doesn't have ULONG_PTR. */
463 for (unsigned iPage = 0, cPages = cbCur >> PAGE_SHIFT; iPage < cPages; iPage++)
464 {
465 pPage->Phys = (RTHCPHYS)pauPFNs[iPage] << PAGE_SHIFT;
466 pPage->uReserved = 0;
467 pPage++;
468 }
469
470 /* next */
471 cbTotal += cbCur;
472 pu8 += cbCur;
473 }
474
475 /*
476 * Finish structure and return succesfully.
477 */
478 pMem->u.locked.cMdls = cMdls;
479
480 dprintf2(("supdrvOSLockMemOne: pvR3=%p cb=%d cMdls=%d\n",
481 pMem->pvR3, pMem->cb, cMdls));
482 return 0;
483}
484
485
486/**
487 * Unlocks the memory pointed to by pv.
488 *
489 * @param pv Memory to unlock.
490 * @param cb Size of the memory (debug).
491 */
492void VBOXCALL supdrvOSUnlockMemOne(PSUPDRVMEMREF pMem)
493{
494 dprintf2(("supdrvOSUnlockMemOne: pvR3=%p cb=%d cMdl=%p papMdl=%p\n",
495 pMem->pvR3, pMem->cb, pMem->u.locked.cMdls, pMem->u.locked.papMdl));
496
497 for (unsigned i = 0; i < pMem->u.locked.cMdls; i++)
498 {
499 MmUnlockPages(pMem->u.locked.papMdl[i]);
500 IoFreeMdl(pMem->u.locked.papMdl[i]);
501 }
502
503 ExFreePool(pMem->u.locked.papMdl);
504 pMem->u.locked.papMdl = NULL;
505}
506
507
508/**
509 * OS Specific code for allocating page aligned memory with continuous fixed
510 * physical paged backing.
511 *
512 * @returns 0 on success.
513 * @returns SUPDRV_ERR_* on failure.
514 * @param pMem Memory reference record of the memory to be allocated.
515 * (This is not linked in anywhere.)
516 * @param ppvR0 Where to store the virtual address of the ring-0 mapping. (optional)
517 * @param ppvR3 Where to store the virtual address of the ring-3 mapping.
518 * @param pHCPhys Where to store the physical address.
519 */
520int VBOXCALL supdrvOSContAllocOne(PSUPDRVMEMREF pMem, void **ppvR0, void **ppvR3, PRTHCPHYS pHCPhys)
521{
522 Assert(ppvR3);
523 Assert(pHCPhys);
524
525 /*
526 * Try allocate the memory.
527 */
528 PHYSICAL_ADDRESS Phys;
529 Phys.HighPart = 0;
530 Phys.LowPart = ~0;
531 unsigned cbAligned = RT_ALIGN(pMem->cb, PAGE_SIZE);
532 pMem->pvR0 = MmAllocateContiguousMemory(cbAligned, Phys);
533 if (!pMem->pvR0)
534 return SUPDRV_ERR_NO_MEMORY;
535
536 /*
537 * Map into user space.
538 */
539 int rc = SUPDRV_ERR_NO_MEMORY;
540 pMem->u.cont.pMdl = IoAllocateMdl(pMem->pvR0, cbAligned, FALSE, FALSE, NULL);
541 if (pMem->u.cont.pMdl)
542 {
543 MmBuildMdlForNonPagedPool(pMem->u.cont.pMdl);
544 __try
545 {
546 pMem->pvR3 = MmMapLockedPages(pMem->u.cont.pMdl, UserMode);
547 if (pMem->pvR3)
548 {
549 /*
550 * Done, setup pMem and return values.
551 */
552#ifdef __AMD64__
553 MmProtectMdlSystemAddress(pMem->u.cont.pMdl, PAGE_EXECUTE_READWRITE);
554#endif
555 *ppvR3 = pMem->pvR3;
556 if (ppvR0)
557 *ppvR0 = pMem->pvR0;
558 const uintptr_t *pauPFNs = (const uintptr_t *)(pMem->u.cont.pMdl + 1); /* ASSUMES ULONG_PTR == uintptr_t, NTDDK4 doesn't have ULONG_PTR. */
559 *pHCPhys = (RTHCPHYS)pauPFNs[0] << PAGE_SHIFT;
560 dprintf2(("supdrvOSContAllocOne: pvR0=%p pvR3=%p cb=%d pMdl=%p *pHCPhys=%VHp\n",
561 pMem->pvR0, pMem->pvR3, pMem->cb, pMem->u.mem.pMdl, *pHCPhys));
562 return 0;
563 }
564 }
565 __except(EXCEPTION_EXECUTE_HANDLER)
566 {
567 NTSTATUS rc = GetExceptionCode();
568 dprintf(("supdrvOSContAllocOne: Exception Code %#x\n", rc));
569 }
570 IoFreeMdl(pMem->u.cont.pMdl);
571 rc = SUPDRV_ERR_LOCK_FAILED;
572 }
573 MmFreeContiguousMemory(pMem->pvR0);
574 pMem->pvR0 = NULL;
575 return rc;
576}
577
578
579/**
580 * Frees contiguous memory.
581 *
582 * @param pMem Memory reference record of the memory to be freed.
583 */
584void VBOXCALL supdrvOSContFreeOne(PSUPDRVMEMREF pMem)
585{
586 __try
587 {
588 dprintf2(("supdrvOSContFreeOne: pvR0=%p pvR3=%p cb=%d pMdl=%p\n",
589 pMem->pvR0, pMem->pvR3, pMem->cb, pMem->u.cont.pMdl));
590 if (pMem->pvR3)
591 {
592 MmUnmapLockedPages(pMem->pvR3, pMem->u.cont.pMdl);
593 dprintf2(("MmUnmapLockedPages ok!\n"));
594 pMem->pvR3 = NULL;
595 }
596
597 IoFreeMdl(pMem->u.cont.pMdl);
598 dprintf2(("IoFreeMdl ok!\n"));
599 pMem->u.cont.pMdl = NULL;
600
601 MmFreeContiguousMemory(pMem->pvR0);
602 dprintf2(("MmFreeContiguousMemory ok!\n"));
603 pMem->pvR0 = NULL;
604 }
605 __except(EXCEPTION_EXECUTE_HANDLER)
606 {
607 NTSTATUS rc = GetExceptionCode();
608 dprintf(("supdrvOSContFreeOne: Exception Code %#x\n", rc));
609 }
610}
611
612
613/**
614 * Allocates memory which mapped into both kernel and user space.
615 * The returned memory is page aligned and so is the allocation.
616 *
617 * @returns 0 on success.
618 * @returns SUPDRV_ERR_* on failure.
619 * @param pMem Memory reference record of the memory to be allocated.
620 * (This is not linked in anywhere.)
621 * @param ppvR0 Where to store the address of the Ring-0 mapping.
622 * @param ppvR3 Where to store the address of the Ring-3 mapping.
623 */
624int VBOXCALL supdrvOSMemAllocOne(PSUPDRVMEMREF pMem, void **ppvR0, void **ppvR3)
625{
626 Assert(ppvR0);
627 Assert(ppvR3);
628
629 /*
630 * Try allocate the memory.
631 */
632 unsigned cbAligned = RT_ALIGN(RT_MAX(pMem->cb, PAGE_SIZE * 2), PAGE_SIZE);
633 pMem->pvR0 = ExAllocatePoolWithTag(NonPagedPool, cbAligned, 'vbox');
634 if (!pMem->pvR0)
635 return SUPDRV_ERR_NO_MEMORY;
636
637 /*
638 * Map into user space.
639 */
640 int rc = SUPDRV_ERR_NO_MEMORY;
641 pMem->u.mem.pMdl = IoAllocateMdl(pMem->pvR0, cbAligned, FALSE, FALSE, NULL);
642 if (pMem->u.mem.pMdl)
643 {
644 MmBuildMdlForNonPagedPool(pMem->u.mem.pMdl);
645 __try
646 {
647 pMem->pvR3 = MmMapLockedPages(pMem->u.mem.pMdl, UserMode);
648 if (pMem->pvR3)
649 {
650 /*
651 * Done, setup pMem and return values.
652 */
653 *ppvR3 = pMem->pvR3;
654 *ppvR0 = pMem->pvR0;
655 dprintf2(("supdrvOSContAllocOne: pvR0=%p pvR3=%p cb=%d pMdl=%p\n",
656 pMem->pvR0, pMem->pvR3, pMem->cb, pMem->u.mem.pMdl));
657 return 0;
658 }
659 }
660 __except(EXCEPTION_EXECUTE_HANDLER)
661 {
662 NTSTATUS rc = GetExceptionCode();
663 dprintf(("supdrvOSContAllocOne: Exception Code %#x\n", rc));
664 }
665 rc = SUPDRV_ERR_LOCK_FAILED;
666
667 IoFreeMdl(pMem->u.mem.pMdl);
668 pMem->u.mem.pMdl = NULL;
669 pMem->pvR3 = NULL;
670 }
671
672 MmFreeContiguousMemory(pMem->pvR0);
673 pMem->pvR0 = NULL;
674 return rc;
675}
676
677
678/**
679 * Get the physical addresses of the pages in the allocation.
680 * This is called while inside bundle the spinlock.
681 *
682 * @param pMem Memory reference record of the memory.
683 * @param paPages Where to store the page addresses.
684 */
685void VBOXCALL supdrvOSMemGetPages(PSUPDRVMEMREF pMem, PSUPPAGE paPages)
686{
687 const unsigned cPages = RT_ALIGN(pMem->cb, PAGE_SIZE) >> PAGE_SHIFT;
688 const uintptr_t *pauPFNs = (const uintptr_t *)(pMem->u.mem.pMdl + 1); /* ASSUMES ULONG_PTR == uintptr_t, NTDDK doesn't have ULONG_PTR. */
689 for (unsigned iPage = 0; iPage < cPages; iPage++)
690 {
691 paPages[iPage].Phys = (RTHCPHYS)pauPFNs[iPage] << PAGE_SHIFT;
692 paPages[iPage].uReserved = 0;
693 }
694}
695
696
697/**
698 * Frees memory allocated by supdrvOSMemAllocOne().
699 *
700 * @param pMem Memory reference record of the memory to be free.
701 */
702void VBOXCALL supdrvOSMemFreeOne(PSUPDRVMEMREF pMem)
703{
704 __try
705 {
706 dprintf2(("supdrvOSContFreeOne: pvR0=%p pvR3=%p cb=%d pMdl=%p\n",
707 pMem->pvR0, pMem->pvR3, pMem->cb, pMem->u.mem.pMdl));
708 if (pMem->pvR3)
709 {
710 MmUnmapLockedPages(pMem->pvR3, pMem->u.mem.pMdl);
711 pMem->pvR3 = NULL;
712 dprintf2(("MmUnmapLockedPages ok!\n"));
713 }
714
715 IoFreeMdl(pMem->u.mem.pMdl);
716 pMem->u.mem.pMdl = NULL;
717 dprintf2(("IoFreeMdl ok!\n"));
718
719 ExFreePool(pMem->pvR0);
720 pMem->pvR0 = NULL;
721 dprintf2(("MmFreeContiguousMemory ok!\n"));
722 }
723 __except(EXCEPTION_EXECUTE_HANDLER)
724 {
725 NTSTATUS rc = GetExceptionCode();
726 dprintf(("supdrvOSContFreeOne: Exception Code %#x\n", rc));
727 }
728}
729
730
731/**
732 * Gets the monotone timestamp (nano seconds).
733 * @returns NanoTS.
734 */
735static inline uint64_t supdrvOSMonotime(void)
736{
737 return (uint64_t)KeQueryInterruptTime() * 100;
738}
739
740
741/**
742 * Initializes the GIP.
743 *
744 * @returns NT status code.
745 * @param pDevExt Instance data. GIP stuff may be updated.
746 */
747static NTSTATUS VBoxSupDrvGipInit(PSUPDRVDEVEXT pDevExt)
748{
749 dprintf2(("VBoxSupDrvTermGip:\n"));
750
751 /*
752 * Try allocate the memory.
753 * Make sure it's below 4GB for 32-bit GC support
754 */
755 NTSTATUS rc;
756 PHYSICAL_ADDRESS Phys;
757 Phys.HighPart = 0;
758 Phys.LowPart = ~0;
759 PSUPGLOBALINFOPAGE pGip = (PSUPGLOBALINFOPAGE)MmAllocateContiguousMemory(PAGE_SIZE, Phys);
760 if (pGip)
761 {
762 if (!((uintptr_t)pGip & (PAGE_SIZE - 1)))
763 {
764 pDevExt->pGipMdl = IoAllocateMdl(pGip, PAGE_SIZE, FALSE, FALSE, NULL);
765 if (pDevExt->pGipMdl)
766 {
767 MmBuildMdlForNonPagedPool(pDevExt->pGipMdl);
768
769 /*
770 * Figure the timer interval and frequency.
771 * It turns out trying 1023Hz doesn't work. So, we'll set the max Hz at 128 for now.
772 */
773 ExSetTimerResolution(156250, TRUE);
774 ULONG ulClockIntervalActual = ExSetTimerResolution(0, FALSE);
775 ULONG ulClockInterval = RT_MAX(ulClockIntervalActual, 78125); /* 1/128 */
776 ULONG ulClockFreq = 10000000 / ulClockInterval;
777 pDevExt->ulGipTimerInterval = ulClockInterval / 10000; /* ms */
778
779 /*
780 * Call common initialization routine.
781 */
782 Phys = MmGetPhysicalAddress(pGip); /* could perhaps use the Mdl, not that it looks much better */
783 supdrvGipInit(pDevExt, pGip, (RTHCPHYS)Phys.QuadPart, supdrvOSMonotime(), ulClockFreq);
784
785 /*
786 * Initialize the timer.
787 */
788 KeInitializeTimerEx(&pDevExt->GipTimer, SynchronizationTimer);
789 KeInitializeDpc(&pDevExt->GipDpc, VBoxSupDrvGipTimer, pGip);
790 dprintf(("VBoxSupDrvGipInit: ulClockFreq=%ld ulClockInterval=%ld ulClockIntervalActual=%ld Phys=%x%08x\n",
791 ulClockFreq, ulClockInterval, ulClockIntervalActual, Phys.HighPart, Phys.LowPart));
792 return STATUS_SUCCESS;
793 }
794 else
795 {
796 dprintf(("VBoxSupDrvInitGip: IoAllocateMdl failed for %p/PAGE_SIZE\n", pGip));
797 rc = STATUS_NO_MEMORY;
798 }
799 }
800 else
801 {
802 dprintf(("VBoxSupDrvInitGip: GIP memory is not page aligned! pGip=%p\n", pGip));
803 rc = STATUS_INVALID_ADDRESS;
804 }
805 MmFreeContiguousMemory(pGip);
806 }
807 else
808 {
809 dprintf(("VBoxSupDrvInitGip: no cont memory.\n"));
810 rc = STATUS_NO_MEMORY;
811 }
812 return rc;
813}
814
815
816/**
817 * Terminates the GIP.
818 *
819 * @returns negative errno.
820 * @param pDevExt Instance data. GIP stuff may be updated.
821 */
822static void VBoxSupDrvGipTerm(PSUPDRVDEVEXT pDevExt)
823{
824 dprintf(("VBoxSupDrvTermGip:\n"));
825 PSUPGLOBALINFOPAGE pGip;
826
827 /*
828 * Cancel the timer and wait on DPCs if it was still pending.
829 */
830 if (KeCancelTimer(&pDevExt->GipTimer))
831 {
832 UNICODE_STRING RoutineName;
833 RtlInitUnicodeString(&RoutineName, L"KeFlushQueuedDpcs");
834 VOID (*pfnKeFlushQueuedDpcs)(VOID) = (VOID (*)(VOID))MmGetSystemRoutineAddress(&RoutineName);
835 if (pfnKeFlushQueuedDpcs)
836 pfnKeFlushQueuedDpcs();
837 }
838
839 /*
840 * Uninitialize the content.
841 */
842 pGip = pDevExt->pGip;
843 pDevExt->pGip = NULL;
844 if (pGip)
845 {
846 supdrvGipTerm(pGip);
847
848 /*
849 * Free the page.
850 */
851 if (pDevExt->pGipMdl)
852 {
853 IoFreeMdl(pDevExt->pGipMdl);
854 pDevExt->pGipMdl = NULL;
855 }
856 MmFreeContiguousMemory(pGip);
857 }
858}
859
860
861/**
862 * Timer callback function.
863 * The ulUser parameter is the GIP pointer.
864 */
865static void __stdcall VBoxSupDrvGipTimer(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
866{
867 PSUPGLOBALINFOPAGE pGip = (PSUPGLOBALINFOPAGE)pvUser;
868 supdrvGipUpdate(pGip, supdrvOSMonotime());
869}
870
871
872/**
873 * Maps the GIP into user space.
874 *
875 * @returns negative errno.
876 * @param pDevExt Instance data.
877 */
878int VBOXCALL supdrvOSGipMap(PSUPDRVDEVEXT pDevExt, PCSUPGLOBALINFOPAGE *ppGip)
879{
880 dprintf2(("supdrvOSGipMap: ppGip=%p (pDevExt->pGipMdl=%p)\n", ppGip, pDevExt->pGipMdl));
881
882 /*
883 * Map into user space.
884 */
885 int rc = 0;
886 void *pv = NULL;
887 __try
888 {
889 *ppGip = (PCSUPGLOBALINFOPAGE)MmMapLockedPages(pDevExt->pGipMdl, UserMode);
890 }
891 __except(EXCEPTION_EXECUTE_HANDLER)
892 {
893 NTSTATUS rcNt = GetExceptionCode();
894 dprintf(("supdrvOsGipMap: Exception Code %#x\n", rcNt));
895 rc = SUPDRV_ERR_LOCK_FAILED;
896 }
897
898 dprintf2(("supdrvOSGipMap: returns %d, *ppGip=%p\n", rc, *ppGip));
899 return 0;
900}
901
902
903/**
904 * Maps the GIP into user space.
905 *
906 * @returns negative errno.
907 * @param pDevExt Instance data.
908 */
909int VBOXCALL supdrvOSGipUnmap(PSUPDRVDEVEXT pDevExt, PCSUPGLOBALINFOPAGE pGip)
910{
911 dprintf2(("supdrvOSGipUnmap: pGip=%p (pGipMdl=%p)\n", pGip, pDevExt->pGipMdl));
912
913 int rc = 0;
914 __try
915 {
916 MmUnmapLockedPages((void *)pGip, pDevExt->pGipMdl);
917 }
918 __except(EXCEPTION_EXECUTE_HANDLER)
919 {
920 NTSTATUS rcNt = GetExceptionCode();
921 dprintf(("supdrvOSGipUnmap: Exception Code %#x\n", rcNt));
922 rc = SUPDRV_ERR_GENERAL_FAILURE;
923 }
924 dprintf2(("supdrvOSGipUnmap: returns %d\n", rc));
925 return rc;
926}
927
928
929/**
930 * Resumes the GIP updating.
931 *
932 * @param pDevExt Instance data.
933 */
934void VBOXCALL supdrvOSGipResume(PSUPDRVDEVEXT pDevExt)
935{
936 dprintf2(("supdrvOSGipResume:\n"));
937 LARGE_INTEGER DueTime;
938 DueTime.QuadPart = -10000; /* 1ms, relative */
939 KeSetTimerEx(&pDevExt->GipTimer, DueTime, pDevExt->ulGipTimerInterval, &pDevExt->GipDpc);
940}
941
942
943/**
944 * Suspends the GIP updating.
945 *
946 * @param pDevExt Instance data.
947 */
948void VBOXCALL supdrvOSGipSuspend(PSUPDRVDEVEXT pDevExt)
949{
950 dprintf2(("supdrvOSGipSuspend:\n"));
951 KeCancelTimer(&pDevExt->GipTimer);
952#ifdef __AMD64__
953 ExSetTimerResolution(0, FALSE);
954#endif
955}
956
957
958/**
959 * Allocate small amounts of memory which is does not have the NX bit set.
960 *
961 * @returns Pointer to the allocated memory
962 * @returns NULL if out of memory.
963 * @param cb Size of the memory block.
964 */
965void *VBOXCALL supdrvOSExecAlloc(size_t cb)
966{
967#if 0 //def __AMD64__
968 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
969 void *pv = ExAllocatePoolWithTag(NonPagedPool, cb, 'vbox');
970 if (pv)
971 {
972 /*
973 * Create a kernel mapping which we make PAGE_EXECUTE_READWRITE using
974 * the MmProtectMdlSystemAddress API.
975 */
976 int rc = SUPDRV_ERR_NO_MEMORY;
977 PMDL pMdl = IoAllocateMdl(pv, cb, FALSE, FALSE, NULL);
978 if (pMdl)
979 {
980 MmBuildMdlForNonPagedPool(pMdl);
981 __try
982 {
983 void *pvMapping = MmMapLockedPages(pMdl, KernelMode);
984 if (pvMapping)
985 {
986 NTSTATUS rc = MmProtectMdlSystemAddress(pMdl, PAGE_EXECUTE_READWRITE);
987 if (NT_SUCCESS(rc))
988 {
989 /*
990 * Create tracking structure and insert it into the list.
991 */
992
993
994 return pvMapping;
995 }
996
997 MmUnmapLockedPages(pvMapping, pMdl);
998 }
999 }
1000 __except(EXCEPTION_EXECUTE_HANDLER)
1001 {
1002 NTSTATUS rc = GetExceptionCode();
1003 dprintf(("supdrvOSExecAlloc: Exception Code %#x\n", rc));
1004 }
1005 IoFreeMdl(pMem->u.mem.pMdl);
1006 }
1007 ExFreePool(pv);
1008 }
1009 dprintf2(("supdrvOSExecAlloc(%d): returns NULL\n", cb));
1010 return NULL;
1011#else
1012 void *pv = ExAllocatePoolWithTag(NonPagedPool, cb, 'vbox');
1013 dprintf2(("supdrvOSExecAlloc(%d): returns %p\n", cb, pv));
1014 return pv;
1015#endif
1016}
1017
1018
1019
1020/**
1021 * Converts a supdrv error code to an nt status code.
1022 *
1023 * @returns corresponding nt status code.
1024 * @param rc supdrv error code (SUPDRV_ERR_* defines).
1025 */
1026static NTSTATUS VBoxSupDrvErr2NtStatus(int rc)
1027{
1028 switch (rc)
1029 {
1030 case 0: return STATUS_SUCCESS;
1031 case SUPDRV_ERR_GENERAL_FAILURE: return STATUS_NOT_SUPPORTED;
1032 case SUPDRV_ERR_INVALID_PARAM: return STATUS_INVALID_PARAMETER;
1033 case SUPDRV_ERR_INVALID_MAGIC: return STATUS_UNKNOWN_REVISION;
1034 case SUPDRV_ERR_INVALID_HANDLE: return STATUS_INVALID_HANDLE;
1035 case SUPDRV_ERR_INVALID_POINTER: return STATUS_INVALID_ADDRESS;
1036 case SUPDRV_ERR_LOCK_FAILED: return STATUS_NOT_LOCKED;
1037 case SUPDRV_ERR_ALREADY_LOADED: return STATUS_IMAGE_ALREADY_LOADED;
1038 case SUPDRV_ERR_PERMISSION_DENIED: return STATUS_ACCESS_DENIED;
1039 case SUPDRV_ERR_VERSION_MISMATCH: return STATUS_REVISION_MISMATCH;
1040 }
1041
1042 return STATUS_UNSUCCESSFUL;
1043}
1044
1045
1046/** Runtime assert implementation for Native Win32 Ring-0. */
1047RTDECL(void) AssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
1048{
1049 DbgPrint("\n!!Assertion Failed!!\n"
1050 "Expression: %s\n"
1051 "Location : %s(%d) %s\n",
1052 pszExpr, pszFile, uLine, pszFunction);
1053}
1054
1055int VBOXCALL mymemcmp(const void *pv1, const void *pv2, size_t cb)
1056{
1057 const uint8_t *pb1 = (const uint8_t *)pv1;
1058 const uint8_t *pb2 = (const uint8_t *)pv2;
1059 for (; cb > 0; cb--, pb1++, pb2++)
1060 if (*pb1 != *pb2)
1061 return *pb1 - *pb2;
1062 return 0;
1063}
1064
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette