VirtualBox

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

Last change on this file since 96763 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 14.9 KB
Line 
1/* $Id: alloc-r0drv.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * IPRT - Memory Allocation, Ring-0 Driver.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
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 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
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
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.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define RTMEM_NO_WRAP_TO_EF_APIS
42#include <iprt/mem.h>
43#include "internal/iprt.h"
44
45#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
46# include <iprt/asm-amd64-x86.h>
47#endif
48#include <iprt/assert.h>
49#include <iprt/err.h>
50#ifdef RT_MORE_STRICT
51# include <iprt/mp.h>
52#endif
53#include <iprt/param.h>
54#include <iprt/string.h>
55#include <iprt/thread.h>
56#include "r0drv/alloc-r0drv.h"
57
58
59/*********************************************************************************************************************************
60* Defined Constants And Macros *
61*********************************************************************************************************************************/
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
73/*********************************************************************************************************************************
74* Global Variables *
75*********************************************************************************************************************************/
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
84
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))
98 return NULL;
99 return pHdr;
100}
101
102
103RTDECL(void *) RTMemTmpAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
104{
105 return RTMemAllocTag(cb, pszTag);
106}
107RT_EXPORT_SYMBOL(RTMemTmpAllocTag);
108
109
110RTDECL(void *) RTMemTmpAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
111{
112 return RTMemAllocZTag(cb, pszTag);
113}
114RT_EXPORT_SYMBOL(RTMemTmpAllocZTag);
115
116
117RTDECL(void) RTMemTmpFree(void *pv) RT_NO_THROW_DEF
118{
119 return RTMemFree(pv);
120}
121RT_EXPORT_SYMBOL(RTMemTmpFree);
122
123
124RTDECL(void) RTMemTmpFreeZ(void *pv, size_t cb) RT_NO_THROW_DEF
125{
126 return RTMemFreeZ(pv, cb);
127}
128RT_EXPORT_SYMBOL(RTMemTmpFreeZ);
129
130
131
132
133
134RTDECL(void *) RTMemAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
135{
136 PRTMEMHDR pHdr;
137 RT_ASSERT_INTS_ON();
138 RT_NOREF_PV(pszTag);
139
140 pHdr = rtR0MemAlloc(cb + RTR0MEM_FENCE_EXTRA, 0);
141 if (pHdr)
142 {
143#ifdef RTR0MEM_STRICT
144 pHdr->cbReq = (uint32_t)cb; Assert(pHdr->cbReq == cb);
145 memcpy((uint8_t *)(pHdr + 1) + cb, &g_abFence[0], RTR0MEM_FENCE_EXTRA);
146#endif
147 return pHdr + 1;
148 }
149 return NULL;
150}
151RT_EXPORT_SYMBOL(RTMemAllocTag);
152
153
154RTDECL(void *) RTMemAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
155{
156 PRTMEMHDR pHdr;
157 RT_ASSERT_INTS_ON();
158 RT_NOREF_PV(pszTag);
159
160 pHdr = rtR0MemAlloc(cb + RTR0MEM_FENCE_EXTRA, RTMEMHDR_FLAG_ZEROED);
161 if (pHdr)
162 {
163#ifdef RTR0MEM_STRICT
164 pHdr->cbReq = (uint32_t)cb; Assert(pHdr->cbReq == cb);
165 memcpy((uint8_t *)(pHdr + 1) + cb, &g_abFence[0], RTR0MEM_FENCE_EXTRA);
166 return memset(pHdr + 1, 0, cb);
167#else
168 return memset(pHdr + 1, 0, pHdr->cb);
169#endif
170 }
171 return NULL;
172}
173RT_EXPORT_SYMBOL(RTMemAllocZTag);
174
175
176RTDECL(void *) RTMemAllocVarTag(size_t cbUnaligned, const char *pszTag)
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 *));
183 return RTMemAllocTag(cbAligned, pszTag);
184}
185RT_EXPORT_SYMBOL(RTMemAllocVarTag);
186
187
188RTDECL(void *) RTMemAllocZVarTag(size_t cbUnaligned, const char *pszTag)
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 *));
195 return RTMemAllocZTag(cbAligned, pszTag);
196}
197RT_EXPORT_SYMBOL(RTMemAllocZVarTag);
198
199
200RTDECL(void *) RTMemReallocTag(void *pvOld, size_t cbNew, const char *pszTag) RT_NO_THROW_DEF
201{
202 PRTMEMHDR pHdrOld;
203
204 /* Free. */
205 if (!cbNew && pvOld)
206 {
207 RTMemFree(pvOld);
208 return NULL;
209 }
210
211 /* Alloc. */
212 if (!pvOld)
213 return RTMemAllocTag(cbNew, pszTag);
214
215 /*
216 * Realloc.
217 */
218 pHdrOld = (PRTMEMHDR)pvOld - 1;
219 RT_ASSERT_PREEMPTIBLE();
220
221 if (pHdrOld->u32Magic == RTMEMHDR_MAGIC)
222 {
223 PRTMEMHDR pHdrNew;
224
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)
229 {
230 pHdrOld->cbReq = (uint32_t)cbNew; Assert(pHdrOld->cbReq == cbNew);
231#ifdef RTR0MEM_STRICT
232 memcpy((uint8_t *)(pHdrOld + 1) + cbNew, &g_abFence[0], RTR0MEM_FENCE_EXTRA);
233#endif
234 return pvOld;
235 }
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 }
257 }
258 else
259 AssertMsgFailed(("pHdrOld->u32Magic=%RX32 pvOld=%p cbNew=%#zx\n", pHdrOld->u32Magic, pvOld, cbNew));
260
261 return NULL;
262}
263RT_EXPORT_SYMBOL(RTMemReallocTag);
264
265
266RTDECL(void) RTMemFree(void *pv) RT_NO_THROW_DEF
267{
268 PRTMEMHDR pHdr;
269 RT_ASSERT_INTS_ON();
270
271 if (!pv)
272 return;
273 pHdr = (PRTMEMHDR)pv - 1;
274 if (pHdr->u32Magic == RTMEMHDR_MAGIC)
275 {
276 Assert(!(pHdr->fFlags & RTMEMHDR_FLAG_ALLOC_EX));
277 Assert(!(pHdr->fFlags & RTMEMHDR_FLAG_EXEC));
278#ifdef RTR0MEM_STRICT
279 AssertReleaseMsg(!memcmp((uint8_t *)(pHdr + 1) + pHdr->cbReq, &g_abFence[0], RTR0MEM_FENCE_EXTRA),
280 ("pHdr=%p pv=%p cbReq=%u cb=%u fFlags=%#x\n"
281 "fence: %.*Rhxs\n"
282 "expected: %.*Rhxs\n",
283 pHdr, pv, pHdr->cbReq, pHdr->cb, pHdr->fFlags,
284 RTR0MEM_FENCE_EXTRA, (uint8_t *)(pHdr + 1) + pHdr->cbReq,
285 RTR0MEM_FENCE_EXTRA, &g_abFence[0]));
286#endif
287 rtR0MemFree(pHdr);
288 }
289 else
290 AssertMsgFailed(("pHdr->u32Magic=%RX32 pv=%p\n", pHdr->u32Magic, pv));
291}
292RT_EXPORT_SYMBOL(RTMemFree);
293
294
295RTDECL(void) RTMemFreeZ(void *pv, size_t cb) RT_NO_THROW_DEF
296{
297 PRTMEMHDR pHdr;
298 RT_ASSERT_INTS_ON();
299
300 if (!pv)
301 return;
302 pHdr = (PRTMEMHDR)pv - 1;
303 if (pHdr->u32Magic == RTMEMHDR_MAGIC)
304 {
305 Assert(!(pHdr->fFlags & RTMEMHDR_FLAG_ALLOC_EX));
306 Assert(!(pHdr->fFlags & RTMEMHDR_FLAG_EXEC));
307#ifdef RTR0MEM_STRICT
308 AssertReleaseMsg(!memcmp((uint8_t *)(pHdr + 1) + pHdr->cbReq, &g_abFence[0], RTR0MEM_FENCE_EXTRA),
309 ("pHdr=%p pv=%p cbReq=%u cb=%u fFlags=%#x\n"
310 "fence: %.*Rhxs\n"
311 "expected: %.*Rhxs\n",
312 pHdr, pv, pHdr->cbReq, pHdr->cb, pHdr->fFlags,
313 RTR0MEM_FENCE_EXTRA, (uint8_t *)(pHdr + 1) + pHdr->cbReq,
314 RTR0MEM_FENCE_EXTRA, &g_abFence[0]));
315#endif
316 AssertMsgStmt(cb == pHdr->cbReq, ("cb=%#zx cbReq=%#x\n", cb, pHdr->cbReq), cb = pHdr->cbReq);
317 RT_BZERO(pv, cb);
318 rtR0MemFree(pHdr);
319 }
320 else
321 AssertMsgFailed(("pHdr->u32Magic=%RX32 pv=%p\n", pHdr->u32Magic, pv));
322}
323RT_EXPORT_SYMBOL(RTMemFreeZ);
324
325
326
327
328
329
330RTDECL(void *) RTMemExecAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
331{
332 PRTMEMHDR pHdr;
333#ifdef RT_OS_SOLARIS /** @todo figure out why */
334 RT_ASSERT_INTS_ON();
335#else
336 RT_ASSERT_PREEMPTIBLE();
337#endif
338 RT_NOREF_PV(pszTag);
339
340
341 pHdr = rtR0MemAlloc(cb + RTR0MEM_FENCE_EXTRA, RTMEMHDR_FLAG_EXEC);
342 if (pHdr)
343 {
344#ifdef RTR0MEM_STRICT
345 pHdr->cbReq = (uint32_t)cb; Assert(pHdr->cbReq == cb);
346 memcpy((uint8_t *)(pHdr + 1) + cb, &g_abFence[0], RTR0MEM_FENCE_EXTRA);
347#endif
348 return pHdr + 1;
349 }
350 return NULL;
351}
352RT_EXPORT_SYMBOL(RTMemExecAllocTag);
353
354
355RTDECL(void) RTMemExecFree(void *pv, size_t cb) RT_NO_THROW_DEF
356{
357 PRTMEMHDR pHdr;
358 RT_ASSERT_INTS_ON();
359 RT_NOREF_PV(cb);
360
361 if (!pv)
362 return;
363 pHdr = (PRTMEMHDR)pv - 1;
364 if (pHdr->u32Magic == RTMEMHDR_MAGIC)
365 {
366 Assert(!(pHdr->fFlags & RTMEMHDR_FLAG_ALLOC_EX));
367#ifdef RTR0MEM_STRICT
368 AssertReleaseMsg(!memcmp((uint8_t *)(pHdr + 1) + pHdr->cbReq, &g_abFence[0], RTR0MEM_FENCE_EXTRA),
369 ("pHdr=%p pv=%p cbReq=%u cb=%u fFlags=%#x\n"
370 "fence: %.*Rhxs\n"
371 "expected: %.*Rhxs\n",
372 pHdr, pv, pHdr->cbReq, pHdr->cb, pHdr->fFlags,
373 RTR0MEM_FENCE_EXTRA, (uint8_t *)(pHdr + 1) + pHdr->cbReq,
374 RTR0MEM_FENCE_EXTRA, &g_abFence[0]));
375#endif
376 rtR0MemFree(pHdr);
377 }
378 else
379 AssertMsgFailed(("pHdr->u32Magic=%RX32 pv=%p\n", pHdr->u32Magic, pv));
380}
381RT_EXPORT_SYMBOL(RTMemExecFree);
382
383
384
385
386RTDECL(int) RTMemAllocExTag(size_t cb, size_t cbAlignment, uint32_t fFlags, const char *pszTag, void **ppv) RT_NO_THROW_DEF
387{
388 uint32_t fHdrFlags = RTMEMHDR_FLAG_ALLOC_EX;
389 PRTMEMHDR pHdr;
390 int rc;
391 RT_NOREF_PV(pszTag);
392
393 RT_ASSERT_PREEMPT_CPUID_VAR();
394 if (!(fFlags & RTMEMALLOCEX_FLAGS_ANY_CTX_ALLOC))
395 RT_ASSERT_INTS_ON();
396
397 /*
398 * Fake up some alignment support.
399 */
400 AssertMsgReturn(cbAlignment <= sizeof(void *), ("%zu (%#x)\n", cbAlignment, cbAlignment), VERR_UNSUPPORTED_ALIGNMENT);
401 if (cb < cbAlignment)
402 cb = cbAlignment;
403
404 /*
405 * Validate and convert flags.
406 */
407 AssertMsgReturn(!(fFlags & ~RTMEMALLOCEX_FLAGS_VALID_MASK_R0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
408 if (fFlags & RTMEMALLOCEX_FLAGS_ZEROED)
409 fHdrFlags |= RTMEMHDR_FLAG_ZEROED;
410 if (fFlags & RTMEMALLOCEX_FLAGS_EXEC)
411 fHdrFlags |= RTMEMHDR_FLAG_EXEC;
412 if (fFlags & RTMEMALLOCEX_FLAGS_ANY_CTX_ALLOC)
413 fHdrFlags |= RTMEMHDR_FLAG_ANY_CTX_ALLOC;
414 if (fFlags & RTMEMALLOCEX_FLAGS_ANY_CTX_FREE)
415 fHdrFlags |= RTMEMHDR_FLAG_ANY_CTX_FREE;
416
417 /*
418 * Do the allocation.
419 */
420 rc = rtR0MemAllocEx(cb + RTR0MEM_FENCE_EXTRA, fHdrFlags, &pHdr);
421 if (RT_SUCCESS(rc))
422 {
423 void *pv;
424
425 Assert(pHdr->cbReq == cb + RTR0MEM_FENCE_EXTRA);
426 Assert((pHdr->fFlags & fFlags) == fFlags);
427
428 /*
429 * Calc user pointer, initialize the memory if requested, and if
430 * memory strictness is enable set up the fence.
431 */
432 pv = pHdr + 1;
433 *ppv = pv;
434 if (fFlags & RTMEMHDR_FLAG_ZEROED)
435 memset(pv, 0, pHdr->cb);
436
437#ifdef RTR0MEM_STRICT
438 pHdr->cbReq = (uint32_t)cb;
439 memcpy((uint8_t *)pv + cb, &g_abFence[0], RTR0MEM_FENCE_EXTRA);
440#endif
441 }
442 else if (rc == VERR_NO_MEMORY && (fFlags & RTMEMALLOCEX_FLAGS_EXEC))
443 rc = VERR_NO_EXEC_MEMORY;
444
445 RT_ASSERT_PREEMPT_CPUID();
446 return rc;
447}
448RT_EXPORT_SYMBOL(RTMemAllocExTag);
449
450
451RTDECL(void) RTMemFreeEx(void *pv, size_t cb) RT_NO_THROW_DEF
452{
453 PRTMEMHDR pHdr;
454 RT_NOREF_PV(cb);
455
456 if (!pv)
457 return;
458
459 AssertPtr(pv);
460 pHdr = (PRTMEMHDR)pv - 1;
461 if (pHdr->u32Magic == RTMEMHDR_MAGIC)
462 {
463 RT_ASSERT_PREEMPT_CPUID_VAR();
464
465 Assert(pHdr->fFlags & RTMEMHDR_FLAG_ALLOC_EX);
466 if (!(pHdr->fFlags & RTMEMHDR_FLAG_ANY_CTX_FREE))
467 RT_ASSERT_INTS_ON();
468 AssertMsg(pHdr->cbReq == cb, ("cbReq=%zu cb=%zu\n", pHdr->cb, cb));
469
470#ifdef RTR0MEM_STRICT
471 AssertReleaseMsg(!memcmp((uint8_t *)(pHdr + 1) + pHdr->cbReq, &g_abFence[0], RTR0MEM_FENCE_EXTRA),
472 ("pHdr=%p pv=%p cbReq=%u cb=%u fFlags=%#x\n"
473 "fence: %.*Rhxs\n"
474 "expected: %.*Rhxs\n",
475 pHdr, pv, pHdr->cbReq, pHdr->cb, pHdr->fFlags,
476 RTR0MEM_FENCE_EXTRA, (uint8_t *)(pHdr + 1) + pHdr->cbReq,
477 RTR0MEM_FENCE_EXTRA, &g_abFence[0]));
478#endif
479 rtR0MemFree(pHdr);
480 RT_ASSERT_PREEMPT_CPUID();
481 }
482 else
483 AssertMsgFailed(("pHdr->u32Magic=%RX32 pv=%p\n", pHdr->u32Magic, pv));
484}
485RT_EXPORT_SYMBOL(RTMemFreeEx);
486
Note: See TracBrowser for help on using the repository browser.

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