VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMR3/MM.cpp@ 99370

Last change on this file since 99370 was 99079, checked in by vboxsync, 15 months ago

VMM/MM: For ARMv8 we need to be more flexible when it comes to configure accessible guest RAM, there is no standard layout and every SoC can have RAM at different physical addresses. MM gets a list of memory regions through CFGM and sets up the RAM ranges, bugref:10388

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 29.8 KB
Line 
1/* $Id: MM.cpp 99079 2023-03-21 11:05:38Z vboxsync $ */
2/** @file
3 * MM - Memory Manager.
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 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/** @page pg_mm MM - The Memory Manager
30 *
31 * The memory manager is in charge of the following memory:
32 * - Hypervisor Memory Area (HMA) - Address space management (obsolete in 6.1).
33 * - Hypervisor Heap - A memory heap that lives in all contexts.
34 * - User-Kernel Heap - A memory heap lives in both host context.
35 * - Tagged ring-3 heap.
36 * - Page pools - Primarily used by PGM for shadow page tables.
37 * - Locked process memory - Guest RAM and other. (reduce/obsolete this)
38 * - Physical guest memory (RAM & ROM) - Moving to PGM. (obsolete this)
39 *
40 * The global memory manager (GMM) is the global counter part / partner of MM.
41 * MM will provide therefore ring-3 callable interfaces for some of the GMM APIs
42 * related to resource tracking (PGM is the user).
43 *
44 * @see grp_mm
45 *
46 *
47 * @section sec_mm_hma Hypervisor Memory Area - Obsolete in 6.1
48 *
49 * The HMA is used when executing in raw-mode. We borrow, with the help of
50 * PGMMap, some unused space (one or more page directory entries to be precise)
51 * in the guest's virtual memory context. PGM will monitor the guest's virtual
52 * address space for changes and relocate the HMA when required.
53 *
54 * To give some idea what's in the HMA, study the 'info hma' output:
55 * @verbatim
56VBoxDbg> info hma
57Hypervisor Memory Area (HMA) Layout: Base 00000000a0000000, 0x00800000 bytes
5800000000a05cc000-00000000a05cd000 DYNAMIC fence
5900000000a05c4000-00000000a05cc000 DYNAMIC Dynamic mapping
6000000000a05c3000-00000000a05c4000 DYNAMIC fence
6100000000a05b8000-00000000a05c3000 DYNAMIC Paging
6200000000a05b6000-00000000a05b8000 MMIO2 0000000000000000 PCNetShMem
6300000000a0536000-00000000a05b6000 MMIO2 0000000000000000 VGA VRam
6400000000a0523000-00000000a0536000 00002aaab3d0c000 LOCKED autofree alloc once (PDM_DEVICE)
6500000000a0522000-00000000a0523000 DYNAMIC fence
6600000000a051e000-00000000a0522000 00002aaab36f5000 LOCKED autofree VBoxDD2RC.rc
6700000000a051d000-00000000a051e000 DYNAMIC fence
6800000000a04eb000-00000000a051d000 00002aaab36c3000 LOCKED autofree VBoxDDRC.rc
6900000000a04ea000-00000000a04eb000 DYNAMIC fence
7000000000a04e9000-00000000a04ea000 00002aaab36c2000 LOCKED autofree ram range (High ROM Region)
7100000000a04e8000-00000000a04e9000 DYNAMIC fence
7200000000a040e000-00000000a04e8000 00002aaab2e6d000 LOCKED autofree VMMRC.rc
7300000000a0208000-00000000a040e000 00002aaab2c67000 LOCKED autofree alloc once (PATM)
7400000000a01f7000-00000000a0208000 00002aaaab92d000 LOCKED autofree alloc once (SELM)
7500000000a01e7000-00000000a01f7000 00002aaaab5e8000 LOCKED autofree alloc once (SELM)
7600000000a01e6000-00000000a01e7000 DYNAMIC fence
7700000000a01e5000-00000000a01e6000 00002aaaab5e7000 HCPHYS 00000000c363c000 Core Code
7800000000a01e4000-00000000a01e5000 DYNAMIC fence
7900000000a01e3000-00000000a01e4000 00002aaaaab26000 HCPHYS 00000000619cf000 GIP
8000000000a01a2000-00000000a01e3000 00002aaaabf32000 LOCKED autofree alloc once (PGM_PHYS)
8100000000a016b000-00000000a01a2000 00002aaab233f000 LOCKED autofree alloc once (PGM_POOL)
8200000000a016a000-00000000a016b000 DYNAMIC fence
8300000000a0165000-00000000a016a000 DYNAMIC CR3 mapping
8400000000a0164000-00000000a0165000 DYNAMIC fence
8500000000a0024000-00000000a0164000 00002aaab215f000 LOCKED autofree Heap
8600000000a0023000-00000000a0024000 DYNAMIC fence
8700000000a0001000-00000000a0023000 00002aaab1d24000 LOCKED pages VM
8800000000a0000000-00000000a0001000 DYNAMIC fence
89 @endverbatim
90 *
91 *
92 * @section sec_mm_hyperheap Hypervisor Heap
93 *
94 * The heap is accessible from ring-3, ring-0 and the raw-mode context. That
95 * said, it's not necessarily mapped into ring-0 on if that's possible since we
96 * don't wish to waste kernel address space without a good reason.
97 *
98 * Allocations within the heap are always in the same relative position in all
99 * contexts, so, it's possible to use offset based linking. In fact, the heap is
100 * internally using offset based linked lists tracking heap blocks. We use
101 * offset linked AVL trees and lists in a lot of places where share structures
102 * between RC, R3 and R0, so this is a strict requirement of the heap. However
103 * this means that we cannot easily extend the heap since the extension won't
104 * necessarily be in the continuation of the current heap memory in all (or any)
105 * context.
106 *
107 * All allocations are tagged. Per tag allocation statistics will be maintaining
108 * and exposed thru STAM when VBOX_WITH_STATISTICS is defined.
109 *
110 *
111 * @section sec_mm_r3heap Tagged Ring-3 Heap
112 *
113 * The ring-3 heap is a wrapper around the RTMem API adding allocation
114 * statistics and automatic cleanup on VM destruction.
115 *
116 * Per tag allocation statistics will be maintaining and exposed thru STAM when
117 * VBOX_WITH_STATISTICS is defined.
118 *
119 *
120 * @section sec_mm_page Page Pool
121 *
122 * The MM manages a page pool from which other components can allocate locked,
123 * page aligned and page sized memory objects. The pool provides facilities to
124 * convert back and forth between (host) physical and virtual addresses (within
125 * the pool of course). Several specialized interfaces are provided for the most
126 * common allocations and conversions to save the caller from bothersome casting
127 * and extra parameter passing.
128 *
129 *
130 * @section sec_mm_locked Locked Process Memory
131 *
132 * MM manages the locked process memory. This is used for a bunch of things
133 * (count the LOCKED entries in the 'info hma' output found in @ref sec_mm_hma),
134 * but the main consumer of memory is currently for guest RAM. There is an
135 * ongoing rewrite that will move all the guest RAM allocation to PGM and
136 * GMM.
137 *
138 * The locking of memory is something doing in cooperation with the VirtualBox
139 * support driver, SUPDrv (aka. VBoxDrv), thru the support library API,
140 * SUPR3 (aka. SUPLib).
141 *
142 *
143 * @section sec_mm_phys Physical Guest Memory
144 *
145 * MM is currently managing the physical memory for the guest. It relies heavily
146 * on PGM for this. There is an ongoing rewrite that will move this to PGM. (The
147 * rewrite is driven by the need for more flexible guest ram allocation, but
148 * also motivated by the fact that MMPhys is just adding stupid bureaucracy and
149 * that MMR3PhysReserve is a totally weird artifact that must go away.)
150 *
151 */
152
153
154/*********************************************************************************************************************************
155* Header Files *
156*********************************************************************************************************************************/
157#define LOG_GROUP LOG_GROUP_MM
158#include <VBox/vmm/mm.h>
159#include <VBox/vmm/pgm.h>
160#include <VBox/vmm/cfgm.h>
161#include <VBox/vmm/ssm.h>
162#include <VBox/vmm/gmm.h>
163#include "MMInternal.h"
164#include <VBox/vmm/vm.h>
165#include <VBox/vmm/uvm.h>
166#include <VBox/err.h>
167#include <VBox/param.h>
168
169#include <VBox/log.h>
170#include <iprt/alloc.h>
171#include <iprt/assert.h>
172#include <iprt/string.h>
173
174
175/*********************************************************************************************************************************
176* Defined Constants And Macros *
177*********************************************************************************************************************************/
178/** The current saved state version of MM. */
179#define MM_SAVED_STATE_VERSION 2
180
181
182/*********************************************************************************************************************************
183* Internal Functions *
184*********************************************************************************************************************************/
185static DECLCALLBACK(int) mmR3Save(PVM pVM, PSSMHANDLE pSSM);
186static DECLCALLBACK(int) mmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass);
187
188
189
190
191/**
192 * Initializes the MM members of the UVM.
193 *
194 * This is currently only the ring-3 heap.
195 *
196 * @returns VBox status code.
197 * @param pUVM Pointer to the user mode VM structure.
198 */
199VMMR3DECL(int) MMR3InitUVM(PUVM pUVM)
200{
201 /*
202 * Assert sizes and order.
203 */
204 AssertCompile(sizeof(pUVM->mm.s) <= sizeof(pUVM->mm.padding));
205 AssertRelease(sizeof(pUVM->mm.s) <= sizeof(pUVM->mm.padding));
206 Assert(!pUVM->mm.s.pHeap);
207
208 /*
209 * Init the heap.
210 */
211 int rc = mmR3HeapCreateU(pUVM, &pUVM->mm.s.pHeap);
212 if (RT_SUCCESS(rc))
213 return VINF_SUCCESS;
214 return rc;
215}
216
217
218/**
219 * Initializes the MM.
220 *
221 * MM is managing the virtual address space (among other things) and
222 * setup the hypervisor memory area mapping in the VM structure and
223 * the hypervisor alloc-only-heap. Assuming the current init order
224 * and components the hypervisor memory area looks like this:
225 * -# VM Structure.
226 * -# Hypervisor alloc only heap (also call Hypervisor memory region).
227 * -# Core code.
228 *
229 * MM determines the virtual address of the hypervisor memory area by
230 * checking for location at previous run. If that property isn't available
231 * it will choose a default starting location, currently 0xa0000000.
232 *
233 * @returns VBox status code.
234 * @param pVM The cross context VM structure.
235 */
236VMMR3DECL(int) MMR3Init(PVM pVM)
237{
238 LogFlow(("MMR3Init\n"));
239
240 /*
241 * Assert alignment, sizes and order.
242 */
243 AssertRelease(!(RT_UOFFSETOF(VM, mm.s) & 31));
244 AssertRelease(sizeof(pVM->mm.s) <= sizeof(pVM->mm.padding));
245
246 /*
247 * Register the saved state data unit.
248 */
249 int rc = SSMR3RegisterInternal(pVM, "mm", 1, MM_SAVED_STATE_VERSION, sizeof(uint32_t) * 2,
250 NULL, NULL, NULL,
251 NULL, mmR3Save, NULL,
252 NULL, mmR3Load, NULL);
253 if (RT_SUCCESS(rc))
254 {
255 /*
256 * Statistics.
257 */
258 STAM_REG(pVM, &pVM->mm.s.cBasePages, STAMTYPE_U64, "/MM/Reserved/cBasePages", STAMUNIT_PAGES, "Reserved number of base pages, ROM and Shadow ROM included.");
259 STAM_REG(pVM, &pVM->mm.s.cHandyPages, STAMTYPE_U32, "/MM/Reserved/cHandyPages", STAMUNIT_PAGES, "Reserved number of handy pages.");
260 STAM_REG(pVM, &pVM->mm.s.cShadowPages, STAMTYPE_U32, "/MM/Reserved/cShadowPages", STAMUNIT_PAGES, "Reserved number of shadow paging pages.");
261 STAM_REG(pVM, &pVM->mm.s.cFixedPages, STAMTYPE_U32, "/MM/Reserved/cFixedPages", STAMUNIT_PAGES, "Reserved number of fixed pages (MMIO2).");
262 STAM_REG(pVM, &pVM->mm.s.cbRamBase, STAMTYPE_U64, "/MM/cbRamBase", STAMUNIT_BYTES, "Size of the base RAM.");
263
264 return rc;
265 }
266
267 return rc;
268}
269
270
271#if defined(VBOX_VMM_TARGET_ARMV8)
272/**
273 * This sets up the RAM ranges from the VM config.
274 *
275 * @returns VBox status code.
276 * @param pVM The cross context VM structure.
277 * @param pMMCfg Pointer to the CFGM node holding the RAM config.
278 *
279 * @note On ARM there is no "standard" way to handle RAM like on x86.
280 * Every SoC can have multiple RAM regions scattered across the whole
281 * address space so we have to be much more flexible here.
282 */
283static int mmR3InitRamArmV8(PVM pVM, PCFGMNODE pMMCfg)
284{
285 int rc = VINF_SUCCESS;
286 PCFGMNODE pMemRegions = CFGMR3GetChild(pMMCfg, "MemRegions");
287
288 pVM->mm.s.cbRamBase = 0;
289 pVM->mm.s.cbRamHole = 0;
290 pVM->mm.s.cbRamBelow4GB = 0;
291 pVM->mm.s.cbRamAbove4GB = 0;
292
293 for (PCFGMNODE pCur = CFGMR3GetFirstChild(pMemRegions); pCur; pCur = CFGMR3GetNextChild(pCur))
294 {
295 char szMemRegion[512]; RT_ZERO(szMemRegion);
296 rc = CFGMR3GetName(pCur, &szMemRegion[0], sizeof(szMemRegion));
297 if (RT_FAILURE(rc))
298 {
299 LogRel(("Failed to query memory region name -> %Rrc\n", rc));
300 break;
301 }
302
303 uint64_t u64GCPhysStart = 0;
304 rc = CFGMR3QueryU64(pCur, "GCPhysStart", &u64GCPhysStart);
305 if (RT_FAILURE(rc))
306 {
307 LogRel(("Failed to query \"GCPhysStart\" for memory region %s -> %Rrc\n", szMemRegion, rc));
308 break;
309 }
310
311 uint64_t u64MemSize = 0;
312 rc = CFGMR3QueryU64(pCur, "Size", &u64MemSize);
313 if (RT_FAILURE(rc))
314 {
315 LogRel(("Failed to query \"Size\" for memory region %s -> %Rrc\n", szMemRegion, rc));
316 break;
317 }
318
319 rc = PGMR3PhysRegisterRam(pVM, u64GCPhysStart, u64MemSize, "Conventional RAM");
320 if (RT_FAILURE(rc))
321 {
322 LogRel(("Failed to register memory region '%s' GCPhysStart=%RGp Size=%#RX64 -> %Rrc\n",
323 szMemRegion, u64GCPhysStart, u64MemSize));
324 break;
325 }
326
327 pVM->mm.s.cbRamBase += u64MemSize;
328 if (u64GCPhysStart >= _4G)
329 pVM->mm.s.cbRamAbove4GB += u64MemSize;
330 else if (u64GCPhysStart + u64MemSize > _4G)
331 {
332 uint64_t cbRamAbove4GB = (u64GCPhysStart + u64MemSize) - _4G;
333 pVM->mm.s.cbRamAbove4GB += cbRamAbove4GB;
334 pVM->mm.s.cbRamBelow4GB += (u64MemSize - cbRamAbove4GB);
335 }
336 else
337 pVM->mm.s.cbRamBelow4GB += (uint32_t)u64MemSize;
338 }
339
340 return rc;
341}
342#endif
343
344
345/**
346 * Initializes the MM parts which depends on PGM being initialized.
347 *
348 * @returns VBox status code.
349 * @param pVM The cross context VM structure.
350 * @remark No cleanup necessary since MMR3Term() will be called on failure.
351 */
352VMMR3DECL(int) MMR3InitPaging(PVM pVM)
353{
354 LogFlow(("MMR3InitPaging:\n"));
355
356 /*
357 * Query the CFGM values.
358 */
359 int rc;
360 PCFGMNODE pMMCfg = CFGMR3GetChild(CFGMR3GetRoot(pVM), "MM");
361 if (!pMMCfg)
362 {
363 rc = CFGMR3InsertNode(CFGMR3GetRoot(pVM), "MM", &pMMCfg);
364 AssertRCReturn(rc, rc);
365 }
366
367#if defined(VBOX_VMM_TARGET_ARMV8)
368 rc = mmR3InitRamArmV8(pVM, pMMCfg);
369#else
370 /** @cfgm{/RamSize, uint64_t, 0, 16TB, 0}
371 * Specifies the size of the base RAM that is to be set up during
372 * VM initialization.
373 */
374 uint64_t cbRam;
375 rc = CFGMR3QueryU64(CFGMR3GetRoot(pVM), "RamSize", &cbRam);
376 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
377 cbRam = 0;
378 else
379 AssertMsgRCReturn(rc, ("Configuration error: Failed to query integer \"RamSize\", rc=%Rrc.\n", rc), rc);
380 AssertLogRelMsg(!(cbRam & ~X86_PTE_PAE_PG_MASK), ("%RGp X86_PTE_PAE_PG_MASK=%RX64\n", cbRam, X86_PTE_PAE_PG_MASK));
381 AssertLogRelMsgReturn(cbRam <= GMM_GCPHYS_LAST, ("cbRam=%RGp GMM_GCPHYS_LAST=%RX64\n", cbRam, GMM_GCPHYS_LAST), VERR_OUT_OF_RANGE);
382 cbRam &= X86_PTE_PAE_PG_MASK;
383 pVM->mm.s.cbRamBase = cbRam;
384
385 /** @cfgm{/RamHoleSize, uint32_t, 0, 4032MB, 512MB}
386 * Specifies the size of the memory hole. The memory hole is used
387 * to avoid mapping RAM to the range normally used for PCI memory regions.
388 * Must be aligned on a 4MB boundary. */
389 uint32_t cbRamHole;
390 rc = CFGMR3QueryU32Def(CFGMR3GetRoot(pVM), "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
391 AssertLogRelMsgRCReturn(rc, ("Configuration error: Failed to query integer \"RamHoleSize\", rc=%Rrc.\n", rc), rc);
392 AssertLogRelMsgReturn(cbRamHole <= 4032U * _1M,
393 ("Configuration error: \"RamHoleSize\"=%#RX32 is too large.\n", cbRamHole), VERR_OUT_OF_RANGE);
394 AssertLogRelMsgReturn(cbRamHole > 16 * _1M,
395 ("Configuration error: \"RamHoleSize\"=%#RX32 is too large.\n", cbRamHole), VERR_OUT_OF_RANGE);
396 AssertLogRelMsgReturn(!(cbRamHole & (_4M - 1)),
397 ("Configuration error: \"RamHoleSize\"=%#RX32 is misaligned.\n", cbRamHole), VERR_OUT_OF_RANGE);
398 uint64_t const offRamHole = _4G - cbRamHole;
399 if (cbRam < offRamHole)
400 Log(("MM: %RU64 bytes of RAM\n", cbRam));
401 else
402 Log(("MM: %RU64 bytes of RAM with a hole at %RU64 up to 4GB.\n", cbRam, offRamHole));
403
404 /** @cfgm{/MM/Policy, string, no overcommitment}
405 * Specifies the policy to use when reserving memory for this VM. The recognized
406 * value is 'no overcommitment' (default). See GMMPOLICY.
407 */
408 GMMOCPOLICY enmOcPolicy;
409 char sz[64];
410 rc = CFGMR3QueryString(CFGMR3GetRoot(pVM), "Policy", sz, sizeof(sz));
411 if (RT_SUCCESS(rc))
412 {
413 if ( !RTStrICmp(sz, "no_oc")
414 || !RTStrICmp(sz, "no overcommitment"))
415 enmOcPolicy = GMMOCPOLICY_NO_OC;
416 else
417 return VMSetError(pVM, VERR_INVALID_PARAMETER, RT_SRC_POS, "Unknown \"MM/Policy\" value \"%s\"", sz);
418 }
419 else if (rc == VERR_CFGM_VALUE_NOT_FOUND)
420 enmOcPolicy = GMMOCPOLICY_NO_OC;
421 else
422 AssertMsgFailedReturn(("Configuration error: Failed to query string \"MM/Policy\", rc=%Rrc.\n", rc), rc);
423
424 /** @cfgm{/MM/Priority, string, normal}
425 * Specifies the memory priority of this VM. The priority comes into play when the
426 * system is overcommitted and the VMs needs to be milked for memory. The recognized
427 * values are 'low', 'normal' (default) and 'high'. See GMMPRIORITY.
428 */
429 GMMPRIORITY enmPriority;
430 rc = CFGMR3QueryString(CFGMR3GetRoot(pVM), "Priority", sz, sizeof(sz));
431 if (RT_SUCCESS(rc))
432 {
433 if (!RTStrICmp(sz, "low"))
434 enmPriority = GMMPRIORITY_LOW;
435 else if (!RTStrICmp(sz, "normal"))
436 enmPriority = GMMPRIORITY_NORMAL;
437 else if (!RTStrICmp(sz, "high"))
438 enmPriority = GMMPRIORITY_HIGH;
439 else
440 return VMSetError(pVM, VERR_INVALID_PARAMETER, RT_SRC_POS, "Unknown \"MM/Priority\" value \"%s\"", sz);
441 }
442 else if (rc == VERR_CFGM_VALUE_NOT_FOUND)
443 enmPriority = GMMPRIORITY_NORMAL;
444 else
445 AssertMsgFailedReturn(("Configuration error: Failed to query string \"MM/Priority\", rc=%Rrc.\n", rc), rc);
446
447 /*
448 * Make the initial memory reservation with GMM.
449 */
450 uint32_t const cbUma = _1M - 640*_1K;
451 uint64_t cBasePages = ((cbRam - cbUma) >> GUEST_PAGE_SHIFT) + pVM->mm.s.cBasePages;
452 rc = GMMR3InitialReservation(pVM,
453 RT_MAX(cBasePages + pVM->mm.s.cHandyPages, 1),
454 RT_MAX(pVM->mm.s.cShadowPages, 1),
455 RT_MAX(pVM->mm.s.cFixedPages, 1),
456 enmOcPolicy,
457 enmPriority);
458 if (RT_FAILURE(rc))
459 {
460 if (rc == VERR_GMM_MEMORY_RESERVATION_DECLINED)
461 return VMSetError(pVM, rc, RT_SRC_POS,
462 N_("Insufficient free memory to start the VM (cbRam=%#RX64 enmOcPolicy=%d enmPriority=%d)"),
463 cbRam, enmOcPolicy, enmPriority);
464 return VMSetError(pVM, rc, RT_SRC_POS, "GMMR3InitialReservation(,%#RX64,0,0,%d,%d)",
465 cbRam >> GUEST_PAGE_SHIFT, enmOcPolicy, enmPriority);
466 }
467
468 /*
469 * If RamSize is 0 we're done now.
470 */
471 if (cbRam < GUEST_PAGE_SIZE)
472 {
473 Log(("MM: No RAM configured\n"));
474 return VINF_SUCCESS;
475 }
476
477 /*
478 * Setup the base ram (PGM).
479 */
480 pVM->mm.s.cbRamHole = cbRamHole;
481 pVM->mm.s.cbRamBelow4GB = cbRam > offRamHole ? offRamHole : cbRam;
482 pVM->mm.s.cbRamAbove4GB = cbRam > offRamHole ? cbRam - offRamHole : 0;
483
484 /* First the conventional memory: */
485 rc = PGMR3PhysRegisterRam(pVM, 0, RT_MIN(cbRam, 640*_1K), "Conventional RAM");
486 if (RT_SUCCESS(rc) && cbRam >= _1M)
487 {
488 /* The extended memory from 1MiB to 2MiB to align better with large pages in NEM mode: */
489 rc = PGMR3PhysRegisterRam(pVM, _1M, RT_MIN(_1M, cbRam - _1M), "Extended RAM, 1-2MB");
490 if (cbRam > _2M)
491 {
492 /* The extended memory from 2MiB up to 4GiB: */
493 rc = PGMR3PhysRegisterRam(pVM, _2M, pVM->mm.s.cbRamBelow4GB - _2M, "Extended RAM, >2MB");
494
495 /* Then all the memory above 4GiB: */
496 if (RT_SUCCESS(rc) && pVM->mm.s.cbRamAbove4GB > 0)
497 rc = PGMR3PhysRegisterRam(pVM, _4G, cbRam - offRamHole, "Above 4GB Base RAM");
498 }
499 }
500#endif /* !VBOX_VMM_TARGET_ARMV8 */
501
502 /*
503 * Enabled mmR3UpdateReservation here since we don't want the
504 * PGMR3PhysRegisterRam calls above mess things up.
505 */
506 pVM->mm.s.fDoneMMR3InitPaging = true;
507#if !defined(VBOX_VMM_TARGET_ARMV8)
508 AssertMsg(pVM->mm.s.cBasePages == cBasePages || RT_FAILURE(rc), ("%RX64 != %RX64\n", pVM->mm.s.cBasePages, cBasePages));
509#endif
510
511 LogFlow(("MMR3InitPaging: returns %Rrc\n", rc));
512 return rc;
513}
514
515
516/**
517 * Terminates the MM.
518 *
519 * Termination means cleaning up and freeing all resources,
520 * the VM it self is at this point powered off or suspended.
521 *
522 * @returns VBox status code.
523 * @param pVM The cross context VM structure.
524 */
525VMMR3DECL(int) MMR3Term(PVM pVM)
526{
527 RT_NOREF(pVM);
528 return VINF_SUCCESS;
529}
530
531
532/**
533 * Terminates the UVM part of MM.
534 *
535 * Termination means cleaning up and freeing all resources,
536 * the VM it self is at this point powered off or suspended.
537 *
538 * @returns VBox status code.
539 * @param pUVM Pointer to the user mode VM structure.
540 */
541VMMR3DECL(void) MMR3TermUVM(PUVM pUVM)
542{
543 /*
544 * Destroy the heap.
545 */
546 mmR3HeapDestroy(pUVM->mm.s.pHeap);
547 pUVM->mm.s.pHeap = NULL;
548}
549
550
551/**
552 * Execute state save operation.
553 *
554 * @returns VBox status code.
555 * @param pVM The cross context VM structure.
556 * @param pSSM SSM operation handle.
557 */
558static DECLCALLBACK(int) mmR3Save(PVM pVM, PSSMHANDLE pSSM)
559{
560 LogFlow(("mmR3Save:\n"));
561
562 /* (PGM saves the physical memory.) */
563 SSMR3PutU64(pSSM, pVM->mm.s.cBasePages);
564 return SSMR3PutU64(pSSM, pVM->mm.s.cbRamBase);
565}
566
567
568/**
569 * Execute state load operation.
570 *
571 * @returns VBox status code.
572 * @param pVM The cross context VM structure.
573 * @param pSSM SSM operation handle.
574 * @param uVersion Data layout version.
575 * @param uPass The data pass.
576 */
577static DECLCALLBACK(int) mmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
578{
579 LogFlow(("mmR3Load:\n"));
580 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
581
582 /*
583 * Validate version.
584 */
585 if ( SSM_VERSION_MAJOR_CHANGED(uVersion, MM_SAVED_STATE_VERSION)
586 || !uVersion)
587 {
588 AssertMsgFailed(("mmR3Load: Invalid version uVersion=%d!\n", uVersion));
589 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
590 }
591
592 /*
593 * Check the cBasePages and cbRamBase values.
594 */
595 int rc;
596 RTUINT cb1;
597
598 /* cBasePages (ignored) */
599 uint64_t cGuestPages;
600 if (uVersion >= 2)
601 rc = SSMR3GetU64(pSSM, &cGuestPages);
602 else
603 {
604 rc = SSMR3GetUInt(pSSM, &cb1);
605 cGuestPages = cb1 >> GUEST_PAGE_SHIFT;
606 }
607 if (RT_FAILURE(rc))
608 return rc;
609
610 /* cbRamBase */
611 uint64_t cb;
612 if (uVersion != 1)
613 rc = SSMR3GetU64(pSSM, &cb);
614 else
615 {
616 rc = SSMR3GetUInt(pSSM, &cb1);
617 cb = cb1;
618 }
619 if (RT_FAILURE(rc))
620 return rc;
621 AssertLogRelMsgReturn(cb == pVM->mm.s.cbRamBase,
622 ("Memory configuration has changed. cbRamBase=%#RX64 save=%#RX64\n", pVM->mm.s.cbRamBase, cb),
623 VERR_SSM_LOAD_MEMORY_SIZE_MISMATCH);
624
625 /* (PGM restores the physical memory.) */
626 return rc;
627}
628
629
630/**
631 * Updates GMM with memory reservation changes.
632 *
633 * Called when MM::cbRamRegistered, MM::cShadowPages or MM::cFixedPages changes.
634 *
635 * @returns VBox status code - see GMMR0UpdateReservation.
636 * @param pVM The cross context VM structure.
637 */
638int mmR3UpdateReservation(PVM pVM)
639{
640 VM_ASSERT_EMT(pVM);
641 if (pVM->mm.s.fDoneMMR3InitPaging)
642 return GMMR3UpdateReservation(pVM,
643 RT_MAX(pVM->mm.s.cBasePages + pVM->mm.s.cHandyPages, 1),
644 RT_MAX(pVM->mm.s.cShadowPages, 1),
645 RT_MAX(pVM->mm.s.cFixedPages, 1));
646 return VINF_SUCCESS;
647}
648
649
650/**
651 * Interface for PGM to increase the reservation of RAM and ROM pages.
652 *
653 * This can be called before MMR3InitPaging.
654 *
655 * @returns VBox status code. Will set VM error on failure.
656 * @param pVM The cross context VM structure.
657 * @param cAddBasePages The number of pages to add.
658 */
659VMMR3DECL(int) MMR3IncreaseBaseReservation(PVM pVM, uint64_t cAddBasePages)
660{
661 uint64_t cOld = pVM->mm.s.cBasePages;
662 pVM->mm.s.cBasePages += cAddBasePages;
663 LogFlow(("MMR3IncreaseBaseReservation: +%RU64 (%RU64 -> %RU64)\n", cAddBasePages, cOld, pVM->mm.s.cBasePages));
664 int rc = mmR3UpdateReservation(pVM);
665 if (RT_FAILURE(rc))
666 {
667 VMSetError(pVM, rc, RT_SRC_POS, N_("Failed to reserved physical memory for the RAM (%#RX64 -> %#RX64 + %#RX32)"),
668 cOld, pVM->mm.s.cBasePages, pVM->mm.s.cHandyPages);
669 pVM->mm.s.cBasePages = cOld;
670 }
671 return rc;
672}
673
674
675/**
676 * Interface for PGM to make reservations for handy pages in addition to the
677 * base memory.
678 *
679 * This can be called before MMR3InitPaging.
680 *
681 * @returns VBox status code. Will set VM error on failure.
682 * @param pVM The cross context VM structure.
683 * @param cHandyPages The number of handy pages.
684 */
685VMMR3DECL(int) MMR3ReserveHandyPages(PVM pVM, uint32_t cHandyPages)
686{
687 AssertReturn(!pVM->mm.s.cHandyPages, VERR_WRONG_ORDER);
688
689 pVM->mm.s.cHandyPages = cHandyPages;
690 LogFlow(("MMR3ReserveHandyPages: %RU32 (base %RU64)\n", pVM->mm.s.cHandyPages, pVM->mm.s.cBasePages));
691 int rc = mmR3UpdateReservation(pVM);
692 if (RT_FAILURE(rc))
693 {
694 VMSetError(pVM, rc, RT_SRC_POS, N_("Failed to reserved physical memory for the RAM (%#RX64 + %#RX32)"),
695 pVM->mm.s.cBasePages, pVM->mm.s.cHandyPages);
696 pVM->mm.s.cHandyPages = 0;
697 }
698 return rc;
699}
700
701
702/**
703 * Interface for PGM to adjust the reservation of fixed pages.
704 *
705 * This can be called before MMR3InitPaging.
706 *
707 * @returns VBox status code. Will set VM error on failure.
708 * @param pVM The cross context VM structure.
709 * @param cDeltaFixedPages The number of guest pages to add (positive) or
710 * subtract (negative).
711 * @param pszDesc Some description associated with the reservation.
712 */
713VMMR3DECL(int) MMR3AdjustFixedReservation(PVM pVM, int32_t cDeltaFixedPages, const char *pszDesc)
714{
715 const uint32_t cOld = pVM->mm.s.cFixedPages;
716 pVM->mm.s.cFixedPages += cDeltaFixedPages;
717 LogFlow(("MMR3AdjustFixedReservation: %d (%u -> %u)\n", cDeltaFixedPages, cOld, pVM->mm.s.cFixedPages));
718 int rc = mmR3UpdateReservation(pVM);
719 if (RT_FAILURE(rc))
720 {
721 VMSetError(pVM, rc, RT_SRC_POS, N_("Failed to reserve physical memory (%#x -> %#x; %s)"),
722 cOld, pVM->mm.s.cFixedPages, pszDesc);
723 pVM->mm.s.cFixedPages = cOld;
724 }
725 return rc;
726}
727
728
729/**
730 * Interface for PGM to update the reservation of shadow pages.
731 *
732 * This can be called before MMR3InitPaging.
733 *
734 * @returns VBox status code. Will set VM error on failure.
735 * @param pVM The cross context VM structure.
736 * @param cShadowPages The new page count.
737 */
738VMMR3DECL(int) MMR3UpdateShadowReservation(PVM pVM, uint32_t cShadowPages)
739{
740 const uint32_t cOld = pVM->mm.s.cShadowPages;
741 pVM->mm.s.cShadowPages = cShadowPages;
742 LogFlow(("MMR3UpdateShadowReservation: %u -> %u\n", cOld, pVM->mm.s.cShadowPages));
743 int rc = mmR3UpdateReservation(pVM);
744 if (RT_FAILURE(rc))
745 {
746 VMSetError(pVM, rc, RT_SRC_POS, N_("Failed to reserve physical memory for shadow page tables (%#x -> %#x)"), cOld, pVM->mm.s.cShadowPages);
747 pVM->mm.s.cShadowPages = cOld;
748 }
749 return rc;
750}
751
752
753/**
754 * Get the size of the base RAM.
755 * This usually means the size of the first contiguous block of physical memory.
756 *
757 * @returns The guest base RAM size.
758 * @param pVM The cross context VM structure.
759 * @thread Any.
760 *
761 * @deprecated
762 */
763VMMR3DECL(uint64_t) MMR3PhysGetRamSize(PVM pVM)
764{
765 return pVM->mm.s.cbRamBase;
766}
767
768
769/**
770 * Get the size of RAM below 4GB (starts at address 0x00000000).
771 *
772 * @returns The amount of RAM below 4GB in bytes.
773 * @param pVM The cross context VM structure.
774 * @thread Any.
775 */
776VMMR3DECL(uint32_t) MMR3PhysGetRamSizeBelow4GB(PVM pVM)
777{
778 VM_ASSERT_VALID_EXT_RETURN(pVM, UINT32_MAX);
779 return pVM->mm.s.cbRamBelow4GB;
780}
781
782
783/**
784 * Get the size of RAM above 4GB (starts at address 0x000100000000).
785 *
786 * @returns The amount of RAM above 4GB in bytes.
787 * @param pVM The cross context VM structure.
788 * @thread Any.
789 */
790VMMR3DECL(uint64_t) MMR3PhysGetRamSizeAbove4GB(PVM pVM)
791{
792 VM_ASSERT_VALID_EXT_RETURN(pVM, UINT64_MAX);
793 return pVM->mm.s.cbRamAbove4GB;
794}
795
796
797/**
798 * Get the size of the RAM hole below 4GB.
799 *
800 * @returns Size in bytes.
801 * @param pVM The cross context VM structure.
802 * @thread Any.
803 */
804VMMR3DECL(uint32_t) MMR3PhysGet4GBRamHoleSize(PVM pVM)
805{
806 VM_ASSERT_VALID_EXT_RETURN(pVM, UINT32_MAX);
807 return pVM->mm.s.cbRamHole;
808}
809
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use