VirtualBox

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

Last change on this file since 103914 was 98103, checked in by vboxsync, 22 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
Line 
1/* $Id: alloc-r0drv.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Memory Allocation, Ring-0 Driver.
4 */
5
6/*
7 * Copyright (C) 2006-2023 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#ifdef RTR0MEM_STRICT
278 AssertReleaseMsg(!memcmp((uint8_t *)(pHdr + 1) + pHdr->cbReq, &g_abFence[0], RTR0MEM_FENCE_EXTRA),
279 ("pHdr=%p pv=%p cbReq=%u cb=%u fFlags=%#x\n"
280 "fence: %.*Rhxs\n"
281 "expected: %.*Rhxs\n",
282 pHdr, pv, pHdr->cbReq, pHdr->cb, pHdr->fFlags,
283 RTR0MEM_FENCE_EXTRA, (uint8_t *)(pHdr + 1) + pHdr->cbReq,
284 RTR0MEM_FENCE_EXTRA, &g_abFence[0]));
285#endif
286 rtR0MemFree(pHdr);
287 }
288 else
289 AssertMsgFailed(("pHdr->u32Magic=%RX32 pv=%p\n", pHdr->u32Magic, pv));
290}
291RT_EXPORT_SYMBOL(RTMemFree);
292
293
294RTDECL(void) RTMemFreeZ(void *pv, size_t cb) RT_NO_THROW_DEF
295{
296 PRTMEMHDR pHdr;
297 RT_ASSERT_INTS_ON();
298
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);
322
323
324RTDECL(int) RTMemAllocExTag(size_t cb, size_t cbAlignment, uint32_t fFlags, const char *pszTag, void **ppv) RT_NO_THROW_DEF
325{
326 uint32_t fHdrFlags = RTMEMHDR_FLAG_ALLOC_EX;
327 PRTMEMHDR pHdr;
328 int rc;
329 RT_NOREF_PV(pszTag);
330
331 RT_ASSERT_PREEMPT_CPUID_VAR();
332 if (!(fFlags & RTMEMALLOCEX_FLAGS_ANY_CTX_ALLOC))
333 RT_ASSERT_INTS_ON();
334 AssertReturn(!(fFlags & RTMEMALLOCEX_FLAGS_EXEC), VERR_INVALID_FLAGS);
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 */
346 AssertMsgReturn(!(fFlags & ~RTMEMALLOCEX_FLAGS_VALID_MASK_R0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
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;
382}
383RT_EXPORT_SYMBOL(RTMemAllocExTag);
384
385
386RTDECL(void) RTMemFreeEx(void *pv, size_t cb) RT_NO_THROW_DEF
387{
388 PRTMEMHDR pHdr;
389 RT_NOREF_PV(cb);
390
391 if (!pv)
392 return;
393
394 AssertPtr(pv);
395 pHdr = (PRTMEMHDR)pv - 1;
396 if (pHdr->u32Magic == RTMEMHDR_MAGIC)
397 {
398 RT_ASSERT_PREEMPT_CPUID_VAR();
399
400 Assert(pHdr->fFlags & RTMEMHDR_FLAG_ALLOC_EX);
401 if (!(pHdr->fFlags & RTMEMHDR_FLAG_ANY_CTX_FREE))
402 RT_ASSERT_INTS_ON();
403 AssertMsg(pHdr->cbReq == cb, ("cbReq=%zu cb=%zu\n", pHdr->cb, cb));
404
405#ifdef RTR0MEM_STRICT
406 AssertReleaseMsg(!memcmp((uint8_t *)(pHdr + 1) + pHdr->cbReq, &g_abFence[0], RTR0MEM_FENCE_EXTRA),
407 ("pHdr=%p pv=%p cbReq=%u cb=%u fFlags=%#x\n"
408 "fence: %.*Rhxs\n"
409 "expected: %.*Rhxs\n",
410 pHdr, pv, pHdr->cbReq, pHdr->cb, pHdr->fFlags,
411 RTR0MEM_FENCE_EXTRA, (uint8_t *)(pHdr + 1) + pHdr->cbReq,
412 RTR0MEM_FENCE_EXTRA, &g_abFence[0]));
413#endif
414 rtR0MemFree(pHdr);
415 RT_ASSERT_PREEMPT_CPUID();
416 }
417 else
418 AssertMsgFailed(("pHdr->u32Magic=%RX32 pv=%p\n", pHdr->u32Magic, pv));
419}
420RT_EXPORT_SYMBOL(RTMemFreeEx);
421
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