VirtualBox

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

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

No longer require contiguous memory for the VM structure.
Did long overdue IOCtl cleanup wrt R3/R0 pointers.

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