VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/darwin/memobj-r0drv-darwin.cpp@ 10450

Last change on this file since 10450 was 9063, checked in by vboxsync, 16 years ago

Workaround for #2833.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 23.4 KB
Line 
1/* $Id: memobj-r0drv-darwin.cpp 9063 2008-05-23 08:50:12Z vboxsync $ */
2/** @file
3 * IPRT - Ring-0 Memory Objects, Darwin.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include "the-darwin-kernel.h"
36
37#include <iprt/memobj.h>
38#include <iprt/alloc.h>
39#include <iprt/assert.h>
40#include <iprt/log.h>
41#include <iprt/param.h>
42#include <iprt/string.h>
43#include <iprt/process.h>
44#include "internal/memobj.h"
45
46#define USE_VM_MAP_WIRE
47
48
49/*******************************************************************************
50* Structures and Typedefs *
51*******************************************************************************/
52/**
53 * The Darwin version of the memory object structure.
54 */
55typedef struct RTR0MEMOBJDARWIN
56{
57 /** The core structure. */
58 RTR0MEMOBJINTERNAL Core;
59 /** Pointer to the memory descriptor created for allocated and locked memory. */
60 IOMemoryDescriptor *pMemDesc;
61 /** Pointer to the memory mapping object for mapped memory. */
62 IOMemoryMap *pMemMap;
63} RTR0MEMOBJDARWIN, *PRTR0MEMOBJDARWIN;
64
65
66int rtR0MemObjNativeFree(RTR0MEMOBJ pMem)
67{
68 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)pMem;
69
70 /*
71 * Release the IOMemoryDescriptor/IOMemoryMap associated with the object.
72 */
73 if (pMemDarwin->pMemDesc)
74 {
75 if (pMemDarwin->Core.enmType == RTR0MEMOBJTYPE_LOCK)
76 pMemDarwin->pMemDesc->complete(); /* paranoia */
77 pMemDarwin->pMemDesc->release();
78 pMemDarwin->pMemDesc = NULL;
79 Assert(!pMemDarwin->pMemMap);
80 }
81 else if (pMemDarwin->pMemMap)
82 {
83 pMemDarwin->pMemMap->release();
84 pMemDarwin->pMemMap = NULL;
85 }
86
87 /*
88 * Release any memory that we've allocated or locked.
89 */
90 switch (pMemDarwin->Core.enmType)
91 {
92 case RTR0MEMOBJTYPE_LOW:
93 case RTR0MEMOBJTYPE_PAGE:
94 IOFreeAligned(pMemDarwin->Core.pv, pMemDarwin->Core.cb);
95 break;
96
97 case RTR0MEMOBJTYPE_CONT:
98 IOFreeContiguous(pMemDarwin->Core.pv, pMemDarwin->Core.cb);
99 break;
100
101 case RTR0MEMOBJTYPE_LOCK:
102 {
103#ifdef USE_VM_MAP_WIRE
104 vm_map_t Map = pMemDarwin->Core.u.Lock.R0Process != NIL_RTR0PROCESS
105 ? get_task_map((task_t)pMemDarwin->Core.u.Lock.R0Process)
106 : kernel_map;
107 kern_return_t kr = vm_map_unwire(Map,
108 (vm_map_offset_t)pMemDarwin->Core.pv,
109 (vm_map_offset_t)pMemDarwin->Core.pv + pMemDarwin->Core.cb,
110 0 /* not user */);
111 AssertRC(kr == KERN_SUCCESS); /** @todo don't ignore... */
112#endif
113 break;
114 }
115
116 case RTR0MEMOBJTYPE_PHYS:
117 /*if (pMemDarwin->Core.u.Phys.fAllocated)
118 IOFreePhysical(pMemDarwin->Core.u.Phys.PhysBase, pMemDarwin->Core.cb);*/
119 Assert(!pMemDarwin->Core.u.Phys.fAllocated);
120 break;
121
122 case RTR0MEMOBJTYPE_PHYS_NC:
123 AssertMsgFailed(("RTR0MEMOBJTYPE_PHYS_NC\n"));
124 return VERR_INTERNAL_ERROR;
125 break;
126
127 case RTR0MEMOBJTYPE_RES_VIRT:
128 AssertMsgFailed(("RTR0MEMOBJTYPE_RES_VIRT\n"));
129 return VERR_INTERNAL_ERROR;
130 break;
131
132 case RTR0MEMOBJTYPE_MAPPING:
133 /* nothing to do here. */
134 break;
135
136 default:
137 AssertMsgFailed(("enmType=%d\n", pMemDarwin->Core.enmType));
138 return VERR_INTERNAL_ERROR;
139 }
140
141 return VINF_SUCCESS;
142}
143
144
145int rtR0MemObjNativeAllocPage(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
146{
147 /*
148 * Try allocate the memory and create it's IOMemoryDescriptor first.
149 */
150 int rc = VERR_NO_PAGE_MEMORY;
151 AssertCompile(sizeof(IOPhysicalAddress) == 4);
152 void *pv = IOMallocAligned(cb, PAGE_SIZE);
153 if (pv)
154 {
155 IOMemoryDescriptor *pMemDesc = IOMemoryDescriptor::withAddress((vm_address_t)pv, cb, kIODirectionInOut, kernel_task);
156 if (pMemDesc)
157 {
158 /*
159 * Create the IPRT memory object.
160 */
161 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)rtR0MemObjNew(sizeof(*pMemDarwin), RTR0MEMOBJTYPE_PAGE, pv, cb);
162 if (pMemDarwin)
163 {
164 pMemDarwin->pMemDesc = pMemDesc;
165 *ppMem = &pMemDarwin->Core;
166 return VINF_SUCCESS;
167 }
168
169 rc = VERR_NO_MEMORY;
170 pMemDesc->release();
171 }
172 else
173 rc = VERR_MEMOBJ_INIT_FAILED;
174 IOFreeAligned(pv, cb);
175 }
176 return rc;
177}
178
179
180int rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
181{
182#if 1
183 /*
184 * Allocating 128KB continguous memory for the low page pool can bit a bit
185 * exhausting on the kernel, it frequently causes the entire box to lock
186 * up on startup.
187 *
188 * So, try allocate the memory using IOMallocAligned first and if we get any high
189 * physical memory we'll release it and fall back on IOMAllocContiguous.
190 */
191 int rc = VERR_NO_PAGE_MEMORY;
192 AssertCompile(sizeof(IOPhysicalAddress) == 4);
193 void *pv = IOMallocAligned(cb, PAGE_SIZE);
194 if (pv)
195 {
196 IOMemoryDescriptor *pMemDesc = IOMemoryDescriptor::withAddress((vm_address_t)pv, cb, kIODirectionInOut, kernel_task);
197 if (pMemDesc)
198 {
199 /*
200 * Check if it's all below 4GB.
201 */
202 for (IOByteCount off = 0; off < cb; off += PAGE_SIZE)
203 {
204 addr64_t Addr = pMemDesc->getPhysicalSegment64(off, NULL);
205 if (Addr > (uint32_t)(_4G - PAGE_SIZE))
206 {
207 /* Ok, we failed, fall back on contiguous allocation. */
208 pMemDesc->release();
209 IOFreeAligned(pv, cb);
210 return rtR0MemObjNativeAllocCont(ppMem, cb, fExecutable);
211 }
212 }
213
214 /*
215 * Create the IPRT memory object.
216 */
217 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)rtR0MemObjNew(sizeof(*pMemDarwin), RTR0MEMOBJTYPE_LOW, pv, cb);
218 if (pMemDarwin)
219 {
220 pMemDarwin->pMemDesc = pMemDesc;
221 *ppMem = &pMemDarwin->Core;
222 return VINF_SUCCESS;
223 }
224
225 rc = VERR_NO_MEMORY;
226 pMemDesc->release();
227 }
228 else
229 rc = VERR_MEMOBJ_INIT_FAILED;
230 IOFreeAligned(pv, cb);
231 }
232 return rc;
233
234#else
235
236 /*
237 * IOMallocContiguous is the most suitable API.
238 */
239 return rtR0MemObjNativeAllocCont(ppMem, cb, fExecutable);
240#endif
241}
242
243
244int rtR0MemObjNativeAllocCont(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
245{
246 /*
247 * Try allocate the memory and create it's IOMemoryDescriptor first.
248 */
249 int rc = VERR_NO_CONT_MEMORY;
250 AssertCompile(sizeof(IOPhysicalAddress) == 4);
251
252 /// @todo
253 // Use IOBufferMemoryDescriptor::inTaskWithPhysicalMask(kernel_task, kIOMemoryKernelUserShared | kIODirectionInOut,
254 // cb, (_4G - 1) ^ PAGE_OFFSET_MASK);
255#if 1 /* seems to work fine for cb == PAGE_SIZE, the other variant doesn't. */
256 IOPhysicalAddress PhysAddrIgnored = 0;
257 void *pv = IOMallocContiguous(cb, PAGE_SIZE, &PhysAddrIgnored);
258#else
259 void *pv = IOMallocContiguous(cb, PAGE_SIZE, NULL);
260#endif
261 if (pv)
262 {
263 IOMemoryDescriptor *pMemDesc = IOMemoryDescriptor::withAddress((vm_address_t)pv, cb, kIODirectionInOut, kernel_task);
264 if (pMemDesc)
265 {
266 /* a bit of useful paranoia. */
267 addr64_t PhysAddr = pMemDesc->getPhysicalSegment64(0, NULL);
268 Assert(PhysAddr == pMemDesc->getPhysicalAddress());
269 if ( PhysAddr > 0
270 && PhysAddr <= _4G
271 && PhysAddr + cb <= _4G)
272 {
273 /*
274 * Create the IPRT memory object.
275 */
276 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)rtR0MemObjNew(sizeof(*pMemDarwin), RTR0MEMOBJTYPE_CONT, pv, cb);
277 if (pMemDarwin)
278 {
279 pMemDarwin->Core.u.Cont.Phys = PhysAddr;
280 pMemDarwin->pMemDesc = pMemDesc;
281 *ppMem = &pMemDarwin->Core;
282 return VINF_SUCCESS;
283 }
284
285 rc = VERR_NO_MEMORY;
286 }
287 else
288 {
289 printf("rtR0MemObjNativeAllocCont: PhysAddr=%llx cb=%#x\n", (unsigned long long)PhysAddr, cb);
290 AssertMsgFailed(("PhysAddr=%llx\n", (unsigned long long)PhysAddr));
291 rc = VERR_INTERNAL_ERROR;
292 }
293 pMemDesc->release();
294 }
295 else
296 rc = VERR_MEMOBJ_INIT_FAILED;
297 IOFreeContiguous(pv, cb);
298 }
299
300 /*
301 * Workaround for odd IOMallocContiguous behavior, just in case.
302 */
303 if (rc == VERR_INTERNAL_ERROR && cb <= PAGE_SIZE)
304 rc = rtR0MemObjNativeAllocCont(ppMem, cb + PAGE_SIZE, fExecutable);
305 return rc;
306}
307
308
309int rtR0MemObjNativeAllocPhys(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest)
310{
311#if 0 /* turned out IOMallocPhysical isn't exported yet. sigh. */
312 /*
313 * Try allocate the memory and create it's IOMemoryDescriptor first.
314 * Note that IOMallocPhysical is not working correctly (it's ignoring the mask).
315 */
316
317 /* first calc the mask (in the hope that it'll be used) */
318 IOPhysicalAddress PhysMask = ~(IOPhysicalAddress)PAGE_OFFSET_MASK;
319 if (PhysHighest != NIL_RTHCPHYS)
320 {
321 PhysMask = ~(IOPhysicalAddress)0;
322 while (PhysMask > PhysHighest)
323 PhysMask >>= 1;
324 AssertReturn(PhysMask + 1 < cb, VERR_INVALID_PARAMETER);
325 PhysMask &= ~(IOPhysicalAddress)PAGE_OFFSET_MASK;
326 }
327
328 /* try allocate physical memory. */
329 int rc = VERR_NO_PHYS_MEMORY;
330 mach_vm_address_t PhysAddr64 = IOMallocPhysical(cb, PhysMask);
331 if (PhysAddr64)
332 {
333 IOPhysicalAddress PhysAddr = PhysAddr64;
334 if ( PhysAddr == PhysAddr64
335 && PhysAddr < PhysHighest
336 && PhysAddr + cb <= PhysHighest)
337 {
338 /* create a descriptor. */
339 IOMemoryDescriptor *pMemDesc = IOMemoryDescriptor::withPhysicalAddress(PhysAddr, cb, kIODirectionInOut);
340 if (pMemDesc)
341 {
342 Assert(PhysAddr == pMemDesc->getPhysicalAddress());
343
344 /*
345 * Create the IPRT memory object.
346 */
347 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)rtR0MemObjNew(sizeof(*pMemDarwin), RTR0MEMOBJTYPE_PHYS, NULL, cb);
348 if (pMemDarwin)
349 {
350 pMemDarwin->Core.u.Phys.PhysBase = PhysAddr;
351 pMemDarwin->Core.u.Phys.fAllocated = true;
352 pMemDarwin->pMemDesc = pMemDesc;
353 *ppMem = &pMemDarwin->Core;
354 return VINF_SUCCESS;
355 }
356
357 rc = VERR_NO_MEMORY;
358 pMemDesc->release();
359 }
360 else
361 rc = VERR_MEMOBJ_INIT_FAILED;
362 }
363 else
364 {
365 AssertMsgFailed(("PhysAddr=%#llx PhysAddr64=%#llx PhysHigest=%#llx\n", (unsigned long long)PhysAddr,
366 (unsigned long long)PhysAddr64, (unsigned long long)PhysHighest));
367 rc = VERR_INTERNAL_ERROR;
368 }
369
370 IOFreePhysical(PhysAddr64, cb);
371 }
372
373 /*
374 * Just in case IOMallocContiguous doesn't work right, we can try fall back
375 * on a contiguous allcation.
376 */
377 if (rc == VERR_INTERNAL_ERROR || rc == VERR_NO_PHYS_MEMORY)
378 {
379 int rc2 = rtR0MemObjNativeAllocCont(ppMem, cb, false);
380 if (RT_SUCCESS(rc2))
381 rc = rc2;
382 }
383
384 return rc;
385
386#else
387
388 return rtR0MemObjNativeAllocCont(ppMem, cb, false);
389#endif
390}
391
392
393int rtR0MemObjNativeAllocPhysNC(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest)
394{
395 /** @todo rtR0MemObjNativeAllocPhys / darwin.
396 * This might be a bit problematic and may very well require having to create our own
397 * object which we populate with pages but without mapping it into any address space.
398 * Estimate is 2-3 days.
399 */
400 return VERR_NOT_SUPPORTED;
401}
402
403
404int rtR0MemObjNativeEnterPhys(PPRTR0MEMOBJINTERNAL ppMem, RTHCPHYS Phys, size_t cb)
405{
406 /*
407 * Validate the address range and create a descriptor for it.
408 */
409 int rc = VERR_ADDRESS_TOO_BIG;
410 IOPhysicalAddress PhysAddr = Phys;
411 if (PhysAddr == Phys)
412 {
413 IOMemoryDescriptor *pMemDesc = IOMemoryDescriptor::withPhysicalAddress(PhysAddr, cb, kIODirectionInOut);
414 if (pMemDesc)
415 {
416 Assert(PhysAddr == pMemDesc->getPhysicalAddress());
417
418 /*
419 * Create the IPRT memory object.
420 */
421 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)rtR0MemObjNew(sizeof(*pMemDarwin), RTR0MEMOBJTYPE_PHYS, NULL, cb);
422 if (pMemDarwin)
423 {
424 pMemDarwin->Core.u.Phys.PhysBase = PhysAddr;
425 pMemDarwin->Core.u.Phys.fAllocated = false;
426 pMemDarwin->pMemDesc = pMemDesc;
427 *ppMem = &pMemDarwin->Core;
428 return VINF_SUCCESS;
429 }
430
431 rc = VERR_NO_MEMORY;
432 pMemDesc->release();
433 }
434 }
435 else
436 AssertMsgFailed(("%#llx\n", (unsigned long long)Phys));
437 return rc;
438}
439
440
441/**
442 * Internal worker for locking down pages.
443 *
444 * @return IPRT status code.
445 *
446 * @param ppMem Where to store the memory object pointer.
447 * @param pv First page.
448 * @param cb Number of bytes.
449 * @param Task The task \a pv and \a cb refers to.
450 */
451static int rtR0MemObjNativeLock(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb, task_t Task)
452{
453#ifdef USE_VM_MAP_WIRE
454 vm_map_t Map = get_task_map(Task);
455 Assert(Map);
456
457 /*
458 * First try lock the memory.
459 */
460 int rc = VERR_LOCK_FAILED;
461 kern_return_t kr = vm_map_wire(get_task_map(Task),
462 (vm_map_offset_t)pv,
463 (vm_map_offset_t)pv + cb,
464 VM_PROT_DEFAULT,
465 0 /* not user */);
466 if (kr == KERN_SUCCESS)
467 {
468 /*
469 * Create the IPRT memory object.
470 */
471 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)rtR0MemObjNew(sizeof(*pMemDarwin), RTR0MEMOBJTYPE_LOCK, pv, cb);
472 if (pMemDarwin)
473 {
474 pMemDarwin->Core.u.Lock.R0Process = (RTR0PROCESS)Task;
475 *ppMem = &pMemDarwin->Core;
476 return VINF_SUCCESS;
477 }
478
479 kr = vm_map_unwire(get_task_map(Task), (vm_map_offset_t)pv, (vm_map_offset_t)pv + cb, 0 /* not user */);
480 Assert(kr == KERN_SUCCESS);
481 rc = VERR_NO_MEMORY;
482 }
483
484#else
485
486 /*
487 * Create a descriptor and try lock it (prepare).
488 */
489 int rc = VERR_MEMOBJ_INIT_FAILED;
490 IOMemoryDescriptor *pMemDesc = IOMemoryDescriptor::withAddress((vm_address_t)pv, cb, kIODirectionInOut, Task);
491 if (pMemDesc)
492 {
493 IOReturn IORet = pMemDesc->prepare(kIODirectionInOut);
494 if (IORet == kIOReturnSuccess)
495 {
496 /*
497 * Create the IPRT memory object.
498 */
499 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)rtR0MemObjNew(sizeof(*pMemDarwin), RTR0MEMOBJTYPE_LOCK, pv, cb);
500 if (pMemDarwin)
501 {
502 pMemDarwin->Core.u.Lock.R0Process = (RTR0PROCESS)Task;
503 pMemDarwin->pMemDesc = pMemDesc;
504 *ppMem = &pMemDarwin->Core;
505 return VINF_SUCCESS;
506 }
507
508 pMemDesc->complete();
509 rc = VERR_NO_MEMORY;
510 }
511 else
512 rc = VERR_LOCK_FAILED;
513 pMemDesc->release();
514 }
515#endif
516 return rc;
517}
518
519
520int rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3Ptr, size_t cb, RTR0PROCESS R0Process)
521{
522 return rtR0MemObjNativeLock(ppMem, (void *)R3Ptr, cb, (task_t)R0Process);
523}
524
525
526int rtR0MemObjNativeLockKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb)
527{
528 return rtR0MemObjNativeLock(ppMem, pv, cb, kernel_task);
529}
530
531
532int rtR0MemObjNativeReserveKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pvFixed, size_t cb, size_t uAlignment)
533{
534 return VERR_NOT_IMPLEMENTED;
535}
536
537
538int rtR0MemObjNativeReserveUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment, RTR0PROCESS R0Process)
539{
540 return VERR_NOT_IMPLEMENTED;
541}
542
543
544int rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, void *pvFixed, size_t uAlignment, unsigned fProt)
545{
546 /*
547 * Must have a memory descriptor.
548 */
549 int rc = VERR_INVALID_PARAMETER;
550 PRTR0MEMOBJDARWIN pMemToMapDarwin = (PRTR0MEMOBJDARWIN)pMemToMap;
551 if (pMemToMapDarwin->pMemDesc)
552 {
553 IOMemoryMap *pMemMap = pMemToMapDarwin->pMemDesc->map(kernel_task, kIOMapAnywhere,
554 kIOMapAnywhere | kIOMapDefaultCache);
555 if (pMemMap)
556 {
557 IOVirtualAddress VirtAddr = pMemMap->getVirtualAddress();
558 void *pv = (void *)(uintptr_t)VirtAddr;
559 if ((uintptr_t)pv == VirtAddr)
560 {
561 /*
562 * Create the IPRT memory object.
563 */
564 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)rtR0MemObjNew(sizeof(*pMemDarwin), RTR0MEMOBJTYPE_MAPPING,
565 pv, pMemToMapDarwin->Core.cb);
566 if (pMemDarwin)
567 {
568 pMemDarwin->Core.u.Mapping.R0Process = NIL_RTR0PROCESS;
569 pMemDarwin->pMemMap = pMemMap;
570 *ppMem = &pMemDarwin->Core;
571 return VINF_SUCCESS;
572 }
573
574 rc = VERR_NO_MEMORY;
575 }
576 else
577 rc = VERR_ADDRESS_TOO_BIG;
578 pMemMap->release();
579 }
580 else
581 rc = VERR_MAP_FAILED;
582 }
583 return rc;
584}
585
586
587int rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, RTR3PTR R3PtrFixed, size_t uAlignment, unsigned fProt, RTR0PROCESS R0Process)
588{
589 /*
590 * Must have a memory descriptor.
591 */
592 int rc = VERR_INVALID_PARAMETER;
593 PRTR0MEMOBJDARWIN pMemToMapDarwin = (PRTR0MEMOBJDARWIN)pMemToMap;
594 if (pMemToMapDarwin->pMemDesc)
595 {
596 IOMemoryMap *pMemMap = pMemToMapDarwin->pMemDesc->map((task_t)R0Process, kIOMapAnywhere,
597 kIOMapAnywhere | kIOMapDefaultCache);
598 if (pMemMap)
599 {
600 IOVirtualAddress VirtAddr = pMemMap->getVirtualAddress();
601 void *pv = (void *)(uintptr_t)VirtAddr;
602 if ((uintptr_t)pv == VirtAddr)
603 {
604 /*
605 * Create the IPRT memory object.
606 */
607 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)rtR0MemObjNew(sizeof(*pMemDarwin), RTR0MEMOBJTYPE_MAPPING,
608 pv, pMemToMapDarwin->Core.cb);
609 if (pMemDarwin)
610 {
611 pMemDarwin->Core.u.Mapping.R0Process = R0Process;
612 pMemDarwin->pMemMap = pMemMap;
613 *ppMem = &pMemDarwin->Core;
614 return VINF_SUCCESS;
615 }
616
617 rc = VERR_NO_MEMORY;
618 }
619 else
620 rc = VERR_ADDRESS_TOO_BIG;
621 pMemMap->release();
622 }
623 else
624 rc = VERR_MAP_FAILED;
625 }
626 return rc;
627}
628
629
630RTHCPHYS rtR0MemObjNativeGetPagePhysAddr(PRTR0MEMOBJINTERNAL pMem, size_t iPage)
631{
632 RTHCPHYS PhysAddr;
633 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)pMem;
634
635#ifdef USE_VM_MAP_WIRE
636 /*
637 * Locked memory doesn't have a memory descriptor and
638 * needs to be handled differently.
639 */
640 if (pMemDarwin->Core.enmType == RTR0MEMOBJTYPE_LOCK)
641 {
642 ppnum_t PgNo;
643 if (pMemDarwin->Core.u.Lock.R0Process == NIL_RTR0PROCESS)
644 PgNo = pmap_find_phys(kernel_pmap, (uintptr_t)pMemDarwin->Core.pv + iPage * PAGE_SIZE);
645 else
646 {
647 /*
648 * From what I can tell, Apple seems to have locked up the all the
649 * available interfaces that could help us obtain the pmap_t of a task
650 * or vm_map_t.
651
652 * So, we'll have to figure out where in the vm_map_t structure it is
653 * and read it our selves. ASSUMING that kernel_pmap is pointed to by
654 * kernel_map->pmap, we scan kernel_map to locate the structure offset.
655 * Not nice, but it will hopefully do the job in a reliable manner...
656 *
657 * (get_task_pmap, get_map_pmap or vm_map_pmap is what we really need btw.)
658 */
659 static int s_offPmap = -1;
660 if (RT_UNLIKELY(s_offPmap == -1))
661 {
662 pmap_t const *p = (pmap_t *)kernel_map;
663 pmap_t const * const pEnd = p + 64;
664 for (; p < pEnd; p++)
665 if (*p == kernel_pmap)
666 {
667 s_offPmap = (uintptr_t)p - (uintptr_t)kernel_map;
668 break;
669 }
670 AssertReturn(s_offPmap >= 0, NIL_RTHCPHYS);
671 }
672 pmap_t Pmap = *(pmap_t *)((uintptr_t)get_task_map((task_t)pMemDarwin->Core.u.Lock.R0Process) + s_offPmap);
673 PgNo = pmap_find_phys(Pmap, (uintptr_t)pMemDarwin->Core.pv + iPage * PAGE_SIZE);
674 }
675
676 AssertReturn(PgNo, NIL_RTHCPHYS);
677 PhysAddr = (RTHCPHYS)PgNo << PAGE_SHIFT;
678 Assert((PhysAddr >> PAGE_SHIFT) == PgNo);
679 }
680 else
681#endif /* USE_VM_MAP_WIRE */
682 {
683 /*
684 * Get the memory descriptor.
685 */
686 IOMemoryDescriptor *pMemDesc = pMemDarwin->pMemDesc;
687 if (!pMemDesc)
688 pMemDesc = pMemDarwin->pMemMap->getMemoryDescriptor();
689 AssertReturn(pMemDesc, NIL_RTHCPHYS);
690
691 /*
692 * If we've got a memory descriptor, use getPhysicalSegment64().
693 */
694 addr64_t Addr = pMemDesc->getPhysicalSegment64(iPage * PAGE_SIZE, NULL);
695 AssertMsgReturn(Addr, ("iPage=%u\n", iPage), NIL_RTHCPHYS);
696 PhysAddr = Addr;
697 AssertMsgReturn(PhysAddr == Addr, ("PhysAddr=%VHp Addr=%RX64\n", PhysAddr, (uint64_t)Addr), NIL_RTHCPHYS);
698 }
699
700 return PhysAddr;
701}
702
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