~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/Runtime/r3/posix/alloc-posix.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

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