VirtualBox

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

Last change on this file since 109008 was 108963, checked in by vboxsync, 8 days ago

VMM/GMM: Eliminated IN_GMM_R3/R0.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 14.1 KB
Line 
1/* $Id: GMM.cpp 108963 2025-04-14 10:12:43Z 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 */
49VMMR3_INT_DECL(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 */
75VMMR3_INT_DECL(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 */
104VMMR3_INT_DECL(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 */
130VMMR3_INT_DECL(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 */
150VMMR3_INT_DECL(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 */
165VMMR3_INT_DECL(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 */
192VMMR3_INT_DECL(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 */
211VMMR3_INT_DECL(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 */
242VMMR3_INT_DECL(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 */
256VMMR3_INT_DECL(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 */
284VMMR3_INT_DECL(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 */
312VMMR3_INT_DECL(int) GMMR3QueryHypervisorMemoryStats(PVM pVM, uint64_t *pcTotalAllocPages, uint64_t *pcTotalFreePages,
313 uint64_t *pcTotalBalloonPages, uint64_t *puTotalBalloonSize)
314{
315 GMMMEMSTATSREQ Req;
316 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
317 Req.Hdr.cbReq = sizeof(Req);
318 Req.cAllocPages = 0;
319 Req.cFreePages = 0;
320 Req.cBalloonedPages = 0;
321 Req.cSharedPages = 0;
322
323 *pcTotalAllocPages = 0;
324 *pcTotalFreePages = 0;
325 *pcTotalBalloonPages = 0;
326 *puTotalBalloonSize = 0;
327
328 /* Must be callable from any thread, so can't use VMMR3CallR0. */
329 int rc = SUPR3CallVMMR0Ex(VMCC_GET_VMR0_FOR_CALL(pVM), NIL_VMCPUID, VMMR0_DO_GMM_QUERY_HYPERVISOR_MEM_STATS, 0, &Req.Hdr);
330 if (rc == VINF_SUCCESS)
331 {
332 *pcTotalAllocPages = Req.cAllocPages;
333 *pcTotalFreePages = Req.cFreePages;
334 *pcTotalBalloonPages = Req.cBalloonedPages;
335 *puTotalBalloonSize = Req.cSharedPages;
336 }
337 return rc;
338}
339
340
341/**
342 * @see GMMR0QueryMemoryStatsReq
343 */
344VMMR3_INT_DECL(int) GMMR3QueryMemoryStats(PVM pVM, uint64_t *pcAllocPages, uint64_t *pcMaxPages, uint64_t *pcBalloonPages)
345{
346 GMMMEMSTATSREQ Req;
347 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
348 Req.Hdr.cbReq = sizeof(Req);
349 Req.cAllocPages = 0;
350 Req.cFreePages = 0;
351 Req.cBalloonedPages = 0;
352
353 *pcAllocPages = 0;
354 *pcMaxPages = 0;
355 *pcBalloonPages = 0;
356
357 int rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_QUERY_MEM_STATS, 0, &Req.Hdr);
358 if (rc == VINF_SUCCESS)
359 {
360 *pcAllocPages = Req.cAllocPages;
361 *pcMaxPages = Req.cMaxPages;
362 *pcBalloonPages = Req.cBalloonedPages;
363 }
364 return rc;
365}
366
367
368/**
369 * @see GMMR0MapUnmapChunk
370 */
371VMMR3_INT_DECL(int) GMMR3MapUnmapChunk(PVM pVM, uint32_t idChunkMap, uint32_t idChunkUnmap, PRTR3PTR ppvR3)
372{
373 GMMMAPUNMAPCHUNKREQ Req;
374 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
375 Req.Hdr.cbReq = sizeof(Req);
376 Req.idChunkMap = idChunkMap;
377 Req.idChunkUnmap = idChunkUnmap;
378 Req.pvR3 = NULL;
379 int rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_MAP_UNMAP_CHUNK, 0, &Req.Hdr);
380 if (RT_SUCCESS(rc) && ppvR3)
381 *ppvR3 = Req.pvR3;
382 return rc;
383}
384
385
386/**
387 * @see GMMR0FreeLargePage
388 */
389VMMR3_INT_DECL(int) GMMR3FreeLargePage(PVM pVM, uint32_t idPage)
390{
391 GMMFREELARGEPAGEREQ Req;
392 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
393 Req.Hdr.cbReq = sizeof(Req);
394 Req.idPage = idPage;
395 return VMMR3CallR0(pVM, VMMR0_DO_GMM_FREE_LARGE_PAGE, 0, &Req.Hdr);
396}
397
398
399/**
400 * @see GMMR0RegisterSharedModule
401 */
402VMMR3_INT_DECL(int) GMMR3RegisterSharedModule(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq)
403{
404 pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
405 pReq->Hdr.cbReq = RT_UOFFSETOF_DYN(GMMREGISTERSHAREDMODULEREQ, aRegions[pReq->cRegions]);
406 int rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_REGISTER_SHARED_MODULE, 0, &pReq->Hdr);
407 if (rc == VINF_SUCCESS)
408 rc = pReq->rc;
409 return rc;
410}
411
412
413/**
414 * @see GMMR0RegisterSharedModule
415 */
416VMMR3_INT_DECL(int) GMMR3UnregisterSharedModule(PVM pVM, PGMMUNREGISTERSHAREDMODULEREQ pReq)
417{
418 pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
419 pReq->Hdr.cbReq = sizeof(*pReq);
420 return VMMR3CallR0(pVM, VMMR0_DO_GMM_UNREGISTER_SHARED_MODULE, 0, &pReq->Hdr);
421}
422
423
424/**
425 * @see GMMR0ResetSharedModules
426 */
427VMMR3_INT_DECL(int) GMMR3ResetSharedModules(PVM pVM)
428{
429 if (!SUPR3IsDriverless())
430 return VMMR3CallR0(pVM, VMMR0_DO_GMM_RESET_SHARED_MODULES, 0, NULL);
431 return VINF_SUCCESS;
432}
433
434
435/**
436 * @see GMMR0CheckSharedModules
437 */
438VMMR3_INT_DECL(int) GMMR3CheckSharedModules(PVM pVM)
439{
440 return VMMR3CallR0(pVM, VMMR0_DO_GMM_CHECK_SHARED_MODULES, 0, NULL);
441}
442
443
444# if defined(VBOX_STRICT) && HC_ARCH_BITS == 64
445/**
446 * @see GMMR0FindDuplicatePage
447 */
448VMMR3_INT_DECL(bool) GMMR3IsDuplicatePage(PVM pVM, uint32_t idPage)
449{
450 GMMFINDDUPLICATEPAGEREQ Req;
451 Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
452 Req.Hdr.cbReq = sizeof(Req);
453 Req.idPage = idPage;
454 Req.fDuplicate = false;
455
456 /* Must be callable from any thread, so can't use VMMR3CallR0. */
457 int rc = SUPR3CallVMMR0Ex(VMCC_GET_VMR0_FOR_CALL(pVM), NIL_VMCPUID, VMMR0_DO_GMM_FIND_DUPLICATE_PAGE, 0, &Req.Hdr);
458 if (rc == VINF_SUCCESS)
459 return Req.fDuplicate;
460 return false;
461}
462# endif /* VBOX_STRICT && HC_ARCH_BITS == 64 */
463
464#endif /* defined(VBOX_WITH_R0_MODULES) && !defined(VBOX_WITH_MINIMAL_R0) */
465
Note: See TracBrowser for help on using the repository browser.

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