VirtualBox

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

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

Use RTR0ProcHandleSelf / RTProcSelf. Implemented clientDied() cleanup on darwin.

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