VirtualBox

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

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

iprt/process.h

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