VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/alloc-r0drv.cpp

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 13.1 KB
RevLine 
[1]1/* $Id: alloc-r0drv.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
[8245]3 * IPRT - Memory Allocation, Ring-0 Driver.
[1]4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[1]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
[5999]11 *
[96407]12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
[5999]25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
[96407]27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
[5999]29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
[96407]33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
[1]35 */
36
37
[57358]38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
[36190]41#define RTMEM_NO_WRAP_TO_EF_APIS
[21337]42#include <iprt/mem.h>
43#include "internal/iprt.h"
44
[29250]45#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
46# include <iprt/asm-amd64-x86.h>
47#endif
[1]48#include <iprt/assert.h>
[76346]49#include <iprt/err.h>
[32707]50#ifdef RT_MORE_STRICT
51# include <iprt/mp.h>
52#endif
[1]53#include <iprt/param.h>
[22052]54#include <iprt/string.h>
55#include <iprt/thread.h>
[1]56#include "r0drv/alloc-r0drv.h"
57
58
[57358]59/*********************************************************************************************************************************
60* Defined Constants And Macros *
61*********************************************************************************************************************************/
[7042]62#ifdef RT_STRICT
63# define RTR0MEM_STRICT
64#endif
65
66#ifdef RTR0MEM_STRICT
67# define RTR0MEM_FENCE_EXTRA 16
68#else
69# define RTR0MEM_FENCE_EXTRA 0
70#endif
71
72
[57358]73/*********************************************************************************************************************************
74* Global Variables *
75*********************************************************************************************************************************/
[32707]76#ifdef RTR0MEM_STRICT
77/** Fence data. */
78static uint8_t const g_abFence[RTR0MEM_FENCE_EXTRA] =
79{
80 0x77, 0x88, 0x66, 0x99, 0x55, 0xaa, 0x44, 0xbb,
81 0x33, 0xcc, 0x22, 0xdd, 0x11, 0xee, 0x00, 0xff
82};
83#endif
[31157]84
[32707]85
86/**
87 * Wrapper around rtR0MemAllocEx.
88 *
89 * @returns Pointer to the allocated memory block header.
90 * @param cb The number of bytes to allocate (sans header).
91 * @param fFlags The allocation flags.
92 */
93DECLINLINE(PRTMEMHDR) rtR0MemAlloc(size_t cb, uint32_t fFlags)
94{
95 PRTMEMHDR pHdr;
96 int rc = rtR0MemAllocEx(cb, fFlags, &pHdr);
97 if (RT_FAILURE(rc))
[40938]98 return NULL;
[32707]99 return pHdr;
100}
101
102
[57432]103RTDECL(void *) RTMemTmpAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
[1]104{
[31157]105 return RTMemAllocTag(cb, pszTag);
[1]106}
[31157]107RT_EXPORT_SYMBOL(RTMemTmpAllocTag);
[1]108
109
[57432]110RTDECL(void *) RTMemTmpAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
[1]111{
[31157]112 return RTMemAllocZTag(cb, pszTag);
[1]113}
[31157]114RT_EXPORT_SYMBOL(RTMemTmpAllocZTag);
[1]115
116
[57432]117RTDECL(void) RTMemTmpFree(void *pv) RT_NO_THROW_DEF
[1]118{
119 return RTMemFree(pv);
120}
[21337]121RT_EXPORT_SYMBOL(RTMemTmpFree);
[1]122
123
[83546]124RTDECL(void) RTMemTmpFreeZ(void *pv, size_t cb) RT_NO_THROW_DEF
125{
126 return RTMemFreeZ(pv, cb);
127}
128RT_EXPORT_SYMBOL(RTMemTmpFreeZ);
[31157]129
130
131
[83546]132
133
[57432]134RTDECL(void *) RTMemAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
[1]135{
[22052]136 PRTMEMHDR pHdr;
[22125]137 RT_ASSERT_INTS_ON();
[62566]138 RT_NOREF_PV(pszTag);
[22052]139
[28298]140 pHdr = rtR0MemAlloc(cb + RTR0MEM_FENCE_EXTRA, 0);
[1]141 if (pHdr)
[7042]142 {
143#ifdef RTR0MEM_STRICT
[14068]144 pHdr->cbReq = (uint32_t)cb; Assert(pHdr->cbReq == cb);
[7244]145 memcpy((uint8_t *)(pHdr + 1) + cb, &g_abFence[0], RTR0MEM_FENCE_EXTRA);
[7042]146#endif
[1]147 return pHdr + 1;
[7042]148 }
[1]149 return NULL;
150}
[31157]151RT_EXPORT_SYMBOL(RTMemAllocTag);
[1]152
153
[57432]154RTDECL(void *) RTMemAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
[1]155{
[22052]156 PRTMEMHDR pHdr;
[22125]157 RT_ASSERT_INTS_ON();
[62566]158 RT_NOREF_PV(pszTag);
[22052]159
[28298]160 pHdr = rtR0MemAlloc(cb + RTR0MEM_FENCE_EXTRA, RTMEMHDR_FLAG_ZEROED);
[1]161 if (pHdr)
[7042]162 {
163#ifdef RTR0MEM_STRICT
[14068]164 pHdr->cbReq = (uint32_t)cb; Assert(pHdr->cbReq == cb);
[7244]165 memcpy((uint8_t *)(pHdr + 1) + cb, &g_abFence[0], RTR0MEM_FENCE_EXTRA);
[7042]166 return memset(pHdr + 1, 0, cb);
167#else
[1]168 return memset(pHdr + 1, 0, pHdr->cb);
[7042]169#endif
170 }
[1]171 return NULL;
172}
[31157]173RT_EXPORT_SYMBOL(RTMemAllocZTag);
[1]174
175
[31157]176RTDECL(void *) RTMemAllocVarTag(size_t cbUnaligned, const char *pszTag)
[28298]177{
178 size_t cbAligned;
179 if (cbUnaligned >= 16)
180 cbAligned = RT_ALIGN_Z(cbUnaligned, 16);
181 else
182 cbAligned = RT_ALIGN_Z(cbUnaligned, sizeof(void *));
[31157]183 return RTMemAllocTag(cbAligned, pszTag);
[28298]184}
[31157]185RT_EXPORT_SYMBOL(RTMemAllocVarTag);
[28298]186
187
[31157]188RTDECL(void *) RTMemAllocZVarTag(size_t cbUnaligned, const char *pszTag)
[28298]189{
190 size_t cbAligned;
191 if (cbUnaligned >= 16)
192 cbAligned = RT_ALIGN_Z(cbUnaligned, 16);
193 else
194 cbAligned = RT_ALIGN_Z(cbUnaligned, sizeof(void *));
[31157]195 return RTMemAllocZTag(cbAligned, pszTag);
[28298]196}
[31157]197RT_EXPORT_SYMBOL(RTMemAllocZVarTag);
[28298]198
199
[57432]200RTDECL(void *) RTMemReallocTag(void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW_DEF
[1]201{
[37672]202 PRTMEMHDR pHdrOld;
203
[36982]204 /* Free. */
205 if (!cbNew && pvOld)
206 {
[1]207 RTMemFree(pvOld);
[36982]208 return NULL;
209 }
210
211 /* Alloc. */
212 if (!pvOld)
[31157]213 return RTMemAllocTag(cbNew, pszTag);
[36982]214
215 /*
216 * Realloc.
217 */
[37672]218 pHdrOld = (PRTMEMHDR)pvOld - 1;
[36982]219 RT_ASSERT_PREEMPTIBLE();
220
221 if (pHdrOld->u32Magic == RTMEMHDR_MAGIC)
[1]222 {
[36982]223 PRTMEMHDR pHdrNew;
[22052]224
[36982]225 /* If there is sufficient space in the old block and we don't cause
226 substantial internal fragmentation, reuse the old block. */
227 if ( pHdrOld->cb >= cbNew + RTR0MEM_FENCE_EXTRA
228 && pHdrOld->cb - (cbNew + RTR0MEM_FENCE_EXTRA) <= 128)
[1]229 {
[36982]230 pHdrOld->cbReq = (uint32_t)cbNew; Assert(pHdrOld->cbReq == cbNew);
[7042]231#ifdef RTR0MEM_STRICT
[36982]232 memcpy((uint8_t *)(pHdrOld + 1) + cbNew, &g_abFence[0], RTR0MEM_FENCE_EXTRA);
[7042]233#endif
[36982]234 return pvOld;
[1]235 }
[36982]236
237 /* Allocate a new block and copy over the content. */
238 pHdrNew = rtR0MemAlloc(cbNew + RTR0MEM_FENCE_EXTRA, 0);
239 if (pHdrNew)
240 {
241 size_t cbCopy = RT_MIN(pHdrOld->cb, pHdrNew->cb);
242 memcpy(pHdrNew + 1, pvOld, cbCopy);
243#ifdef RTR0MEM_STRICT
244 pHdrNew->cbReq = (uint32_t)cbNew; Assert(pHdrNew->cbReq == cbNew);
245 memcpy((uint8_t *)(pHdrNew + 1) + cbNew, &g_abFence[0], RTR0MEM_FENCE_EXTRA);
246 AssertReleaseMsg(!memcmp((uint8_t *)(pHdrOld + 1) + pHdrOld->cbReq, &g_abFence[0], RTR0MEM_FENCE_EXTRA),
247 ("pHdr=%p pvOld=%p cbReq=%u cb=%u cbNew=%zu fFlags=%#x\n"
248 "fence: %.*Rhxs\n"
249 "expected: %.*Rhxs\n",
250 pHdrOld, pvOld, pHdrOld->cbReq, pHdrOld->cb, cbNew, pHdrOld->fFlags,
251 RTR0MEM_FENCE_EXTRA, (uint8_t *)(pHdrOld + 1) + pHdrOld->cbReq,
252 RTR0MEM_FENCE_EXTRA, &g_abFence[0]));
253#endif
254 rtR0MemFree(pHdrOld);
255 return pHdrNew + 1;
256 }
[1]257 }
[36982]258 else
259 AssertMsgFailed(("pHdrOld->u32Magic=%RX32 pvOld=%p cbNew=%#zx\n", pHdrOld->u32Magic, pvOld, cbNew));
[1]260
261 return NULL;
262}
[31157]263RT_EXPORT_SYMBOL(RTMemReallocTag);
[1]264
265
[57432]266RTDECL(void) RTMemFree(void *pv) RT_NO_THROW_DEF
[1]267{
[217]268 PRTMEMHDR pHdr;
[22052]269 RT_ASSERT_INTS_ON();
270
[217]271 if (!pv)
272 return;
273 pHdr = (PRTMEMHDR)pv - 1;
[1]274 if (pHdr->u32Magic == RTMEMHDR_MAGIC)
275 {
[32707]276 Assert(!(pHdr->fFlags & RTMEMHDR_FLAG_ALLOC_EX));
[7042]277#ifdef RTR0MEM_STRICT
[7244]278 AssertReleaseMsg(!memcmp((uint8_t *)(pHdr + 1) + pHdr->cbReq, &g_abFence[0], RTR0MEM_FENCE_EXTRA),
[36982]279 ("pHdr=%p pv=%p cbReq=%u cb=%u fFlags=%#x\n"
[7042]280 "fence: %.*Rhxs\n"
281 "expected: %.*Rhxs\n",
[36982]282 pHdr, pv, pHdr->cbReq, pHdr->cb, pHdr->fFlags,
283 RTR0MEM_FENCE_EXTRA, (uint8_t *)(pHdr + 1) + pHdr->cbReq,
[7244]284 RTR0MEM_FENCE_EXTRA, &g_abFence[0]));
[7042]285#endif
[28298]286 rtR0MemFree(pHdr);
[1]287 }
288 else
289 AssertMsgFailed(("pHdr->u32Magic=%RX32 pv=%p\n", pHdr->u32Magic, pv));
290}
[21337]291RT_EXPORT_SYMBOL(RTMemFree);
[1]292
293
[83546]294RTDECL(void) RTMemFreeZ(void *pv, size_t cb) RT_NO_THROW_DEF
295{
296 PRTMEMHDR pHdr;
297 RT_ASSERT_INTS_ON();
[31157]298
[83546]299 if (!pv)
300 return;
301 pHdr = (PRTMEMHDR)pv - 1;
302 if (pHdr->u32Magic == RTMEMHDR_MAGIC)
303 {
304 Assert(!(pHdr->fFlags & RTMEMHDR_FLAG_ALLOC_EX));
305#ifdef RTR0MEM_STRICT
306 AssertReleaseMsg(!memcmp((uint8_t *)(pHdr + 1) + pHdr->cbReq, &g_abFence[0], RTR0MEM_FENCE_EXTRA),
307 ("pHdr=%p pv=%p cbReq=%u cb=%u fFlags=%#x\n"
308 "fence: %.*Rhxs\n"
309 "expected: %.*Rhxs\n",
310 pHdr, pv, pHdr->cbReq, pHdr->cb, pHdr->fFlags,
311 RTR0MEM_FENCE_EXTRA, (uint8_t *)(pHdr + 1) + pHdr->cbReq,
312 RTR0MEM_FENCE_EXTRA, &g_abFence[0]));
313#endif
314 AssertMsgStmt(cb == pHdr->cbReq, ("cb=%#zx cbReq=%#x\n", cb, pHdr->cbReq), cb = pHdr->cbReq);
315 RT_BZERO(pv, cb);
316 rtR0MemFree(pHdr);
317 }
318 else
319 AssertMsgFailed(("pHdr->u32Magic=%RX32 pv=%p\n", pHdr->u32Magic, pv));
320}
321RT_EXPORT_SYMBOL(RTMemFreeZ);
[31157]322
323
[57432]324RTDECL(int) RTMemAllocExTag(size_t cb, size_t cbAlignment, uint32_t fFlags, const char *pszTag, void **ppv) RT_NO_THROW_DEF
[32674]325{
[32707]326 uint32_t fHdrFlags = RTMEMHDR_FLAG_ALLOC_EX;
327 PRTMEMHDR pHdr;
328 int rc;
[62566]329 RT_NOREF_PV(pszTag);
[32707]330
331 RT_ASSERT_PREEMPT_CPUID_VAR();
[46565]332 if (!(fFlags & RTMEMALLOCEX_FLAGS_ANY_CTX_ALLOC))
[32707]333 RT_ASSERT_INTS_ON();
[97909]334 AssertReturn(!(fFlags & RTMEMALLOCEX_FLAGS_EXEC), VERR_INVALID_FLAGS);
[32707]335
336 /*
337 * Fake up some alignment support.
338 */
339 AssertMsgReturn(cbAlignment <= sizeof(void *), ("%zu (%#x)\n", cbAlignment, cbAlignment), VERR_UNSUPPORTED_ALIGNMENT);
340 if (cb < cbAlignment)
341 cb = cbAlignment;
342
343 /*
344 * Validate and convert flags.
345 */
[46567]346 AssertMsgReturn(!(fFlags & ~RTMEMALLOCEX_FLAGS_VALID_MASK_R0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
[32707]347 if (fFlags & RTMEMALLOCEX_FLAGS_ZEROED)
348 fHdrFlags |= RTMEMHDR_FLAG_ZEROED;
349 if (fFlags & RTMEMALLOCEX_FLAGS_ANY_CTX_ALLOC)
350 fHdrFlags |= RTMEMHDR_FLAG_ANY_CTX_ALLOC;
351 if (fFlags & RTMEMALLOCEX_FLAGS_ANY_CTX_FREE)
352 fHdrFlags |= RTMEMHDR_FLAG_ANY_CTX_FREE;
353
354 /*
355 * Do the allocation.
356 */
357 rc = rtR0MemAllocEx(cb + RTR0MEM_FENCE_EXTRA, fHdrFlags, &pHdr);
358 if (RT_SUCCESS(rc))
359 {
360 void *pv;
361
362 Assert(pHdr->cbReq == cb + RTR0MEM_FENCE_EXTRA);
363 Assert((pHdr->fFlags & fFlags) == fFlags);
364
365 /*
366 * Calc user pointer, initialize the memory if requested, and if
367 * memory strictness is enable set up the fence.
368 */
369 pv = pHdr + 1;
370 *ppv = pv;
371 if (fFlags & RTMEMHDR_FLAG_ZEROED)
372 memset(pv, 0, pHdr->cb);
373
374#ifdef RTR0MEM_STRICT
375 pHdr->cbReq = (uint32_t)cb;
376 memcpy((uint8_t *)pv + cb, &g_abFence[0], RTR0MEM_FENCE_EXTRA);
377#endif
378 }
379
380 RT_ASSERT_PREEMPT_CPUID();
381 return rc;
[32674]382}
[32707]383RT_EXPORT_SYMBOL(RTMemAllocExTag);
[32674]384
385
[57432]386RTDECL(void) RTMemFreeEx(void *pv, size_t cb) RT_NO_THROW_DEF
[32674]387{
388 PRTMEMHDR pHdr;
[62567]389 RT_NOREF_PV(cb);
[32674]390
391 if (!pv)
392 return;
[32707]393
394 AssertPtr(pv);
[32674]395 pHdr = (PRTMEMHDR)pv - 1;
396 if (pHdr->u32Magic == RTMEMHDR_MAGIC)
397 {
[32707]398 RT_ASSERT_PREEMPT_CPUID_VAR();
399
[32674]400 Assert(pHdr->fFlags & RTMEMHDR_FLAG_ALLOC_EX);
[32707]401 if (!(pHdr->fFlags & RTMEMHDR_FLAG_ANY_CTX_FREE))
[32674]402 RT_ASSERT_INTS_ON();
[32707]403 AssertMsg(pHdr->cbReq == cb, ("cbReq=%zu cb=%zu\n", pHdr->cb, cb));
[32674]404
405#ifdef RTR0MEM_STRICT
406 AssertReleaseMsg(!memcmp((uint8_t *)(pHdr + 1) + pHdr->cbReq, &g_abFence[0], RTR0MEM_FENCE_EXTRA),
[36982]407 ("pHdr=%p pv=%p cbReq=%u cb=%u fFlags=%#x\n"
[32674]408 "fence: %.*Rhxs\n"
409 "expected: %.*Rhxs\n",
[36982]410 pHdr, pv, pHdr->cbReq, pHdr->cb, pHdr->fFlags,
411 RTR0MEM_FENCE_EXTRA, (uint8_t *)(pHdr + 1) + pHdr->cbReq,
[32674]412 RTR0MEM_FENCE_EXTRA, &g_abFence[0]));
413#endif
414 rtR0MemFree(pHdr);
[32707]415 RT_ASSERT_PREEMPT_CPUID();
[32674]416 }
417 else
418 AssertMsgFailed(("pHdr->u32Magic=%RX32 pv=%p\n", pHdr->u32Magic, pv));
419}
[32707]420RT_EXPORT_SYMBOL(RTMemFreeEx);
[32674]421
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use