Index: trunk/src/VBox/Runtime/r0drv/darwin/memobj-r0drv-darwin.cpp
===================================================================
--- trunk/src/VBox/Runtime/r0drv/darwin/memobj-r0drv-darwin.cpp	(revision 20506)
+++ trunk/src/VBox/Runtime/r0drv/darwin/memobj-r0drv-darwin.cpp	(revision 20507)
@@ -44,4 +44,5 @@
 #include <iprt/process.h>
 #include <iprt/string.h>
+#include <iprt/thread.h>
 
 #include "internal/memobj.h"
@@ -67,4 +68,172 @@
 
 
+/**
+ * HACK ALERT!
+ *
+ * Touch the pages to force the kernel to create  the page
+ * table entries. This is necessary since the kernel gets
+ * upset if we take a page fault when preemption is disabled
+ * and/or we own a simple lock. It has no problems with us
+ * disabling interrupts when taking the traps, weird stuff.
+ *
+ * @param  pv           Pointer to the first page.
+ * @param  cb           The number of bytes.
+ */
+static void rtR0MemObjDarwinTouchPages(void *pv, size_t cb)
+{
+    uint32_t volatile  *pu32 = (uint32_t volatile *)pv;
+    for (;;)
+    {
+        ASMAtomicCmpXchgU32(pu32, 0xdeadbeef, 0xdeadbeef);
+        if (cb <= PAGE_SIZE)
+            break;
+        cb -= PAGE_SIZE;
+        pu32 += PAGE_SIZE / sizeof(uint32_t);
+    }
+}
+
+#ifdef RT_STRICT
+
+/**
+ * Read from a physical page.
+ *
+ * @param   HCPhys      The address to start reading at.
+ * @param   cb          How many bytes to read.
+ * @param   pvDst       Where to put the bytes. This is zero'ed on failure.
+ */
+static void rtR0MemObjDarwinReadPhys(RTHCPHYS HCPhys, size_t cb, void *pvDst)
+{
+    memset(pvDst, '\0', cb);
+
+    IOAddressRange      aRanges[1]  = { { (mach_vm_address_t)HCPhys, RT_ALIGN(cb, PAGE_SIZE) } };
+    IOMemoryDescriptor *pMemDesc    = IOMemoryDescriptor::withAddressRanges(&aRanges[0], RT_ELEMENTS(aRanges),
+                                                                            kIODirectionIn, NULL /*task*/);
+    if (pMemDesc)
+    {
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
+        IOMemoryMap *pMemMap = pMemDesc->createMappingInTask(kernel_task, 0, kIOMapAnywhere | kIOMapDefaultCache);
+#else
+        IOMemoryMap *pMemMap = pMemDesc->map(kernel_task, 0, kIOMapAnywhere | kIOMapDefaultCache);
+#endif
+        if (pMemMap)
+        {
+            void const *pvSrc = (void const *)(uintptr_t)pMemMap->getVirtualAddress();
+            memcpy(pvDst, pvSrc, cb);
+            pMemMap->release();
+        }
+        else
+            printf("rtR0MemObjDarwinReadPhys: createMappingInTask failed; HCPhys=%llx\n", HCPhys);
+
+        pMemDesc->release();
+    }
+    else
+        printf("rtR0MemObjDarwinReadPhys: withAddressRanges failed; HCPhys=%llx\n", HCPhys);
+}
+
+
+/**
+ * Gets the PTE for a page.
+ *
+ * @returns the PTE.
+ * @param   pvPage      The virtual address to get the PTE for.
+ */
+uint64_t rtR0MemObjDarwinGetPTE(void *pvPage)
+{
+    RTUINT64U   u64;
+    RTCCUINTREG cr3 = ASMGetCR3();
+    RTCCUINTREG cr4 = ASMGetCR4();
+    bool        fPAE = false;
+    bool        fLMA = false;
+    if (cr4 & RT_BIT(5) /*X86_CR4_PAE*/)
+    {
+        fPAE = true;
+        uint32_t fAmdFeatures = ASMCpuId_EDX(0x80000001);
+        if (fAmdFeatures & RT_BIT(29) /*X86_CPUID_AMD_FEATURE_EDX_LONG_MODE*/)
+        {
+            uint64_t efer = ASMRdMsr(0xc0000080 /*MSR_K6_EFER*/);
+            if (efer & RT_BIT(10) /*MSR_K6_EFER_LMA*/)
+                fLMA = true;
+        }
+    }
+
+    if (fLMA)
+    {
+        /* PML4 */
+        rtR0MemObjDarwinReadPhys((cr3 & ~(RTCCUINTREG)PAGE_OFFSET_MASK) | (((uint64_t)(uintptr_t)pvPage >> 39) & 0x1ff) * 8, 8, &u64);
+        if (!(u64.u & RT_BIT(0) /* present */))
+        {
+            printf("rtR0MemObjDarwinGetPTE: %p -> PML4E !p\n", pvPage);
+            return 0;
+        }
+
+        /* PDPTR */
+        rtR0MemObjDarwinReadPhys((u64.u & ~(uint64_t)PAGE_OFFSET_MASK) | (((uintptr_t)pvPage >> 30) & 0x1ff) * 8, 8, &u64);
+        if (!(u64.u & RT_BIT(0) /* present */))
+        {
+            printf("rtR0MemObjDarwinGetPTE: %p -> PDPTE !p\n", pvPage);
+            return 0;
+        }
+        if (u64.u & RT_BIT(7) /* big */)
+            return (u64.u & ~(uint64_t)(_1G -1)) | ((uintptr_t)pvPage & (_1G -1));
+
+        /* PD */
+        rtR0MemObjDarwinReadPhys((u64.u & ~(uint64_t)PAGE_OFFSET_MASK) | (((uintptr_t)pvPage >> 21) & 0x1ff) * 8, 8, &u64);
+        if (!(u64.u & RT_BIT(0) /* present */))
+        {
+            printf("rtR0MemObjDarwinGetPTE: %p -> PDE !p\n", pvPage);
+            return 0;
+        }
+        if (u64.u & RT_BIT(7) /* big */)
+            return (u64.u & ~(uint64_t)(_2M -1)) | ((uintptr_t)pvPage & (_2M -1));
+
+        /* PD */
+        rtR0MemObjDarwinReadPhys((u64.u & ~(uint64_t)PAGE_OFFSET_MASK) | (((uintptr_t)pvPage >> 12) & 0x1ff) * 8, 8, &u64);
+        if (!(u64.u & RT_BIT(0) /* present */))
+        {
+            printf("rtR0MemObjDarwinGetPTE: %p -> PTE !p\n", pvPage);
+            return 0;
+        }
+        return u64.u;
+    }
+
+    if (fPAE)
+    {
+        /* PDPTR */
+        rtR0MemObjDarwinReadPhys((u64.u & 0xffffffe0 /*X86_CR3_PAE_PAGE_MASK*/) | (((uintptr_t)pvPage >> 30) & 0x3) * 8, 8, &u64);
+        if (!(u64.u & RT_BIT(0) /* present */))
+            return 0;
+
+        /* PD */
+        rtR0MemObjDarwinReadPhys((u64.u & ~(uint64_t)PAGE_OFFSET_MASK) | (((uintptr_t)pvPage >> 21) & 0x1ff) * 8, 8, &u64);
+        if (!(u64.u & RT_BIT(0) /* present */))
+            return 0;
+        if (u64.u & RT_BIT(7) /* big */)
+            return (u64.u & ~(uint64_t)(_2M -1)) | ((uintptr_t)pvPage & (_2M -1));
+
+        /* PD */
+        rtR0MemObjDarwinReadPhys((u64.u & ~(uint64_t)PAGE_OFFSET_MASK) | (((uintptr_t)pvPage >> 12) & 0x1ff) * 8, 8, &u64);
+        if (!(u64.u & RT_BIT(0) /* present */))
+            return 0;
+        return u64.u;
+    }
+
+    /* PD */
+    rtR0MemObjDarwinReadPhys((u64.au32[0] & ~(uint32_t)PAGE_OFFSET_MASK) | (((uintptr_t)pvPage >> 22) & 0x3ff) * 4, 4, &u64);
+    if (!(u64.au32[0] & RT_BIT(0) /* present */))
+        return 0;
+    if (u64.au32[0] & RT_BIT(7) /* big */)
+        return (u64.u & ~(uint64_t)(_2M -1)) | ((uintptr_t)pvPage & (_2M -1));
+
+    /* PD */
+    rtR0MemObjDarwinReadPhys((u64.au32[0] & ~(uint32_t)PAGE_OFFSET_MASK) | (((uintptr_t)pvPage >> 12) & 0x3ff) * 4, 4, &u64);
+    if (!(u64.au32[0] & RT_BIT(0) /* present */))
+        return 0;
+    return u64.au32[0];
+
+    return 0;
+}
+
+#endif /* RT_STRICT */
+
 int rtR0MemObjNativeFree(RTR0MEMOBJ pMem)
 {
@@ -72,5 +241,5 @@
 
     /*
-     * Release the IOMemoryDescriptor/IOMemoryMap associated with the object.
+     * Release the IOMemoryDescriptor or/and IOMemoryMap associated with the object.
      */
     if (pMemDarwin->pMemDesc)
@@ -80,7 +249,7 @@
         pMemDarwin->pMemDesc->release();
         pMemDarwin->pMemDesc = NULL;
-        Assert(!pMemDarwin->pMemMap);
-    }
-    else if (pMemDarwin->pMemMap)
+    }
+
+    if (pMemDarwin->pMemMap)
     {
         pMemDarwin->pMemMap->release();
@@ -167,10 +336,10 @@
      * we'll use rtR0MemObjNativeAllocCont as a fallback for dealing with that.
      *
-     * The kIOMemorySharingTypeMask flag just forces the result to be page aligned.
+     * The kIOMemoryKernelUserShared flag just forces the result to be page aligned.
      */
     int rc;
     IOBufferMemoryDescriptor *pMemDesc =
         IOBufferMemoryDescriptor::inTaskWithPhysicalMask(kernel_task,
-                                                           kIOMemorySharingTypeMask
+                                                           kIOMemoryKernelUserShared
                                                          | kIODirectionInOut
                                                          | (fContiguous ? kIOMemoryPhysicallyContiguous : 0),
@@ -207,5 +376,5 @@
                         pMemDesc->release();
                         if (PhysMask)
-                            LogAlways(("rtR0MemObjNativeAllocLow: off=%x Addr=%llx AddrPrev=%llx MaxPhysAddr=%llx PhysMas=%llx - buggy API!\n",
+                            LogAlways(("rtR0MemObjNativeAllocWorker: off=%x Addr=%llx AddrPrev=%llx MaxPhysAddr=%llx PhysMas=%llx - buggy API!\n",
                                        off, Addr, AddrPrev, MaxPhysAddr, PhysMask));
                         return VERR_ADDRESS_TOO_BIG;
@@ -213,4 +382,14 @@
                     AddrPrev = Addr;
                 }
+
+#ifdef RT_STRICT
+                /* check that the memory is actually mapped. */
+                //addr64_t Addr = pMemDesc->getPhysicalSegment64(0, NULL);
+                //printf("rtR0MemObjNativeAllocWorker: pv=%p %8llx %8llx\n", pv, rtR0MemObjDarwinGetPTE(pv), Addr);
+                RTTHREADPREEMPTSTATE State = RTTHREADPREEMPTSTATE_INITIALIZER;
+                RTThreadPreemptDisable(&State);
+                rtR0MemObjDarwinTouchPages(pv, cb);
+                RTThreadPreemptRestore(&State);
+#endif
 
                 /*
@@ -487,5 +666,5 @@
 
     /*
-     * Must have a memory descriptor.
+     * Must have a memory descriptor that we can map.
      */
     int rc = VERR_INVALID_PARAMETER;
@@ -500,7 +679,9 @@
                                                                               cbSub);
 #else
-        IOMemoryMap *pMemMap = pMemToMapDarwin->pMemDesc->map(kernel_task, 0,
+        IOMemoryMap *pMemMap = pMemToMapDarwin->pMemDesc->map(kernel_task,
+                                                              0,
                                                               kIOMapAnywhere | kIOMapDefaultCache,
-                                                              offSub, cbSub);
+                                                              offSub,
+                                                              cbSub);
 #endif
         if (pMemMap)
@@ -510,38 +691,60 @@
             if ((uintptr_t)pv == VirtAddr)
             {
-                /*
-                 * HACK ALERT!
-                 *
-                 * Touch the pages to force the kernel to create  the page
-                 * table entries. This is necessary since the kernel gets
-                 * upset if we take a page fault when preemption is disabled
-                 * and/or we own a simple lock. It has no problems with us
-                 * disabling interrupts when taking the traps, weird stuff.
-                 */
-                uint32_t volatile  *pu32   = (uint32_t volatile *)pv;
-                size_t              cbLeft = cbSub;
-                for (;;)
-                {
-                    ASMAtomicCmpXchgU32(pu32, 0xdeadbeef, 0xdeadbeef);
-                    if (cbLeft <= PAGE_SIZE)
-                        break;
-                    cbLeft -= PAGE_SIZE;
-                    pu32 += PAGE_SIZE / sizeof(uint32_t);
-                }
-
-                /*
-                 * Create the IPRT memory object.
-                 */
-                PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)rtR0MemObjNew(sizeof(*pMemDarwin), RTR0MEMOBJTYPE_MAPPING,
-                                                                                pv, pMemToMapDarwin->Core.cb);
-                if (pMemDarwin)
-                {
-                    pMemDarwin->Core.u.Mapping.R0Process = NIL_RTR0PROCESS;
-                    pMemDarwin->pMemMap = pMemMap;
-                    *ppMem = &pMemDarwin->Core;
-                    return VINF_SUCCESS;
-                }
-
-                rc = VERR_NO_MEMORY;
+                //addr64_t Addr = pMemToMapDarwin->pMemDesc->getPhysicalSegment64(offSub, NULL);
+                //printf("pv=%p: %8llx %8llx\n", pv, rtR0MemObjDarwinGetPTE(pv), Addr);
+
+//                /*
+//                 * Explicitly lock it so that we're sure it is present and that
+//                 * its PTEs cannot be recycled.
+//                 * Note! withAddressRange() doesn't work as it adds kIOMemoryTypeVirtual64
+//                 *       to the options which causes prepare() to not wire the pages.
+//                 *       This is probably a bug.
+//                 */
+//                IOAddressRange Range = { (mach_vm_address_t)pv, cbSub };
+//                IOMemoryDescriptor *pMemDesc = IOMemoryDescriptor::withOptions(&Range,
+//                                                                               1 /* count */,
+//                                                                               0 /* offset */,
+//                                                                               kernel_task,
+//                                                                               kIODirectionInOut | kIOMemoryTypeVirtual,
+//                                                                               kIOMapperSystem);
+//                if (pMemDesc)
+//                {
+//                    IOReturn IORet = pMemDesc->prepare(kIODirectionInOut);
+//                    if (IORet == kIOReturnSuccess)
+//                    {
+                        /* HACK ALERT! */
+                        rtR0MemObjDarwinTouchPages(pv, cbSub);
+                        /** @todo First, the memory should've been mapped by now, and second, it
+                         *        shouild have the wired attribute in the PTE (bit 9). Neither is
+                         *        seems to be the case. The disabled locking code doesn't make any
+                         *        difference, which is extremely odd, and breaks
+                         *        rtR0MemObjNativeGetPagePhysAddr (getPhysicalSegment64 -> 64 for the
+                         *        lock descriptor. */
+                        //addr64_t Addr = pMemDesc->getPhysicalSegment64(0, NULL);
+                        //printf("pv=%p: %8llx %8llx (%d)\n", pv, rtR0MemObjDarwinGetPTE(pv), Addr, 2);
+
+                        /*
+                         * Create the IPRT memory object.
+                         */
+                        PRTR0MEMOBJDARWIN pMemDarwin = (PRTR0MEMOBJDARWIN)rtR0MemObjNew(sizeof(*pMemDarwin), RTR0MEMOBJTYPE_MAPPING,
+                                                                                        pv, cbSub);
+                        if (pMemDarwin)
+                        {
+                            pMemDarwin->Core.u.Mapping.R0Process = NIL_RTR0PROCESS;
+                            pMemDarwin->pMemMap = pMemMap;
+//                            pMemDarwin->pMemDesc = pMemDesc;
+                            *ppMem = &pMemDarwin->Core;
+                            return VINF_SUCCESS;
+                        }
+
+//                        pMemDesc->complete();
+//                        rc = VERR_NO_MEMORY;
+//                    }
+//                    else
+//                        rc = RTErrConvertFromDarwinIO(IORet);
+//                    pMemDesc->release();
+//                }
+//                else
+//                    rc = VERR_MEMOBJ_INIT_FAILED;
             }
             else
@@ -574,5 +777,6 @@
                                                                               0 /* length */);
 #else
-        IOMemoryMap *pMemMap = pMemToMapDarwin->pMemDesc->map((task_t)R0Process, 0,
+        IOMemoryMap *pMemMap = pMemToMapDarwin->pMemDesc->map((task_t)R0Process,
+                                                              0,
                                                               kIOMapAnywhere | kIOMapDefaultCache);
 #endif
