VirtualBox

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

Last change on this file since 103425 was 100321, checked in by vboxsync, 16 months ago

Runtime/r0drv/linux/alloc-r0drv-linux.c: Make it work on ARM, bugref:10457

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 7.7 KB
Line 
1/* $Id: alloc-r0drv-linux.c 100321 2023-06-28 10:55:34Z 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 void *pvRet;
158#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
159 struct page *paPages;
160#endif
161 IPRT_LINUX_SAVE_EFL_AC();
162
163 /*
164 * validate input.
165 */
166 AssertPtr(pPhys);
167 Assert(cb > 0);
168
169 /*
170 * Allocate page pointer array.
171 */
172 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
173 cPages = cb >> PAGE_SHIFT;
174 cOrder = CalcPowerOf2Order(cPages);
175#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
176# if (defined(RT_ARCH_AMD64) || defined(CONFIG_X86_PAE)) && defined(GFP_DMA32)
177 /* ZONE_DMA32: 0-4GB */
178 paPages = alloc_pages(GFP_DMA32 | __GFP_NOWARN, cOrder);
179 if (!paPages)
180# endif
181# ifdef RT_ARCH_AMD64
182 /* ZONE_DMA; 0-16MB */
183 paPages = alloc_pages(GFP_DMA | __GFP_NOWARN, cOrder);
184# else
185 /* ZONE_NORMAL: 0-896MB */
186 paPages = alloc_pages(GFP_USER | __GFP_NOWARN, cOrder);
187# endif
188 if (paPages)
189 {
190 /*
191 * Reserve the pages and mark them executable.
192 */
193 unsigned iPage;
194 for (iPage = 0; iPage < cPages; iPage++)
195 {
196 Assert(!PageHighMem(&paPages[iPage]));
197 if (iPage + 1 < cPages)
198 {
199 AssertMsg( (uintptr_t)phys_to_virt(page_to_phys(&paPages[iPage])) + PAGE_SIZE
200 == (uintptr_t)phys_to_virt(page_to_phys(&paPages[iPage + 1]))
201 && page_to_phys(&paPages[iPage]) + PAGE_SIZE
202 == page_to_phys(&paPages[iPage + 1]),
203 ("iPage=%i cPages=%u [0]=%#llx,%p [1]=%#llx,%p\n", iPage, cPages,
204 (long long)page_to_phys(&paPages[iPage]), phys_to_virt(page_to_phys(&paPages[iPage])),
205 (long long)page_to_phys(&paPages[iPage + 1]), phys_to_virt(page_to_phys(&paPages[iPage + 1])) ));
206 }
207
208 SetPageReserved(&paPages[iPage]);
209 }
210 *pPhys = page_to_phys(paPages);
211 pvRet = phys_to_virt(page_to_phys(paPages));
212 }
213 else
214 pvRet = NULL;
215#else
216 pvRet = (void *)__get_free_pages(GFP_DMA32 | __GFP_NOWARN, cOrder);
217 if (pvRet)
218 *pPhys = virt_to_phys(pvRet);
219#endif
220
221 IPRT_LINUX_RESTORE_EFL_AC();
222 return pvRet;
223}
224RT_EXPORT_SYMBOL(RTMemContAlloc);
225
226
227/**
228 * Frees memory allocated using RTMemContAlloc().
229 *
230 * @param pv Pointer to return from RTMemContAlloc().
231 * @param cb The cb parameter passed to RTMemContAlloc().
232 */
233RTR0DECL(void) RTMemContFree(void *pv, size_t cb)
234{
235 if (pv)
236 {
237 int cOrder;
238 unsigned cPages;
239#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
240 unsigned iPage;
241 struct page *paPages;
242#endif
243 IPRT_LINUX_SAVE_EFL_AC();
244
245 /* validate */
246 AssertMsg(!((uintptr_t)pv & PAGE_OFFSET_MASK), ("pv=%p\n", pv));
247 Assert(cb > 0);
248
249 /* calc order and get pages */
250 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
251 cPages = cb >> PAGE_SHIFT;
252 cOrder = CalcPowerOf2Order(cPages);
253#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
254 paPages = virt_to_page(pv);
255
256 /*
257 * Restore page attributes freeing the pages.
258 */
259 for (iPage = 0; iPage < cPages; iPage++)
260 {
261 ClearPageReserved(&paPages[iPage]);
262 }
263 __free_pages(paPages, cOrder);
264#else
265 free_pages((uintptr_t)pv, cOrder);
266#endif
267 IPRT_LINUX_RESTORE_EFL_AC();
268 }
269}
270RT_EXPORT_SYMBOL(RTMemContFree);
271
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