VirtualBox

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

Last change on this file since 5474 was 4901, checked in by vboxsync, 17 years ago

don't kill the heap, it'll be taken care of in VMR3Create if we fail.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 18.8 KB
Line 
1/* $Id: MM.cpp 4901 2007-09-19 13:29:27Z vboxsync $ */
2/** @file
3 * MM - Memory Monitor(/Manager).
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/** @page pg_mm MM - The Memory Monitor/Manager
20 *
21 * It seems like this is going to be the entity taking care of memory allocations
22 * and the locking of physical memory for a VM. MM will track these allocations and
23 * pinnings so pointer conversions, memory read and write, and correct clean up can
24 * be done.
25 *
26 * Memory types:
27 * - Hypervisor Memory Area (HMA).
28 * - Page tables.
29 * - Physical pages.
30 *
31 * The first two types are not accessible using the generic conversion functions
32 * for GC memory, there are special functions for these.
33 *
34 *
35 * A decent structure for this component need to be eveloped as we see usage. One
36 * or two rewrites is probabaly needed to get it right...
37 *
38 *
39 *
40 * @section Hypervisor Memory Area
41 *
42 * The hypervisor is give 4MB of space inside the guest, we assume that we can
43 * steal an page directory entry from the guest OS without cause trouble. In
44 * addition to these 4MB we'll be mapping memory for the graphics emulation,
45 * but that will be an independant mapping.
46 *
47 * The 4MBs are divided into two main parts:
48 * -# The static code and data
49 * -# The shortlived page mappings.
50 *
51 * The first part is used for the VM structure, the core code (VMMSwitch),
52 * GC modules, and the alloc-only-heap. The size will be determined at a
53 * later point but initially we'll say 2MB of locked memory, most of which
54 * is non contiguous physically.
55 *
56 * The second part is used for mapping pages to the hypervisor. We'll be using
57 * a simple round robin when doing these mappings. This means that no-one can
58 * assume that a mapping hangs around for very long, while the managing of the
59 * pages are very simple.
60 *
61 *
62 *
63 * @section Page Pool
64 *
65 * The MM manages a per VM page pool from which other components can allocate
66 * locked, page aligned and page granular memory objects. The pool provides
67 * facilities to convert back and forth between physical and virtual addresses
68 * (within the pool of course). Several specialized interfaces are provided
69 * for the most common alloctions and convertions to save the caller from
70 * bothersome casting and extra parameter passing.
71 *
72 *
73 */
74
75
76
77/*******************************************************************************
78* Header Files *
79*******************************************************************************/
80#define LOG_GROUP LOG_GROUP_MM
81#include <VBox/mm.h>
82#include <VBox/pgm.h>
83#include <VBox/cfgm.h>
84#include <VBox/ssm.h>
85#include "MMInternal.h"
86#include <VBox/vm.h>
87#include <VBox/err.h>
88#include <VBox/param.h>
89
90#include <VBox/log.h>
91#include <iprt/alloc.h>
92#include <iprt/assert.h>
93#include <iprt/string.h>
94
95
96/*******************************************************************************
97* Internal Functions *
98*******************************************************************************/
99static int mmR3Term(PVM pVM, bool fKeepTheHeap);
100static DECLCALLBACK(int) mmR3Save(PVM pVM, PSSMHANDLE pSSM);
101static DECLCALLBACK(int) mmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version);
102
103
104
105/**
106 * Initializes the MM.
107 *
108 * MM is managing the virtual address space (among other things) and
109 * setup the hypvervisor memory area mapping in the VM structure and
110 * the hypvervisor alloc-only-heap. Assuming the current init order
111 * and components the hypvervisor memory area looks like this:
112 * -# VM Structure.
113 * -# Hypervisor alloc only heap (also call Hypervisor memory region).
114 * -# Core code.
115 *
116 * MM determins the virtual address of the hypvervisor memory area by
117 * checking for location at previous run. If that property isn't available
118 * it will choose a default starting location, currently 0xe0000000.
119 *
120 * @returns VBox status code.
121 * @param pVM The VM to operate on.
122 */
123MMR3DECL(int) MMR3Init(PVM pVM)
124{
125 LogFlow(("MMR3Init\n"));
126
127 /*
128 * Assert alignment, sizes and order.
129 */
130 AssertRelease(!(RT_OFFSETOF(VM, mm.s) & 31));
131 AssertRelease(sizeof(pVM->mm.s) <= sizeof(pVM->mm.padding));
132 AssertMsg(pVM->mm.s.offVM == 0, ("Already initialized!\n"));
133
134 /*
135 * Init the structure.
136 */
137 pVM->mm.s.offVM = RT_OFFSETOF(VM, mm);
138 pVM->mm.s.offLookupHyper = NIL_OFFSET;
139
140 /*
141 * Init the heap (may already be initialized already if someone used it).
142 */
143 if (!pVM->mm.s.pHeap)
144 {
145 int rc = mmr3HeapCreate(pVM, &pVM->mm.s.pHeap);
146 if (!VBOX_SUCCESS(rc))
147 return rc;
148 }
149
150 /*
151 * Init the page pool.
152 */
153 int rc = mmr3PagePoolInit(pVM);
154 if (VBOX_SUCCESS(rc))
155 {
156 /*
157 * Init the hypervisor related stuff.
158 */
159 rc = mmr3HyperInit(pVM);
160 if (VBOX_SUCCESS(rc))
161 {
162 /*
163 * Register the saved state data unit.
164 */
165 rc = SSMR3RegisterInternal(pVM, "mm", 1, 1, sizeof(uint32_t) * 2,
166 NULL, mmR3Save, NULL,
167 NULL, mmR3Load, NULL);
168 if (VBOX_SUCCESS(rc))
169 return rc;
170
171 /* .... failure .... */
172 }
173 }
174 mmR3Term(pVM, true /* keep the heap */);
175 return rc;
176}
177
178
179/**
180 * Initializes the MM parts which depends on PGM being initialized.
181 *
182 * @returns VBox status code.
183 * @param pVM The VM to operate on.
184 * @remark No cleanup necessary since MMR3Term() will be called on failure.
185 */
186MMR3DECL(int) MMR3InitPaging(PVM pVM)
187{
188 LogFlow(("MMR3InitPaging:\n"));
189 bool fPreAlloc;
190 int rc = CFGMR3QueryBool(CFGMR3GetRoot(pVM), "RamPreAlloc", &fPreAlloc);
191 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
192 fPreAlloc = false;
193 else
194 AssertMsgRCReturn(rc, ("Configuration error: Failed to query integer \"RamPreAlloc\", rc=%Vrc.\n", rc), rc);
195
196 uint64_t cbRam;
197 rc = CFGMR3QueryU64(CFGMR3GetRoot(pVM), "RamSize", &cbRam);
198 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
199 cbRam = 0;
200 if (VBOX_SUCCESS(rc) || rc == VERR_CFGM_VALUE_NOT_FOUND)
201 {
202 if (cbRam < PAGE_SIZE)
203 {
204 Log(("MM: No RAM configured\n"));
205 return VINF_SUCCESS;
206 }
207#ifdef PGM_DYNAMIC_RAM_ALLOC
208 Log(("MM: %llu bytes of RAM%s\n", cbRam, fPreAlloc ? " (PreAlloc)" : ""));
209 pVM->mm.s.pvRamBaseHC = 0; /** @todo obsolete */
210 pVM->mm.s.cbRamBase = cbRam & PAGE_BASE_GC_MASK;
211 rc = MMR3PhysRegister(pVM, pVM->mm.s.pvRamBaseHC, 0, pVM->mm.s.cbRamBase, MM_RAM_FLAGS_DYNAMIC_ALLOC, "Main Memory");
212 if (VBOX_SUCCESS(rc))
213 {
214 /* Allocate the first chunk, as we'll map ROM ranges there. */
215 rc = PGM3PhysGrowRange(pVM, (RTGCPHYS)0);
216 if (VBOX_SUCCESS(rc))
217 {
218 /* Should we preallocate the entire guest RAM? */
219 if (fPreAlloc)
220 {
221 for (RTGCPHYS GCPhys = PGM_DYNAMIC_CHUNK_SIZE; GCPhys < cbRam; GCPhys += PGM_DYNAMIC_CHUNK_SIZE)
222 {
223 rc = PGM3PhysGrowRange(pVM, GCPhys);
224 if (VBOX_FAILURE(rc))
225 return rc;
226 }
227 }
228 return rc;
229 }
230 }
231#else
232 unsigned cPages = cbRam >> PAGE_SHIFT;
233 Log(("MM: %llu bytes of RAM (%d pages)\n", cbRam, cPages));
234 rc = SUPPageAlloc(cPages, &pVM->mm.s.pvRamBaseHC);
235 if (VBOX_SUCCESS(rc))
236 {
237 pVM->mm.s.cbRamBase = cPages << PAGE_SHIFT;
238 rc = MMR3PhysRegister(pVM, pVM->mm.s.pvRamBaseHC, 0, pVM->mm.s.cbRamBase, 0, "Main Memory");
239 if (VBOX_SUCCESS(rc))
240 return rc;
241 SUPPageFree(pVM->mm.s.pvRamBaseHC);
242 }
243 else
244 LogRel(("MMR3InitPage: Failed to allocate %u bytes of RAM! rc=%Vrc\n", cPages << PAGE_SHIFT));
245#endif
246 }
247 else
248 AssertMsgFailed(("Configuration error: Failed to query integer \"RamSize\", rc=%Vrc.\n", rc));
249
250 LogFlow(("MMR3InitPaging: returns %Vrc\n", rc));
251 return rc;
252}
253
254
255/**
256 * Terminates the MM.
257 *
258 * Termination means cleaning up and freeing all resources,
259 * the VM it self is at this point powered off or suspended.
260 *
261 * @returns VBox status code.
262 * @param pVM The VM to operate on.
263 */
264MMR3DECL(int) MMR3Term(PVM pVM)
265{
266 return mmR3Term(pVM, false /* free the heap */);
267}
268
269
270/**
271 * Worker for MMR3Term and MMR3Init.
272 *
273 * The tricky bit here is that we must not destroy the heap if we're
274 * called from MMR3Init, otherwise we'll get into trouble when
275 * CFGMR3Term is called later in the bailout process.
276 *
277 * @returns VBox status code.
278 * @param pVM The VM to operate on.
279 * @param fKeepTheHeap Whether or not to keep the heap.
280 */
281static int mmR3Term(PVM pVM, bool fKeepTheHeap)
282{
283 /*
284 * Destroy the page pool. (first as it used the hyper heap)
285 */
286 mmr3PagePoolTerm(pVM);
287
288 /*
289 * Release locked memory.
290 * (Associated record are released by the heap.)
291 */
292 PMMLOCKEDMEM pLockedMem = pVM->mm.s.pLockedMem;
293 while (pLockedMem)
294 {
295 int rc = SUPPageUnlock(pLockedMem->pv);
296 AssertMsgRC(rc, ("SUPPageUnlock(%p) -> rc=%d\n", pLockedMem->pv, rc));
297 switch (pLockedMem->eType)
298 {
299 case MM_LOCKED_TYPE_HYPER:
300 rc = SUPPageFree(pLockedMem->pv, pLockedMem->cb >> PAGE_SHIFT);
301 AssertMsgRC(rc, ("SUPPageFree(%p) -> rc=%d\n", pLockedMem->pv, rc));
302 break;
303 case MM_LOCKED_TYPE_HYPER_NOFREE:
304 case MM_LOCKED_TYPE_HYPER_PAGES:
305 case MM_LOCKED_TYPE_PHYS:
306 /* nothing to do. */
307 break;
308 }
309 /* next */
310 pLockedMem = pLockedMem->pNext;
311 }
312
313 /*
314 * Destroy the heap if requested.
315 */
316 if (!fKeepTheHeap)
317 {
318 mmr3HeapDestroy(pVM->mm.s.pHeap);
319 pVM->mm.s.pHeap = NULL;
320 }
321
322 /*
323 * Zero stuff to detect after termination use of the MM interface
324 */
325 pVM->mm.s.offLookupHyper = NIL_OFFSET;
326 pVM->mm.s.pLockedMem = NULL;
327 pVM->mm.s.pHyperHeapHC = NULL; /* freed above. */
328 pVM->mm.s.pHyperHeapGC = 0; /* freed above. */
329 pVM->mm.s.offVM = 0; /* init assertion on this */
330
331 return 0;
332}
333
334
335/**
336 * Reset notification.
337 *
338 * MM will reload shadow ROMs into RAM at this point and make
339 * the ROM writable.
340 *
341 * @param pVM The VM handle.
342 */
343MMR3DECL(void) MMR3Reset(PVM pVM)
344{
345 mmR3PhysRomReset(pVM);
346}
347
348
349/**
350 * Execute state save operation.
351 *
352 * @returns VBox status code.
353 * @param pVM VM Handle.
354 * @param pSSM SSM operation handle.
355 */
356static DECLCALLBACK(int) mmR3Save(PVM pVM, PSSMHANDLE pSSM)
357{
358 LogFlow(("mmR3Save:\n"));
359
360 /* (PGM saves the physical memory.) */
361 SSMR3PutUInt(pSSM, pVM->mm.s.cbRAMSize);
362 return SSMR3PutUInt(pSSM, pVM->mm.s.cbRamBase);
363}
364
365
366/**
367 * Execute state load operation.
368 *
369 * @returns VBox status code.
370 * @param pVM VM Handle.
371 * @param pSSM SSM operation handle.
372 * @param u32Version Data layout version.
373 */
374static DECLCALLBACK(int) mmR3Load(PVM pVM, PSSMHANDLE pSSM, uint32_t u32Version)
375{
376 LogFlow(("mmR3Load:\n"));
377
378 /*
379 * Validate version.
380 */
381 if (u32Version != 1)
382 {
383 Log(("mmR3Load: Invalid version u32Version=%d!\n", u32Version));
384 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
385 }
386
387 /*
388 * Check the cbRAMSize and cbRamBase values.
389 */
390 RTUINT cb;
391 int rc = SSMR3GetUInt(pSSM, &cb);
392 if (VBOX_FAILURE(rc))
393 return rc;
394 if (cb != pVM->mm.s.cbRAMSize)
395 {
396 Log(("mmR3Load: Memory configuration has changed. cbRAMSize=%#x save %#x\n", pVM->mm.s.cbRAMSize, cb));
397 return VERR_SSM_LOAD_MEMORY_SIZE_MISMATCH;
398 }
399
400 rc = SSMR3GetUInt(pSSM, &cb);
401 if (VBOX_FAILURE(rc))
402 return rc;
403 if (cb != pVM->mm.s.cbRamBase)
404 {
405 Log(("mmR3Load: Memory configuration has changed. cbRamBase=%#x save %#x\n", pVM->mm.s.cbRamBase, cb));
406 return VERR_SSM_LOAD_MEMORY_SIZE_MISMATCH;
407 }
408
409 /* PGM restores the physical memory. */
410 return rc;
411}
412
413
414/**
415 * Locks physical memory which backs a virtual memory range (HC) adding
416 * the required records to the pLockedMem list.
417 *
418 * @returns VBox status code.
419 * @param pVM The VM handle.
420 * @param pv Pointer to memory range which shall be locked down.
421 * This pointer is page aligned.
422 * @param cb Size of memory range (in bytes). This size is page aligned.
423 * @param eType Memory type.
424 * @param ppLockedMem Where to store the pointer to the created locked memory record.
425 * This is optional, pass NULL if not used.
426 * @param fSilentFailure Don't raise an error when unsuccessful. Upper layer with deal with it.
427 */
428int mmr3LockMem(PVM pVM, void *pv, size_t cb, MMLOCKEDTYPE eType, PMMLOCKEDMEM *ppLockedMem, bool fSilentFailure)
429{
430 Assert(RT_ALIGN_P(pv, PAGE_SIZE) == pv);
431 Assert(RT_ALIGN_Z(cb, PAGE_SIZE) == cb);
432
433 if (ppLockedMem)
434 *ppLockedMem = NULL;
435
436 /*
437 * Allocate locked mem structure.
438 */
439 unsigned cPages = cb >> PAGE_SHIFT;
440 AssertReturn(cPages == (cb >> PAGE_SHIFT), VERR_OUT_OF_RANGE);
441 PMMLOCKEDMEM pLockedMem = (PMMLOCKEDMEM)MMR3HeapAlloc(pVM, MM_TAG_MM, RT_OFFSETOF(MMLOCKEDMEM, aPhysPages[cPages]));
442 if (!pLockedMem)
443 return VERR_NO_MEMORY;
444 pLockedMem->pv = pv;
445 pLockedMem->cb = cb;
446 pLockedMem->eType = eType;
447 memset(&pLockedMem->u, 0, sizeof(pLockedMem->u));
448
449 /*
450 * Lock the memory.
451 */
452 int rc = SUPPageLock(pv, cPages, &pLockedMem->aPhysPages[0]);
453 if (VBOX_SUCCESS(rc))
454 {
455 /*
456 * Setup the reserved field.
457 */
458 PSUPPAGE pPhysPage = &pLockedMem->aPhysPages[0];
459 for (unsigned c = cPages; c > 0; c--, pPhysPage++)
460 pPhysPage->uReserved = (RTHCUINTPTR)pLockedMem;
461
462 /*
463 * Insert into the list.
464 *
465 * ASSUME no protected needed here as only one thread in the system can possibly
466 * be doing this. No other threads will walk this list either we assume.
467 */
468 pLockedMem->pNext = pVM->mm.s.pLockedMem;
469 pVM->mm.s.pLockedMem = pLockedMem;
470 /* Set return value. */
471 if (ppLockedMem)
472 *ppLockedMem = pLockedMem;
473 }
474 else
475 {
476 AssertMsgFailed(("SUPPageLock failed with rc=%d\n", rc));
477 MMR3HeapFree(pLockedMem);
478 if (!fSilentFailure)
479 rc = VMSetError(pVM, rc, RT_SRC_POS, N_("Failed to lock %d bytes of host memory (out of memory)"), cb);
480 }
481
482 return rc;
483}
484
485
486/**
487 * Maps a part of or an entire locked memory region into the guest context.
488 *
489 * @returns VBox status.
490 * God knows what happens if we fail...
491 * @param pVM VM handle.
492 * @param pLockedMem Locked memory structure.
493 * @param Addr GC Address where to start the mapping.
494 * @param iPage Page number in the locked memory region.
495 * @param cPages Number of pages to map.
496 * @param fFlags See the fFlags argument of PGR3Map().
497 */
498int mmr3MapLocked(PVM pVM, PMMLOCKEDMEM pLockedMem, RTGCPTR Addr, unsigned iPage, size_t cPages, unsigned fFlags)
499{
500 /*
501 * Adjust ~0 argument
502 */
503 if (cPages == ~(size_t)0)
504 cPages = (pLockedMem->cb >> PAGE_SHIFT) - iPage;
505 Assert(cPages != ~0U);
506 /* no incorrect arguments are accepted */
507 Assert(RT_ALIGN_GCPT(Addr, PAGE_SIZE, RTGCPTR) == Addr);
508 AssertMsg(iPage < (pLockedMem->cb >> PAGE_SHIFT), ("never even think about giving me a bad iPage(=%d)\n", iPage));
509 AssertMsg(iPage + cPages <= (pLockedMem->cb >> PAGE_SHIFT), ("never even think about giving me a bad cPages(=%d)\n", cPages));
510
511 /*
512 * Map the the pages.
513 */
514 PSUPPAGE pPhysPage = &pLockedMem->aPhysPages[iPage];
515 while (cPages)
516 {
517 RTHCPHYS HCPhys = pPhysPage->Phys;
518 int rc = PGMMap(pVM, Addr, HCPhys, PAGE_SIZE, fFlags);
519 if (VBOX_FAILURE(rc))
520 {
521 /** @todo how the hell can we do a proper bailout here. */
522 return rc;
523 }
524
525 /* next */
526 cPages--;
527 iPage++;
528 pPhysPage++;
529 Addr += PAGE_SIZE;
530 }
531
532 return VINF_SUCCESS;
533}
534
535
536/**
537 * Convert HC Physical address to HC Virtual address.
538 *
539 * @returns VBox status.
540 * @param pVM VM handle.
541 * @param HCPhys The host context virtual address.
542 * @param ppv Where to store the resulting address.
543 * @thread The Emulation Thread.
544 */
545MMR3DECL(int) MMR3HCPhys2HCVirt(PVM pVM, RTHCPHYS HCPhys, void **ppv)
546{
547 /*
548 * Try page tables.
549 */
550 int rc = MMPagePhys2PageTry(pVM, HCPhys, ppv);
551 if (VBOX_SUCCESS(rc))
552 return rc;
553
554 /*
555 * Iterate the locked memory - very slow.
556 */
557 uint32_t off = HCPhys & PAGE_OFFSET_MASK;
558 HCPhys &= X86_PTE_PAE_PG_MASK;
559 for (PMMLOCKEDMEM pCur = pVM->mm.s.pLockedMem; pCur; pCur = pCur->pNext)
560 {
561 size_t iPage = pCur->cb >> PAGE_SHIFT;
562 while (iPage-- > 0)
563 if ((pCur->aPhysPages[iPage].Phys & X86_PTE_PAE_PG_MASK) == HCPhys)
564 {
565 *ppv = (char *)pCur->pv + (iPage << PAGE_SHIFT) + off;
566 return VINF_SUCCESS;
567 }
568 }
569 /* give up */
570 return VERR_INVALID_POINTER;
571}
572
573
574/**
575 * Read memory from GC virtual address using the current guest CR3.
576 *
577 * @returns VBox status.
578 * @param pVM VM handle.
579 * @param pvDst Destination address (HC of course).
580 * @param GCPtr GC virtual address.
581 * @param cb Number of bytes to read.
582 */
583MMR3DECL(int) MMR3ReadGCVirt(PVM pVM, void *pvDst, RTGCPTR GCPtr, size_t cb)
584{
585 if (GCPtr - pVM->mm.s.pvHyperAreaGC < pVM->mm.s.cbHyperArea)
586 return MMR3HyperReadGCVirt(pVM, pvDst, GCPtr, cb);
587 return PGMPhysReadGCPtr(pVM, pvDst, GCPtr, cb);
588}
589
590
591/**
592 * Write to memory at GC virtual address translated using the current guest CR3.
593 *
594 * @returns VBox status.
595 * @param pVM VM handle.
596 * @param GCPtrDst GC virtual address.
597 * @param pvSrc The source address (HC of course).
598 * @param cb Number of bytes to read.
599 */
600MMR3DECL(int) MMR3WriteGCVirt(PVM pVM, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb)
601{
602 if (GCPtrDst - pVM->mm.s.pvHyperAreaGC < pVM->mm.s.cbHyperArea)
603 return VERR_ACCESS_DENIED;
604 return PGMPhysWriteGCPtr(pVM, GCPtrDst, pvSrc, cb);
605}
606
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