VirtualBox

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

Last change on this file since 68123 was 63063, checked in by vboxsync, 8 years ago

IPRT: warnings

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 35.4 KB
Line 
1/* $Id: memobj-r0drv-nt.cpp 63063 2016-08-05 21:14:33Z vboxsync $ */
2/** @file
3 * IPRT - Ring-0 Memory Objects, NT.
4 */
5
6/*
7 * Copyright (C) 2006-2016 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 RT_NOREF1(fExecutable);
251
252 /*
253 * Try allocate the memory and create an MDL for them so
254 * we can query the physical addresses and do mappings later
255 * without running into out-of-memory conditions and similar problems.
256 */
257 int rc = VERR_NO_PAGE_MEMORY;
258 void *pv = ExAllocatePoolWithTag(NonPagedPool, cb, IPRT_NT_POOL_TAG);
259 if (pv)
260 {
261 PMDL pMdl = IoAllocateMdl(pv, (ULONG)cb, FALSE, FALSE, NULL);
262 if (pMdl)
263 {
264 MmBuildMdlForNonPagedPool(pMdl);
265#ifdef RT_ARCH_AMD64
266 MmProtectMdlSystemAddress(pMdl, PAGE_EXECUTE_READWRITE);
267#endif
268
269 /*
270 * Create the IPRT memory object.
271 */
272 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_PAGE, pv, cb);
273 if (pMemNt)
274 {
275 pMemNt->cMdls = 1;
276 pMemNt->apMdls[0] = pMdl;
277 *ppMem = &pMemNt->Core;
278 return VINF_SUCCESS;
279 }
280
281 rc = VERR_NO_MEMORY;
282 IoFreeMdl(pMdl);
283 }
284 ExFreePool(pv);
285 }
286 return rc;
287}
288
289
290DECLHIDDEN(int) rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
291{
292 AssertMsgReturn(cb <= _1G, ("%#x\n", cb), VERR_OUT_OF_RANGE); /* for safe size_t -> ULONG */
293
294 /*
295 * Try see if we get lucky first...
296 * (We could probably just assume we're lucky on NT4.)
297 */
298 int rc = rtR0MemObjNativeAllocPage(ppMem, cb, fExecutable);
299 if (RT_SUCCESS(rc))
300 {
301 size_t iPage = cb >> PAGE_SHIFT;
302 while (iPage-- > 0)
303 if (rtR0MemObjNativeGetPagePhysAddr(*ppMem, iPage) >= _4G)
304 {
305 rc = VERR_NO_LOW_MEMORY;
306 break;
307 }
308 if (RT_SUCCESS(rc))
309 return rc;
310
311 /* The following ASSUMES that rtR0MemObjNativeAllocPage returns a completed object. */
312 RTR0MemObjFree(*ppMem, false);
313 *ppMem = NULL;
314 }
315
316#ifndef IPRT_TARGET_NT4
317 /*
318 * Use MmAllocatePagesForMdl to specify the range of physical addresses we wish to use.
319 */
320 PHYSICAL_ADDRESS Zero;
321 Zero.QuadPart = 0;
322 PHYSICAL_ADDRESS HighAddr;
323 HighAddr.QuadPart = _4G - 1;
324 PMDL pMdl = MmAllocatePagesForMdl(Zero, HighAddr, Zero, cb);
325 if (pMdl)
326 {
327 if (MmGetMdlByteCount(pMdl) >= cb)
328 {
329 __try
330 {
331 void *pv = MmMapLockedPagesSpecifyCache(pMdl, KernelMode, MmCached, NULL /* no base address */,
332 FALSE /* no bug check on failure */, NormalPagePriority);
333 if (pv)
334 {
335 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_LOW, pv, cb);
336 if (pMemNt)
337 {
338 pMemNt->fAllocatedPagesForMdl = true;
339 pMemNt->cMdls = 1;
340 pMemNt->apMdls[0] = pMdl;
341 *ppMem = &pMemNt->Core;
342 return VINF_SUCCESS;
343 }
344 MmUnmapLockedPages(pv, pMdl);
345 }
346 }
347 __except(EXCEPTION_EXECUTE_HANDLER)
348 {
349# ifdef LOG_ENABLED
350 NTSTATUS rcNt = GetExceptionCode();
351 Log(("rtR0MemObjNativeAllocLow: Exception Code %#x\n", rcNt));
352# endif
353 /* nothing */
354 }
355 }
356 MmFreePagesFromMdl(pMdl);
357 ExFreePool(pMdl);
358 }
359#endif /* !IPRT_TARGET_NT4 */
360
361 /*
362 * Fall back on contiguous memory...
363 */
364 return rtR0MemObjNativeAllocCont(ppMem, cb, fExecutable);
365}
366
367
368/**
369 * Internal worker for rtR0MemObjNativeAllocCont(), rtR0MemObjNativeAllocPhys()
370 * and rtR0MemObjNativeAllocPhysNC() that takes a max physical address in addition
371 * to what rtR0MemObjNativeAllocCont() does.
372 *
373 * @returns IPRT status code.
374 * @param ppMem Where to store the pointer to the ring-0 memory object.
375 * @param cb The size.
376 * @param fExecutable Whether the mapping should be executable or not.
377 * @param PhysHighest The highest physical address for the pages in allocation.
378 * @param uAlignment The alignment of the physical memory to allocate.
379 * Supported values are PAGE_SIZE, _2M, _4M and _1G.
380 */
381static int rtR0MemObjNativeAllocContEx(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable, RTHCPHYS PhysHighest,
382 size_t uAlignment)
383{
384 AssertMsgReturn(cb <= _1G, ("%#x\n", cb), VERR_OUT_OF_RANGE); /* for safe size_t -> ULONG */
385 RT_NOREF1(fExecutable);
386#ifdef IPRT_TARGET_NT4
387 if (uAlignment != PAGE_SIZE)
388 return VERR_NOT_SUPPORTED;
389#endif
390
391 /*
392 * Allocate the memory and create an MDL for it.
393 */
394 PHYSICAL_ADDRESS PhysAddrHighest;
395 PhysAddrHighest.QuadPart = PhysHighest;
396#ifndef IPRT_TARGET_NT4
397 PHYSICAL_ADDRESS PhysAddrLowest, PhysAddrBoundary;
398 PhysAddrLowest.QuadPart = 0;
399 PhysAddrBoundary.QuadPart = (uAlignment == PAGE_SIZE) ? 0 : uAlignment;
400 void *pv = MmAllocateContiguousMemorySpecifyCache(cb, PhysAddrLowest, PhysAddrHighest, PhysAddrBoundary, MmCached);
401#else
402 void *pv = MmAllocateContiguousMemory(cb, PhysAddrHighest);
403#endif
404 if (!pv)
405 return VERR_NO_MEMORY;
406
407 PMDL pMdl = IoAllocateMdl(pv, (ULONG)cb, FALSE, FALSE, NULL);
408 if (pMdl)
409 {
410 MmBuildMdlForNonPagedPool(pMdl);
411#ifdef RT_ARCH_AMD64
412 MmProtectMdlSystemAddress(pMdl, PAGE_EXECUTE_READWRITE);
413#endif
414
415 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_CONT, pv, cb);
416 if (pMemNt)
417 {
418 pMemNt->Core.u.Cont.Phys = (RTHCPHYS)*MmGetMdlPfnArray(pMdl) << PAGE_SHIFT;
419 pMemNt->cMdls = 1;
420 pMemNt->apMdls[0] = pMdl;
421 *ppMem = &pMemNt->Core;
422 return VINF_SUCCESS;
423 }
424
425 IoFreeMdl(pMdl);
426 }
427 MmFreeContiguousMemory(pv);
428 return VERR_NO_MEMORY;
429}
430
431
432DECLHIDDEN(int) rtR0MemObjNativeAllocCont(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
433{
434 return rtR0MemObjNativeAllocContEx(ppMem, cb, fExecutable, _4G-1, PAGE_SIZE /* alignment */);
435}
436
437
438DECLHIDDEN(int) rtR0MemObjNativeAllocPhys(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest, size_t uAlignment)
439{
440#ifndef IPRT_TARGET_NT4
441 /*
442 * Try and see if we're lucky and get a contiguous chunk from MmAllocatePagesForMdl.
443 *
444 * This is preferable to using MmAllocateContiguousMemory because there are
445 * a few situations where the memory shouldn't be mapped, like for instance
446 * VT-x control memory. Since these are rather small allocations (one or
447 * two pages) MmAllocatePagesForMdl will probably be able to satisfy the
448 * request.
449 *
450 * If the allocation is big, the chances are *probably* not very good. The
451 * current limit is kind of random...
452 */
453 if ( cb < _128K
454 && uAlignment == PAGE_SIZE)
455
456 {
457 PHYSICAL_ADDRESS Zero;
458 Zero.QuadPart = 0;
459 PHYSICAL_ADDRESS HighAddr;
460 HighAddr.QuadPart = PhysHighest == NIL_RTHCPHYS ? MAXLONGLONG : PhysHighest;
461 PMDL pMdl = MmAllocatePagesForMdl(Zero, HighAddr, Zero, cb);
462 if (pMdl)
463 {
464 if (MmGetMdlByteCount(pMdl) >= cb)
465 {
466 PPFN_NUMBER paPfns = MmGetMdlPfnArray(pMdl);
467 PFN_NUMBER Pfn = paPfns[0] + 1;
468 const size_t cPages = cb >> PAGE_SHIFT;
469 size_t iPage;
470 for (iPage = 1; iPage < cPages; iPage++, Pfn++)
471 if (paPfns[iPage] != Pfn)
472 break;
473 if (iPage >= cPages)
474 {
475 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_PHYS, NULL, cb);
476 if (pMemNt)
477 {
478 pMemNt->Core.u.Phys.fAllocated = true;
479 pMemNt->Core.u.Phys.PhysBase = (RTHCPHYS)paPfns[0] << PAGE_SHIFT;
480 pMemNt->fAllocatedPagesForMdl = true;
481 pMemNt->cMdls = 1;
482 pMemNt->apMdls[0] = pMdl;
483 *ppMem = &pMemNt->Core;
484 return VINF_SUCCESS;
485 }
486 }
487 }
488 MmFreePagesFromMdl(pMdl);
489 ExFreePool(pMdl);
490 }
491 }
492#endif /* !IPRT_TARGET_NT4 */
493
494 return rtR0MemObjNativeAllocContEx(ppMem, cb, false, PhysHighest, uAlignment);
495}
496
497
498DECLHIDDEN(int) rtR0MemObjNativeAllocPhysNC(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest)
499{
500#ifndef IPRT_TARGET_NT4
501 PHYSICAL_ADDRESS Zero;
502 Zero.QuadPart = 0;
503 PHYSICAL_ADDRESS HighAddr;
504 HighAddr.QuadPart = PhysHighest == NIL_RTHCPHYS ? MAXLONGLONG : PhysHighest;
505 PMDL pMdl = MmAllocatePagesForMdl(Zero, HighAddr, Zero, cb);
506 if (pMdl)
507 {
508 if (MmGetMdlByteCount(pMdl) >= cb)
509 {
510 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_PHYS_NC, NULL, cb);
511 if (pMemNt)
512 {
513 pMemNt->fAllocatedPagesForMdl = true;
514 pMemNt->cMdls = 1;
515 pMemNt->apMdls[0] = pMdl;
516 *ppMem = &pMemNt->Core;
517 return VINF_SUCCESS;
518 }
519 }
520 MmFreePagesFromMdl(pMdl);
521 ExFreePool(pMdl);
522 }
523 return VERR_NO_MEMORY;
524#else /* IPRT_TARGET_NT4 */
525 RT_NOREF(ppMem, cb, PhysHighest);
526 return VERR_NOT_SUPPORTED;
527#endif /* IPRT_TARGET_NT4 */
528}
529
530
531DECLHIDDEN(int) rtR0MemObjNativeEnterPhys(PPRTR0MEMOBJINTERNAL ppMem, RTHCPHYS Phys, size_t cb, uint32_t uCachePolicy)
532{
533 AssertReturn(uCachePolicy == RTMEM_CACHE_POLICY_DONT_CARE || uCachePolicy == RTMEM_CACHE_POLICY_MMIO, VERR_NOT_SUPPORTED);
534
535 /*
536 * Validate the address range and create a descriptor for it.
537 */
538 PFN_NUMBER Pfn = (PFN_NUMBER)(Phys >> PAGE_SHIFT);
539 if (((RTHCPHYS)Pfn << PAGE_SHIFT) != Phys)
540 return VERR_ADDRESS_TOO_BIG;
541
542 /*
543 * Create the IPRT memory object.
544 */
545 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_PHYS, NULL, cb);
546 if (pMemNt)
547 {
548 pMemNt->Core.u.Phys.PhysBase = Phys;
549 pMemNt->Core.u.Phys.fAllocated = false;
550 pMemNt->Core.u.Phys.uCachePolicy = uCachePolicy;
551 *ppMem = &pMemNt->Core;
552 return VINF_SUCCESS;
553 }
554 return VERR_NO_MEMORY;
555}
556
557
558/**
559 * Internal worker for locking down pages.
560 *
561 * @return IPRT status code.
562 *
563 * @param ppMem Where to store the memory object pointer.
564 * @param pv First page.
565 * @param cb Number of bytes.
566 * @param fAccess The desired access, a combination of RTMEM_PROT_READ
567 * and RTMEM_PROT_WRITE.
568 * @param R0Process The process \a pv and \a cb refers to.
569 */
570static int rtR0MemObjNtLock(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb, uint32_t fAccess, RTR0PROCESS R0Process)
571{
572 /*
573 * Calc the number of MDLs we need and allocate the memory object structure.
574 */
575 size_t cMdls = cb / MAX_LOCK_MEM_SIZE;
576 if (cb % MAX_LOCK_MEM_SIZE)
577 cMdls++;
578 if (cMdls >= UINT32_MAX)
579 return VERR_OUT_OF_RANGE;
580 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(RT_OFFSETOF(RTR0MEMOBJNT, apMdls[cMdls]),
581 RTR0MEMOBJTYPE_LOCK, pv, cb);
582 if (!pMemNt)
583 return VERR_NO_MEMORY;
584
585 /*
586 * Loop locking down the sub parts of the memory.
587 */
588 int rc = VINF_SUCCESS;
589 size_t cbTotal = 0;
590 uint8_t *pb = (uint8_t *)pv;
591 uint32_t iMdl;
592 for (iMdl = 0; iMdl < cMdls; iMdl++)
593 {
594 /*
595 * Calc the Mdl size and allocate it.
596 */
597 size_t cbCur = cb - cbTotal;
598 if (cbCur > MAX_LOCK_MEM_SIZE)
599 cbCur = MAX_LOCK_MEM_SIZE;
600 AssertMsg(cbCur, ("cbCur: 0!\n"));
601 PMDL pMdl = IoAllocateMdl(pb, (ULONG)cbCur, FALSE, FALSE, NULL);
602 if (!pMdl)
603 {
604 rc = VERR_NO_MEMORY;
605 break;
606 }
607
608 /*
609 * Lock the pages.
610 */
611 __try
612 {
613 MmProbeAndLockPages(pMdl,
614 R0Process == NIL_RTR0PROCESS ? KernelMode : UserMode,
615 fAccess == RTMEM_PROT_READ
616 ? IoReadAccess
617 : fAccess == RTMEM_PROT_WRITE
618 ? IoWriteAccess
619 : IoModifyAccess);
620
621 pMemNt->apMdls[iMdl] = pMdl;
622 pMemNt->cMdls++;
623 }
624 __except(EXCEPTION_EXECUTE_HANDLER)
625 {
626 IoFreeMdl(pMdl);
627 rc = VERR_LOCK_FAILED;
628 break;
629 }
630
631 if (R0Process != NIL_RTR0PROCESS)
632 {
633 /* Make sure the user process can't change the allocation. */
634 pMemNt->pvSecureMem = MmSecureVirtualMemory(pv, cb,
635 fAccess & RTMEM_PROT_WRITE
636 ? PAGE_READWRITE
637 : PAGE_READONLY);
638 if (!pMemNt->pvSecureMem)
639 {
640 rc = VERR_NO_MEMORY;
641 break;
642 }
643 }
644
645 /* next */
646 cbTotal += cbCur;
647 pb += cbCur;
648 }
649 if (RT_SUCCESS(rc))
650 {
651 Assert(pMemNt->cMdls == cMdls);
652 pMemNt->Core.u.Lock.R0Process = R0Process;
653 *ppMem = &pMemNt->Core;
654 return rc;
655 }
656
657 /*
658 * We failed, perform cleanups.
659 */
660 while (iMdl-- > 0)
661 {
662 MmUnlockPages(pMemNt->apMdls[iMdl]);
663 IoFreeMdl(pMemNt->apMdls[iMdl]);
664 pMemNt->apMdls[iMdl] = NULL;
665 }
666 if (pMemNt->pvSecureMem)
667 {
668 MmUnsecureVirtualMemory(pMemNt->pvSecureMem);
669 pMemNt->pvSecureMem = NULL;
670 }
671
672 rtR0MemObjDelete(&pMemNt->Core);
673 return rc;
674}
675
676
677DECLHIDDEN(int) rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3Ptr, size_t cb, uint32_t fAccess,
678 RTR0PROCESS R0Process)
679{
680 AssertMsgReturn(R0Process == RTR0ProcHandleSelf(), ("%p != %p\n", R0Process, RTR0ProcHandleSelf()), VERR_NOT_SUPPORTED);
681 /* (Can use MmProbeAndLockProcessPages if we need to mess with other processes later.) */
682 return rtR0MemObjNtLock(ppMem, (void *)R3Ptr, cb, fAccess, R0Process);
683}
684
685
686DECLHIDDEN(int) rtR0MemObjNativeLockKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb, uint32_t fAccess)
687{
688 return rtR0MemObjNtLock(ppMem, pv, cb, fAccess, NIL_RTR0PROCESS);
689}
690
691
692DECLHIDDEN(int) rtR0MemObjNativeReserveKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pvFixed, size_t cb, size_t uAlignment)
693{
694 /*
695 * MmCreateSection(SEC_RESERVE) + MmMapViewInSystemSpace perhaps?
696 */
697 RT_NOREF4(ppMem, pvFixed, cb, uAlignment);
698 return VERR_NOT_SUPPORTED;
699}
700
701
702DECLHIDDEN(int) rtR0MemObjNativeReserveUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment,
703 RTR0PROCESS R0Process)
704{
705 /*
706 * ZeCreateSection(SEC_RESERVE) + ZwMapViewOfSection perhaps?
707 */
708 RT_NOREF5(ppMem, R3PtrFixed, cb, uAlignment, R0Process);
709 return VERR_NOT_SUPPORTED;
710}
711
712
713/**
714 * Internal worker for rtR0MemObjNativeMapKernel and rtR0MemObjNativeMapUser.
715 *
716 * @returns IPRT status code.
717 * @param ppMem Where to store the memory object for the mapping.
718 * @param pMemToMap The memory object to map.
719 * @param pvFixed Where to map it. (void *)-1 if anywhere is fine.
720 * @param uAlignment The alignment requirement for the mapping.
721 * @param fProt The desired page protection for the mapping.
722 * @param R0Process If NIL_RTR0PROCESS map into system (kernel) memory.
723 * If not nil, it's the current process.
724 */
725static int rtR0MemObjNtMap(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, void *pvFixed, size_t uAlignment,
726 unsigned fProt, RTR0PROCESS R0Process)
727{
728 int rc = VERR_MAP_FAILED;
729
730 /*
731 * Check that the specified alignment is supported.
732 */
733 if (uAlignment > PAGE_SIZE)
734 return VERR_NOT_SUPPORTED;
735
736 /*
737 * There are two basic cases here, either we've got an MDL and can
738 * map it using MmMapLockedPages, or we've got a contiguous physical
739 * range (MMIO most likely) and can use MmMapIoSpace.
740 */
741 PRTR0MEMOBJNT pMemNtToMap = (PRTR0MEMOBJNT)pMemToMap;
742 if (pMemNtToMap->cMdls)
743 {
744 /* don't attempt map locked regions with more than one mdl. */
745 if (pMemNtToMap->cMdls != 1)
746 return VERR_NOT_SUPPORTED;
747
748#ifdef IPRT_TARGET_NT4
749 /* NT SP0 can't map to a specific address. */
750 if (pvFixed != (void *)-1)
751 return VERR_NOT_SUPPORTED;
752#endif
753
754 /* we can't map anything to the first page, sorry. */
755 if (pvFixed == 0)
756 return VERR_NOT_SUPPORTED;
757
758 /* only one system mapping for now - no time to figure out MDL restrictions right now. */
759 if ( pMemNtToMap->Core.uRel.Parent.cMappings
760 && R0Process == NIL_RTR0PROCESS)
761 return VERR_NOT_SUPPORTED;
762
763 __try
764 {
765 /** @todo uAlignment */
766 /** @todo How to set the protection on the pages? */
767#ifdef IPRT_TARGET_NT4
768 void *pv = MmMapLockedPages(pMemNtToMap->apMdls[0],
769 R0Process == NIL_RTR0PROCESS ? KernelMode : UserMode);
770#else
771 void *pv = MmMapLockedPagesSpecifyCache(pMemNtToMap->apMdls[0],
772 R0Process == NIL_RTR0PROCESS ? KernelMode : UserMode,
773 MmCached,
774 pvFixed != (void *)-1 ? pvFixed : NULL,
775 FALSE /* no bug check on failure */,
776 NormalPagePriority);
777#endif
778 if (pv)
779 {
780 NOREF(fProt);
781
782 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_MAPPING, pv,
783 pMemNtToMap->Core.cb);
784 if (pMemNt)
785 {
786 pMemNt->Core.u.Mapping.R0Process = R0Process;
787 *ppMem = &pMemNt->Core;
788 return VINF_SUCCESS;
789 }
790
791 rc = VERR_NO_MEMORY;
792 MmUnmapLockedPages(pv, pMemNtToMap->apMdls[0]);
793 }
794 }
795 __except(EXCEPTION_EXECUTE_HANDLER)
796 {
797#ifdef LOG_ENABLED
798 NTSTATUS rcNt = GetExceptionCode();
799 Log(("rtR0MemObjNtMap: Exception Code %#x\n", rcNt));
800#endif
801
802 /* nothing */
803 rc = VERR_MAP_FAILED;
804 }
805
806 }
807 else
808 {
809 AssertReturn( pMemNtToMap->Core.enmType == RTR0MEMOBJTYPE_PHYS
810 && !pMemNtToMap->Core.u.Phys.fAllocated, VERR_INTERNAL_ERROR);
811
812 /* cannot map phys mem to user space (yet). */
813 if (R0Process != NIL_RTR0PROCESS)
814 return VERR_NOT_SUPPORTED;
815
816 /** @todo uAlignment */
817 /** @todo How to set the protection on the pages? */
818 PHYSICAL_ADDRESS Phys;
819 Phys.QuadPart = pMemNtToMap->Core.u.Phys.PhysBase;
820 void *pv = MmMapIoSpace(Phys, pMemNtToMap->Core.cb,
821 pMemNtToMap->Core.u.Phys.uCachePolicy == RTMEM_CACHE_POLICY_MMIO ? MmNonCached : MmCached);
822 if (pv)
823 {
824 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)rtR0MemObjNew(sizeof(*pMemNt), RTR0MEMOBJTYPE_MAPPING, pv,
825 pMemNtToMap->Core.cb);
826 if (pMemNt)
827 {
828 pMemNt->Core.u.Mapping.R0Process = R0Process;
829 *ppMem = &pMemNt->Core;
830 return VINF_SUCCESS;
831 }
832
833 rc = VERR_NO_MEMORY;
834 MmUnmapIoSpace(pv, pMemNtToMap->Core.cb);
835 }
836 }
837
838 NOREF(uAlignment); NOREF(fProt);
839 return rc;
840}
841
842
843DECLHIDDEN(int) rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, void *pvFixed, size_t uAlignment,
844 unsigned fProt, size_t offSub, size_t cbSub)
845{
846 AssertMsgReturn(!offSub && !cbSub, ("%#x %#x\n", offSub, cbSub), VERR_NOT_SUPPORTED);
847 return rtR0MemObjNtMap(ppMem, pMemToMap, pvFixed, uAlignment, fProt, NIL_RTR0PROCESS);
848}
849
850
851DECLHIDDEN(int) rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, RTR3PTR R3PtrFixed, size_t uAlignment, unsigned fProt, RTR0PROCESS R0Process)
852{
853 AssertReturn(R0Process == RTR0ProcHandleSelf(), VERR_NOT_SUPPORTED);
854 return rtR0MemObjNtMap(ppMem, pMemToMap, (void *)R3PtrFixed, uAlignment, fProt, R0Process);
855}
856
857
858DECLHIDDEN(int) rtR0MemObjNativeProtect(PRTR0MEMOBJINTERNAL pMem, size_t offSub, size_t cbSub, uint32_t fProt)
859{
860#if 0
861 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)pMem;
862#endif
863 if (!g_fResolvedDynamicApis)
864 rtR0MemObjNtResolveDynamicApis();
865
866 /*
867 * Seems there are some issues with this MmProtectMdlSystemAddress API, so
868 * this code isn't currently enabled until we've tested it with the verifier.
869 */
870#if 0
871 /*
872 * The API we've got requires a kernel mapping.
873 */
874 if ( pMemNt->cMdls
875 && g_pfnMmProtectMdlSystemAddress
876 && (g_uMajorVersion > 6 || (g_uMajorVersion == 6 && g_uMinorVersion >= 1)) /* Windows 7 and later. */
877 && pMemNt->Core.pv != NULL
878 && ( pMemNt->Core.enmType == RTR0MEMOBJTYPE_PAGE
879 || pMemNt->Core.enmType == RTR0MEMOBJTYPE_LOW
880 || pMemNt->Core.enmType == RTR0MEMOBJTYPE_CONT
881 || ( pMemNt->Core.enmType == RTR0MEMOBJTYPE_LOCK
882 && pMemNt->Core.u.Lock.R0Process == NIL_RTPROCESS)
883 || ( pMemNt->Core.enmType == RTR0MEMOBJTYPE_MAPPING
884 && pMemNt->Core.u.Mapping.R0Process == NIL_RTPROCESS) ) )
885 {
886 /* Convert the protection. */
887 LOCK_OPERATION enmLockOp;
888 ULONG fAccess;
889 switch (fProt)
890 {
891 case RTMEM_PROT_NONE:
892 fAccess = PAGE_NOACCESS;
893 enmLockOp = IoReadAccess;
894 break;
895 case RTMEM_PROT_READ:
896 fAccess = PAGE_READONLY;
897 enmLockOp = IoReadAccess;
898 break;
899 case RTMEM_PROT_WRITE:
900 case RTMEM_PROT_WRITE | RTMEM_PROT_READ:
901 fAccess = PAGE_READWRITE;
902 enmLockOp = IoModifyAccess;
903 break;
904 case RTMEM_PROT_EXEC:
905 fAccess = PAGE_EXECUTE;
906 enmLockOp = IoReadAccess;
907 break;
908 case RTMEM_PROT_EXEC | RTMEM_PROT_READ:
909 fAccess = PAGE_EXECUTE_READ;
910 enmLockOp = IoReadAccess;
911 break;
912 case RTMEM_PROT_EXEC | RTMEM_PROT_WRITE:
913 case RTMEM_PROT_EXEC | RTMEM_PROT_WRITE | RTMEM_PROT_READ:
914 fAccess = PAGE_EXECUTE_READWRITE;
915 enmLockOp = IoModifyAccess;
916 break;
917 default:
918 AssertFailedReturn(VERR_INVALID_FLAGS);
919 }
920
921 NTSTATUS rcNt = STATUS_SUCCESS;
922# if 0 /** @todo test this against the verifier. */
923 if (offSub == 0 && pMemNt->Core.cb == cbSub)
924 {
925 uint32_t iMdl = pMemNt->cMdls;
926 while (iMdl-- > 0)
927 {
928 rcNt = g_pfnMmProtectMdlSystemAddress(pMemNt->apMdls[i], fAccess);
929 if (!NT_SUCCESS(rcNt))
930 break;
931 }
932 }
933 else
934# endif
935 {
936 /*
937 * We ASSUME the following here:
938 * - MmProtectMdlSystemAddress can deal with nonpaged pool memory
939 * - MmProtectMdlSystemAddress doesn't actually store anything in the MDL we pass it.
940 * - We are not required to call MmProtectMdlSystemAddress with PAGE_READWRITE for the
941 * exact same ranges prior to freeing them.
942 *
943 * So, we lock the pages temporarily, call the API and unlock them.
944 */
945 uint8_t *pbCur = (uint8_t *)pMemNt->Core.pv + offSub;
946 while (cbSub > 0 && NT_SUCCESS(rcNt))
947 {
948 size_t cbCur = cbSub;
949 if (cbCur > MAX_LOCK_MEM_SIZE)
950 cbCur = MAX_LOCK_MEM_SIZE;
951 PMDL pMdl = IoAllocateMdl(pbCur, (ULONG)cbCur, FALSE, FALSE, NULL);
952 if (pMdl)
953 {
954 __try
955 {
956 MmProbeAndLockPages(pMdl, KernelMode, enmLockOp);
957 }
958 __except(EXCEPTION_EXECUTE_HANDLER)
959 {
960 rcNt = GetExceptionCode();
961 }
962 if (NT_SUCCESS(rcNt))
963 {
964 rcNt = g_pfnMmProtectMdlSystemAddress(pMdl, fAccess);
965 MmUnlockPages(pMdl);
966 }
967 IoFreeMdl(pMdl);
968 }
969 else
970 rcNt = STATUS_NO_MEMORY;
971 pbCur += cbCur;
972 cbSub -= cbCur;
973 }
974 }
975
976 if (NT_SUCCESS(rcNt))
977 return VINF_SUCCESS;
978 return RTErrConvertFromNtStatus(rcNt);
979 }
980#else
981 RT_NOREF4(pMem, offSub, cbSub, fProt);
982#endif
983
984 return VERR_NOT_SUPPORTED;
985}
986
987
988DECLHIDDEN(RTHCPHYS) rtR0MemObjNativeGetPagePhysAddr(PRTR0MEMOBJINTERNAL pMem, size_t iPage)
989{
990 PRTR0MEMOBJNT pMemNt = (PRTR0MEMOBJNT)pMem;
991
992 if (pMemNt->cMdls)
993 {
994 if (pMemNt->cMdls == 1)
995 {
996 PPFN_NUMBER paPfns = MmGetMdlPfnArray(pMemNt->apMdls[0]);
997 return (RTHCPHYS)paPfns[iPage] << PAGE_SHIFT;
998 }
999
1000 size_t iMdl = iPage / (MAX_LOCK_MEM_SIZE >> PAGE_SHIFT);
1001 size_t iMdlPfn = iPage % (MAX_LOCK_MEM_SIZE >> PAGE_SHIFT);
1002 PPFN_NUMBER paPfns = MmGetMdlPfnArray(pMemNt->apMdls[iMdl]);
1003 return (RTHCPHYS)paPfns[iMdlPfn] << PAGE_SHIFT;
1004 }
1005
1006 switch (pMemNt->Core.enmType)
1007 {
1008 case RTR0MEMOBJTYPE_MAPPING:
1009 return rtR0MemObjNativeGetPagePhysAddr(pMemNt->Core.uRel.Child.pParent, iPage);
1010
1011 case RTR0MEMOBJTYPE_PHYS:
1012 return pMemNt->Core.u.Phys.PhysBase + (iPage << PAGE_SHIFT);
1013
1014 case RTR0MEMOBJTYPE_PAGE:
1015 case RTR0MEMOBJTYPE_PHYS_NC:
1016 case RTR0MEMOBJTYPE_LOW:
1017 case RTR0MEMOBJTYPE_CONT:
1018 case RTR0MEMOBJTYPE_LOCK:
1019 default:
1020 AssertMsgFailed(("%d\n", pMemNt->Core.enmType));
1021 case RTR0MEMOBJTYPE_RES_VIRT:
1022 return NIL_RTHCPHYS;
1023 }
1024}
1025
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