VirtualBox

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

Last change on this file since 16195 was 15835, checked in by vboxsync, 16 years ago

rtR0MemObjNativeEnterPhys: Use method supporting 64-bit physical addresses. Should fix VERR_ADDRESS_TOO_BIG error (#3485).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 23.9 KB
Line 
1/* $Id: memobj-r0drv-darwin.cpp 15835 2009-01-07 15:18:17Z 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 - may re-enable later when non-mapped allocations are added. */
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 * Create a descriptor for it (the validation is always true on intel macs, but
408 * as it doesn't harm us keep it in).
409 */
410 int rc = VERR_ADDRESS_TOO_BIG;
411 IOAddressRange aRanges[1] = { Phys, cb };
412 if ( aRanges[0].address == Phys
413 && aRanges[0].length == cb)
414 {
415 IOMemoryDescriptor *pMemDesc = IOMemoryDescriptor::withAddressRanges(&aRanges[0], RT_ELEMENTS(aRanges),
416 kIODirectionInOut, NULL /*task*/);
417 if (pMemDesc)
418 {
419 Assert(Phys == pMemDesc->getPhysicalAddress());
420
421 /*
422 * Create the IPRT memory object.
423 */
424 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)rtR0MemObjNew(sizeof(*pMemDarwin), RTR0MEMOBJTYPE_PHYS, NULL, cb);
425 if (pMemDarwin)
426 {
427 pMemDarwin->Core.u.Phys.PhysBase = Phys;
428 pMemDarwin->Core.u.Phys.fAllocated = false;
429 pMemDarwin->pMemDesc = pMemDesc;
430 *ppMem = &pMemDarwin->Core;
431 return VINF_SUCCESS;
432 }
433
434 rc = VERR_NO_MEMORY;
435 pMemDesc->release();
436 }
437 else
438 rc = VERR_MEMOBJ_INIT_FAILED;
439 }
440 else
441 AssertMsgFailed(("%#llx %llx\n", (unsigned long long)Phys, (unsigned long long)cb));
442 return rc;
443}
444
445
446/**
447 * Internal worker for locking down pages.
448 *
449 * @return IPRT status code.
450 *
451 * @param ppMem Where to store the memory object pointer.
452 * @param pv First page.
453 * @param cb Number of bytes.
454 * @param Task The task \a pv and \a cb refers to.
455 */
456static int rtR0MemObjNativeLock(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb, task_t Task)
457{
458#ifdef USE_VM_MAP_WIRE
459 vm_map_t Map = get_task_map(Task);
460 Assert(Map);
461
462 /*
463 * First try lock the memory.
464 */
465 int rc = VERR_LOCK_FAILED;
466 kern_return_t kr = vm_map_wire(get_task_map(Task),
467 (vm_map_offset_t)pv,
468 (vm_map_offset_t)pv + cb,
469 VM_PROT_DEFAULT,
470 0 /* not user */);
471 if (kr == KERN_SUCCESS)
472 {
473 /*
474 * Create the IPRT memory object.
475 */
476 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)rtR0MemObjNew(sizeof(*pMemDarwin), RTR0MEMOBJTYPE_LOCK, pv, cb);
477 if (pMemDarwin)
478 {
479 pMemDarwin->Core.u.Lock.R0Process = (RTR0PROCESS)Task;
480 *ppMem = &pMemDarwin->Core;
481 return VINF_SUCCESS;
482 }
483
484 kr = vm_map_unwire(get_task_map(Task), (vm_map_offset_t)pv, (vm_map_offset_t)pv + cb, 0 /* not user */);
485 Assert(kr == KERN_SUCCESS);
486 rc = VERR_NO_MEMORY;
487 }
488
489#else
490
491 /*
492 * Create a descriptor and try lock it (prepare).
493 */
494 int rc = VERR_MEMOBJ_INIT_FAILED;
495 IOMemoryDescriptor *pMemDesc = IOMemoryDescriptor::withAddress((vm_address_t)pv, cb, kIODirectionInOut, Task);
496 if (pMemDesc)
497 {
498 IOReturn IORet = pMemDesc->prepare(kIODirectionInOut);
499 if (IORet == kIOReturnSuccess)
500 {
501 /*
502 * Create the IPRT memory object.
503 */
504 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)rtR0MemObjNew(sizeof(*pMemDarwin), RTR0MEMOBJTYPE_LOCK, pv, cb);
505 if (pMemDarwin)
506 {
507 pMemDarwin->Core.u.Lock.R0Process = (RTR0PROCESS)Task;
508 pMemDarwin->pMemDesc = pMemDesc;
509 *ppMem = &pMemDarwin->Core;
510 return VINF_SUCCESS;
511 }
512
513 pMemDesc->complete();
514 rc = VERR_NO_MEMORY;
515 }
516 else
517 rc = VERR_LOCK_FAILED;
518 pMemDesc->release();
519 }
520#endif
521 return rc;
522}
523
524
525int rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3Ptr, size_t cb, RTR0PROCESS R0Process)
526{
527 return rtR0MemObjNativeLock(ppMem, (void *)R3Ptr, cb, (task_t)R0Process);
528}
529
530
531int rtR0MemObjNativeLockKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pv, size_t cb)
532{
533 return rtR0MemObjNativeLock(ppMem, pv, cb, kernel_task);
534}
535
536
537int rtR0MemObjNativeReserveKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pvFixed, size_t cb, size_t uAlignment)
538{
539 return VERR_NOT_IMPLEMENTED;
540}
541
542
543int rtR0MemObjNativeReserveUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment, RTR0PROCESS R0Process)
544{
545 return VERR_NOT_IMPLEMENTED;
546}
547
548
549int rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, void *pvFixed, size_t uAlignment,
550 unsigned fProt, size_t offSub, size_t cbSub)
551{
552 /*
553 * Must have a memory descriptor.
554 */
555 int rc = VERR_INVALID_PARAMETER;
556 PRTR0MEMOBJDARWIN pMemToMapDarwin = (PRTR0MEMOBJDARWIN)pMemToMap;
557 if (pMemToMapDarwin->pMemDesc)
558 {
559 IOMemoryMap *pMemMap = pMemToMapDarwin->pMemDesc->map(kernel_task, kIOMapAnywhere,
560 kIOMapAnywhere | kIOMapDefaultCache,
561 offSub, cbSub);
562 if (pMemMap)
563 {
564 IOVirtualAddress VirtAddr = pMemMap->getVirtualAddress();
565 void *pv = (void *)(uintptr_t)VirtAddr;
566 if ((uintptr_t)pv == VirtAddr)
567 {
568 /*
569 * Create the IPRT memory object.
570 */
571 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)rtR0MemObjNew(sizeof(*pMemDarwin), RTR0MEMOBJTYPE_MAPPING,
572 pv, pMemToMapDarwin->Core.cb);
573 if (pMemDarwin)
574 {
575 pMemDarwin->Core.u.Mapping.R0Process = NIL_RTR0PROCESS;
576 pMemDarwin->pMemMap = pMemMap;
577 *ppMem = &pMemDarwin->Core;
578 return VINF_SUCCESS;
579 }
580
581 rc = VERR_NO_MEMORY;
582 }
583 else
584 rc = VERR_ADDRESS_TOO_BIG;
585 pMemMap->release();
586 }
587 else
588 rc = VERR_MAP_FAILED;
589 }
590 return rc;
591}
592
593
594int rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, RTR3PTR R3PtrFixed, size_t uAlignment, unsigned fProt, RTR0PROCESS R0Process)
595{
596 /*
597 * Must have a memory descriptor.
598 */
599 int rc = VERR_INVALID_PARAMETER;
600 PRTR0MEMOBJDARWIN pMemToMapDarwin = (PRTR0MEMOBJDARWIN)pMemToMap;
601 if (pMemToMapDarwin->pMemDesc)
602 {
603 IOMemoryMap *pMemMap = pMemToMapDarwin->pMemDesc->map((task_t)R0Process, kIOMapAnywhere,
604 kIOMapAnywhere | kIOMapDefaultCache);
605 if (pMemMap)
606 {
607 IOVirtualAddress VirtAddr = pMemMap->getVirtualAddress();
608 void *pv = (void *)(uintptr_t)VirtAddr;
609 if ((uintptr_t)pv == VirtAddr)
610 {
611 /*
612 * Create the IPRT memory object.
613 */
614 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)rtR0MemObjNew(sizeof(*pMemDarwin), RTR0MEMOBJTYPE_MAPPING,
615 pv, pMemToMapDarwin->Core.cb);
616 if (pMemDarwin)
617 {
618 pMemDarwin->Core.u.Mapping.R0Process = R0Process;
619 pMemDarwin->pMemMap = pMemMap;
620 *ppMem = &pMemDarwin->Core;
621 return VINF_SUCCESS;
622 }
623
624 rc = VERR_NO_MEMORY;
625 }
626 else
627 rc = VERR_ADDRESS_TOO_BIG;
628 pMemMap->release();
629 }
630 else
631 rc = VERR_MAP_FAILED;
632 }
633 return rc;
634}
635
636
637RTHCPHYS rtR0MemObjNativeGetPagePhysAddr(PRTR0MEMOBJINTERNAL pMem, size_t iPage)
638{
639 RTHCPHYS PhysAddr;
640 PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)pMem;
641
642#ifdef USE_VM_MAP_WIRE
643 /*
644 * Locked memory doesn't have a memory descriptor and
645 * needs to be handled differently.
646 */
647 if (pMemDarwin->Core.enmType == RTR0MEMOBJTYPE_LOCK)
648 {
649 ppnum_t PgNo;
650 if (pMemDarwin->Core.u.Lock.R0Process == NIL_RTR0PROCESS)
651 PgNo = pmap_find_phys(kernel_pmap, (uintptr_t)pMemDarwin->Core.pv + iPage * PAGE_SIZE);
652 else
653 {
654 /*
655 * From what I can tell, Apple seems to have locked up the all the
656 * available interfaces that could help us obtain the pmap_t of a task
657 * or vm_map_t.
658
659 * So, we'll have to figure out where in the vm_map_t structure it is
660 * and read it our selves. ASSUMING that kernel_pmap is pointed to by
661 * kernel_map->pmap, we scan kernel_map to locate the structure offset.
662 * Not nice, but it will hopefully do the job in a reliable manner...
663 *
664 * (get_task_pmap, get_map_pmap or vm_map_pmap is what we really need btw.)
665 */
666 static int s_offPmap = -1;
667 if (RT_UNLIKELY(s_offPmap == -1))
668 {
669 pmap_t const *p = (pmap_t *)kernel_map;
670 pmap_t const * const pEnd = p + 64;
671 for (; p < pEnd; p++)
672 if (*p == kernel_pmap)
673 {
674 s_offPmap = (uintptr_t)p - (uintptr_t)kernel_map;
675 break;
676 }
677 AssertReturn(s_offPmap >= 0, NIL_RTHCPHYS);
678 }
679 pmap_t Pmap = *(pmap_t *)((uintptr_t)get_task_map((task_t)pMemDarwin->Core.u.Lock.R0Process) + s_offPmap);
680 PgNo = pmap_find_phys(Pmap, (uintptr_t)pMemDarwin->Core.pv + iPage * PAGE_SIZE);
681 }
682
683 AssertReturn(PgNo, NIL_RTHCPHYS);
684 PhysAddr = (RTHCPHYS)PgNo << PAGE_SHIFT;
685 Assert((PhysAddr >> PAGE_SHIFT) == PgNo);
686 }
687 else
688#endif /* USE_VM_MAP_WIRE */
689 {
690 /*
691 * Get the memory descriptor.
692 */
693 IOMemoryDescriptor *pMemDesc = pMemDarwin->pMemDesc;
694 if (!pMemDesc)
695 pMemDesc = pMemDarwin->pMemMap->getMemoryDescriptor();
696 AssertReturn(pMemDesc, NIL_RTHCPHYS);
697
698 /*
699 * If we've got a memory descriptor, use getPhysicalSegment64().
700 */
701 addr64_t Addr = pMemDesc->getPhysicalSegment64(iPage * PAGE_SIZE, NULL);
702 AssertMsgReturn(Addr, ("iPage=%u\n", iPage), NIL_RTHCPHYS);
703 PhysAddr = Addr;
704 AssertMsgReturn(PhysAddr == Addr, ("PhysAddr=%RHp Addr=%RX64\n", PhysAddr, (uint64_t)Addr), NIL_RTHCPHYS);
705 }
706
707 return PhysAddr;
708}
709
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