alloc-r0drv-linux.c revision fca58371c88ea44110fed3a316ae0cb9c7690f91
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync/* $Id$ */
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync/** @file
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * IPRT - Memory Allocation, Ring-0 Driver, Linux.
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync */
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync/*
c7814cf6e1240a519cbec0441e033d0e2470ed00vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync *
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * available from http://www.virtualbox.org. This file is free software;
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * you can redistribute it and/or modify it under the terms of the GNU
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * General Public License (GPL) as published by the Free Software
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync *
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * The contents of this file may alternatively be used under the terms
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * of the Common Development and Distribution License Version 1.0
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * VirtualBox OSE distribution, in which case the provisions of the
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * CDDL are applicable instead of those of the GPL.
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync *
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * You may elect to license modified versions of this file under the
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * terms and conditions of either the GPL or the CDDL or both.
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync *
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * additional information or have any questions.
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync */
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync/*******************************************************************************
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync* Header Files *
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync*******************************************************************************/
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync#include "the-linux-kernel.h"
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync#include "internal/iprt.h"
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync#include <iprt/mem.h>
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync#include <iprt/assert.h>
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync#include "r0drv/alloc-r0drv.h"
dd90fee6b212c87998fe80f39a1645e4bbe1acb9vboxsync
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync#if defined(RT_ARCH_AMD64) || defined(__DOXYGEN__)
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync/**
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * We need memory in the module range (~2GB to ~0) this can only be obtained
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * thru APIs that are not exported (see module_alloc()).
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync *
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * So, we'll have to create a quick and dirty heap here using BSS memory.
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * Very annoying and it's going to restrict us!
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync */
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync# define RTMEMALLOC_EXEC_HEAP
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync#endif
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync#ifdef RTMEMALLOC_EXEC_HEAP
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync# include <iprt/heap.h>
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync# include <iprt/spinlock.h>
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync# include <iprt/err.h>
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync#endif
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync/*******************************************************************************
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync* Global Variables *
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync*******************************************************************************/
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync#ifdef RTMEMALLOC_EXEC_HEAP
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync/** The heap. */
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsyncstatic RTHEAPSIMPLE g_HeapExec = NIL_RTHEAPSIMPLE;
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync/** Spinlock protecting the heap. */
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsyncstatic RTSPINLOCK g_HeapExecSpinlock = NIL_RTSPINLOCK;
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync/**
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * API for cleaning up the heap spinlock on IPRT termination.
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * This is as RTMemExecDonate specific to AMD64 Linux/GNU.
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync */
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsyncvoid rtR0MemExecCleanup(void)
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync{
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync RTSpinlockDestroy(g_HeapExecSpinlock);
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync g_HeapExecSpinlock = NIL_RTSPINLOCK;
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync}
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync/**
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * Donate read+write+execute memory to the exec heap.
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync *
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * This API is specific to AMD64 and Linux/GNU. A kernel module that desires to
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * use RTMemExecAlloc on AMD64 Linux/GNU will have to donate some statically
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * allocated memory in the module if it wishes for GCC generated code to work.
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * GCC can only generate modules that work in the address range ~2GB to ~0
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * currently.
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync *
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync * The API only accept one single donation.
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync *
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync * @returns IPRT status code.
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync * @param pvMemory Pointer to the memory block.
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync * @param cb The size of the memory block.
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync */
6d22c1a25757a476158a4ed2b463f6baf09ae813vboxsyncRTR0DECL(int) RTR0MemExecDonate(void *pvMemory, size_t cb)
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync{
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync int rc;
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync AssertReturn(g_HeapExec == NIL_RTHEAPSIMPLE, VERR_WRONG_ORDER);
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync rc = RTSpinlockCreate(&g_HeapExecSpinlock);
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync if (RT_SUCCESS(rc))
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync {
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync rc = RTHeapSimpleInit(&g_HeapExec, pvMemory, cb);
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync if (RT_FAILURE(rc))
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync rtR0MemExecCleanup();
0fb42f85d3c82308466ce750f2126a11f56005dfvboxsync }
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync return rc;
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync}
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsyncRT_EXPORT_SYMBOL(RTR0MemExecDonate);
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync#endif /* RTMEMALLOC_EXEC_HEAP */
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync/**
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync * OS specific allocation function.
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync */
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsyncPRTMEMHDR rtMemAlloc(size_t cb, uint32_t fFlags)
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync{
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync /*
0fb42f85d3c82308466ce750f2126a11f56005dfvboxsync * Allocate.
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync */
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync PRTMEMHDR pHdr;
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync if (fFlags & RTMEMHDR_FLAG_EXEC)
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync {
3e6da1894f26075b74820b75bf5ef7e4a64070edvboxsync#if defined(RT_ARCH_AMD64)
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync# ifdef RTMEMALLOC_EXEC_HEAP
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync if (g_HeapExec != NIL_RTHEAPSIMPLE)
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync {
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync RTSpinlockAcquireNoInts(g_HeapExecSpinlock, &SpinlockTmp);
dd90fee6b212c87998fe80f39a1645e4bbe1acb9vboxsync pHdr = (PRTMEMHDR)RTHeapSimpleAlloc(g_HeapExec, cb + sizeof(*pHdr), 0);
dd90fee6b212c87998fe80f39a1645e4bbe1acb9vboxsync RTSpinlockReleaseNoInts(g_HeapExecSpinlock, &SpinlockTmp);
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync fFlags |= RTMEMHDR_FLAG_EXEC_HEAP;
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync }
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync else
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync pHdr = NULL;
dd90fee6b212c87998fe80f39a1645e4bbe1acb9vboxsync# else /* !RTMEMALLOC_EXEC_HEAP */
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync pHdr = (PRTMEMHDR)__vmalloc(cb + sizeof(*pHdr), GFP_KERNEL | __GFP_HIGHMEM, MY_PAGE_KERNEL_EXEC);
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync# endif /* !RTMEMALLOC_EXEC_HEAP */
0fb42f85d3c82308466ce750f2126a11f56005dfvboxsync
0fb42f85d3c82308466ce750f2126a11f56005dfvboxsync#elif defined(PAGE_KERNEL_EXEC) && defined(CONFIG_X86_PAE)
0fb42f85d3c82308466ce750f2126a11f56005dfvboxsync pHdr = (PRTMEMHDR)__vmalloc(cb + sizeof(*pHdr), GFP_KERNEL | __GFP_HIGHMEM, MY_PAGE_KERNEL_EXEC);
0fb42f85d3c82308466ce750f2126a11f56005dfvboxsync#else
0fb42f85d3c82308466ce750f2126a11f56005dfvboxsync pHdr = (PRTMEMHDR)vmalloc(cb + sizeof(*pHdr));
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync#endif
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync }
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync else
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync {
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync if (cb <= PAGE_SIZE)
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync {
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync fFlags |= RTMEMHDR_FLAG_KMALLOC;
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync pHdr = kmalloc(cb + sizeof(*pHdr), GFP_KERNEL);
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync }
dd90fee6b212c87998fe80f39a1645e4bbe1acb9vboxsync else
dd90fee6b212c87998fe80f39a1645e4bbe1acb9vboxsync pHdr = vmalloc(cb + sizeof(*pHdr));
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync }
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync /*
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync * Initialize.
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync */
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync if (pHdr)
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync {
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync pHdr->u32Magic = RTMEMHDR_MAGIC;
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync pHdr->fFlags = fFlags;
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync pHdr->cb = cb;
0fb42f85d3c82308466ce750f2126a11f56005dfvboxsync pHdr->cbReq = cb;
f655cf8b865e5960fa2e54012ae8481b4303f441vboxsync }
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync return pHdr;
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync}
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync/**
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync * OS specific free function.
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync */
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsyncvoid rtMemFree(PRTMEMHDR pHdr)
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync{
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync pHdr->u32Magic += 1;
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync if (pHdr->fFlags & RTMEMHDR_FLAG_KMALLOC)
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync kfree(pHdr);
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync#ifdef RTMEMALLOC_EXEC_HEAP
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync else if (pHdr->fFlags & RTMEMHDR_FLAG_EXEC_HEAP)
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync {
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync RTSpinlockAcquireNoInts(g_HeapExecSpinlock, &SpinlockTmp);
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync RTHeapSimpleFree(g_HeapExec, pHdr);
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync RTSpinlockReleaseNoInts(g_HeapExecSpinlock, &SpinlockTmp);
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync }
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync#endif
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync else
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync vfree(pHdr);
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync}
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync/**
0fb42f85d3c82308466ce750f2126a11f56005dfvboxsync * Compute order. Some functions allocate 2^order pages.
0fb42f85d3c82308466ce750f2126a11f56005dfvboxsync *
c08d89470d5384eaa863a8a371c0e4a38e9ded60vboxsync * @returns order.
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync * @param cPages Number of pages.
c08d89470d5384eaa863a8a371c0e4a38e9ded60vboxsync */
c08d89470d5384eaa863a8a371c0e4a38e9ded60vboxsyncstatic int CalcPowerOf2Order(unsigned long cPages)
c08d89470d5384eaa863a8a371c0e4a38e9ded60vboxsync{
723bfeb3763ffd6c59cb9060cc8b3cd50e832c97vboxsync int iOrder;
723bfeb3763ffd6c59cb9060cc8b3cd50e832c97vboxsync unsigned long cTmp;
723bfeb3763ffd6c59cb9060cc8b3cd50e832c97vboxsync
723bfeb3763ffd6c59cb9060cc8b3cd50e832c97vboxsync for (iOrder = 0, cTmp = cPages; cTmp >>= 1; ++iOrder)
723bfeb3763ffd6c59cb9060cc8b3cd50e832c97vboxsync ;
c08d89470d5384eaa863a8a371c0e4a38e9ded60vboxsync if (cPages & ~(1 << iOrder))
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync ++iOrder;
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync return iOrder;
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync}
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync/**
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync * Allocates physical contiguous memory (below 4GB).
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync * The allocation is page aligned and the content is undefined.
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync *
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync * @returns Pointer to the memory block. This is page aligned.
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync * @param pPhys Where to store the physical address.
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync * @param cb The allocation size in bytes. This is always
0fb42f85d3c82308466ce750f2126a11f56005dfvboxsync * rounded up to PAGE_SIZE.
0fb42f85d3c82308466ce750f2126a11f56005dfvboxsync */
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsyncRTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb)
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync{
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync int cOrder;
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync unsigned cPages;
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync struct page *paPages;
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync /*
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * validate input.
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync */
dd90fee6b212c87998fe80f39a1645e4bbe1acb9vboxsync Assert(VALID_PTR(pPhys));
dd90fee6b212c87998fe80f39a1645e4bbe1acb9vboxsync Assert(cb > 0);
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
dd90fee6b212c87998fe80f39a1645e4bbe1acb9vboxsync /*
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * Allocate page pointer array.
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync */
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync cb = RT_ALIGN_Z(cb, PAGE_SIZE);
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync cPages = cb >> PAGE_SHIFT;
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync cOrder = CalcPowerOf2Order(cPages);
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync#ifdef RT_ARCH_AMD64
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync /** @todo check out if there is a correct way of getting memory below 4GB (physically).
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync * GFP_DMA32 is available since Linux 2.6.15 */
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync paPages = alloc_pages(GFP_DMA, cOrder);
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync#else
dd90fee6b212c87998fe80f39a1645e4bbe1acb9vboxsync /** XXX Wrong: GFP_USER can return page frames above 4GB! */
dd90fee6b212c87998fe80f39a1645e4bbe1acb9vboxsync paPages = alloc_pages(GFP_USER, cOrder);
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync#endif
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync if (paPages)
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync {
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync /*
d736beed1ca63b0f4b16c4973ebf9188c3d8dda6vboxsync * Reserve the pages and mark them executable.
d736beed1ca63b0f4b16c4973ebf9188c3d8dda6vboxsync */
d736beed1ca63b0f4b16c4973ebf9188c3d8dda6vboxsync unsigned iPage;
d736beed1ca63b0f4b16c4973ebf9188c3d8dda6vboxsync for (iPage = 0; iPage < cPages; iPage++)
d736beed1ca63b0f4b16c4973ebf9188c3d8dda6vboxsync {
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync Assert(!PageHighMem(&paPages[iPage]));
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync if (iPage + 1 < cPages)
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync {
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync AssertMsg( (uintptr_t)phys_to_virt(page_to_phys(&paPages[iPage])) + PAGE_SIZE
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync == (uintptr_t)phys_to_virt(page_to_phys(&paPages[iPage + 1]))
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync && page_to_phys(&paPages[iPage]) + PAGE_SIZE
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync == page_to_phys(&paPages[iPage + 1]),
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync ("iPage=%i cPages=%u [0]=%#llx,%p [1]=%#llx,%p\n", iPage, cPages,
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync (long long)page_to_phys(&paPages[iPage]), phys_to_virt(page_to_phys(&paPages[iPage])),
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync (long long)page_to_phys(&paPages[iPage + 1]), phys_to_virt(page_to_phys(&paPages[iPage + 1])) ));
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync }
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync
ba31bc205e96548d3557ae82087dc020a52b6a0avboxsync SetPageReserved(&paPages[iPage]);
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 20) /** @todo find the exact kernel where change_page_attr was introduced. */
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync MY_SET_PAGES_EXEC(&paPages[iPage], 1);
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync#endif
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync }
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync *pPhys = page_to_phys(paPages);
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync return phys_to_virt(page_to_phys(paPages));
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync }
5923a1e1a9eff5786a4dc5a281e11b7dc4fd0811vboxsync
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync return NULL;
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync}
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsyncRT_EXPORT_SYMBOL(RTMemContAlloc);
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync/**
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync * Frees memory allocated ysing RTMemContAlloc().
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync *
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync * @param pv Pointer to return from RTMemContAlloc().
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync * @param cb The cb parameter passed to RTMemContAlloc().
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync */
f450e6365ee42333841dd494583809428b504e37vboxsyncRTR0DECL(void) RTMemContFree(void *pv, size_t cb)
f450e6365ee42333841dd494583809428b504e37vboxsync{
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync if (pv)
f450e6365ee42333841dd494583809428b504e37vboxsync {
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync int cOrder;
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync unsigned cPages;
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync unsigned iPage;
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync struct page *paPages;
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync
f450e6365ee42333841dd494583809428b504e37vboxsync /* validate */
4a4a02cc2a09b5e3c55908c6995182c6b038e398vboxsync AssertMsg(!((uintptr_t)pv & PAGE_OFFSET_MASK), ("pv=%p\n", pv));
f450e6365ee42333841dd494583809428b504e37vboxsync Assert(cb > 0);
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync /* calc order and get pages */
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync cb = RT_ALIGN_Z(cb, PAGE_SIZE);
f450e6365ee42333841dd494583809428b504e37vboxsync cPages = cb >> PAGE_SHIFT;
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync cOrder = CalcPowerOf2Order(cPages);
7753dc7a3bcd14c9ec9d969cbc1a0155b0673c06vboxsync paPages = virt_to_page(pv);
4bb5cfa1f4d9e95d7d34b5d6ede18d9f4d433bc6vboxsync
4bb5cfa1f4d9e95d7d34b5d6ede18d9f4d433bc6vboxsync /*
04b02ffb8824a60fd37777bc1f7d2f35104a274cvboxsync * Restore page attributes freeing the pages.
04b02ffb8824a60fd37777bc1f7d2f35104a274cvboxsync */
04b02ffb8824a60fd37777bc1f7d2f35104a274cvboxsync for (iPage = 0; iPage < cPages; iPage++)
4bb5cfa1f4d9e95d7d34b5d6ede18d9f4d433bc6vboxsync {
4bb5cfa1f4d9e95d7d34b5d6ede18d9f4d433bc6vboxsync ClearPageReserved(&paPages[iPage]);
04b02ffb8824a60fd37777bc1f7d2f35104a274cvboxsync#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 20) /** @todo find the exact kernel where change_page_attr was introduced. */
4bb5cfa1f4d9e95d7d34b5d6ede18d9f4d433bc6vboxsync MY_SET_PAGES_NOEXEC(&paPages[iPage], 1);
4bb5cfa1f4d9e95d7d34b5d6ede18d9f4d433bc6vboxsync#endif
4bb5cfa1f4d9e95d7d34b5d6ede18d9f4d433bc6vboxsync }
4bb5cfa1f4d9e95d7d34b5d6ede18d9f4d433bc6vboxsync __free_pages(paPages, cOrder);
4bb5cfa1f4d9e95d7d34b5d6ede18d9f4d433bc6vboxsync }
4bb5cfa1f4d9e95d7d34b5d6ede18d9f4d433bc6vboxsync}
4bb5cfa1f4d9e95d7d34b5d6ede18d9f4d433bc6vboxsyncRT_EXPORT_SYMBOL(RTMemContFree);
4bb5cfa1f4d9e95d7d34b5d6ede18d9f4d433bc6vboxsync
4bb5cfa1f4d9e95d7d34b5d6ede18d9f4d433bc6vboxsync