alloc-r0drv-linux.c revision 097de894d6a9a01ff7763f8a12d2b8882b29cd69
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/* $Id$ */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** @file
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * IPRT - Memory Allocation, Ring-0 Driver, Linux.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2006-2010 Oracle Corporation
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * available from http://www.virtualbox.org. This file is free software;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * The contents of this file may alternatively be used under the terms
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * of the Common Development and Distribution License Version 1.0
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * VirtualBox OSE distribution, in which case the provisions of the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * CDDL are applicable instead of those of the GPL.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * You may elect to license modified versions of this file under the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * terms and conditions of either the GPL or the CDDL or both.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
7e960d3a0a8a3a84d7aba2cca45d72b1c31cc97bvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/*******************************************************************************
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync* Header Files *
d31ded334a29f575e23dc889b603b1a586759348vboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include "the-linux-kernel.h"
d31ded334a29f575e23dc889b603b1a586759348vboxsync#include "internal/iprt.h"
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/mem.h>
61fa69e2bc9fc9e7490feed1c020273f3ddb238dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/assert.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include <iprt/err.h>
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#include "r0drv/alloc-r0drv.h"
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync#if defined(RT_ARCH_AMD64) || defined(DOXYGEN_RUNNING)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Starting with 2.6.23 we can use __get_vm_area and map_vm_area to allocate
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * memory in the moduel range. This is preferrable to the exec heap below.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync# define RTMEMALLOC_EXEC_VM_AREA
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync# else
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync/**
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync * We need memory in the module range (~2GB to ~0) this can only be obtained
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * thru APIs that are not exported (see module_alloc()).
afed5ab737f4aacfae3fe73776f40e989190a7cavboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * So, we'll have to create a quick and dirty heap here using BSS memory.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Very annoying and it's going to restrict us!
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync# define RTMEMALLOC_EXEC_HEAP
0174432b2b1a760b89840ba696f7ba51def65dddvboxsync# endif
2daaccf68be3773aee600c5c3e48bcf5401418a6vboxsync#endif
0174432b2b1a760b89840ba696f7ba51def65dddvboxsync
614cbe11a7e5588dc8d369e223174b1441a09359vboxsync#ifdef RTMEMALLOC_EXEC_HEAP
614cbe11a7e5588dc8d369e223174b1441a09359vboxsync# include <iprt/heap.h>
614cbe11a7e5588dc8d369e223174b1441a09359vboxsync# include <iprt/spinlock.h>
7666082b743c5e146a8cee6cc794ff4bc3fd0ffdvboxsync# include <iprt/err.h>
7666082b743c5e146a8cee6cc794ff4bc3fd0ffdvboxsync#endif
7666082b743c5e146a8cee6cc794ff4bc3fd0ffdvboxsync
7666082b743c5e146a8cee6cc794ff4bc3fd0ffdvboxsync
7666082b743c5e146a8cee6cc794ff4bc3fd0ffdvboxsync/*******************************************************************************
7666082b743c5e146a8cee6cc794ff4bc3fd0ffdvboxsync* Structures and Typedefs *
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef RTMEMALLOC_EXEC_VM_AREA
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Extended header used for headers marked with RTMEMHDR_FLAG_EXEC_VM_AREA.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * This is used with allocating executable memory, for things like generated
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * code and loaded modules.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef struct RTMEMLNXHDREX
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** The VM area for this allocation. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync struct vm_struct *pVmArea;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync void *pvDummy;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** The header we present to the generic API. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTMEMHDR Hdr;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync} RTMEMLNXHDREX;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncAssertCompileSize(RTMEMLNXHDREX, 32);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** Pointer to an extended memory header. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsynctypedef RTMEMLNXHDREX *PRTMEMLNXHDREX;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
22e281e75ed636601178296c6daebda8f1d17c59vboxsync/*******************************************************************************
22e281e75ed636601178296c6daebda8f1d17c59vboxsync* Global Variables *
22e281e75ed636601178296c6daebda8f1d17c59vboxsync*******************************************************************************/
22e281e75ed636601178296c6daebda8f1d17c59vboxsync#ifdef RTMEMALLOC_EXEC_HEAP
22e281e75ed636601178296c6daebda8f1d17c59vboxsync/** The heap. */
22e281e75ed636601178296c6daebda8f1d17c59vboxsyncstatic RTHEAPSIMPLE g_HeapExec = NIL_RTHEAPSIMPLE;
22e281e75ed636601178296c6daebda8f1d17c59vboxsync/** Spinlock protecting the heap. */
22e281e75ed636601178296c6daebda8f1d17c59vboxsyncstatic RTSPINLOCK g_HeapExecSpinlock = NIL_RTSPINLOCK;
22e281e75ed636601178296c6daebda8f1d17c59vboxsync
22e281e75ed636601178296c6daebda8f1d17c59vboxsync
22e281e75ed636601178296c6daebda8f1d17c59vboxsync/**
22e281e75ed636601178296c6daebda8f1d17c59vboxsync * API for cleaning up the heap spinlock on IPRT termination.
22e281e75ed636601178296c6daebda8f1d17c59vboxsync * This is as RTMemExecDonate specific to AMD64 Linux/GNU.
22e281e75ed636601178296c6daebda8f1d17c59vboxsync */
22e281e75ed636601178296c6daebda8f1d17c59vboxsyncDECLHIDDEN(void) rtR0MemExecCleanup(void)
22e281e75ed636601178296c6daebda8f1d17c59vboxsync{
22e281e75ed636601178296c6daebda8f1d17c59vboxsync RTSpinlockDestroy(g_HeapExecSpinlock);
22e281e75ed636601178296c6daebda8f1d17c59vboxsync g_HeapExecSpinlock = NIL_RTSPINLOCK;
22e281e75ed636601178296c6daebda8f1d17c59vboxsync}
22e281e75ed636601178296c6daebda8f1d17c59vboxsync
22e281e75ed636601178296c6daebda8f1d17c59vboxsync
22e281e75ed636601178296c6daebda8f1d17c59vboxsync/**
22e281e75ed636601178296c6daebda8f1d17c59vboxsync * Donate read+write+execute memory to the exec heap.
7b80828e5760a8814fe6cd494d2715a4544fbddcvboxsync *
22e281e75ed636601178296c6daebda8f1d17c59vboxsync * This API is specific to AMD64 and Linux/GNU. A kernel module that desires to
22e281e75ed636601178296c6daebda8f1d17c59vboxsync * use RTMemExecAlloc on AMD64 Linux/GNU will have to donate some statically
22e281e75ed636601178296c6daebda8f1d17c59vboxsync * allocated memory in the module if it wishes for GCC generated code to work.
22e281e75ed636601178296c6daebda8f1d17c59vboxsync * GCC can only generate modules that work in the address range ~2GB to ~0
22e281e75ed636601178296c6daebda8f1d17c59vboxsync * currently.
22e281e75ed636601178296c6daebda8f1d17c59vboxsync *
22e281e75ed636601178296c6daebda8f1d17c59vboxsync * The API only accept one single donation.
22e281e75ed636601178296c6daebda8f1d17c59vboxsync *
22e281e75ed636601178296c6daebda8f1d17c59vboxsync * @returns IPRT status code.
22e281e75ed636601178296c6daebda8f1d17c59vboxsync * @param pvMemory Pointer to the memory block.
22e281e75ed636601178296c6daebda8f1d17c59vboxsync * @param cb The size of the memory block.
22e281e75ed636601178296c6daebda8f1d17c59vboxsync */
22e281e75ed636601178296c6daebda8f1d17c59vboxsyncRTR0DECL(int) RTR0MemExecDonate(void *pvMemory, size_t cb)
22e281e75ed636601178296c6daebda8f1d17c59vboxsync{
22e281e75ed636601178296c6daebda8f1d17c59vboxsync int rc;
22e281e75ed636601178296c6daebda8f1d17c59vboxsync AssertReturn(g_HeapExec == NIL_RTHEAPSIMPLE, VERR_WRONG_ORDER);
22e281e75ed636601178296c6daebda8f1d17c59vboxsync
d1cbbd799d8912978f5146960b6780f387bb414bvboxsync rc = RTSpinlockCreate(&g_HeapExecSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "RTR0MemExecDonate");
22e281e75ed636601178296c6daebda8f1d17c59vboxsync if (RT_SUCCESS(rc))
22e281e75ed636601178296c6daebda8f1d17c59vboxsync {
c17f5c90f2cb60b38ecabebce128724c6ff2d036vboxsync rc = RTHeapSimpleInit(&g_HeapExec, pvMemory, cb);
22e281e75ed636601178296c6daebda8f1d17c59vboxsync if (RT_FAILURE(rc))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rtR0MemExecCleanup();
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return rc;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncRT_EXPORT_SYMBOL(RTR0MemExecDonate);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif /* RTMEMALLOC_EXEC_HEAP */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#ifdef RTMEMALLOC_EXEC_VM_AREA
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
b1c3cdef473df2fbc621d5da81acc82dbfb8a11avboxsync * Allocate executable kernel memory in the module range.
a11c569636fa6838bd423f4631a9660a5a84204bvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns Pointer to a allocation header success. NULL on failure.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cb The size the user requested.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic PRTMEMHDR rtR0MemAllocExecVmArea(size_t cb)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync size_t const cbAlloc = RT_ALIGN_Z(sizeof(RTMEMLNXHDREX) + cb, PAGE_SIZE);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync size_t const cPages = cbAlloc >> PAGE_SHIFT;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync struct page **papPages;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync struct vm_struct *pVmArea;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync size_t iPage;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVmArea = __get_vm_area(cbAlloc, VM_ALLOC, MODULES_VADDR, MODULES_END);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!pVmArea)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return NULL;
3ecf9412133496b2aeb090cfd33a286404ec59fbvboxsync pVmArea->nr_pages = 0; /* paranoia? */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVmArea->pages = NULL; /* paranoia? */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync papPages = (struct page **)kmalloc(cPages * sizeof(papPages[0]), GFP_KERNEL);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!papPages)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync vunmap(pVmArea->addr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
750d4d0506a38b2e80c997075d40aad474e675fbvboxsync for (iPage = 0; iPage < cPages; iPage++)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync papPages[iPage] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!papPages[iPage])
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync break;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (iPage == cPages)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /*
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Map the pages. The API requires an iterator argument, which can be
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * used, in case of failure, to figure out how much was actually
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * mapped. Not sure how useful this really is, but whatever.
aaeb2e2f6ed5b164f1dec9a16a7adeb84f64cf31vboxsync *
223cf005b18af2c21352a70693ebaf0582f68ebcvboxsync * Not entirely sure we really need to set nr_pages and pages here, but
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync * they provide a very convenient place for storing something we need
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync * in the free function, if nothing else...
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync */
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync struct page **papPagesIterator = papPages;
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync pVmArea->nr_pages = cPages;
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync pVmArea->pages = papPages;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (!map_vm_area(pVmArea, PAGE_KERNEL_EXEC, &papPagesIterator))
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync PRTMEMLNXHDREX pHdrEx = (PRTMEMLNXHDREX)pVmArea->addr;
576d4214137bce409cdcf01e8df4a0bca5e0b2d1vboxsync pHdrEx->pVmArea = pVmArea;
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync pHdrEx->pvDummy = NULL;
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync return &pHdrEx->Hdr;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
72ef2b9fc5ffc01d0dabd5052d6e8baa3a952773vboxsync
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync /* bail out */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pVmArea->nr_pages = papPagesIterator - papPages;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync vunmap(pVmArea->addr);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync while (iPage-- > 0)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync __free_page(papPages[iPage]);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync kfree(papPages);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync return NULL;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync}
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif /* RTMEMALLOC_EXEC_VM_AREA */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/**
9e4166cf5ed4940f506bc718ea6c89bf7ed252c8vboxsync * OS specific allocation function.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
9e4166cf5ed4940f506bc718ea6c89bf7ed252c8vboxsyncDECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync{
909f4391cc20b4a3a9a2d3f8718084b669663ab2vboxsync PRTMEMHDR pHdr;
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync
22e281e75ed636601178296c6daebda8f1d17c59vboxsync /*
8a132edc1577cbe2a19cd778c1b2bea6ae5e8515vboxsync * Allocate.
69deddbc68802f1cf1c3a404a9f816b8accb3385vboxsync */
3ecd8008b81f02a04220705ae0033142af363280vboxsync if (fFlags & RTMEMHDR_FLAG_EXEC)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (fFlags & RTMEMHDR_FLAG_ANY_CTX)
576d4214137bce409cdcf01e8df4a0bca5e0b2d1vboxsync return VERR_NOT_SUPPORTED;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#if defined(RT_ARCH_AMD64)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync# ifdef RTMEMALLOC_EXEC_HEAP
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (g_HeapExec != NIL_RTHEAPSIMPLE)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTSpinlockAcquire(g_HeapExecSpinlock);
f9147fe1eaa4e35287f8f39282c7f92f0d7de0b7vboxsync pHdr = (PRTMEMHDR)RTHeapSimpleAlloc(g_HeapExec, cb + sizeof(*pHdr), 0);
585f64d6f624f9e683321dabeb21b0eb2e6aa473vboxsync RTSpinlockRelease(g_HeapExecSpinlock);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync fFlags |= RTMEMHDR_FLAG_EXEC_HEAP;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync }
3ecd8008b81f02a04220705ae0033142af363280vboxsync else
3ecd8008b81f02a04220705ae0033142af363280vboxsync pHdr = NULL;
22e281e75ed636601178296c6daebda8f1d17c59vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync# elif defined(RTMEMALLOC_EXEC_VM_AREA)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHdr = rtR0MemAllocExecVmArea(cb);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync fFlags |= RTMEMHDR_FLAG_EXEC_VM_AREA;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
b978e5849454446957177fd47ee98609ab0457a6vboxsync# else /* !RTMEMALLOC_EXEC_HEAP */
22e281e75ed636601178296c6daebda8f1d17c59vboxsync# error "you don not want to go here..."
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHdr = (PRTMEMHDR)__vmalloc(cb + sizeof(*pHdr), GFP_KERNEL | __GFP_HIGHMEM, MY_PAGE_KERNEL_EXEC);
247b55faa8d054157f2481e68caca36f4dc9542cvboxsync# endif /* !RTMEMALLOC_EXEC_HEAP */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#elif defined(PAGE_KERNEL_EXEC) && defined(CONFIG_X86_PAE)
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync pHdr = (PRTMEMHDR)__vmalloc(cb + sizeof(*pHdr), GFP_KERNEL | __GFP_HIGHMEM, MY_PAGE_KERNEL_EXEC);
57399ab65e2825c324fb9dcb4642d4ae2c232509vboxsync#else
22e281e75ed636601178296c6daebda8f1d17c59vboxsync pHdr = (PRTMEMHDR)vmalloc(cb + sizeof(*pHdr));
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync#endif
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
82e90599291da476b2de7c8db33cfb0f2cbac774vboxsync if (
82e90599291da476b2de7c8db33cfb0f2cbac774vboxsync#if 1 /* vmalloc has serious performance issues, avoid it. */
6ae4b1c72625a8e5c369effea7f018b578d733c4vboxsync cb <= PAGE_SIZE*16 - sizeof(*pHdr)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#else
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync cb <= PAGE_SIZE
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync || (fFlags & RTMEMHDR_FLAG_ANY_CTX)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync )
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
533ffcb943c4af2c5fe6385d816d0ba3eda9383bvboxsync fFlags |= RTMEMHDR_FLAG_KMALLOC;
b978e5849454446957177fd47ee98609ab0457a6vboxsync pHdr = kmalloc(cb + sizeof(*pHdr),
22e281e75ed636601178296c6daebda8f1d17c59vboxsync (fFlags & RTMEMHDR_FLAG_ANY_CTX_ALLOC) ? GFP_ATOMIC : GFP_KERNEL);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_UNLIKELY( !pHdr
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && cb > PAGE_SIZE
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && !(fFlags & RTMEMHDR_FLAG_ANY_CTX) ))
247b55faa8d054157f2481e68caca36f4dc9542cvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync fFlags &= ~RTMEMHDR_FLAG_KMALLOC;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHdr = vmalloc(cb + sizeof(*pHdr));
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync }
22e281e75ed636601178296c6daebda8f1d17c59vboxsync }
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync else
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync pHdr = vmalloc(cb + sizeof(*pHdr));
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (RT_UNLIKELY(!pHdr))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return VERR_NO_MEMORY;
82e90599291da476b2de7c8db33cfb0f2cbac774vboxsync
82e90599291da476b2de7c8db33cfb0f2cbac774vboxsync /*
6ae4b1c72625a8e5c369effea7f018b578d733c4vboxsync * Initialize.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHdr->u32Magic = RTMEMHDR_MAGIC;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pHdr->fFlags = fFlags;
533ffcb943c4af2c5fe6385d816d0ba3eda9383bvboxsync pHdr->cb = cb;
533ffcb943c4af2c5fe6385d816d0ba3eda9383bvboxsync pHdr->cbReq = cb;
00599f6d39cc25ca39845c2433cd75de7b9f6971vboxsync
00599f6d39cc25ca39845c2433cd75de7b9f6971vboxsync *ppHdr = pHdr;
00599f6d39cc25ca39845c2433cd75de7b9f6971vboxsync return VINF_SUCCESS;
00599f6d39cc25ca39845c2433cd75de7b9f6971vboxsync}
533ffcb943c4af2c5fe6385d816d0ba3eda9383bvboxsync
533ffcb943c4af2c5fe6385d816d0ba3eda9383bvboxsync
533ffcb943c4af2c5fe6385d816d0ba3eda9383bvboxsync/**
533ffcb943c4af2c5fe6385d816d0ba3eda9383bvboxsync * OS specific free function.
22e281e75ed636601178296c6daebda8f1d17c59vboxsync */
00599f6d39cc25ca39845c2433cd75de7b9f6971vboxsyncDECLHIDDEN(void) rtR0MemFree(PRTMEMHDR pHdr)
e50404712a2b5234c42bdf9740bddab5729ba188vboxsync{
b978e5849454446957177fd47ee98609ab0457a6vboxsync pHdr->u32Magic += 1;
57399ab65e2825c324fb9dcb4642d4ae2c232509vboxsync if (pHdr->fFlags & RTMEMHDR_FLAG_KMALLOC)
533ffcb943c4af2c5fe6385d816d0ba3eda9383bvboxsync kfree(pHdr);
57399ab65e2825c324fb9dcb4642d4ae2c232509vboxsync#ifdef RTMEMALLOC_EXEC_HEAP
533ffcb943c4af2c5fe6385d816d0ba3eda9383bvboxsync else if (pHdr->fFlags & RTMEMHDR_FLAG_EXEC_HEAP)
13ba5527caaa9b8c4fee29f22e374fa67c4c6f72vboxsync {
1843553dbdf4e46417158b4c6348c503adf10740vboxsync RTSpinlockAcquire(g_HeapExecSpinlock);
1843553dbdf4e46417158b4c6348c503adf10740vboxsync RTHeapSimpleFree(g_HeapExec, pHdr);
22e281e75ed636601178296c6daebda8f1d17c59vboxsync RTSpinlockRelease(g_HeapExecSpinlock);
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync }
1843553dbdf4e46417158b4c6348c503adf10740vboxsync#endif
806d0b554daa555364af5f87bc96eccbe760db7avboxsync#ifdef RTMEMALLOC_EXEC_VM_AREA
1843553dbdf4e46417158b4c6348c503adf10740vboxsync else if (pHdr->fFlags & RTMEMHDR_FLAG_EXEC_VM_AREA)
1843553dbdf4e46417158b4c6348c503adf10740vboxsync {
13ba5527caaa9b8c4fee29f22e374fa67c4c6f72vboxsync PRTMEMLNXHDREX pHdrEx = RT_FROM_MEMBER(pHdr, RTMEMLNXHDREX, Hdr);
1843553dbdf4e46417158b4c6348c503adf10740vboxsync size_t iPage = pHdrEx->pVmArea->nr_pages;
1843553dbdf4e46417158b4c6348c503adf10740vboxsync struct page **papPages = pHdrEx->pVmArea->pages;
1843553dbdf4e46417158b4c6348c503adf10740vboxsync void *pvMapping = pHdrEx->pVmArea->addr;
22e281e75ed636601178296c6daebda8f1d17c59vboxsync
1843553dbdf4e46417158b4c6348c503adf10740vboxsync vunmap(pvMapping);
1843553dbdf4e46417158b4c6348c503adf10740vboxsync
1843553dbdf4e46417158b4c6348c503adf10740vboxsync while (iPage-- > 0)
6ae4b1c72625a8e5c369effea7f018b578d733c4vboxsync __free_page(papPages[iPage]);
1843553dbdf4e46417158b4c6348c503adf10740vboxsync kfree(papPages);
ebbb1f6c7e8bae363a4efda4b35b58c8467d24bcvboxsync }
1843553dbdf4e46417158b4c6348c503adf10740vboxsync#endif
9e4166cf5ed4940f506bc718ea6c89bf7ed252c8vboxsync else
9e4166cf5ed4940f506bc718ea6c89bf7ed252c8vboxsync vfree(pHdr);
533ffcb943c4af2c5fe6385d816d0ba3eda9383bvboxsync}
1843553dbdf4e46417158b4c6348c503adf10740vboxsync
1843553dbdf4e46417158b4c6348c503adf10740vboxsync
ebbb1f6c7e8bae363a4efda4b35b58c8467d24bcvboxsync
13ba5527caaa9b8c4fee29f22e374fa67c4c6f72vboxsync/**
1843553dbdf4e46417158b4c6348c503adf10740vboxsync * Compute order. Some functions allocate 2^order pages.
1843553dbdf4e46417158b4c6348c503adf10740vboxsync *
22e281e75ed636601178296c6daebda8f1d17c59vboxsync * @returns order.
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync * @param cPages Number of pages.
1843553dbdf4e46417158b4c6348c503adf10740vboxsync */
806d0b554daa555364af5f87bc96eccbe760db7avboxsyncstatic int CalcPowerOf2Order(unsigned long cPages)
1843553dbdf4e46417158b4c6348c503adf10740vboxsync{
1843553dbdf4e46417158b4c6348c503adf10740vboxsync int iOrder;
13ba5527caaa9b8c4fee29f22e374fa67c4c6f72vboxsync unsigned long cTmp;
1843553dbdf4e46417158b4c6348c503adf10740vboxsync
1843553dbdf4e46417158b4c6348c503adf10740vboxsync for (iOrder = 0, cTmp = cPages; cTmp >>= 1; ++iOrder)
1843553dbdf4e46417158b4c6348c503adf10740vboxsync ;
22e281e75ed636601178296c6daebda8f1d17c59vboxsync if (cPages & ~(1 << iOrder))
1843553dbdf4e46417158b4c6348c503adf10740vboxsync ++iOrder;
1843553dbdf4e46417158b4c6348c503adf10740vboxsync
1843553dbdf4e46417158b4c6348c503adf10740vboxsync return iOrder;
6ae4b1c72625a8e5c369effea7f018b578d733c4vboxsync}
1843553dbdf4e46417158b4c6348c503adf10740vboxsync
ebbb1f6c7e8bae363a4efda4b35b58c8467d24bcvboxsync
533ffcb943c4af2c5fe6385d816d0ba3eda9383bvboxsync/**
533ffcb943c4af2c5fe6385d816d0ba3eda9383bvboxsync * Allocates physical contiguous memory (below 4GB).
533ffcb943c4af2c5fe6385d816d0ba3eda9383bvboxsync * The allocation is page aligned and the content is undefined.
533ffcb943c4af2c5fe6385d816d0ba3eda9383bvboxsync *
533ffcb943c4af2c5fe6385d816d0ba3eda9383bvboxsync * @returns Pointer to the memory block. This is page aligned.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pPhys Where to store the physical address.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cb The allocation size in bytes. This is always
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * rounded up to PAGE_SIZE.
22e281e75ed636601178296c6daebda8f1d17c59vboxsync */
e52f819639386db020b2a635b47a415248c7fbf9vboxsyncRTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb)
b978e5849454446957177fd47ee98609ab0457a6vboxsync{
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int cOrder;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync unsigned cPages;
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync struct page *paPages;
22e281e75ed636601178296c6daebda8f1d17c59vboxsync
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync /*
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync * validate input.
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(VALID_PTR(pPhys));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(cb > 0);
2f0d866e126dd288169fed591c259c1c6b4016e5vboxsync
82e90599291da476b2de7c8db33cfb0f2cbac774vboxsync /*
6ae4b1c72625a8e5c369effea7f018b578d733c4vboxsync * Allocate page pointer array.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync */
0e77737b0ba913683e614db11463b31ca67aacbevboxsync cb = RT_ALIGN_Z(cb, PAGE_SIZE);
0e77737b0ba913683e614db11463b31ca67aacbevboxsync cPages = cb >> PAGE_SHIFT;
9e4166cf5ed4940f506bc718ea6c89bf7ed252c8vboxsync cOrder = CalcPowerOf2Order(cPages);
9e4166cf5ed4940f506bc718ea6c89bf7ed252c8vboxsync#if (defined(RT_ARCH_AMD64) || defined(CONFIG_X86_PAE)) && defined(GFP_DMA32)
0e77737b0ba913683e614db11463b31ca67aacbevboxsync /* ZONE_DMA32: 0-4GB */
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync paPages = alloc_pages(GFP_DMA32, cOrder);
22e281e75ed636601178296c6daebda8f1d17c59vboxsync if (!paPages)
e9a217d585085a6a6d129d27ca0d96a1b8e6d0eevboxsync#endif
2d53f6e472561965d363674e17f48d3bdffc24d3vboxsync#ifdef RT_ARCH_AMD64
2d53f6e472561965d363674e17f48d3bdffc24d3vboxsync /* ZONE_DMA; 0-16MB */
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync paPages = alloc_pages(GFP_DMA, cOrder);
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync#else
22e281e75ed636601178296c6daebda8f1d17c59vboxsync /* ZONE_NORMAL: 0-896MB */
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync paPages = alloc_pages(GFP_USER, cOrder);
22e281e75ed636601178296c6daebda8f1d17c59vboxsync#endif
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync if (paPages)
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync {
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync /*
2d53f6e472561965d363674e17f48d3bdffc24d3vboxsync * Reserve the pages and mark them executable.
b74ca013e5f201a2dd371e6c438433ceac12af30vboxsync */
82e90599291da476b2de7c8db33cfb0f2cbac774vboxsync unsigned iPage;
82e90599291da476b2de7c8db33cfb0f2cbac774vboxsync for (iPage = 0; iPage < cPages; iPage++)
6ae4b1c72625a8e5c369effea7f018b578d733c4vboxsync {
2d53f6e472561965d363674e17f48d3bdffc24d3vboxsync Assert(!PageHighMem(&paPages[iPage]));
0e77737b0ba913683e614db11463b31ca67aacbevboxsync if (iPage + 1 < cPages)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync {
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsg( (uintptr_t)phys_to_virt(page_to_phys(&paPages[iPage])) + PAGE_SIZE
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync == (uintptr_t)phys_to_virt(page_to_phys(&paPages[iPage + 1]))
3080f6c0871099df43a4e91b31894d9c2b1369a8vboxsync && page_to_phys(&paPages[iPage]) + PAGE_SIZE
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync == page_to_phys(&paPages[iPage + 1]),
22e281e75ed636601178296c6daebda8f1d17c59vboxsync ("iPage=%i cPages=%u [0]=%#llx,%p [1]=%#llx,%p\n", iPage, cPages,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync (long long)page_to_phys(&paPages[iPage]), phys_to_virt(page_to_phys(&paPages[iPage])),
8e972b677df5ee27b99211fc7e456a5aa50f3e68vboxsync (long long)page_to_phys(&paPages[iPage + 1]), phys_to_virt(page_to_phys(&paPages[iPage + 1])) ));
8e972b677df5ee27b99211fc7e456a5aa50f3e68vboxsync }
b978e5849454446957177fd47ee98609ab0457a6vboxsync
13ba5527caaa9b8c4fee29f22e374fa67c4c6f72vboxsync SetPageReserved(&paPages[iPage]);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 20) /** @todo find the exact kernel where change_page_attr was introduced. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync MY_SET_PAGES_EXEC(&paPages[iPage], 1);
22e281e75ed636601178296c6daebda8f1d17c59vboxsync#endif
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync }
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync *pPhys = page_to_phys(paPages);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return phys_to_virt(page_to_phys(paPages));
806d0b554daa555364af5f87bc96eccbe760db7avboxsync }
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync
13ba5527caaa9b8c4fee29f22e374fa67c4c6f72vboxsync return NULL;
13ba5527caaa9b8c4fee29f22e374fa67c4c6f72vboxsync}
806d0b554daa555364af5f87bc96eccbe760db7avboxsyncRT_EXPORT_SYMBOL(RTMemContAlloc);
13ba5527caaa9b8c4fee29f22e374fa67c4c6f72vboxsync
806d0b554daa555364af5f87bc96eccbe760db7avboxsync
806d0b554daa555364af5f87bc96eccbe760db7avboxsync/**
806d0b554daa555364af5f87bc96eccbe760db7avboxsync * Frees memory allocated using RTMemContAlloc().
806d0b554daa555364af5f87bc96eccbe760db7avboxsync *
22e281e75ed636601178296c6daebda8f1d17c59vboxsync * @param pv Pointer to return from RTMemContAlloc().
806d0b554daa555364af5f87bc96eccbe760db7avboxsync * @param cb The cb parameter passed to RTMemContAlloc().
806d0b554daa555364af5f87bc96eccbe760db7avboxsync */
806d0b554daa555364af5f87bc96eccbe760db7avboxsyncRTR0DECL(void) RTMemContFree(void *pv, size_t cb)
6ae4b1c72625a8e5c369effea7f018b578d733c4vboxsync{
806d0b554daa555364af5f87bc96eccbe760db7avboxsync if (pv)
806d0b554daa555364af5f87bc96eccbe760db7avboxsync {
d98e61ba075ed7d0b567a5d884bc85d643fe3de7vboxsync int cOrder;
9e4166cf5ed4940f506bc718ea6c89bf7ed252c8vboxsync unsigned cPages;
9e4166cf5ed4940f506bc718ea6c89bf7ed252c8vboxsync unsigned iPage;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync struct page *paPages;
e08de24d4792d31b7f2aac29db5cb8840d940009vboxsync
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* validate */
806d0b554daa555364af5f87bc96eccbe760db7avboxsync AssertMsg(!((uintptr_t)pv & PAGE_OFFSET_MASK), ("pv=%p\n", pv));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(cb > 0);
13ba5527caaa9b8c4fee29f22e374fa67c4c6f72vboxsync
806d0b554daa555364af5f87bc96eccbe760db7avboxsync /* calc order and get pages */
806d0b554daa555364af5f87bc96eccbe760db7avboxsync cb = RT_ALIGN_Z(cb, PAGE_SIZE);
22e281e75ed636601178296c6daebda8f1d17c59vboxsync cPages = cb >> PAGE_SHIFT;
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync cOrder = CalcPowerOf2Order(cPages);
e0b9d3c357adf9b7d05f55540e86f22943fc4b23vboxsync paPages = virt_to_page(pv);
806d0b554daa555364af5f87bc96eccbe760db7avboxsync
e149c362e69e5f0bbd82da11fd8163b2d29c3a72vboxsync /*
806d0b554daa555364af5f87bc96eccbe760db7avboxsync * Restore page attributes freeing the pages.
13ba5527caaa9b8c4fee29f22e374fa67c4c6f72vboxsync */
13ba5527caaa9b8c4fee29f22e374fa67c4c6f72vboxsync for (iPage = 0; iPage < cPages; iPage++)
806d0b554daa555364af5f87bc96eccbe760db7avboxsync {
13ba5527caaa9b8c4fee29f22e374fa67c4c6f72vboxsync ClearPageReserved(&paPages[iPage]);
806d0b554daa555364af5f87bc96eccbe760db7avboxsync#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 20) /** @todo find the exact kernel where change_page_attr was introduced. */
806d0b554daa555364af5f87bc96eccbe760db7avboxsync MY_SET_PAGES_NOEXEC(&paPages[iPage], 1);
806d0b554daa555364af5f87bc96eccbe760db7avboxsync#endif
806d0b554daa555364af5f87bc96eccbe760db7avboxsync }
22e281e75ed636601178296c6daebda8f1d17c59vboxsync __free_pages(paPages, cOrder);
806d0b554daa555364af5f87bc96eccbe760db7avboxsync }
806d0b554daa555364af5f87bc96eccbe760db7avboxsync}
806d0b554daa555364af5f87bc96eccbe760db7avboxsyncRT_EXPORT_SYMBOL(RTMemContFree);
6ae4b1c72625a8e5c369effea7f018b578d733c4vboxsync
806d0b554daa555364af5f87bc96eccbe760db7avboxsync