alloc-r0drv-linux.c revision 501311711d2beab90b719964f7f1c68bb3d37c85
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync/* $Id$ */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync/** @file
0f70ed40798198e1d9099c6ae3bdb239d2b8cf0dvboxsync * InnoTek Portable Runtime - Memory Allocation, Ring-0 Driver, Linux.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
0f70ed40798198e1d9099c6ae3bdb239d2b8cf0dvboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync/*
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Copyright (C) 2006 InnoTek Systemberatung GmbH
a9749534ba173982f6c3bafe8d51ccd22960e493vboxsync *
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * available from http://www.virtualbox.org. This file is free software;
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * you can redistribute it and/or modify it under the terms of the GNU
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * General Public License as published by the Free Software Foundation,
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
82bcaaf8077ba892f39afb721dca149353c63d2cvboxsync *
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * If you received this file as part of a commercial VirtualBox
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * distribution, then only the terms of your commercial VirtualBox
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * license agreement apply instead of the previous paragraph.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync/*******************************************************************************
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync* Header Files *
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync*******************************************************************************/
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync#include "the-linux-kernel.h"
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync#include <iprt/alloc.h>
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync#include <iprt/assert.h>
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync#include "r0drv/alloc-r0drv.h"
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync#if defined(__AMD64__) || defined(__DOXYGEN__)
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync/**
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync * We need memory in the module range (~2GB to ~0) this can only be obtained
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * thru APIs that are not exported (see module_alloc()).
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync *
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * So, we'll have to create a quick and dirty heap here using BSS memory.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Very annoying and it's going to restrict us!
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync# define RTMEMALLOC_EXEC_HEAP
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync#endif
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync#ifdef RTMEMALLOC_EXEC_HEAP
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync# include <iprt/heap.h>
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync# include <iprt/spinlock.h>
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync# include <iprt/err.h>
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync#endif
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync/*******************************************************************************
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync* Global Variables *
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync*******************************************************************************/
2622c26c6b4105d944a29c5e2c77b6ef26e10101vboxsync#ifdef RTMEMALLOC_EXEC_HEAP
500aaaf3dc1d98456808e7618db3fb2e7c8fb8e0vboxsync/** The heap. */
8ffcab9595cc0d56977968cd496363502fd814aevboxsyncstatic RTHEAPSIMPLE g_HeapExec = NIL_RTHEAPSIMPLE;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync/** Spinlock protecting the heap. */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsyncstatic RTSPINLOCK g_HeapExecSpinlock = NIL_RTHEAPSIMPLE;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync/**
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * API for cleaning up the heap spinlock on IPRT termination.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * This is as RTMemExecDonate specific to AMD64 Linux/GNU.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsyncRTDECL(void) RTMemExecCleanup(void)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync{
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync RTSpinlockDestroy(g_HeapExecSpinlock);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync g_HeapExecSpinlock = NIL_RTSPINLOCK;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync}
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync/**
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Donate read+write+execute memory to the exec heap.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync *
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * This API is specific to AMD64 and Linux/GNU. A kernel module that desires to
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync * use RTMemExecAlloc on AMD64 Linux/GNU will have to donate some statically
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync * allocated memory in the module if it wishes for GCC generated code to work.
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync * GCC can only generate modules that work in the address range ~2GB to ~0
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync * currently.
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync *
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync * The API only accept one single donation.
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync *
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync * @returns IPRT status code.
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync * @param pvMemory Pointer to the memory block.
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync * @param cb The size of the memory block.
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync */
e2843ed205192b88e54eef60ad541d00bbbc932avboxsyncRTDECL(int) RTMemExecDonate(void *pvMemory, size_t cb)
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync{
77da7a074c86956d36759983037056c00cb87535vboxsync AssertReturn(g_HeapExec == NIL_RTHEAPSIMPLE, VERR_WRONG_ORDER);
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync int rc = RTSpinlockCreate(&g_HeapExecSpinlock);
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync if (RT_SUCCESS(rc))
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync {
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync rc = RTHeapSimpleInit(&g_HeapExec, pvMemory, cb);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (RT_FAILURE(rc))
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync RTMemExecCleanup();
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync }
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync return rc;
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync}
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync#endif /* RTMEMALLOC_EXEC_HEAP */
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync/**
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync * OS specific allocation function.
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync */
d5b5f09d8841828e647de9da5003fda55ca4cd5evboxsyncPRTMEMHDR rtMemAlloc(size_t cb, uint32_t fFlags)
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync{
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync /*
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync * Allocate.
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync */
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync PRTMEMHDR pHdr;
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync Assert(cb != sizeof(void *)); /* 99% of pointer sized allocations are wrong. */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (fFlags & RTMEMHDR_FLAG_EXEC)
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync {
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync#if defined(__AMD64__)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync# ifdef RTMEMALLOC_EXEC_HEAP
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (g_HeapExec != NIL_RTHEAPSIMPLE)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync {
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync fFlags |= RTMEMHDR_FLAG_EXEC_HEAP;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync RTSPINLOCKTMP SpinlockTmp = RTSPINLOCKTMP_INITIALIZER;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync RTSpinlockAcquireNoInts(g_HeapExecSpinlock, &SpinlockTmp);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync pHdr = (PRTMEMHDR)RTHeapSimpleAlloc(g_HeapExec, cb + sizeof(*pHdr), 0);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync RTSpinlockReleaseNoInts(g_HeapExecSpinlock, &SpinlockTmp);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync }
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync else
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync# endif
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync pHdr = (PRTMEMHDR)__vmalloc(cb + sizeof(*pHdr), GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync#elif defined(PAGE_KERNEL_EXEC) && defined(CONFIG_X86_PAE)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync pHdr = (PRTMEMHDR)__vmalloc(cb + sizeof(*pHdr), GFP_KERNEL | __GFP_HIGHMEM,
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync __pgprot(cpu_has_pge ? _PAGE_KERNEL_EXEC | _PAGE_GLOBAL : _PAGE_KERNEL_EXEC));
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync#else
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync pHdr = (PRTMEMHDR)vmalloc(cb + sizeof(*pHdr));
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync#endif
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync }
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync else
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync {
2622c26c6b4105d944a29c5e2c77b6ef26e10101vboxsync if (cb <= PAGE_SIZE)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync {
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync fFlags |= RTMEMHDR_FLAG_KMALLOC;
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync pHdr = kmalloc(cb + sizeof(*pHdr), GFP_KERNEL);
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync }
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync else
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync pHdr = vmalloc(cb + sizeof(*pHdr));
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync }
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync /*
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Initialize.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (pHdr)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync {
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync pHdr->u32Magic = RTMEMHDR_MAGIC;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync pHdr->fFlags = fFlags;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync pHdr->cb = cb;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync pHdr->u32Padding= 0;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync }
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return pHdr;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync}
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync/**
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * OS specific free function.
2622c26c6b4105d944a29c5e2c77b6ef26e10101vboxsync */
2622c26c6b4105d944a29c5e2c77b6ef26e10101vboxsyncvoid rtMemFree(PRTMEMHDR pHdr)
2622c26c6b4105d944a29c5e2c77b6ef26e10101vboxsync{
2622c26c6b4105d944a29c5e2c77b6ef26e10101vboxsync pHdr->u32Magic += 1;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (pHdr->fFlags & RTMEMHDR_FLAG_KMALLOC)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync kfree(pHdr);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync#ifdef RTMEMALLOC_EXEC_HEAP
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync else if (pHdr->fFlags & RTMEMHDR_FLAG_EXEC_HEAP)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync {
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync RTSpinlockAcquireNoInts(g_HeapExecSpinlock, &SpinlockTmp);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync RTHeapSimpleFree(g_HeapExec, pHdr);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync RTSpinlockReleaseNoInts(g_HeapExecSpinlock, &SpinlockTmp);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync }
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync#endif
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync else
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync vfree(pHdr);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync}
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync/**
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Compute order. Some functions allocate 2^order pages.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync *
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @returns order.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param cPages Number of pages.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsyncstatic int CalcPowerOf2Order(unsigned long cPages)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync{
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync int iOrder;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync unsigned long cTmp;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync for (iOrder = 0, cTmp = cPages; cTmp >>= 1; ++iOrder)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync ;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (cPages & ~(1 << iOrder))
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync ++iOrder;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return iOrder;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync}
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync/**
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Allocates physical contiguous memory (below 4GB).
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * The allocation is page aligned and the content is undefined.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync *
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @returns Pointer to the memory block. This is page aligned.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pPhys Where to store the physical address.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param cb The allocation size in bytes. This is always
77da7a074c86956d36759983037056c00cb87535vboxsync * rounded up to PAGE_SIZE.
77da7a074c86956d36759983037056c00cb87535vboxsync */
77da7a074c86956d36759983037056c00cb87535vboxsyncRTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync{
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync int cOrder;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync unsigned cPages;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync struct page *paPages;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /*
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * validate input.
8ffcab9595cc0d56977968cd496363502fd814aevboxsync */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync Assert(VALID_PTR(pPhys));
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync Assert(cb > 0);
7f67048412d241d45c0835b9c403a5bb1c879030vboxsync
8ffcab9595cc0d56977968cd496363502fd814aevboxsync /*
8ffcab9595cc0d56977968cd496363502fd814aevboxsync * Allocate page pointer array.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync cb = RT_ALIGN_Z(cb, PAGE_SIZE);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync cPages = cb >> PAGE_SHIFT;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync cOrder = CalcPowerOf2Order(cPages);
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync#ifdef __AMD64__ /** @todo check out if there is a correct way of getting memory below 4GB (physically). */
7f67048412d241d45c0835b9c403a5bb1c879030vboxsync paPages = alloc_pages(GFP_DMA, cOrder);
7f67048412d241d45c0835b9c403a5bb1c879030vboxsync#else
7f67048412d241d45c0835b9c403a5bb1c879030vboxsync paPages = alloc_pages(GFP_USER, cOrder);
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync#endif
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync if (paPages)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync {
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /*
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Reserve the pages and mark them executable.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync unsigned iPage;
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync for (iPage = 0; iPage < cPages; iPage++)
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync {
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync Assert(!PageHighMem(&paPages[iPage]));
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync if (iPage + 1 < cPages)
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync {
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync AssertMsg( (uintptr_t)phys_to_virt(page_to_phys(&paPages[iPage])) + PAGE_SIZE
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync == (uintptr_t)phys_to_virt(page_to_phys(&paPages[iPage + 1]))
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync && page_to_phys(&paPages[iPage]) + PAGE_SIZE
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync == page_to_phys(&paPages[iPage + 1]),
e2843ed205192b88e54eef60ad541d00bbbc932avboxsync ("iPage=%i cPages=%u [0]=%#llx,%p [1]=%#llx,%p\n", iPage, cPages,
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync (long long)page_to_phys(&paPages[iPage]), phys_to_virt(page_to_phys(&paPages[iPage])),
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync (long long)page_to_phys(&paPages[iPage + 1]), phys_to_virt(page_to_phys(&paPages[iPage + 1])) ));
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync }
2e2dec6e64c09dd7e3fe4ad0ee8bb5cf7d63762evboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync SetPageReserved(&paPages[iPage]);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL))
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync MY_CHANGE_PAGE_ATTR(&paPages[iPage], 1, MY_PAGE_KERNEL_EXEC);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync }
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync *pPhys = page_to_phys(paPages);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return phys_to_virt(page_to_phys(paPages));
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync }
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync return NULL;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync}
8a8d7629deae8875b70c6899e8b0f683b2a543e1vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync/**
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Frees memory allocated ysing RTMemContAlloc().
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync *
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param pv Pointer to return from RTMemContAlloc().
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * @param cb The cb parameter passed to RTMemContAlloc().
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
8a8d7629deae8875b70c6899e8b0f683b2a543e1vboxsyncRTR0DECL(void) RTMemContFree(void *pv, size_t cb)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync{
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (pv)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync {
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync int cOrder;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync unsigned cPages;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync unsigned iPage;
8a8d7629deae8875b70c6899e8b0f683b2a543e1vboxsync struct page *paPages;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /* validate */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync AssertMsg(!((uintptr_t)pv & PAGE_OFFSET_MASK), ("pv=%p\n", pv));
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync Assert(cb > 0);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /* calc order and get pages */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync cb = RT_ALIGN_Z(cb, PAGE_SIZE);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync cPages = cb >> PAGE_SHIFT;
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync cOrder = CalcPowerOf2Order(cPages);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync paPages = virt_to_page(pv);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync /*
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync * Restore page attributes freeing the pages.
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync */
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync for (iPage = 0; iPage < cPages; iPage++)
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync {
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync ClearPageReserved(&paPages[iPage]);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync if (pgprot_val(MY_PAGE_KERNEL_EXEC) != pgprot_val(PAGE_KERNEL))
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync MY_CHANGE_PAGE_ATTR(&paPages[iPage], 1, PAGE_KERNEL);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync }
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync __free_pages(paPages, cOrder);
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync }
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync}
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync
d1a00c93378091ef28db9d959b2d692cc8143a07vboxsync