VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/GMM.cpp@ 107215

Last change on this file since 107215 was 107171, checked in by vboxsync, 2 months ago

VMM/PGM: Introducing VBOX_WITH_ONLY_PGM_NEM_MODE to disable lots unused code on *.arm64 and darwin. jiraref:VBP-1466

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 14.0 KB
Line 
1/* $Id: GMM.cpp 107171 2024-11-28 10:38:10Z vboxsync $ */
2/** @file
3 * GMM - Global Memory Manager, ring-3 request wrappers.
4 */
5
6/*
7 * Copyright (C) 2008-2024 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 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_GMM
33#include <VBox/vmm/gmm.h>
34#include <VBox/vmm/vmm.h>
35#include <VBox/vmm/vmcc.h>
36#include <VBox/sup.h>
37#include <VBox/err.h>
38#include <VBox/param.h>
39
40#include <iprt/assert.h>
41#include <VBox/log.h>
42#include <iprt/mem.h>
43#include <iprt/string.h>
44
45
46/**
47 * @see GMMR0InitialReservation
48 */
49GMMR3DECL(int) GMMR3InitialReservation(PVM pVM, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages,
50 GMMOCPOLICY enmPolicy, GMMPRIORITY enmPriority)
51{
52#if defined(VBOX_WITH_R0_MODULES) && !defined(VBOX_WITH_MINIMAL_R0)
53 if (!SUPR3IsDriverless())
54 {
55 GMMINITIALRESERVATIONREQ Req;
56 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
57 Req.Hdr.cbReq = sizeof(Req);
58 Req.cBasePages = cBasePages;
59 Req.cShadowPages = cShadowPages;
60 Req.cFixedPages = cFixedPages;
61 Req.enmPolicy = enmPolicy;
62 Req.enmPriority = enmPriority;
63 return VMMR3CallR0(pVM, VMMR0_DO_GMM_INITIAL_RESERVATION, 0, &Req.Hdr);
64 }
65#else
66 RT_NOREF(pVM, cBasePages, cShadowPages, cFixedPages, enmPolicy, enmPriority);
67#endif
68 return VINF_SUCCESS;
69}
70
71
72/**
73 * @see GMMR0UpdateReservation
74 */
75GMMR3DECL(int) GMMR3UpdateReservation(PVM pVM, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages)
76{
77#if defined(VBOX_WITH_R0_MODULES) && !defined(VBOX_WITH_MINIMAL_R0)
78 if (!SUPR3IsDriverless())
79 {
80 GMMUPDATERESERVATIONREQ Req;
81 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
82 Req.Hdr.cbReq = sizeof(Req);
83 Req.cBasePages = cBasePages;
84 Req.cShadowPages = cShadowPages;
85 Req.cFixedPages = cFixedPages;
86 return VMMR3CallR0(pVM, VMMR0_DO_GMM_UPDATE_RESERVATION, 0, &Req.Hdr);
87 }
88#else
89 RT_NOREF(pVM, cBasePages, cShadowPages, cFixedPages);
90#endif
91 return VINF_SUCCESS;
92}
93
94
95/**
96 * Prepares a GMMR0AllocatePages request.
97 *
98 * @returns VINF_SUCCESS or VERR_NO_TMP_MEMORY.
99 * @param pVM The cross context VM structure.
100 * @param[out] ppReq Where to store the pointer to the request packet.
101 * @param cPages The number of pages that's to be allocated.
102 * @param enmAccount The account to charge.
103 */
104GMMR3DECL(int) GMMR3AllocatePagesPrepare(PVM pVM, PGMMALLOCATEPAGESREQ *ppReq, uint32_t cPages, GMMACCOUNT enmAccount)
105{
106 uint32_t cb = RT_UOFFSETOF_DYN(GMMALLOCATEPAGESREQ, aPages[cPages]);
107 PGMMALLOCATEPAGESREQ pReq = (PGMMALLOCATEPAGESREQ)RTMemTmpAllocZ(cb);
108 if (!pReq)
109 return VERR_NO_TMP_MEMORY;
110
111 pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
112 pReq->Hdr.cbReq = cb;
113 pReq->enmAccount = enmAccount;
114 pReq->cPages = cPages;
115 NOREF(pVM);
116 *ppReq = pReq;
117 return VINF_SUCCESS;
118}
119
120
121/**
122 * Performs a GMMR0AllocatePages request.
123 *
124 * This will call VMSetError on failure.
125 *
126 * @returns VBox status code.
127 * @param pVM The cross context VM structure.
128 * @param pReq Pointer to the request (returned by GMMR3AllocatePagesPrepare).
129 */
130GMMR3DECL(int) GMMR3AllocatePagesPerform(PVM pVM, PGMMALLOCATEPAGESREQ pReq)
131{
132 int rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_ALLOCATE_PAGES, 0, &pReq->Hdr);
133 if (RT_SUCCESS(rc))
134 {
135#ifdef LOG_ENABLED
136 for (uint32_t iPage = 0; iPage < pReq->cPages; iPage++)
137 Log3(("GMMR3AllocatePagesPerform: idPage=%#x HCPhys=%RHp fZeroed=%d\n",
138 pReq->aPages[iPage].idPage, pReq->aPages[iPage].HCPhysGCPhys, pReq->aPages[iPage].fZeroed));
139#endif
140 return rc;
141 }
142 return VMSetError(pVM, rc, RT_SRC_POS, N_("GMMR0AllocatePages failed to allocate %u pages"), pReq->cPages);
143}
144
145
146/**
147 * Cleans up a GMMR0AllocatePages request.
148 * @param pReq Pointer to the request (returned by GMMR3AllocatePagesPrepare).
149 */
150GMMR3DECL(void) GMMR3AllocatePagesCleanup(PGMMALLOCATEPAGESREQ pReq)
151{
152 RTMemTmpFree(pReq);
153}
154
155
156/**
157 * Prepares a GMMR0FreePages request.
158 *
159 * @returns VINF_SUCCESS or VERR_NO_TMP_MEMORY.
160 * @param pVM The cross context VM structure.
161 * @param[out] ppReq Where to store the pointer to the request packet.
162 * @param cPages The number of pages that's to be freed.
163 * @param enmAccount The account to charge.
164 */
165GMMR3DECL(int) GMMR3FreePagesPrepare(PVM pVM, PGMMFREEPAGESREQ *ppReq, uint32_t cPages, GMMACCOUNT enmAccount)
166{
167 uint32_t cb = RT_UOFFSETOF_DYN(GMMFREEPAGESREQ, aPages[cPages]);
168 PGMMFREEPAGESREQ pReq = (PGMMFREEPAGESREQ)RTMemTmpAllocZ(cb);
169 if (!pReq)
170 return VERR_NO_TMP_MEMORY;
171
172 pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
173 pReq->Hdr.cbReq = cb;
174 pReq->enmAccount = enmAccount;
175 pReq->cPages = cPages;
176 NOREF(pVM);
177 *ppReq = pReq;
178 return VINF_SUCCESS;
179}
180
181
182/**
183 * Re-prepares a GMMR0FreePages request.
184 *
185 * @param pVM The cross context VM structure.
186 * @param pReq A request buffer previously returned by
187 * GMMR3FreePagesPrepare().
188 * @param cPages The number of pages originally passed to
189 * GMMR3FreePagesPrepare().
190 * @param enmAccount The account to charge.
191 */
192GMMR3DECL(void) GMMR3FreePagesRePrep(PVM pVM, PGMMFREEPAGESREQ pReq, uint32_t cPages, GMMACCOUNT enmAccount)
193{
194 Assert(pReq->Hdr.u32Magic == SUPVMMR0REQHDR_MAGIC);
195 pReq->Hdr.cbReq = RT_UOFFSETOF_DYN(GMMFREEPAGESREQ, aPages[cPages]);
196 pReq->enmAccount = enmAccount;
197 pReq->cPages = cPages;
198 NOREF(pVM);
199}
200
201
202/**
203 * Performs a GMMR0FreePages request.
204 * This will call VMSetError on failure.
205 *
206 * @returns VBox status code.
207 * @param pVM The cross context VM structure.
208 * @param pReq Pointer to the request (returned by GMMR3FreePagesPrepare).
209 * @param cActualPages The number of pages actually freed.
210 */
211GMMR3DECL(int) GMMR3FreePagesPerform(PVM pVM, PGMMFREEPAGESREQ pReq, uint32_t cActualPages)
212{
213 /*
214 * Adjust the request if we ended up with fewer pages than anticipated.
215 */
216 if (cActualPages != pReq->cPages)
217 {
218 AssertReturn(cActualPages < pReq->cPages, VERR_GMM_ACTUAL_PAGES_IPE);
219 if (!cActualPages)
220 return VINF_SUCCESS;
221 pReq->cPages = cActualPages;
222 pReq->Hdr.cbReq = RT_UOFFSETOF_DYN(GMMFREEPAGESREQ, aPages[cActualPages]);
223 }
224
225 /*
226 * Do the job.
227 */
228 int rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_FREE_PAGES, 0, &pReq->Hdr);
229 if (RT_SUCCESS(rc))
230 return rc;
231 AssertRC(rc);
232 return VMSetError(pVM, rc, RT_SRC_POS,
233 N_("GMMR0FreePages failed to free %u pages"),
234 pReq->cPages);
235}
236
237
238/**
239 * Cleans up a GMMR0FreePages request.
240 * @param pReq Pointer to the request (returned by GMMR3FreePagesPrepare).
241 */
242GMMR3DECL(void) GMMR3FreePagesCleanup(PGMMFREEPAGESREQ pReq)
243{
244 RTMemTmpFree(pReq);
245}
246
247
248/**
249 * Frees allocated pages, for bailing out on failure.
250 *
251 * This will not call VMSetError on failure but will use AssertLogRel instead.
252 *
253 * @param pVM The cross context VM structure.
254 * @param pAllocReq The allocation request to undo.
255 */
256GMMR3DECL(void) GMMR3FreeAllocatedPages(PVM pVM, GMMALLOCATEPAGESREQ const *pAllocReq)
257{
258 uint32_t cb = RT_UOFFSETOF_DYN(GMMFREEPAGESREQ, aPages[pAllocReq->cPages]);
259 PGMMFREEPAGESREQ pReq = (PGMMFREEPAGESREQ)RTMemTmpAllocZ(cb);
260 AssertLogRelReturnVoid(pReq);
261
262 pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
263 pReq->Hdr.cbReq = cb;
264 pReq->enmAccount = pAllocReq->enmAccount;
265 pReq->cPages = pAllocReq->cPages;
266 uint32_t iPage = pAllocReq->cPages;
267 while (iPage-- > 0)
268 {
269 Assert(pAllocReq->aPages[iPage].idPage != NIL_GMM_PAGEID);
270 pReq->aPages[iPage].idPage = pAllocReq->aPages[iPage].idPage;
271 }
272
273 int rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_FREE_PAGES, 0, &pReq->Hdr);
274 AssertLogRelRC(rc);
275
276 RTMemTmpFree(pReq);
277}
278
279#if defined(VBOX_WITH_R0_MODULES) && !defined(VBOX_WITH_MINIMAL_R0)
280
281/**
282 * @see GMMR0BalloonedPages
283 */
284GMMR3DECL(int) GMMR3BalloonedPages(PVM pVM, GMMBALLOONACTION enmAction, uint32_t cBalloonedPages)
285{
286 int rc;
287 if (!SUPR3IsDriverless())
288 {
289 GMMBALLOONEDPAGESREQ Req;
290 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
291 Req.Hdr.cbReq = sizeof(Req);
292 Req.enmAction = enmAction;
293 Req.cBalloonedPages = cBalloonedPages;
294
295 rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_BALLOONED_PAGES, 0, &Req.Hdr);
296 }
297 /*
298 * Ignore reset and fail all other requests.
299 */
300 else if (enmAction == GMMBALLOONACTION_RESET && cBalloonedPages == 0)
301 rc = VINF_SUCCESS;
302 else
303 rc = VERR_SUP_DRIVERLESS;
304 return rc;
305}
306
307
308/**
309 * @note Caller does the driverless check.
310 * @see GMMR0QueryVMMMemoryStatsReq
311 */
312GMMR3DECL(int) GMMR3QueryHypervisorMemoryStats(PVM pVM, uint64_t *pcTotalAllocPages, uint64_t *pcTotalFreePages, uint64_t *pcTotalBalloonPages, uint64_t *puTotalBalloonSize)
313{
314 GMMMEMSTATSREQ Req;
315 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
316 Req.Hdr.cbReq = sizeof(Req);
317 Req.cAllocPages = 0;
318 Req.cFreePages = 0;
319 Req.cBalloonedPages = 0;
320 Req.cSharedPages = 0;
321
322 *pcTotalAllocPages = 0;
323 *pcTotalFreePages = 0;
324 *pcTotalBalloonPages = 0;
325 *puTotalBalloonSize = 0;
326
327 /* Must be callable from any thread, so can't use VMMR3CallR0. */
328 int rc = SUPR3CallVMMR0Ex(VMCC_GET_VMR0_FOR_CALL(pVM), NIL_VMCPUID, VMMR0_DO_GMM_QUERY_HYPERVISOR_MEM_STATS, 0, &Req.Hdr);
329 if (rc == VINF_SUCCESS)
330 {
331 *pcTotalAllocPages = Req.cAllocPages;
332 *pcTotalFreePages = Req.cFreePages;
333 *pcTotalBalloonPages = Req.cBalloonedPages;
334 *puTotalBalloonSize = Req.cSharedPages;
335 }
336 return rc;
337}
338
339
340/**
341 * @see GMMR0QueryMemoryStatsReq
342 */
343GMMR3DECL(int) GMMR3QueryMemoryStats(PVM pVM, uint64_t *pcAllocPages, uint64_t *pcMaxPages, uint64_t *pcBalloonPages)
344{
345 GMMMEMSTATSREQ Req;
346 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
347 Req.Hdr.cbReq = sizeof(Req);
348 Req.cAllocPages = 0;
349 Req.cFreePages = 0;
350 Req.cBalloonedPages = 0;
351
352 *pcAllocPages = 0;
353 *pcMaxPages = 0;
354 *pcBalloonPages = 0;
355
356 int rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_QUERY_MEM_STATS, 0, &Req.Hdr);
357 if (rc == VINF_SUCCESS)
358 {
359 *pcAllocPages = Req.cAllocPages;
360 *pcMaxPages = Req.cMaxPages;
361 *pcBalloonPages = Req.cBalloonedPages;
362 }
363 return rc;
364}
365
366
367/**
368 * @see GMMR0MapUnmapChunk
369 */
370GMMR3DECL(int) GMMR3MapUnmapChunk(PVM pVM, uint32_t idChunkMap, uint32_t idChunkUnmap, PRTR3PTR ppvR3)
371{
372 GMMMAPUNMAPCHUNKREQ Req;
373 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
374 Req.Hdr.cbReq = sizeof(Req);
375 Req.idChunkMap = idChunkMap;
376 Req.idChunkUnmap = idChunkUnmap;
377 Req.pvR3 = NULL;
378 int rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_MAP_UNMAP_CHUNK, 0, &Req.Hdr);
379 if (RT_SUCCESS(rc) && ppvR3)
380 *ppvR3 = Req.pvR3;
381 return rc;
382}
383
384
385/**
386 * @see GMMR0FreeLargePage
387 */
388GMMR3DECL(int) GMMR3FreeLargePage(PVM pVM, uint32_t idPage)
389{
390 GMMFREELARGEPAGEREQ Req;
391 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
392 Req.Hdr.cbReq = sizeof(Req);
393 Req.idPage = idPage;
394 return VMMR3CallR0(pVM, VMMR0_DO_GMM_FREE_LARGE_PAGE, 0, &Req.Hdr);
395}
396
397
398/**
399 * @see GMMR0RegisterSharedModule
400 */
401GMMR3DECL(int) GMMR3RegisterSharedModule(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq)
402{
403 pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
404 pReq->Hdr.cbReq = RT_UOFFSETOF_DYN(GMMREGISTERSHAREDMODULEREQ, aRegions[pReq->cRegions]);
405 int rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_REGISTER_SHARED_MODULE, 0, &pReq->Hdr);
406 if (rc == VINF_SUCCESS)
407 rc = pReq->rc;
408 return rc;
409}
410
411
412/**
413 * @see GMMR0RegisterSharedModule
414 */
415GMMR3DECL(int) GMMR3UnregisterSharedModule(PVM pVM, PGMMUNREGISTERSHAREDMODULEREQ pReq)
416{
417 pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
418 pReq->Hdr.cbReq = sizeof(*pReq);
419 return VMMR3CallR0(pVM, VMMR0_DO_GMM_UNREGISTER_SHARED_MODULE, 0, &pReq->Hdr);
420}
421
422
423/**
424 * @see GMMR0ResetSharedModules
425 */
426GMMR3DECL(int) GMMR3ResetSharedModules(PVM pVM)
427{
428 if (!SUPR3IsDriverless())
429 return VMMR3CallR0(pVM, VMMR0_DO_GMM_RESET_SHARED_MODULES, 0, NULL);
430 return VINF_SUCCESS;
431}
432
433
434/**
435 * @see GMMR0CheckSharedModules
436 */
437GMMR3DECL(int) GMMR3CheckSharedModules(PVM pVM)
438{
439 return VMMR3CallR0(pVM, VMMR0_DO_GMM_CHECK_SHARED_MODULES, 0, NULL);
440}
441
442
443# if defined(VBOX_STRICT) && HC_ARCH_BITS == 64
444/**
445 * @see GMMR0FindDuplicatePage
446 */
447GMMR3DECL(bool) GMMR3IsDuplicatePage(PVM pVM, uint32_t idPage)
448{
449 GMMFINDDUPLICATEPAGEREQ Req;
450 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
451 Req.Hdr.cbReq = sizeof(Req);
452 Req.idPage = idPage;
453 Req.fDuplicate = false;
454
455 /* Must be callable from any thread, so can't use VMMR3CallR0. */
456 int rc = SUPR3CallVMMR0Ex(VMCC_GET_VMR0_FOR_CALL(pVM), NIL_VMCPUID, VMMR0_DO_GMM_FIND_DUPLICATE_PAGE, 0, &Req.Hdr);
457 if (rc == VINF_SUCCESS)
458 return Req.fDuplicate;
459 return false;
460}
461# endif /* VBOX_STRICT && HC_ARCH_BITS == 64 */
462
463#endif /* defined(VBOX_WITH_R0_MODULES) && !defined(VBOX_WITH_MINIMAL_R0) */
464
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