VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/linux/alloc-r0drv-linux.c@ 98103

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

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 7.3 KB
Line 
1/* $Id: alloc-r0drv-linux.c 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Memory Allocation, Ring-0 Driver, Linux.
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#include "the-linux-kernel.h"
42#include "internal/iprt.h"
43#include <iprt/mem.h>
44
45#include <iprt/assert.h>
46#include <iprt/errcore.h>
47#include "r0drv/alloc-r0drv.h"
48
49#include "internal/initterm.h"
50
51
52
53/**
54 * OS specific allocation function.
55 */
56DECLHIDDEN(int) rtR0MemAllocEx(size_t cb, uint32_t fFlags, PRTMEMHDR *ppHdr)
57{
58 PRTMEMHDR pHdr;
59 IPRT_LINUX_SAVE_EFL_AC();
60
61 /*
62 * Allocate.
63 */
64 if (
65#if 1 /* vmalloc has serious performance issues, avoid it. */
66 cb <= PAGE_SIZE*16 - sizeof(*pHdr)
67#else
68 cb <= PAGE_SIZE
69#endif
70 || (fFlags & RTMEMHDR_FLAG_ANY_CTX)
71 )
72 {
73 fFlags |= RTMEMHDR_FLAG_KMALLOC;
74 pHdr = kmalloc(cb + sizeof(*pHdr),
75 fFlags & RTMEMHDR_FLAG_ANY_CTX_ALLOC ? GFP_ATOMIC | __GFP_NOWARN : GFP_KERNEL | __GFP_NOWARN);
76 if (RT_UNLIKELY( !pHdr
77 && cb > PAGE_SIZE
78 && !(fFlags & RTMEMHDR_FLAG_ANY_CTX) ))
79 {
80 fFlags &= ~RTMEMHDR_FLAG_KMALLOC;
81 pHdr = vmalloc(cb + sizeof(*pHdr));
82 }
83 }
84 else
85 pHdr = vmalloc(cb + sizeof(*pHdr));
86 if (RT_LIKELY(pHdr))
87 {
88 /*
89 * Initialize.
90 */
91 pHdr->u32Magic = RTMEMHDR_MAGIC;
92 pHdr->fFlags = fFlags;
93 pHdr->cb = cb;
94 pHdr->cbReq = cb;
95
96 *ppHdr = pHdr;
97 IPRT_LINUX_RESTORE_EFL_AC();
98 return VINF_SUCCESS;
99 }
100
101 IPRT_LINUX_RESTORE_EFL_AC();
102 return VERR_NO_MEMORY;
103}
104
105
106/**
107 * OS specific free function.
108 */
109DECLHIDDEN(void) rtR0MemFree(PRTMEMHDR pHdr)
110{
111 IPRT_LINUX_SAVE_EFL_AC();
112
113 pHdr->u32Magic += 1;
114 if (pHdr->fFlags & RTMEMHDR_FLAG_KMALLOC)
115 kfree(pHdr);
116 else
117 vfree(pHdr);
118
119 IPRT_LINUX_RESTORE_EFL_AC();
120}
121
122
123
124/**
125 * Compute order. Some functions allocate 2^order pages.
126 *
127 * @returns order.
128 * @param cPages Number of pages.
129 */
130static int CalcPowerOf2Order(unsigned long cPages)
131{
132 int iOrder;
133 unsigned long cTmp;
134
135 for (iOrder = 0, cTmp = cPages; cTmp >>= 1; ++iOrder)
136 ;
137 if (cPages & ~(1 << iOrder))
138 ++iOrder;
139
140 return iOrder;
141}
142
143
144/**
145 * Allocates physical contiguous memory (below 4GB).
146 * The allocation is page aligned and the content is undefined.
147 *
148 * @returns Pointer to the memory block. This is page aligned.
149 * @param pPhys Where to store the physical address.
150 * @param cb The allocation size in bytes. This is always
151 * rounded up to PAGE_SIZE.
152 */
153RTR0DECL(void *) RTMemContAlloc(PRTCCPHYS pPhys, size_t cb)
154{
155 int cOrder;
156 unsigned cPages;
157 struct page *paPages;
158 void *pvRet;
159 IPRT_LINUX_SAVE_EFL_AC();
160
161 /*
162 * validate input.
163 */
164 AssertPtr(pPhys);
165 Assert(cb > 0);
166
167 /*
168 * Allocate page pointer array.
169 */
170 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
171 cPages = cb >> PAGE_SHIFT;
172 cOrder = CalcPowerOf2Order(cPages);
173#if (defined(RT_ARCH_AMD64) || defined(CONFIG_X86_PAE)) && defined(GFP_DMA32)
174 /* ZONE_DMA32: 0-4GB */
175 paPages = alloc_pages(GFP_DMA32 | __GFP_NOWARN, cOrder);
176 if (!paPages)
177#endif
178#ifdef RT_ARCH_AMD64
179 /* ZONE_DMA; 0-16MB */
180 paPages = alloc_pages(GFP_DMA | __GFP_NOWARN, cOrder);
181#else
182 /* ZONE_NORMAL: 0-896MB */
183 paPages = alloc_pages(GFP_USER | __GFP_NOWARN, cOrder);
184#endif
185 if (paPages)
186 {
187 /*
188 * Reserve the pages and mark them executable.
189 */
190 unsigned iPage;
191 for (iPage = 0; iPage < cPages; iPage++)
192 {
193 Assert(!PageHighMem(&paPages[iPage]));
194 if (iPage + 1 < cPages)
195 {
196 AssertMsg( (uintptr_t)phys_to_virt(page_to_phys(&paPages[iPage])) + PAGE_SIZE
197 == (uintptr_t)phys_to_virt(page_to_phys(&paPages[iPage + 1]))
198 && page_to_phys(&paPages[iPage]) + PAGE_SIZE
199 == page_to_phys(&paPages[iPage + 1]),
200 ("iPage=%i cPages=%u [0]=%#llx,%p [1]=%#llx,%p\n", iPage, cPages,
201 (long long)page_to_phys(&paPages[iPage]), phys_to_virt(page_to_phys(&paPages[iPage])),
202 (long long)page_to_phys(&paPages[iPage + 1]), phys_to_virt(page_to_phys(&paPages[iPage + 1])) ));
203 }
204
205 SetPageReserved(&paPages[iPage]);
206 }
207 *pPhys = page_to_phys(paPages);
208 pvRet = phys_to_virt(page_to_phys(paPages));
209 }
210 else
211 pvRet = NULL;
212
213 IPRT_LINUX_RESTORE_EFL_AC();
214 return pvRet;
215}
216RT_EXPORT_SYMBOL(RTMemContAlloc);
217
218
219/**
220 * Frees memory allocated using RTMemContAlloc().
221 *
222 * @param pv Pointer to return from RTMemContAlloc().
223 * @param cb The cb parameter passed to RTMemContAlloc().
224 */
225RTR0DECL(void) RTMemContFree(void *pv, size_t cb)
226{
227 if (pv)
228 {
229 int cOrder;
230 unsigned cPages;
231 unsigned iPage;
232 struct page *paPages;
233 IPRT_LINUX_SAVE_EFL_AC();
234
235 /* validate */
236 AssertMsg(!((uintptr_t)pv & PAGE_OFFSET_MASK), ("pv=%p\n", pv));
237 Assert(cb > 0);
238
239 /* calc order and get pages */
240 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
241 cPages = cb >> PAGE_SHIFT;
242 cOrder = CalcPowerOf2Order(cPages);
243 paPages = virt_to_page(pv);
244
245 /*
246 * Restore page attributes freeing the pages.
247 */
248 for (iPage = 0; iPage < cPages; iPage++)
249 {
250 ClearPageReserved(&paPages[iPage]);
251 }
252 __free_pages(paPages, cOrder);
253 IPRT_LINUX_RESTORE_EFL_AC();
254 }
255}
256RT_EXPORT_SYMBOL(RTMemContFree);
257
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