VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/nt/memobj-r0drv-nt.cpp@ 62448

Last change on this file since 62448 was 58268, checked in by vboxsync, 9 years ago

r0drv/nt: Some rtR0MemObjNativeProtect sketches.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 35.1 KB
Line 
1/* $Id: memobj-r0drv-nt.cpp 58268 2015-10-15 18:18:17Z vboxsync $ */
2/** @file
3 * IPRT - Ring-0 Memory Objects, NT.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include "the-nt-kernel.h"
32
33#include <iprt/memobj.h>
34#include <iprt/alloc.h>
35#include <iprt/assert.h>
36#include <iprt/log.h>
37#include <iprt/param.h>
38#include <iprt/string.h>
39#include <iprt/process.h>
40#include "internal/memobj.h"
41
42
43/*********************************************************************************************************************************
44* Defined Constants And Macros *
45*********************************************************************************************************************************/
46/** Maximum number of bytes we try to lock down in one go.
47 * This is supposed to have a limit right below 256MB, but this appears
48 * to actually be much lower. The values here have been determined experimentally.
49 */
50#ifdef RT_ARCH_X86
51# define MAX_LOCK_MEM_SIZE (32*1024*1024) /* 32MB */
52#endif
53#ifdef RT_ARCH_AMD64
54# define MAX_LOCK_MEM_SIZE (24*1024*1024) /* 24MB */
55#endif
56
57
58/*********************************************************************************************************************************
59* Structures and Typedefs *
60*********************************************************************************************************************************/
61/**
62 * The NT version of the memory object structure.
63 */
64typedef struct RTR0MEMOBJNT
65{
66 /** The core structure. */
67 RTR0MEMOBJINTERNAL Core;
68#ifndef IPRT_TARGET_NT4
69 /** Used MmAllocatePagesForMdl(). */
70 bool fAllocatedPagesForMdl;
71#endif
72 /** Pointer returned by MmSecureVirtualMemory */
73 PVOID pvSecureMem;
74 /** The number of PMDLs (memory descriptor lists) in the array. */
75 uint32_t cMdls;
76 /** Array of MDL pointers. (variable size) */
77 PMDL apMdls[1];
78} RTR0MEMOBJNT, *PRTR0MEMOBJNT;
79
80
81/*********************************************************************************************************************************
82* Global Variables *
83*********************************************************************************************************************************/
84/** Pointer to the MmProtectMdlSystemAddress kernel function if it's available.
85 * This API was introduced in XP. */
86static decltype(MmProtectMdlSystemAddress) *g_pfnMmProtectMdlSystemAddress = NULL;
87/** Set if we've resolved the dynamic APIs. */
88static bool volatile g_fResolvedDynamicApis = false;
89static ULONG g_uMajorVersion = 5;
90static ULONG g_uMinorVersion = 1;
91
92
93static void rtR0MemObjNtResolveDynamicApis(void)
94{
95 ULONG uBuildNumber = 0;
96 PsGetVersion(&g_uMajorVersion, &g_uMinorVersion, &uBuildNumber, NULL);
97
98#ifndef IPRT_TARGET_NT4 /* MmGetSystemRoutineAddress was introduced in w2k. */
99
100 UNICODE_STRING RoutineName;
101 RtlInitUnicodeString(&RoutineName, L"MmProtectMdlSystemAddress");
102 g_pfnMmProtectMdlSystemAddress = (decltype(MmProtectMdlSystemAddress) *)MmGetSystemRoutineAddress(&RoutineName);
103
104#endif
105 ASMCompilerBarrier();
106 g_fResolvedDynamicApis = true;
107}
108
109
110DECLHIDDEN(int) rtR0MemObjNativeFree(RTR0MEMOBJ pMem)
111{
112 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)pMem;
113
114 /*
115 * Deal with it on a per type basis (just as a variation).
116 */
117 switch (pMemNt->Core.enmType)
118 {
119 case RTR0MEMOBJTYPE_LOW:
120#ifndef IPRT_TARGET_NT4
121 if (pMemNt->fAllocatedPagesForMdl)
122 {
123 Assert(pMemNt->Core.pv && pMemNt->cMdls == 1 && pMemNt->apMdls[0]);
124 MmUnmapLockedPages(pMemNt->Core.pv, pMemNt->apMdls[0]);
125 pMemNt->Core.pv = NULL;
126 if (pMemNt->pvSecureMem)
127 {
128 MmUnsecureVirtualMemory(pMemNt->pvSecureMem);
129 pMemNt->pvSecureMem = NULL;
130 }
131
132 MmFreePagesFromMdl(pMemNt->apMdls[0]);
133 ExFreePool(pMemNt->apMdls[0]);
134 pMemNt->apMdls[0] = NULL;
135 pMemNt->cMdls = 0;
136 break;
137 }
138#endif
139 AssertFailed();
140 break;
141
142 case RTR0MEMOBJTYPE_PAGE:
143 Assert(pMemNt->Core.pv);
144 ExFreePool(pMemNt->Core.pv);
145 pMemNt->Core.pv = NULL;
146
147 Assert(pMemNt->cMdls == 1 && pMemNt->apMdls[0]);
148 IoFreeMdl(pMemNt->apMdls[0]);
149 pMemNt->apMdls[0] = NULL;
150 pMemNt->cMdls = 0;
151 break;
152
153 case RTR0MEMOBJTYPE_CONT:
154 Assert(pMemNt->Core.pv);
155 MmFreeContiguousMemory(pMemNt->Core.pv);
156 pMemNt->Core.pv = NULL;
157
158 Assert(pMemNt->cMdls == 1 && pMemNt->apMdls[0]);
159 IoFreeMdl(pMemNt->apMdls[0]);
160 pMemNt->apMdls[0] = NULL;
161 pMemNt->cMdls = 0;
162 break;
163
164 case RTR0MEMOBJTYPE_PHYS:
165 /* rtR0MemObjNativeEnterPhys? */
166 if (!pMemNt->Core.u.Phys.fAllocated)
167 {
168#ifndef IPRT_TARGET_NT4
169 Assert(!pMemNt->fAllocatedPagesForMdl);
170#endif
171 /* Nothing to do here. */
172 break;
173 }
174 /* fall thru */
175
176 case RTR0MEMOBJTYPE_PHYS_NC:
177#ifndef IPRT_TARGET_NT4
178 if (pMemNt->fAllocatedPagesForMdl)
179 {
180 MmFreePagesFromMdl(pMemNt->apMdls[0]);
181 ExFreePool(pMemNt->apMdls[0]);
182 pMemNt->apMdls[0] = NULL;
183 pMemNt->cMdls = 0;
184 break;
185 }
186#endif
187 AssertFailed();
188 break;
189
190 case RTR0MEMOBJTYPE_LOCK:
191 if (pMemNt->pvSecureMem)
192 {
193 MmUnsecureVirtualMemory(pMemNt->pvSecureMem);
194 pMemNt->pvSecureMem = NULL;
195 }
196 for (uint32_t i = 0; i < pMemNt->cMdls; i++)
197 {
198 MmUnlockPages(pMemNt->apMdls[i]);
199 IoFreeMdl(pMemNt->apMdls[i]);
200 pMemNt->apMdls[i] = NULL;
201 }
202 break;
203
204 case RTR0MEMOBJTYPE_RES_VIRT:
205/* if (pMemNt->Core.u.ResVirt.R0Process == NIL_RTR0PROCESS)
206 {
207 }
208 else
209 {
210 }*/
211 AssertMsgFailed(("RTR0MEMOBJTYPE_RES_VIRT\n"));
212 return VERR_INTERNAL_ERROR;
213 break;
214
215 case RTR0MEMOBJTYPE_MAPPING:
216 {
217 Assert(pMemNt->cMdls == 0 && pMemNt->Core.pv);
218 PRTR0MEMOBJNT pMemNtParent = (PRTR0MEMOBJNT)pMemNt->Core.uRel.Child.pParent;
219 Assert(pMemNtParent);
220 if (pMemNtParent->cMdls)
221 {
222 Assert(pMemNtParent->cMdls == 1 && pMemNtParent->apMdls[0]);
223 Assert( pMemNt->Core.u.Mapping.R0Process == NIL_RTR0PROCESS
224 || pMemNt->Core.u.Mapping.R0Process == RTR0ProcHandleSelf());
225 MmUnmapLockedPages(pMemNt->Core.pv, pMemNtParent->apMdls[0]);
226 }
227 else
228 {
229 Assert( pMemNtParent->Core.enmType == RTR0MEMOBJTYPE_PHYS
230 && !pMemNtParent->Core.u.Phys.fAllocated);
231 Assert(pMemNt->Core.u.Mapping.R0Process == NIL_RTR0PROCESS);
232 MmUnmapIoSpace(pMemNt->Core.pv, pMemNt->Core.cb);
233 }
234 pMemNt->Core.pv = NULL;
235 break;
236 }
237
238 default:
239 AssertMsgFailed(("enmType=%d\n", pMemNt->Core.enmType));
240 return VERR_INTERNAL_ERROR;
241 }
242
243 return VINF_SUCCESS;
244}
245
246
247DECLHIDDEN(int) rtR0MemObjNativeAllocPage(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
248{
249 AssertMsgReturn(cb <= _1G, ("%#x\n", cb), VERR_OUT_OF_RANGE); /* for safe size_t -> ULONG */
250
251 /*
252 * Try allocate the memory and create an MDL for them so
253 * we can query the physical addresses and do mappings later
254 * without running into out-of-memory conditions and similar problems.
255 */
256 int rc = VERR_NO_PAGE_MEMORY;
257 void *pv = ExAllocatePoolWithTag(NonPagedPool, cb, IPRT_NT_POOL_TAG);
258 if (pv)
259 {
260 PMDL pMdl = IoAllocateMdl(pv, (ULONG)cb, FALSE, FALSE, NULL);
261 if (pMdl)
262 {
263 MmBuildMdlForNonPagedPool(pMdl);
264#ifdef RT_ARCH_AMD64
265 MmProtectMdlSystemAddress(pMdl, PAGE_EXECUTE_READWRITE);
266#endif
267
268 /*
269 * Create the IPRT memory object.
270 */
271 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_PAGE, pv, cb);
272 if (pMemNt)
273 {
274 pMemNt->cMdls = 1;
275 pMemNt->apMdls[0] = pMdl;
276 *ppMem = &pMemNt->Core;
277 return VINF_SUCCESS;
278 }
279
280 rc = VERR_NO_MEMORY;
281 IoFreeMdl(pMdl);
282 }
283 ExFreePool(pv);
284 }
285 return rc;
286}
287
288
289DECLHIDDEN(int) rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
290{
291 AssertMsgReturn(cb <= _1G, ("%#x\n", cb), VERR_OUT_OF_RANGE); /* for safe size_t -> ULONG */
292
293 /*
294 * Try see if we get lucky first...
295 * (We could probably just assume we're lucky on NT4.)
296 */
297 int rc = rtR0MemObjNativeAllocPage(ppMem, cb, fExecutable);
298 if (RT_SUCCESS(rc))
299 {
300 size_t iPage = cb >> PAGE_SHIFT;
301 while (iPage-- > 0)
302 if (rtR0MemObjNativeGetPagePhysAddr(*ppMem, iPage) >= _4G)
303 {
304 rc = VERR_NO_LOW_MEMORY;
305 break;
306 }
307 if (RT_SUCCESS(rc))
308 return rc;
309
310 /* The following ASSUMES that rtR0MemObjNativeAllocPage returns a completed object. */
311 RTR0MemObjFree(*ppMem, false);
312 *ppMem = NULL;
313 }
314
315#ifndef IPRT_TARGET_NT4
316 /*
317 * Use MmAllocatePagesForMdl to specify the range of physical addresses we wish to use.
318 */
319 PHYSICAL_ADDRESS Zero;
320 Zero.QuadPart = 0;
321 PHYSICAL_ADDRESS HighAddr;
322 HighAddr.QuadPart = _4G - 1;
323 PMDL pMdl = MmAllocatePagesForMdl(Zero, HighAddr, Zero, cb);
324 if (pMdl)
325 {
326 if (MmGetMdlByteCount(pMdl) >= cb)
327 {
328 __try
329 {
330 void *pv = MmMapLockedPagesSpecifyCache(pMdl, KernelMode, MmCached, NULL /* no base address */,
331 FALSE /* no bug check on failure */, NormalPagePriority);
332 if (pv)
333 {
334 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_LOW, pv, cb);
335 if (pMemNt)
336 {
337 pMemNt->fAllocatedPagesForMdl = true;
338 pMemNt->cMdls = 1;
339 pMemNt->apMdls[0] = pMdl;
340 *ppMem = &pMemNt->Core;
341 return VINF_SUCCESS;
342 }
343 MmUnmapLockedPages(pv, pMdl);
344 }
345 }
346 __except(EXCEPTION_EXECUTE_HANDLER)
347 {
348 NTSTATUS rcNt = GetExceptionCode();
349 Log(("rtR0MemObjNativeAllocLow: Exception Code %#x\n", rcNt));
350 /* nothing */
351 }
352 }
353 MmFreePagesFromMdl(pMdl);
354 ExFreePool(pMdl);
355 }
356#endif /* !IPRT_TARGET_NT4 */
357
358 /*
359 * Fall back on contiguous memory...
360 */
361 return rtR0MemObjNativeAllocCont(ppMem, cb, fExecutable);
362}
363
364
365/**
366 * Internal worker for rtR0MemObjNativeAllocCont(), rtR0MemObjNativeAllocPhys()
367 * and rtR0MemObjNativeAllocPhysNC() that takes a max physical address in addition
368 * to what rtR0MemObjNativeAllocCont() does.
369 *
370 * @returns IPRT status code.
371 * @param ppMem Where to store the pointer to the ring-0 memory object.
372 * @param cb The size.
373 * @param fExecutable Whether the mapping should be executable or not.
374 * @param PhysHighest The highest physical address for the pages in allocation.
375 * @param uAlignment The alignment of the physical memory to allocate.
376 * Supported values are PAGE_SIZE, _2M, _4M and _1G.
377 */
378static int rtR0MemObjNativeAllocContEx(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable, RTHCPHYS PhysHighest,
379 size_t uAlignment)
380{
381 AssertMsgReturn(cb <= _1G, ("%#x\n", cb), VERR_OUT_OF_RANGE); /* for safe size_t -> ULONG */
382#ifdef IPRT_TARGET_NT4
383 if (uAlignment != PAGE_SIZE)
384 return VERR_NOT_SUPPORTED;
385#endif
386
387 /*
388 * Allocate the memory and create an MDL for it.
389 */
390 PHYSICAL_ADDRESS PhysAddrHighest;
391 PhysAddrHighest.QuadPart = PhysHighest;
392#ifndef IPRT_TARGET_NT4
393 PHYSICAL_ADDRESS PhysAddrLowest, PhysAddrBoundary;
394 PhysAddrLowest.QuadPart = 0;
395 PhysAddrBoundary.QuadPart = (uAlignment == PAGE_SIZE) ? 0 : uAlignment;
396 void *pv = MmAllocateContiguousMemorySpecifyCache(cb, PhysAddrLowest, PhysAddrHighest, PhysAddrBoundary, MmCached);
397#else
398 void *pv = MmAllocateContiguousMemory(cb, PhysAddrHighest);
399#endif
400 if (!pv)
401 return VERR_NO_MEMORY;
402
403 PMDL pMdl = IoAllocateMdl(pv, (ULONG)cb, FALSE, FALSE, NULL);
404 if (pMdl)
405 {
406 MmBuildMdlForNonPagedPool(pMdl);
407#ifdef RT_ARCH_AMD64
408 MmProtectMdlSystemAddress(pMdl, PAGE_EXECUTE_READWRITE);
409#endif
410
411 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_CONT, pv, cb);
412 if (pMemNt)
413 {
414 pMemNt->Core.u.Cont.Phys = (RTHCPHYS)*MmGetMdlPfnArray(pMdl) << PAGE_SHIFT;
415 pMemNt->cMdls = 1;
416 pMemNt->apMdls[0] = pMdl;
417 *ppMem = &pMemNt->Core;
418 return VINF_SUCCESS;
419 }
420
421 IoFreeMdl(pMdl);
422 }
423 MmFreeContiguousMemory(pv);
424 return VERR_NO_MEMORY;
425}
426
427
428DECLHIDDEN(int) rtR0MemObjNativeAllocCont(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
429{
430 return rtR0MemObjNativeAllocContEx(ppMem, cb, fExecutable, _4G-1, PAGE_SIZE /* alignment */);
431}
432
433
434DECLHIDDEN(int) rtR0MemObjNativeAllocPhys(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest, size_t uAlignment)
435{
436#ifndef IPRT_TARGET_NT4
437 /*
438 * Try and see if we're lucky and get a contiguous chunk from MmAllocatePagesForMdl.
439 *
440 * This is preferable to using MmAllocateContiguousMemory because there are
441 * a few situations where the memory shouldn't be mapped, like for instance
442 * VT-x control memory. Since these are rather small allocations (one or
443 * two pages) MmAllocatePagesForMdl will probably be able to satisfy the
444 * request.
445 *
446 * If the allocation is big, the chances are *probably* not very good. The
447 * current limit is kind of random...
448 */
449 if ( cb < _128K
450 && uAlignment == PAGE_SIZE)
451
452 {
453 PHYSICAL_ADDRESS Zero;
454 Zero.QuadPart = 0;
455 PHYSICAL_ADDRESS HighAddr;
456 HighAddr.QuadPart = PhysHighest == NIL_RTHCPHYS ? MAXLONGLONG : PhysHighest;
457 PMDL pMdl = MmAllocatePagesForMdl(Zero, HighAddr, Zero, cb);
458 if (pMdl)
459 {
460 if (MmGetMdlByteCount(pMdl) >= cb)
461 {
462 PPFN_NUMBER paPfns = MmGetMdlPfnArray(pMdl);
463 PFN_NUMBER Pfn = paPfns[0] + 1;
464 const size_t cPages = cb >> PAGE_SHIFT;
465 size_t iPage;
466 for (iPage = 1; iPage < cPages; iPage++, Pfn++)
467 if (paPfns[iPage] != Pfn)
468 break;
469 if (iPage >= cPages)
470 {
471 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_PHYS, NULL, cb);
472 if (pMemNt)
473 {
474 pMemNt->Core.u.Phys.fAllocated = true;
475 pMemNt->Core.u.Phys.PhysBase = (RTHCPHYS)paPfns[0] << PAGE_SHIFT;
476 pMemNt->fAllocatedPagesForMdl = true;
477 pMemNt->cMdls = 1;
478 pMemNt->apMdls[0] = pMdl;
479 *ppMem = &pMemNt->Core;
480 return VINF_SUCCESS;
481 }
482 }
483 }
484 MmFreePagesFromMdl(pMdl);
485 ExFreePool(pMdl);
486 }
487 }
488#endif /* !IPRT_TARGET_NT4 */
489
490 return rtR0MemObjNativeAllocContEx(ppMem, cb, false, PhysHighest, uAlignment);
491}
492
493
494DECLHIDDEN(int) rtR0MemObjNativeAllocPhysNC(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest)
495{
496#ifndef IPRT_TARGET_NT4
497 PHYSICAL_ADDRESS Zero;
498 Zero.QuadPart = 0;
499 PHYSICAL_ADDRESS HighAddr;
500 HighAddr.QuadPart = PhysHighest == NIL_RTHCPHYS ? MAXLONGLONG : PhysHighest;
501 PMDL pMdl = MmAllocatePagesForMdl(Zero, HighAddr, Zero, cb);
502 if (pMdl)
503 {
504 if (MmGetMdlByteCount(pMdl) >= cb)
505 {
506 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_PHYS_NC, NULL, cb);
507 if (pMemNt)
508 {
509 pMemNt->fAllocatedPagesForMdl = true;
510 pMemNt->cMdls = 1;
511 pMemNt->apMdls[0] = pMdl;
512 *ppMem = &pMemNt->Core;
513 return VINF_SUCCESS;
514 }
515 }
516 MmFreePagesFromMdl(pMdl);
517 ExFreePool(pMdl);
518 }
519 return VERR_NO_MEMORY;
520#else /* IPRT_TARGET_NT4 */
521 return VERR_NOT_SUPPORTED;
522#endif /* IPRT_TARGET_NT4 */
523}
524
525
526DECLHIDDEN(int) rtR0MemObjNativeEnterPhys(PPRTR0MEMOBJINTERNAL ppMem, RTHCPHYS Phys, size_t cb, uint32_t uCachePolicy)
527{
528 AssertReturn(uCachePolicy == RTMEM_CACHE_POLICY_DONT_CARE || uCachePolicy == RTMEM_CACHE_POLICY_MMIO, VERR_NOT_SUPPORTED);
529
530 /*
531 * Validate the address range and create a descriptor for it.
532 */
533 PFN_NUMBER Pfn = (PFN_NUMBER)(Phys >> PAGE_SHIFT);
534 if (((RTHCPHYS)Pfn << PAGE_SHIFT) != Phys)
535 return VERR_ADDRESS_TOO_BIG;
536
537 /*
538 * Create the IPRT memory object.
539 */
540 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_PHYS, NULL, cb);
541 if (pMemNt)
542 {
543 pMemNt->Core.u.Phys.PhysBase = Phys;
544 pMemNt->Core.u.Phys.fAllocated = false;
545 pMemNt->Core.u.Phys.uCachePolicy = uCachePolicy;
546 *ppMem = &pMemNt->Core;
547 return VINF_SUCCESS;
548 }
549 return VERR_NO_MEMORY;
550}
551
552
553/**
554 * Internal worker for locking down pages.
555 *
556 * @return IPRT status code.
557 *
558 * @param ppMem Where to store the memory object pointer.
559 * @param pv First page.
560 * @param cb Number of bytes.
561 * @param fAccess The desired access, a combination of RTMEM_PROT_READ
562 * and RTMEM_PROT_WRITE.
563 * @param R0Process The process \a pv and \a cb refers to.
564 */
565static int rtR0MemObjNtLock(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb, uint32_t fAccess, RTR0PROCESS R0Process)
566{
567 /*
568 * Calc the number of MDLs we need and allocate the memory object structure.
569 */
570 size_t cMdls = cb / MAX_LOCK_MEM_SIZE;
571 if (cb % MAX_LOCK_MEM_SIZE)
572 cMdls++;
573 if (cMdls >= UINT32_MAX)
574 return VERR_OUT_OF_RANGE;
575 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(RT_OFFSETOF(RTR0MEMOBJNT, apMdls[cMdls]),
576 RTR0MEMOBJTYPE_LOCK, pv, cb);
577 if (!pMemNt)
578 return VERR_NO_MEMORY;
579
580 /*
581 * Loop locking down the sub parts of the memory.
582 */
583 int rc = VINF_SUCCESS;
584 size_t cbTotal = 0;
585 uint8_t *pb = (uint8_t *)pv;
586 uint32_t iMdl;
587 for (iMdl = 0; iMdl < cMdls; iMdl++)
588 {
589 /*
590 * Calc the Mdl size and allocate it.
591 */
592 size_t cbCur = cb - cbTotal;
593 if (cbCur > MAX_LOCK_MEM_SIZE)
594 cbCur = MAX_LOCK_MEM_SIZE;
595 AssertMsg(cbCur, ("cbCur: 0!\n"));
596 PMDL pMdl = IoAllocateMdl(pb, (ULONG)cbCur, FALSE, FALSE, NULL);
597 if (!pMdl)
598 {
599 rc = VERR_NO_MEMORY;
600 break;
601 }
602
603 /*
604 * Lock the pages.
605 */
606 __try
607 {
608 MmProbeAndLockPages(pMdl,
609 R0Process == NIL_RTR0PROCESS ? KernelMode : UserMode,
610 fAccess == RTMEM_PROT_READ
611 ? IoReadAccess
612 : fAccess == RTMEM_PROT_WRITE
613 ? IoWriteAccess
614 : IoModifyAccess);
615
616 pMemNt->apMdls[iMdl] = pMdl;
617 pMemNt->cMdls++;
618 }
619 __except(EXCEPTION_EXECUTE_HANDLER)
620 {
621 IoFreeMdl(pMdl);
622 rc = VERR_LOCK_FAILED;
623 break;
624 }
625
626 if (R0Process != NIL_RTR0PROCESS)
627 {
628 /* Make sure the user process can't change the allocation. */
629 pMemNt->pvSecureMem = MmSecureVirtualMemory(pv, cb,
630 fAccess & RTMEM_PROT_WRITE
631 ? PAGE_READWRITE
632 : PAGE_READONLY);
633 if (!pMemNt->pvSecureMem)
634 {
635 rc = VERR_NO_MEMORY;
636 break;
637 }
638 }
639
640 /* next */
641 cbTotal += cbCur;
642 pb += cbCur;
643 }
644 if (RT_SUCCESS(rc))
645 {
646 Assert(pMemNt->cMdls == cMdls);
647 pMemNt->Core.u.Lock.R0Process = R0Process;
648 *ppMem = &pMemNt->Core;
649 return rc;
650 }
651
652 /*
653 * We failed, perform cleanups.
654 */
655 while (iMdl-- > 0)
656 {
657 MmUnlockPages(pMemNt->apMdls[iMdl]);
658 IoFreeMdl(pMemNt->apMdls[iMdl]);
659 pMemNt->apMdls[iMdl] = NULL;
660 }
661 if (pMemNt->pvSecureMem)
662 {
663 MmUnsecureVirtualMemory(pMemNt->pvSecureMem);
664 pMemNt->pvSecureMem = NULL;
665 }
666
667 rtR0MemObjDelete(&pMemNt->Core);
668 return rc;
669}
670
671
672DECLHIDDEN(int) rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3Ptr, size_t cb, uint32_t fAccess,
673 RTR0PROCESS R0Process)
674{
675 AssertMsgReturn(R0Process == RTR0ProcHandleSelf(), ("%p != %p\n", R0Process, RTR0ProcHandleSelf()), VERR_NOT_SUPPORTED);
676 /* (Can use MmProbeAndLockProcessPages if we need to mess with other processes later.) */
677 return rtR0MemObjNtLock(ppMem, (void *)R3Ptr, cb, fAccess, R0Process);
678}
679
680
681DECLHIDDEN(int) rtR0MemObjNativeLockKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb, uint32_t fAccess)
682{
683 return rtR0MemObjNtLock(ppMem, pv, cb, fAccess, NIL_RTR0PROCESS);
684}
685
686
687DECLHIDDEN(int) rtR0MemObjNativeReserveKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pvFixed, size_t cb, size_t uAlignment)
688{
689 /*
690 * MmCreateSection(SEC_RESERVE) + MmMapViewInSystemSpace perhaps?
691 */
692 return VERR_NOT_SUPPORTED;
693}
694
695
696DECLHIDDEN(int) rtR0MemObjNativeReserveUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment,
697 RTR0PROCESS R0Process)
698{
699 /*
700 * ZeCreateSection(SEC_RESERVE) + ZwMapViewOfSection perhaps?
701 */
702 return VERR_NOT_SUPPORTED;
703}
704
705
706/**
707 * Internal worker for rtR0MemObjNativeMapKernel and rtR0MemObjNativeMapUser.
708 *
709 * @returns IPRT status code.
710 * @param ppMem Where to store the memory object for the mapping.
711 * @param pMemToMap The memory object to map.
712 * @param pvFixed Where to map it. (void *)-1 if anywhere is fine.
713 * @param uAlignment The alignment requirement for the mapping.
714 * @param fProt The desired page protection for the mapping.
715 * @param R0Process If NIL_RTR0PROCESS map into system (kernel) memory.
716 * If not nil, it's the current process.
717 */
718static int rtR0MemObjNtMap(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, void *pvFixed, size_t uAlignment,
719 unsigned fProt, RTR0PROCESS R0Process)
720{
721 int rc = VERR_MAP_FAILED;
722
723 /*
724 * Check that the specified alignment is supported.
725 */
726 if (uAlignment > PAGE_SIZE)
727 return VERR_NOT_SUPPORTED;
728
729 /*
730 * There are two basic cases here, either we've got an MDL and can
731 * map it using MmMapLockedPages, or we've got a contiguous physical
732 * range (MMIO most likely) and can use MmMapIoSpace.
733 */
734 PRTR0MEMOBJNT pMemNtToMap = (PRTR0MEMOBJNT)pMemToMap;
735 if (pMemNtToMap->cMdls)
736 {
737 /* don't attempt map locked regions with more than one mdl. */
738 if (pMemNtToMap->cMdls != 1)
739 return VERR_NOT_SUPPORTED;
740
741#ifdef IPRT_TARGET_NT4
742 /* NT SP0 can't map to a specific address. */
743 if (pvFixed != (void *)-1)
744 return VERR_NOT_SUPPORTED;
745#endif
746
747 /* we can't map anything to the first page, sorry. */
748 if (pvFixed == 0)
749 return VERR_NOT_SUPPORTED;
750
751 /* only one system mapping for now - no time to figure out MDL restrictions right now. */
752 if ( pMemNtToMap->Core.uRel.Parent.cMappings
753 && R0Process == NIL_RTR0PROCESS)
754 return VERR_NOT_SUPPORTED;
755
756 __try
757 {
758 /** @todo uAlignment */
759 /** @todo How to set the protection on the pages? */
760#ifdef IPRT_TARGET_NT4
761 void *pv = MmMapLockedPages(pMemNtToMap->apMdls[0],
762 R0Process == NIL_RTR0PROCESS ? KernelMode : UserMode);
763#else
764 void *pv = MmMapLockedPagesSpecifyCache(pMemNtToMap->apMdls[0],
765 R0Process == NIL_RTR0PROCESS ? KernelMode : UserMode,
766 MmCached,
767 pvFixed != (void *)-1 ? pvFixed : NULL,
768 FALSE /* no bug check on failure */,
769 NormalPagePriority);
770#endif
771 if (pv)
772 {
773 NOREF(fProt);
774
775 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_MAPPING, pv,
776 pMemNtToMap->Core.cb);
777 if (pMemNt)
778 {
779 pMemNt->Core.u.Mapping.R0Process = R0Process;
780 *ppMem = &pMemNt->Core;
781 return VINF_SUCCESS;
782 }
783
784 rc = VERR_NO_MEMORY;
785 MmUnmapLockedPages(pv, pMemNtToMap->apMdls[0]);
786 }
787 }
788 __except(EXCEPTION_EXECUTE_HANDLER)
789 {
790 NTSTATUS rcNt = GetExceptionCode();
791 Log(("rtR0MemObjNtMap: Exception Code %#x\n", rcNt));
792
793 /* nothing */
794 rc = VERR_MAP_FAILED;
795 }
796
797 }
798 else
799 {
800 AssertReturn( pMemNtToMap->Core.enmType == RTR0MEMOBJTYPE_PHYS
801 && !pMemNtToMap->Core.u.Phys.fAllocated, VERR_INTERNAL_ERROR);
802
803 /* cannot map phys mem to user space (yet). */
804 if (R0Process != NIL_RTR0PROCESS)
805 return VERR_NOT_SUPPORTED;
806
807 /** @todo uAlignment */
808 /** @todo How to set the protection on the pages? */
809 PHYSICAL_ADDRESS Phys;
810 Phys.QuadPart = pMemNtToMap->Core.u.Phys.PhysBase;
811 void *pv = MmMapIoSpace(Phys, pMemNtToMap->Core.cb,
812 pMemNtToMap->Core.u.Phys.uCachePolicy == RTMEM_CACHE_POLICY_MMIO ? MmNonCached : MmCached);
813 if (pv)
814 {
815 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_MAPPING, pv,
816 pMemNtToMap->Core.cb);
817 if (pMemNt)
818 {
819 pMemNt->Core.u.Mapping.R0Process = R0Process;
820 *ppMem = &pMemNt->Core;
821 return VINF_SUCCESS;
822 }
823
824 rc = VERR_NO_MEMORY;
825 MmUnmapIoSpace(pv, pMemNtToMap->Core.cb);
826 }
827 }
828
829 NOREF(uAlignment); NOREF(fProt);
830 return rc;
831}
832
833
834DECLHIDDEN(int) rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, void *pvFixed, size_t uAlignment,
835 unsigned fProt, size_t offSub, size_t cbSub)
836{
837 AssertMsgReturn(!offSub && !cbSub, ("%#x %#x\n", offSub, cbSub), VERR_NOT_SUPPORTED);
838 return rtR0MemObjNtMap(ppMem, pMemToMap, pvFixed, uAlignment, fProt, NIL_RTR0PROCESS);
839}
840
841
842DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, RTR3PTR R3PtrFixed, size_t uAlignment, unsigned fProt, RTR0PROCESS R0Process)
843{
844 AssertReturn(R0Process == RTR0ProcHandleSelf(), VERR_NOT_SUPPORTED);
845 return rtR0MemObjNtMap(ppMem, pMemToMap, (void *)R3PtrFixed, uAlignment, fProt, R0Process);
846}
847
848
849DECLHIDDEN(int) rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub, size_t cbSub, uint32_t fProt)
850{
851 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)pMem;
852 if (!g_fResolvedDynamicApis)
853 rtR0MemObjNtResolveDynamicApis();
854
855 /*
856 * Seems there are some issues with this MmProtectMdlSystemAddress API, so
857 * this code isn't currently enabled until we've tested it with the verifier.
858 */
859#if 0
860 /*
861 * The API we've got requires a kernel mapping.
862 */
863 if ( pMemNt->cMdls
864 && g_pfnMmProtectMdlSystemAddress
865 && (g_uMajorVersion > 6 || (g_uMajorVersion == 6 && g_uMinorVersion >= 1)) /* Windows 7 and later. */
866 && pMemNt->Core.pv != NULL
867 && ( pMemNt->Core.enmType == RTR0MEMOBJTYPE_PAGE
868 || pMemNt->Core.enmType == RTR0MEMOBJTYPE_LOW
869 || pMemNt->Core.enmType == RTR0MEMOBJTYPE_CONT
870 || ( pMemNt->Core.enmType == RTR0MEMOBJTYPE_LOCK
871 && pMemNt->Core.u.Lock.R0Process == NIL_RTPROCESS)
872 || ( pMemNt->Core.enmType == RTR0MEMOBJTYPE_MAPPING
873 && pMemNt->Core.u.Mapping.R0Process == NIL_RTPROCESS) ) )
874 {
875 /* Convert the protection. */
876 LOCK_OPERATION enmLockOp;
877 ULONG fAccess;
878 switch (fProt)
879 {
880 case RTMEM_PROT_NONE:
881 fAccess = PAGE_NOACCESS;
882 enmLockOp = IoReadAccess;
883 break;
884 case RTMEM_PROT_READ:
885 fAccess = PAGE_READONLY;
886 enmLockOp = IoReadAccess;
887 break;
888 case RTMEM_PROT_WRITE:
889 case RTMEM_PROT_WRITE | RTMEM_PROT_READ:
890 fAccess = PAGE_READWRITE;
891 enmLockOp = IoModifyAccess;
892 break;
893 case RTMEM_PROT_EXEC:
894 fAccess = PAGE_EXECUTE;
895 enmLockOp = IoReadAccess;
896 break;
897 case RTMEM_PROT_EXEC | RTMEM_PROT_READ:
898 fAccess = PAGE_EXECUTE_READ;
899 enmLockOp = IoReadAccess;
900 break;
901 case RTMEM_PROT_EXEC | RTMEM_PROT_WRITE:
902 case RTMEM_PROT_EXEC | RTMEM_PROT_WRITE | RTMEM_PROT_READ:
903 fAccess = PAGE_EXECUTE_READWRITE;
904 enmLockOp = IoModifyAccess;
905 break;
906 default:
907 AssertFailedReturn(VERR_INVALID_FLAGS);
908 }
909
910 NTSTATUS rcNt = STATUS_SUCCESS;
911# if 0 /** @todo test this against the verifier. */
912 if (offSub == 0 && pMemNt->Core.cb == cbSub)
913 {
914 uint32_t iMdl = pMemNt->cMdls;
915 while (iMdl-- > 0)
916 {
917 rcNt = g_pfnMmProtectMdlSystemAddress(pMemNt->apMdls[i], fAccess);
918 if (!NT_SUCCESS(rcNt))
919 break;
920 }
921 }
922 else
923# endif
924 {
925 /*
926 * We ASSUME the following here:
927 * - MmProtectMdlSystemAddress can deal with nonpaged pool memory
928 * - MmProtectMdlSystemAddress doesn't actually store anything in the MDL we pass it.
929 * - We are not required to call MmProtectMdlSystemAddress with PAGE_READWRITE for the
930 * exact same ranges prior to freeing them.
931 *
932 * So, we lock the pages temporarily, call the API and unlock them.
933 */
934 uint8_t *pbCur = (uint8_t *)pMemNt->Core.pv + offSub;
935 while (cbSub > 0 && NT_SUCCESS(rcNt))
936 {
937 size_t cbCur = cbSub;
938 if (cbCur > MAX_LOCK_MEM_SIZE)
939 cbCur = MAX_LOCK_MEM_SIZE;
940 PMDL pMdl = IoAllocateMdl(pbCur, (ULONG)cbCur, FALSE, FALSE, NULL);
941 if (pMdl)
942 {
943 __try
944 {
945 MmProbeAndLockPages(pMdl, KernelMode, enmLockOp);
946 }
947 __except(EXCEPTION_EXECUTE_HANDLER)
948 {
949 rcNt = GetExceptionCode();
950 }
951 if (NT_SUCCESS(rcNt))
952 {
953 rcNt = g_pfnMmProtectMdlSystemAddress(pMdl, fAccess);
954 MmUnlockPages(pMdl);
955 }
956 IoFreeMdl(pMdl);
957 }
958 else
959 rcNt = STATUS_NO_MEMORY;
960 pbCur += cbCur;
961 cbSub -= cbCur;
962 }
963 }
964
965 if (NT_SUCCESS(rcNt))
966 return VINF_SUCCESS;
967 return RTErrConvertFromNtStatus(rcNt);
968 }
969#endif
970
971 return VERR_NOT_SUPPORTED;
972}
973
974
975DECLHIDDEN(RTHCPHYS) rtR0MemObjNativeGetPagePhysAddr(PRTR0MEMOBJINTERNAL pMem, size_t iPage)
976{
977 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)pMem;
978
979 if (pMemNt->cMdls)
980 {
981 if (pMemNt->cMdls == 1)
982 {
983 PPFN_NUMBER paPfns = MmGetMdlPfnArray(pMemNt->apMdls[0]);
984 return (RTHCPHYS)paPfns[iPage] << PAGE_SHIFT;
985 }
986
987 size_t iMdl = iPage / (MAX_LOCK_MEM_SIZE >> PAGE_SHIFT);
988 size_t iMdlPfn = iPage % (MAX_LOCK_MEM_SIZE >> PAGE_SHIFT);
989 PPFN_NUMBER paPfns = MmGetMdlPfnArray(pMemNt->apMdls[iMdl]);
990 return (RTHCPHYS)paPfns[iMdlPfn] << PAGE_SHIFT;
991 }
992
993 switch (pMemNt->Core.enmType)
994 {
995 case RTR0MEMOBJTYPE_MAPPING:
996 return rtR0MemObjNativeGetPagePhysAddr(pMemNt->Core.uRel.Child.pParent, iPage);
997
998 case RTR0MEMOBJTYPE_PHYS:
999 return pMemNt->Core.u.Phys.PhysBase + (iPage << PAGE_SHIFT);
1000
1001 case RTR0MEMOBJTYPE_PAGE:
1002 case RTR0MEMOBJTYPE_PHYS_NC:
1003 case RTR0MEMOBJTYPE_LOW:
1004 case RTR0MEMOBJTYPE_CONT:
1005 case RTR0MEMOBJTYPE_LOCK:
1006 default:
1007 AssertMsgFailed(("%d\n", pMemNt->Core.enmType));
1008 case RTR0MEMOBJTYPE_RES_VIRT:
1009 return NIL_RTHCPHYS;
1010 }
1011}
1012
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