alloc-r0drv-freebsd.c revision 255e8dbae721e470aaeac22a20a8cfdccda8c646
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/* $Id$ */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/** @file
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * IPRT - Memory Allocation, Ring-0 Driver, FreeBSD.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Permission is hereby granted, free of charge, to any person
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * obtaining a copy of this software and associated documentation
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * files (the "Software"), to deal in the Software without
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * restriction, including without limitation the rights to use,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * copy, modify, merge, publish, distribute, sublicense, and/or sell
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * copies of the Software, and to permit persons to whom the
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Software is furnished to do so, subject to the following
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * conditions:
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * The above copyright notice and this permission notice shall be
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * included in all copies or substantial portions of the Software.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * OTHER DEALINGS IN THE SOFTWARE.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/*******************************************************************************
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync* Header Files *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync*******************************************************************************/
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include "the-freebsd-kernel.h"
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/alloc.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/assert.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include <iprt/param.h>
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#include "r0drv/alloc-r0drv.h"
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/*******************************************************************************
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync* Global Variables *
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync*******************************************************************************/
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync/* These two statements will define two globals and add initializers
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync and destructors that will be called at load/unload time (I think). */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncMALLOC_DEFINE(M_IPRTHEAP, "iprtheap", "IPRT - heap");
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncMALLOC_DEFINE(M_IPRTCONT, "iprtcont", "IPRT - contiguous");
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncPRTMEMHDR rtR0MemAlloc(size_t cb, uint32_t fFlags)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync size_t cbAllocated = cb;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PRTMEMHDR pHdr = NULL;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Things are a bit more complicated on AMD64 for executable memory
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * because we need to be in the ~2GB..~0 range for code.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#ifdef RT_ARCH_AMD64
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (fFlags & RTMEMHDR_FLAG_EXEC)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync# ifdef USE_KMEM_ALLOC_PROT
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pHdr = (PRTMEMHDR)kmem_alloc_prot(kernel_map, cb + sizeof(*pHdr),
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync VM_PROT_ALL, VM_PROT_ALL, KERNBASE);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync# else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync vm_object_t pVmObject = NULL;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync vm_offset_t Addr = KERNBASE;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync cbAllocated = RT_ALIGN_Z(cb + sizeof(*pHdr), PAGE_SIZE);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pVmObject = vm_object_allocate(OBJT_DEFAULT, cbAllocated >> PAGE_SHIFT);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (!pVmObject)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return NULL;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /* Addr contains a start address vm_map_find will start searching for suitable space at. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync int rc = vm_map_find(kernel_map, pVmObject, 0, &Addr,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync cbAllocated, TRUE, VM_PROT_ALL, VM_PROT_ALL, 0);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (rc == KERN_SUCCESS)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync rc = vm_map_wire(kernel_map, Addr, Addr + cbAllocated,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync VM_MAP_WIRE_SYSTEM | VM_MAP_WIRE_NOHOLES);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (rc == KERN_SUCCESS)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pHdr = (PRTMEMHDR)Addr;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (fFlags & RTMEMHDR_FLAG_ZEROED)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync bzero(pHdr, cbAllocated);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync vm_map_remove(kernel_map,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync Addr,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync Addr + cbAllocated);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync vm_object_deallocate(pVmObject);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync# endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pHdr = (PRTMEMHDR)malloc(cb + sizeof(RTMEMHDR), M_IPRTHEAP,
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync fFlags & RTMEMHDR_FLAG_ZEROED ? M_NOWAIT | M_ZERO : M_NOWAIT);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (pHdr)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pHdr->u32Magic = RTMEMHDR_MAGIC;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pHdr->fFlags = fFlags;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pHdr->cb = cbAllocated;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pHdr->cbReq = cb;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pHdr;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return NULL;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncvoid rtR0MemFree(PRTMEMHDR pHdr)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pHdr->u32Magic += 1;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#ifdef RT_ARCH_AMD64
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (pHdr->fFlags & RTMEMHDR_FLAG_EXEC)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync# ifdef USE_KMEM_ALLOC_PROT
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync kmem_free(kernel_map, (vm_offset_t)pHdr, pHdr->cb);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync# else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync vm_map_remove(kernel_map, (vm_offset_t)pHdr, ((vm_offset_t)pHdr) + pHdr->cb);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync# endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync else
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync#endif
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync free(pHdr, M_IPRTHEAP);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync void *pv;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * Validate input.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertPtr(pPhys);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync Assert(cb > 0);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync /*
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync * This API works in pages, so no need to do any size aligning.
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync pv = contigmalloc(cb, /* size */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync M_IPRTCONT, /* type */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync M_NOWAIT | M_ZERO, /* flags */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync 0, /* lowest physical address*/
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync _4G-1, /* highest physical address */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync PAGE_SIZE, /* alignment. */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync 0); /* boundrary */
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (pv)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync Assert(!((uintptr_t)pv & PAGE_OFFSET_MASK));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync *pPhys = vtophys(pv);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync Assert(!(*pPhys & PAGE_OFFSET_MASK));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync return pv;
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsyncRTR0DECL(void) RTMemContFree(void *pv, size_t cb)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync{
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync if (pv)
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync {
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync AssertMsg(!((uintptr_t)pv & PAGE_OFFSET_MASK), ("pv=%p\n", pv));
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync contigfree(pv, cb, M_IPRTCONT);
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync }
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync}
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync
e0e0c19eefceaf5d4ec40f9466b58a771f50e799vboxsync