VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/alloc-posix.cpp@ 28496

Last change on this file since 28496 was 28496, checked in by vboxsync, 15 years ago

Runtime/FreeBSD: Build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 9.2 KB
Line 
1/* $Id: alloc-posix.cpp 28496 2010-04-19 20:48:42Z vboxsync $ */
2/** @file
3 * IPRT - Memory Allocation, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include <iprt/alloc.h>
36#include <iprt/assert.h>
37#include <iprt/param.h>
38#include <iprt/err.h>
39#include <iprt/string.h>
40
41#include <stdlib.h>
42#ifndef RT_OS_FREEBSD /* Deprecated on FreeBSD */
43# include <malloc.h>
44#endif
45#include <errno.h>
46#include <sys/mman.h>
47
48
49/*******************************************************************************
50* Defined Constants And Macros *
51*******************************************************************************/
52#if !defined(RT_USE_MMAP_EXEC) && (defined(RT_OS_LINUX))
53# define RT_USE_MMAP_EXEC
54#endif
55
56#if !defined(RT_USE_MMAP_PAGE) && 0 /** @todo mmap is too slow for full scale EF setup. */
57# define RT_USE_MMAP_PAGE
58#endif
59
60
61/*******************************************************************************
62* Structures and Typedefs *
63*******************************************************************************/
64#ifdef RT_USE_MMAP_EXEC
65/**
66 * RTMemExecAlloc() header used when using mmap for allocating the memory.
67 */
68typedef struct RTMEMEXECHDR
69{
70 /** Magic number (RTMEMEXECHDR_MAGIC). */
71 size_t uMagic;
72 /** The size we requested from mmap. */
73 size_t cb;
74# if ARCH_BITS == 32
75 uint32_t Alignment[2];
76# endif
77} RTMEMEXECHDR, *PRTMEMEXECHDR;
78
79/** Magic for RTMEMEXECHDR. */
80# define RTMEMEXECHDR_MAGIC (~(size_t)0xfeedbabe)
81
82#endif /* RT_USE_MMAP_EXEC */
83
84
85
86/**
87 * Allocates memory which may contain code.
88 *
89 * @returns Pointer to the allocated memory.
90 * @returns NULL on failure.
91 * @param cb Size in bytes of the memory block to allocate.
92 */
93RTDECL(void *) RTMemExecAlloc(size_t cb) RT_NO_THROW
94{
95 AssertMsg(cb, ("Allocating ZERO bytes is really not a good idea! Good luck with the next assertion!\n"));
96
97#ifdef RT_USE_MMAP_EXEC
98 /*
99 * Use mmap to get low memory.
100 */
101 size_t cbAlloc = RT_ALIGN_Z(cb + sizeof(RTMEMEXECHDR), PAGE_SIZE);
102 void *pv = mmap(NULL, cbAlloc, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS
103# if defined(RT_ARCH_AMD64) && defined(MAP_32BIT)
104 | MAP_32BIT
105# endif
106 , -1, 0);
107 AssertMsgReturn(pv != MAP_FAILED, ("errno=%d cb=%#zx\n", errno, cb), NULL);
108 PRTMEMEXECHDR pHdr = (PRTMEMEXECHDR)pv;
109 pHdr->uMagic = RTMEMEXECHDR_MAGIC;
110 pHdr->cb = cbAlloc;
111 pv = pHdr + 1;
112
113#else
114 /*
115 * Allocate first.
116 */
117 cb = RT_ALIGN_Z(cb, 32);
118 void *pv = NULL;
119 int rc = posix_memalign(&pv, 32, cb);
120 AssertMsg(!rc && pv, ("posix_memalign(%zd) failed!!! rc=%d\n", cb, rc));
121 if (pv && !rc)
122 {
123 /*
124 * Add PROT_EXEC flag to the page.
125 *
126 * This is in violation of the SuS where I think it saith that mprotect() shall
127 * only be used with mmap()'ed memory. Works on linux and OS/2 LIBC v0.6.
128 */
129 memset(pv, 0xcc, cb);
130 void *pvProt = (void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK);
131 size_t cbProt = ((uintptr_t)pv & PAGE_OFFSET_MASK) + cb;
132 cbProt = RT_ALIGN_Z(cbProt, PAGE_SIZE);
133 rc = mprotect(pvProt, cbProt, PROT_READ | PROT_WRITE | PROT_EXEC);
134 if (rc)
135 {
136 AssertMsgFailed(("mprotect(%p, %#zx,,) -> rc=%d, errno=%d\n", pvProt, cbProt, rc, errno));
137 free(pv);
138 pv = NULL;
139 }
140 }
141#endif
142 return pv;
143}
144
145
146/**
147 * Free executable/read/write memory allocated by RTMemExecAlloc().
148 *
149 * @param pv Pointer to memory block.
150 */
151RTDECL(void) RTMemExecFree(void *pv) RT_NO_THROW
152{
153 if (pv)
154 {
155#ifdef RT_USE_MMAP_EXEC
156 PRTMEMEXECHDR pHdr = (PRTMEMEXECHDR)pv - 1;
157 AssertMsgReturnVoid(RT_ALIGN_P(pHdr, PAGE_SIZE) == pHdr, ("pHdr=%p pv=%p\n", pHdr, pv));
158 AssertMsgReturnVoid(pHdr->uMagic == RTMEMEXECHDR_MAGIC, ("pHdr=%p(uMagic=%#zx) pv=%p\n", pHdr, pHdr->uMagic, pv));
159 int rc = munmap(pHdr, pHdr->cb);
160 AssertMsg(!rc, ("munmap -> %d errno=%d\n", rc, errno)); NOREF(rc);
161#else
162 free(pv);
163#endif
164 }
165}
166
167
168/**
169 * Allocate page aligned memory.
170 *
171 * @returns Pointer to the allocated memory.
172 * @returns NULL if we're out of memory.
173 * @param cb Size of the memory block. Will be rounded up to page size.
174 */
175RTDECL(void *) RTMemPageAlloc(size_t cb) RT_NO_THROW
176{
177#ifdef RT_USE_MMAP_PAGE
178 size_t cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
179 void *pv = mmap(NULL, cbAligned, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
180 AssertMsgReturn(pv != MAP_FAILED, ("errno=%d cb=%#zx\n", errno, cb), NULL);
181 return pv;
182
183#else
184# if defined(RT_OS_FREEBSD) /** @todo huh? we're using posix_memalign in the next function... */
185 void *pv;
186 int rc = posix_memalign(&pv, PAGE_SIZE, RT_ALIGN_Z(cb, PAGE_SIZE));
187 if (!rc)
188 return pv;
189 return NULL;
190# else /* !RT_OS_FREEBSD */
191 return memalign(PAGE_SIZE, cb);
192# endif
193#endif
194}
195
196
197/**
198 * Allocate zero'ed page aligned memory.
199 *
200 * @returns Pointer to the allocated memory.
201 * @returns NULL if we're out of memory.
202 * @param cb Size of the memory block. Will be rounded up to page size.
203 */
204RTDECL(void *) RTMemPageAllocZ(size_t cb) RT_NO_THROW
205{
206#ifdef RT_USE_MMAP_PAGE
207 size_t cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
208 void *pv = mmap(NULL, cbAligned, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
209 AssertMsgReturn(pv != MAP_FAILED, ("errno=%d cb=%#zx\n", errno, cb), NULL);
210 return pv;
211
212#else
213 void *pv;
214 int rc = posix_memalign(&pv, PAGE_SIZE, RT_ALIGN_Z(cb, PAGE_SIZE));
215 if (!rc)
216 {
217 RT_BZERO(pv, RT_ALIGN_Z(cb, PAGE_SIZE));
218 return pv;
219 }
220 return NULL;
221#endif
222}
223
224
225/**
226 * Free a memory block allocated with RTMemPageAlloc() or RTMemPageAllocZ().
227 *
228 * @param pv Pointer to the block as it was returned by the allocation function.
229 * NULL will be ignored.
230 */
231RTDECL(void) RTMemPageFree(void *pv, size_t cb) RT_NO_THROW
232{
233 if (pv)
234 {
235 Assert(!((uintptr_t)pv & PAGE_OFFSET_MASK));
236
237#ifdef RT_USE_MMAP_PAGE
238 size_t cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
239 int rc = munmap(pv, cbAligned);
240 AssertMsg(!rc, ("munmap(%p, %#zx) -> %d errno=%d\n", pv, cbAligned, rc, errno)); NOREF(rc);
241#else
242 free(pv);
243#endif
244 }
245}
246
247
248/**
249 * Change the page level protection of a memory region.
250 *
251 * @returns iprt status code.
252 * @param pv Start of the region. Will be rounded down to nearest page boundary.
253 * @param cb Size of the region. Will be rounded up to the nearest page boundary.
254 * @param fProtect The new protection, a combination of the RTMEM_PROT_* defines.
255 */
256RTDECL(int) RTMemProtect(void *pv, size_t cb, unsigned fProtect) RT_NO_THROW
257{
258 /*
259 * Validate input.
260 */
261 if (cb == 0)
262 {
263 AssertMsgFailed(("!cb\n"));
264 return VERR_INVALID_PARAMETER;
265 }
266 if (fProtect & ~(RTMEM_PROT_NONE | RTMEM_PROT_READ | RTMEM_PROT_WRITE | RTMEM_PROT_EXEC))
267 {
268 AssertMsgFailed(("fProtect=%#x\n", fProtect));
269 return VERR_INVALID_PARAMETER;
270 }
271
272 /*
273 * Convert the flags.
274 */
275 int fProt;
276#if RTMEM_PROT_NONE == PROT_NONE \
277 && RTMEM_PROT_READ == PROT_READ \
278 && RTMEM_PROT_WRITE == PROT_WRITE \
279 && RTMEM_PROT_EXEC == PROT_EXEC
280 fProt = fProtect;
281#else
282 Assert(!RTMEM_PROT_NONE);
283 if (!fProtect)
284 fProt = PROT_NONE;
285 else
286 {
287 fProt = 0;
288 if (fProtect & RTMEM_PROT_READ)
289 fProt |= PROT_READ;
290 if (fProtect & RTMEM_PROT_WRITE)
291 fProt |= PROT_WRITE;
292 if (fProtect & RTMEM_PROT_EXEC)
293 fProt |= PROT_EXEC;
294 }
295#endif
296
297 /*
298 * Align the request.
299 */
300 cb += (uintptr_t)pv & PAGE_OFFSET_MASK;
301 pv = (void *)((uintptr_t)pv & ~PAGE_OFFSET_MASK);
302
303 /*
304 * Change the page attributes.
305 */
306 int rc = mprotect(pv, cb, fProt);
307 if (!rc)
308 return rc;
309 return RTErrConvertFromErrno(errno);
310}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette