memobj-r0drv-linux.c revision 041d531fb5794a8a4cf6c35886d89ec25cbbdde2
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync/* $Revision$ */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * IPRT - Ring-0 Memory Objects, Linux.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * available from http://www.virtualbox.org. This file is free software;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * you can redistribute it and/or modify it under the terms of the GNU
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * General Public License (GPL) as published by the Free Software
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * The contents of this file may alternatively be used under the terms
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * of the Common Development and Distribution License Version 1.0
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * VirtualBox OSE distribution, in which case the provisions of the
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * CDDL are applicable instead of those of the GPL.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * You may elect to license modified versions of this file under the
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * terms and conditions of either the GPL or the CDDL or both.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * additional information or have any questions.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync/*******************************************************************************
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync* Header Files *
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync*******************************************************************************/
307a7d6149fc07e6bb75bf04f38ef1195c791268vboxsync/*******************************************************************************
307a7d6149fc07e6bb75bf04f38ef1195c791268vboxsync* Defined Constants And Macros *
307a7d6149fc07e6bb75bf04f38ef1195c791268vboxsync*******************************************************************************/
307a7d6149fc07e6bb75bf04f38ef1195c791268vboxsync/* early 2.6 kernels */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * 2.6.29+ kernels don't work with remap_pfn_range() anymore because
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * track_pfn_vma_new() is apparently not defined for non-RAM pages.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * It should be safe to use vm_insert_page() older kernels as well.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync || (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)))
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync/*******************************************************************************
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync* Structures and Typedefs *
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync*******************************************************************************/
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * The Darwin version of the memory object structure.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** The core structure. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** Set if the allocation is contiguous.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * This means it has to be given back as one chunk. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** Set if we've vmap'ed thed memory into ring-0. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** The pages in the apPages array. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** Array of struct page pointers. (variable size) */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Helper that converts from a RTR0PROCESS handle to a linux task.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns The corresponding Linux task.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param R0Process IPRT ring-0 process handle.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstruct task_struct *rtR0ProcessToLinuxTask(RTR0PROCESS R0Process)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** @todo fix rtR0ProcessToLinuxTask!! */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync return R0Process == RTR0ProcHandleSelf() ? current : NULL;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Compute order. Some functions allocate 2^order pages.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns order.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param cPages Number of pages.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync for (iOrder = 0, cTmp = cPages; cTmp >>= 1; ++iOrder)
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync * Converts from RTMEM_PROT_* to Linux PAGE_*.
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync * @returns Linux page protection constant.
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync * @param fProt The IPRT protection mask.
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync * @param fKernel Whether it applies to kernel or user space.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic pgprot_t rtR0MemObjLinuxConvertProt(unsigned fProt, bool fKernel)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync return fKernel ? MY_PAGE_KERNEL_EXEC : PAGE_READONLY_EXEC;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync case RTMEM_PROT_WRITE | RTMEM_PROT_EXEC | RTMEM_PROT_READ:
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync return fKernel ? MY_PAGE_KERNEL_EXEC : PAGE_SHARED_EXEC;
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Internal worker that allocates physical pages and creates the memory object for them.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns IPRT status code.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param ppMemLnx Where to store the memory object pointer.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param enmType The object type.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param cb The number of bytes to allocate.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param fFlagsLnx The page allocation flags (GPFs).
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param fContiguous Whether the allocation must be contiguous.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic int rtR0MemObjLinuxAllocPages(PRTR0MEMOBJLNX *ppMemLnx, RTR0MEMOBJTYPE enmType, size_t cb, unsigned fFlagsLnx, bool fContiguous)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Allocate a memory object structure that's large enough to contain
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * the page pointer array.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync PRTR0MEMOBJLNX pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(RT_OFFSETOF(RTR0MEMOBJLNX, apPages[cPages]), enmType, NULL, cb);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Allocate the pages.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * For small allocations we'll try contiguous first and then fall back on page by page.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync paPages = alloc_pages(fFlagsLnx | __GFP_COMP, rtR0MemObjLinuxOrder(cb >> PAGE_SHIFT));
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync paPages = alloc_pages(fFlagsLnx, rtR0MemObjLinuxOrder(cb >> PAGE_SHIFT));
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync while (iPage-- > 0)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync#else /* < 2.4.22 */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /** @todo figure out why we didn't allocate page-by-page on 2.4.21 and older... */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync paPages = alloc_pages(fFlagsLnx, rtR0MemObjLinuxOrder(cb >> PAGE_SHIFT));
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync#endif /* < 2.4.22 */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Reserve the pages.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Frees the physical pages allocated by the rtR0MemObjLinuxAllocPages() call.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * This method does NOT free the object.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pMemLnx The object which physical pages should be freed.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic void rtR0MemObjLinuxFreePages(PRTR0MEMOBJLNX pMemLnx)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Restore the page flags.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync while (iPage-- > 0)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Free the pages.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync while (iPage-- > 0)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync __free_pages(pMemLnx->apPages[0], rtR0MemObjLinuxOrder(pMemLnx->cPages));
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Maps the allocation into ring-0.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * This will update the RTR0MEMOBJLNX::Core.pv and RTR0MEMOBJ::fMappedToRing0 members.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Contiguous mappings that isn't in 'high' memory will already be mapped into kernel
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * space, so we'll use that mapping if possible. If execute access is required, we'll
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * play safe and do our own mapping.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns IPRT status code.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pMemLnx The linux memory object to map.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param fExecutable Whether execute access is required.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic int rtR0MemObjLinuxVMap(PRTR0MEMOBJLNX pMemLnx, bool fExecutable)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Choose mapping strategy.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync while (iPage-- > 0)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Use vmap - 2.4.22 and later.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync pMemLnx->Core.pv = vmap(&pMemLnx->apPages[0], pMemLnx->cPages, VM_MAP, fPg);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync pMemLnx->Core.pv = vmap(&pMemLnx->apPages[0], pMemLnx->cPages, VM_ALLOC, fPg);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync#else /* < 2.4.22 */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Use the kernel RAM mapping.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync pMemLnx->Core.pv = phys_to_virt(page_to_phys(pMemLnx->apPages[0]));
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Undos what rtR0MemObjLinuxVMap() did.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param pMemLnx The linux memory object.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic void rtR0MemObjLinuxVUnmap(PRTR0MEMOBJLNX pMemLnx)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync#else /* < 2.4.22 */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Release any memory that we've allocated or locked.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync if (pMemLnx->Core.u.Lock.R0Process != NIL_RTR0PROCESS)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync struct task_struct *pTask = rtR0ProcessToLinuxTask(pMemLnx->Core.u.Lock.R0Process);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync while (iPage-- > 0)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* else: kernel memory - nothing to do here. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync if (pMemLnx->Core.u.ResVirt.R0Process != NIL_RTR0PROCESS)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync struct task_struct *pTask = rtR0ProcessToLinuxTask(pMemLnx->Core.u.Lock.R0Process);
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync MY_DO_MUNMAP(pTask->mm, (unsigned long)pMemLnx->Core.pv, pMemLnx->Core.cb);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync Assert(pMemLnx->cPages == 1 && pMemLnx->apPages[0] != NULL);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync Assert(pMemLnx->cPages == 0); Assert(pMemLnx->Core.pv);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync if (pMemLnx->Core.u.ResVirt.R0Process != NIL_RTR0PROCESS)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync struct task_struct *pTask = rtR0ProcessToLinuxTask(pMemLnx->Core.u.Lock.R0Process);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync MY_DO_MUNMAP(pTask->mm, (unsigned long)pMemLnx->Core.pv, pMemLnx->Core.cb);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync AssertMsgFailed(("enmType=%d\n", pMemLnx->Core.enmType));
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncint rtR0MemObjNativeAllocPage(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync rc = rtR0MemObjLinuxAllocPages(&pMemLnx, RTR0MEMOBJTYPE_PAGE, cb, GFP_HIGHUSER, false /* non-contiguous */);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync rc = rtR0MemObjLinuxAllocPages(&pMemLnx, RTR0MEMOBJTYPE_PAGE, cb, GFP_USER, false /* non-contiguous */);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncint rtR0MemObjNativeAllocLow(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync /* Try to avoid GFP_DMA. GFM_DMA32 was introduced with Linux 2.6.15. */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync#if (defined(RT_ARCH_AMD64) || defined(CONFIG_X86_PAE)) && defined(GFP_DMA32)
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync /* ZONE_DMA32: 0-4GB */
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync rc = rtR0MemObjLinuxAllocPages(&pMemLnx, RTR0MEMOBJTYPE_LOW, cb, GFP_DMA32, false /* non-contiguous */);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* ZONE_DMA: 0-16MB */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync rc = rtR0MemObjLinuxAllocPages(&pMemLnx, RTR0MEMOBJTYPE_LOW, cb, GFP_DMA, false /* non-contiguous */);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* ZONE_NORMAL: 0-896MB */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync rc = rtR0MemObjLinuxAllocPages(&pMemLnx, RTR0MEMOBJTYPE_LOW, cb, GFP_USER, false /* non-contiguous */);
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsyncint rtR0MemObjNativeAllocCont(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, bool fExecutable)
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync#if (defined(RT_ARCH_AMD64) || defined(CONFIG_X86_PAE)) && defined(GFP_DMA32)
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync /* ZONE_DMA32: 0-4GB */
1705f7565ed8533058b8541d72d6c5d4453de00fvboxsync rc = rtR0MemObjLinuxAllocPages(&pMemLnx, RTR0MEMOBJTYPE_CONT, cb, GFP_DMA32, true /* contiguous */);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* ZONE_DMA: 0-16MB */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync rc = rtR0MemObjLinuxAllocPages(&pMemLnx, RTR0MEMOBJTYPE_CONT, cb, GFP_DMA, true /* contiguous */);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* ZONE_NORMAL (32-bit hosts): 0-896MB */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync rc = rtR0MemObjLinuxAllocPages(&pMemLnx, RTR0MEMOBJTYPE_CONT, cb, GFP_USER, true /* contiguous */);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync#if defined(RT_STRICT) && (defined(RT_ARCH_AMD64) || defined(CONFIG_HIGHMEM64G))
1705f7565ed8533058b8541d72d6c5d4453de00fvboxsync while (iPage-- > 0)
1705f7565ed8533058b8541d72d6c5d4453de00fvboxsync Assert(page_to_phys(pMemLnx->apPages[iPage]) < _4G);
1705f7565ed8533058b8541d72d6c5d4453de00fvboxsync pMemLnx->Core.u.Cont.Phys = page_to_phys(pMemLnx->apPages[0]);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Worker for rtR0MemObjLinuxAllocPhysSub that tries one allocation strategy.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns IPRT status.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param ppMemLnx Where to
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param enmType The object type.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param cb The size of the allocation.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param PhysHighest See rtR0MemObjNativeAllocPhys.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param fGfp The Linux GFP flags to use for the allocation.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsyncstatic int rtR0MemObjLinuxAllocPhysSub2(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJTYPE enmType, size_t cb, RTHCPHYS PhysHighest, unsigned fGfp)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync rc = rtR0MemObjLinuxAllocPages(&pMemLnx, enmType, cb, fGfp,
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync enmType == RTR0MEMOBJTYPE_PHYS /* contiguous / non-contiguous */);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Check the addresses if necessary. (Can be optimized a bit for PHYS.)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync while (iPage-- > 0)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync if (page_to_phys(pMemLnx->apPages[iPage]) >= PhysHighest)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Complete the object.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync pMemLnx->Core.u.Phys.PhysBase = page_to_phys(pMemLnx->apPages[0]);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * Worker for rtR0MemObjNativeAllocPhys and rtR0MemObjNativeAllocPhysNC.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @returns IPRT status.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param ppMem Where to store the memory object pointer on success.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * @param enmType The object type.
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync * @param cb The size of the allocation.
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync * @param PhysHighest See rtR0MemObjNativeAllocPhys.
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsyncstatic int rtR0MemObjLinuxAllocPhysSub(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJTYPE enmType, size_t cb, RTHCPHYS PhysHighest)
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * There are two clear cases and that's the <=16MB and anything-goes ones.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * When the physical address limit is somewhere inbetween those two we'll
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * just have to try, starting with HIGHUSER and working our way thru the
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * different types, hoping we'll get lucky.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * We should probably move this physical address restriction logic up to
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * the page alloc function as it would be more efficient there. But since
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync * we don't expect this to be a performance issue just yet it can wait.
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* ZONE_HIGHMEM: the whole physical memory */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync rc = rtR0MemObjLinuxAllocPhysSub2(ppMem, enmType, cb, PhysHighest, GFP_HIGHUSER);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* ZONE_DMA: 0-16MB */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync rc = rtR0MemObjLinuxAllocPhysSub2(ppMem, enmType, cb, PhysHighest, GFP_DMA);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* ZONE_HIGHMEM: the whole physical memory */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync rc = rtR0MemObjLinuxAllocPhysSub2(ppMem, enmType, cb, PhysHighest, GFP_HIGHUSER);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* ZONE_NORMAL: 0-896MB */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync rc = rtR0MemObjLinuxAllocPhysSub2(ppMem, enmType, cb, PhysHighest, GFP_USER);
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync /* ZONE_DMA32: 0-4GB */
0c64f283f499a1ec6e8861ea98e7f252284e8358vboxsync rc = rtR0MemObjLinuxAllocPhysSub2(ppMem, enmType, cb, PhysHighest, GFP_DMA32);
return rc;
int rtR0MemObjNativeAllocPhys(PPRTR0MEMOBJINTERNAL ppMem, size_t cb, RTHCPHYS PhysHighest, size_t uAlignment)
if ( uAlignment != 0
return VERR_NOT_SUPPORTED;
if (!pMemLnx)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
int rtR0MemObjNativeLockUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3Ptr, size_t cb, uint32_t fAccess, RTR0PROCESS R0Process)
if (!pTask)
return VERR_NOT_SUPPORTED;
return VERR_OUT_OF_RANGE;
pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(RT_OFFSETOF(RTR0MEMOBJLNX, apPages[cPages]), RTR0MEMOBJTYPE_LOCK, (void *)R3Ptr, cb);
if (!pMemLnx)
return VERR_NO_MEMORY;
if (papVMAs)
while (rc-- > 0)
return VINF_SUCCESS;
while (rc-- > 0)
return rc;
bool fLinearMapping;
int rc;
if (!fLinearMapping)
return VERR_INVALID_PARAMETER;
pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(RT_OFFSETOF(RTR0MEMOBJLNX, apPages[cPages]), RTR0MEMOBJTYPE_LOCK, pv, cb);
if (!pMemLnx)
return VERR_NO_MEMORY;
if (!fLinearMapping)
while (iPage-- > 0)
while (iPage-- > 0)
return VINF_SUCCESS;
return rc;
int rtR0MemObjNativeReserveKernel(PPRTR0MEMOBJINTERNAL ppMem, void *pvFixed, size_t cb, size_t uAlignment)
return VERR_NOT_SUPPORTED;
if (!pDummyPage)
return VERR_NO_MEMORY;
if (papPages)
void *pv;
while (iPage-- > 0)
# ifdef VM_MAP
if (pv)
PRTR0MEMOBJLNX pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(sizeof(*pMemLnx), RTR0MEMOBJTYPE_RES_VIRT, pv, cb);
if (pMemLnx)
return VINF_SUCCESS;
return VERR_NO_MEMORY;
return VERR_NOT_SUPPORTED;
static void *rtR0MemObjLinuxDoMmap(RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment, struct task_struct *pTask, unsigned fProt)
unsigned fLnxProt;
unsigned long ulAddr;
* Convert from IPRT protection to mman.h PROT_ and call do_mmap.
fLnxProt = 0;
return (void *)ulAddr;
int rtR0MemObjNativeReserveUser(PPRTR0MEMOBJINTERNAL ppMem, RTR3PTR R3PtrFixed, size_t cb, size_t uAlignment, RTR0PROCESS R0Process)
void *pv;
if (!pTask)
return VERR_NOT_SUPPORTED;
return VERR_NOT_SUPPORTED;
return VERR_NO_MEMORY;
if (!pMemLnx)
return VERR_NO_MEMORY;
return VINF_SUCCESS;
int rtR0MemObjNativeMapKernel(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, void *pvFixed, size_t uAlignment,
return VERR_NOT_SUPPORTED;
pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(sizeof(*pMemLnx), RTR0MEMOBJTYPE_MAPPING, NULL, pMemLnxToMap->Core.cb);
if (pMemLnx)
# ifdef VM_MAP
return VINF_SUCCESS;
return rc;
#ifdef VBOX_USE_PAE_HACK
if (ptep)
rc = 0;
return rc;
int rtR0MemObjNativeMapUser(PPRTR0MEMOBJINTERNAL ppMem, RTR0MEMOBJ pMemToMap, RTR3PTR R3PtrFixed, size_t uAlignment, unsigned fProt, RTR0PROCESS R0Process)
#ifdef VBOX_USE_PAE_HACK
if (!pTask)
return VERR_NOT_SUPPORTED;
return VERR_NOT_SUPPORTED;
#ifdef VBOX_USE_PAE_HACK
if (!pDummyPage)
return VERR_NO_MEMORY;
pMemLnx = (PRTR0MEMOBJLNX)rtR0MemObjNew(sizeof(*pMemLnx), RTR0MEMOBJTYPE_MAPPING, NULL, pMemLnxToMap->Core.cb);
if (pMemLnx)
void *pv;
rc = 0;
struct vm_area_struct *vma = find_vma(pTask->mm, ulAddrCur); /* this is probably the same for all the pages... */
vma->vm_flags |= VM_RESERVED; /* This flag helps making 100% sure some bad stuff wont happen (swap, core, ++). */
if (!rc)
if (rc)
struct vm_area_struct *vma = find_vma(pTask->mm, ulAddrCur); /* this is probably the same for all the pages... */
if (!rc)
if (rc)
if (!rc)
#ifdef VBOX_USE_PAE_HACK
return VINF_SUCCESS;
#ifdef VBOX_USE_PAE_HACK
return rc;
return VERR_NOT_SUPPORTED;
case RTR0MEMOBJTYPE_CONT:
case RTR0MEMOBJTYPE_PHYS:
case RTR0MEMOBJTYPE_MAPPING:
case RTR0MEMOBJTYPE_LOW:
case RTR0MEMOBJTYPE_LOCK:
case RTR0MEMOBJTYPE_PHYS_NC:
case RTR0MEMOBJTYPE_PAGE:
case RTR0MEMOBJTYPE_RES_VIRT:
return NIL_RTHCPHYS;