VirtualBox

source: vbox/trunk/src/VBox/VMM/MMPhys.cpp@ 13538

Last change on this file since 13538 was 12989, checked in by vboxsync, 16 years ago

VMM + VBox/cdefs.h: consolidated all the XYZ*DECLS of the VMM into VMM*DECL. Removed dead DECL and IN_XYZ* macros.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 18.7 KB
Line 
1/* $Id: MMPhys.cpp 12989 2008-10-06 02:15:39Z vboxsync $ */
2/** @file
3 * MM - Memory Manager - Physical Memory.
4 *
5 * @remarks This will will be eliminated ASAP, all physical memory management
6 * is done by PGM now.
7 */
8
9/*
10 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 *
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
21 * Clara, CA 95054 USA or visit http://www.sun.com if you need
22 * additional information or have any questions.
23 */
24
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29#define LOG_GROUP LOG_GROUP_MM_PHYS
30#include <VBox/mm.h>
31#include <VBox/pgm.h>
32#include <VBox/rem.h>
33#include "MMInternal.h"
34#include <VBox/vm.h>
35
36#include <VBox/log.h>
37#include <VBox/param.h>
38#include <VBox/err.h>
39#include <iprt/alloc.h>
40#include <iprt/assert.h>
41#include <iprt/string.h>
42
43
44/**
45 * Register externally allocated RAM for the virtual machine.
46 *
47 * The memory registered with the VM thru this interface must not be freed
48 * before the virtual machine has been destroyed. Bad things may happen... :-)
49 *
50 * @return VBox status code.
51 * @param pVM VM handle.
52 * @param pvRam Virtual address of the guest's physical memory range Must be page aligned.
53 * @param GCPhys The physical address the ram shall be registered at.
54 * @param cb Size of the memory. Must be page aligend.
55 * @param fFlags Flags of the MM_RAM_FLAGS_* defines.
56 * @param pszDesc Description of the memory.
57 */
58VMMR3DECL(int) MMR3PhysRegister(PVM pVM, void *pvRam, RTGCPHYS GCPhys, unsigned cb, unsigned fFlags, const char *pszDesc)
59{
60 return MMR3PhysRegisterEx(pVM, pvRam, GCPhys, cb, fFlags, MM_PHYS_TYPE_NORMAL, pszDesc);
61}
62
63
64/**
65 * Register externally allocated RAM for the virtual machine.
66 *
67 * The memory registered with the VM thru this interface must not be freed
68 * before the virtual machine has been destroyed. Bad things may happen... :-)
69 *
70 * @return VBox status code.
71 * @param pVM VM handle.
72 * @param pvRam Virtual address of the guest's physical memory range Must be page aligned.
73 * @param GCPhys The physical address the ram shall be registered at.
74 * @param cb Size of the memory. Must be page aligend.
75 * @param fFlags Flags of the MM_RAM_FLAGS_* defines.
76 * @param enmType Physical range type (MM_PHYS_TYPE_*)
77 * @param pszDesc Description of the memory.
78 * @thread The Emulation Thread.
79 *
80 * @deprecated For the old dynamic allocation code only. Will be removed with VBOX_WITH_NEW_PHYS_CODE.
81 */
82/** @todo this function description is not longer up-to-date */
83VMMR3DECL(int) MMR3PhysRegisterEx(PVM pVM, void *pvRam, RTGCPHYS GCPhys, unsigned cb, unsigned fFlags, MMPHYSREG enmType, const char *pszDesc)
84{
85 int rc = VINF_SUCCESS;
86
87 Log(("MMR3PhysRegister: pvRam=%p GCPhys=%VGp cb=%#x fFlags=%#x\n", pvRam, GCPhys, cb, fFlags));
88
89 /*
90 * Validate input.
91 */
92 AssertMsg(pVM, ("Invalid VM pointer\n"));
93 if (pvRam)
94 AssertReturn(RT_ALIGN_P(pvRam, PAGE_SIZE) == pvRam, VERR_INVALID_PARAMETER);
95 else
96 AssertReturn(fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC, VERR_INVALID_PARAMETER);
97 AssertReturn(RT_ALIGN_T(GCPhys, PAGE_SIZE, RTGCPHYS) == GCPhys, VERR_INVALID_PARAMETER);
98 AssertReturn(RT_ALIGN_Z(cb, PAGE_SIZE) == cb, VERR_INVALID_PARAMETER);
99 AssertReturn(enmType == MM_PHYS_TYPE_NORMAL || enmType == MM_PHYS_TYPE_DYNALLOC_CHUNK, VERR_INVALID_PARAMETER);
100 RTGCPHYS GCPhysLast = GCPhys + (cb - 1);
101 AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
102
103
104 /*
105 * Check for conflicts.
106 *
107 * We do not support overlapping physical memory regions yet,
108 * even if that's what the MM_RAM_FLAGS_MMIO2 flags is trying to
109 * tell us to do. Provided that all MMIO2 addresses are very high
110 * there is no real danger we'll be able to assign so much memory
111 * for a guest that it'll ever be a problem.
112 */
113 AssertMsg(!(fFlags & MM_RAM_FLAGS_MMIO2) || GCPhys > 0xc0000000,
114 ("MMIO2 addresses should be above 3GB for avoiding conflicts with real RAM.\n"));
115 PMMLOCKEDMEM pCur = pVM->mm.s.pLockedMem;
116 while (pCur)
117 {
118 if ( pCur->eType == MM_LOCKED_TYPE_PHYS
119 && ( GCPhys - pCur->u.phys.GCPhys < pCur->cb
120 || pCur->u.phys.GCPhys - GCPhys < cb)
121 )
122 {
123 AssertMsgFailed(("Conflicting RAM range. Existing %#x LB%#x, Req %#x LB%#x\n",
124 pCur->u.phys.GCPhys, pCur->cb, GCPhys, cb));
125 return VERR_MM_RAM_CONFLICT;
126 }
127
128 /* next */
129 pCur = pCur->pNext;
130 }
131
132
133 /* Dynamic/on-demand allocation of backing memory? */
134 if (fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC)
135 {
136 /*
137 * Register the ram with PGM.
138 */
139 rc = PGMR3PhysRegister(pVM, pvRam, GCPhys, cb, fFlags, NULL, pszDesc);
140 if (VBOX_SUCCESS(rc))
141 {
142 if (fFlags == MM_RAM_FLAGS_DYNAMIC_ALLOC)
143 pVM->mm.s.cBasePages += cb >> PAGE_SHIFT;
144
145 REMR3NotifyPhysRamRegister(pVM, GCPhys, cb, fFlags);
146 return rc;
147 }
148 }
149 else
150 {
151 /*
152 * Lock the memory. (fully allocated by caller)
153 */
154 PMMLOCKEDMEM pLockedMem;
155 rc = mmR3LockMem(pVM, pvRam, cb, MM_LOCKED_TYPE_PHYS, &pLockedMem, enmType == MM_PHYS_TYPE_DYNALLOC_CHUNK /* fSilentFailure */);
156 if (VBOX_SUCCESS(rc))
157 {
158 pLockedMem->u.phys.GCPhys = GCPhys;
159
160 /*
161 * We set any page flags specified.
162 */
163 if (fFlags)
164 for (unsigned i = 0; i < cb >> PAGE_SHIFT; i++)
165 pLockedMem->aPhysPages[i].Phys |= fFlags;
166
167 /*
168 * Register the ram with PGM.
169 */
170 if (enmType == MM_PHYS_TYPE_NORMAL)
171 {
172 rc = PGMR3PhysRegister(pVM, pvRam, pLockedMem->u.phys.GCPhys, cb, fFlags, &pLockedMem->aPhysPages[0], pszDesc);
173 if (VBOX_SUCCESS(rc))
174 {
175 if (!fFlags)
176 pVM->mm.s.cBasePages += cb >> PAGE_SHIFT;
177
178 REMR3NotifyPhysRamRegister(pVM, GCPhys, cb, fFlags);
179 return rc;
180 }
181 }
182 else
183 {
184 Assert(enmType == MM_PHYS_TYPE_DYNALLOC_CHUNK);
185 return PGMR3PhysRegisterChunk(pVM, pvRam, pLockedMem->u.phys.GCPhys, cb, fFlags, &pLockedMem->aPhysPages[0], pszDesc);
186 }
187 }
188 /* Cleanup is done in VM destruction to which failure of this function will lead. */
189 /* Not true in case of MM_PHYS_TYPE_DYNALLOC_CHUNK */
190 }
191
192 return rc;
193}
194
195
196/**
197 * Register a ROM (BIOS) region.
198 *
199 * It goes without saying that this is read-only memory. The memory region must be
200 * in unassigned memory. I.e. from the top of the address space or on the PC in
201 * the 0xa0000-0xfffff range.
202 *
203 * @returns VBox status.
204 * @param pVM VM Handle.
205 * @param pDevIns The device instance owning the ROM region.
206 * @param GCPhys First physical address in the range.
207 * Must be page aligned!
208 * @param cbRange The size of the range (in bytes).
209 * Must be page aligned!
210 * @param pvBinary Pointer to the binary data backing the ROM image.
211 * This must be cbRange bytes big.
212 * It will be copied and doesn't have to stick around.
213 * It will be copied and doesn't have to stick around if fShadow is clear.
214 * @param fShadow Whether to emulate ROM shadowing. This involves leaving
215 * the ROM writable for a while during the POST and refreshing
216 * it at reset. When this flag is set, the memory pointed to by
217 * pvBinary has to stick around for the lifespan of the VM.
218 * @param pszDesc Pointer to description string. This must not be freed.
219 * @remark There is no way to remove the rom, automatically on device cleanup or
220 * manually from the device yet. At present I doubt we need such features...
221 */
222VMMR3DECL(int) MMR3PhysRomRegister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTUINT cbRange, const void *pvBinary,
223 bool fShadow, const char *pszDesc)
224{
225 /*
226 * Validate input.
227 */
228 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
229 AssertReturn(RT_ALIGN_T(GCPhys, PAGE_SIZE, RTGCPHYS) == GCPhys, VERR_INVALID_PARAMETER);
230 AssertReturn(RT_ALIGN(cbRange, PAGE_SIZE) == cbRange, VERR_INVALID_PARAMETER);
231 RTGCPHYS GCPhysLast = GCPhys + (cbRange - 1);
232 AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
233 AssertPtrReturn(pvBinary, VERR_INVALID_PARAMETER);
234
235
236 /*
237 * Check if this can fit in an existing range.
238 *
239 * We do not handle the case where a new chunk of locked memory is
240 * required to accommodate the ROM since we assume MMR3PhysReserve()
241 * have been called to reserve the memory first.
242 *
243 * To make things even simpler, the pages in question must be
244 * marked as reserved.
245 */
246 PMMLOCKEDMEM pCur = pVM->mm.s.pLockedMem;
247 for ( ; pCur; pCur = pCur->pNext)
248 if ( pCur->eType == MM_LOCKED_TYPE_PHYS
249 && GCPhys - pCur->u.phys.GCPhys < pCur->cb)
250 break;
251 if (!pCur)
252 {
253 AssertMsgFailed(("No physical range was found matching the ROM location (%#VGp LB%#x)\n", GCPhys, cbRange));
254 return VERR_INVALID_PARAMETER;
255 }
256 if (GCPhysLast - pCur->u.phys.GCPhys >= pCur->cb)
257 {
258 AssertMsgFailed(("The ROM range (%#VGp LB%#x) was crossing the end of the physical range (%#VGp LB%#x)\n",
259 GCPhys, cbRange, pCur->u.phys.GCPhys, pCur->cb));
260 return VERR_INVALID_PARAMETER;
261 }
262
263 /* flags must be all reserved. */
264 unsigned iPage = (GCPhys - pCur->u.phys.GCPhys) >> PAGE_SHIFT;
265 unsigned iPageEnd = cbRange >> PAGE_SHIFT;
266 for (; iPage < iPageEnd; iPage++)
267 if ( (pCur->aPhysPages[iPage].Phys & (MM_RAM_FLAGS_RESERVED | MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO | MM_RAM_FLAGS_MMIO2))
268 != MM_RAM_FLAGS_RESERVED)
269 {
270 AssertMsgFailed(("Flags conflict at %VGp, HCPhys=%VHp.\n", pCur->u.phys.GCPhys + (iPage << PAGE_SHIFT), pCur->aPhysPages[iPage].Phys));
271 return VERR_INVALID_PARAMETER;
272 }
273
274 /*
275 * Copy the ram and update the flags.
276 */
277 iPage = (GCPhys - pCur->u.phys.GCPhys) >> PAGE_SHIFT;
278 void *pvCopy = (char *)pCur->pv + (iPage << PAGE_SHIFT);
279 memcpy(pvCopy, pvBinary, cbRange);
280
281 const unsigned fSet = fShadow ? MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO2 : MM_RAM_FLAGS_ROM;
282 for (; iPage < iPageEnd; iPage++)
283 {
284 pCur->aPhysPages[iPage].Phys &= ~MM_RAM_FLAGS_RESERVED;
285 pCur->aPhysPages[iPage].Phys |= fSet;
286 }
287 int rc = PGMR3PhysSetFlags(pVM, GCPhys, cbRange, fSet, ~MM_RAM_FLAGS_RESERVED);
288 AssertRC(rc);
289 if (VBOX_SUCCESS(rc))
290 {
291 /*
292 * To prevent the shadow page table mappings from being RW in raw-mode, we
293 * must currently employ a little hack. We register an write access handler
294 * and thereby ensures a RO mapping of the pages. This is NOT very nice,
295 * and wasn't really my intention when writing the code, consider it a PGM bug.
296 *
297 * ASSUMES that REMR3NotifyPhysRomRegister doesn't call cpu_register_physical_memory
298 * when there is no HC handler. The result would probably be immediate boot failure.
299 */
300 rc = PGMR3HandlerPhysicalRegister(pVM, PGMPHYSHANDLERTYPE_PHYSICAL_WRITE, GCPhys, GCPhys + cbRange - 1,
301 NULL, NULL,
302 NULL, "pgmPhysRomWriteHandler", 0,
303 NULL, "pgmPhysRomWriteHandler", 0, pszDesc);
304 AssertRC(rc);
305 }
306
307 /*
308 * Create a ROM range it so we can make a 'info rom' thingy and more importantly
309 * reload and protect/unprotect shadow ROM correctly.
310 */
311 if (VBOX_SUCCESS(rc))
312 {
313 PMMROMRANGE pRomRange = (PMMROMRANGE)MMR3HeapAlloc(pVM, MM_TAG_MM, sizeof(*pRomRange));
314 AssertReturn(pRomRange, VERR_NO_MEMORY);
315 pRomRange->GCPhys = GCPhys;
316 pRomRange->cbRange = cbRange;
317 pRomRange->pszDesc = pszDesc;
318 pRomRange->fShadow = fShadow;
319 pRomRange->fWritable = fShadow;
320 pRomRange->pvBinary = fShadow ? pvBinary : NULL;
321 pRomRange->pvCopy = pvCopy;
322
323 /* sort it for 'info rom' readability. */
324 PMMROMRANGE pPrev = NULL;
325 PMMROMRANGE pCur = pVM->mm.s.pRomHead;
326 while (pCur && pCur->GCPhys < GCPhys)
327 {
328 pPrev = pCur;
329 pCur = pCur->pNext;
330 }
331 pRomRange->pNext = pCur;
332 if (pPrev)
333 pPrev->pNext = pRomRange;
334 else
335 pVM->mm.s.pRomHead = pRomRange;
336 }
337
338 REMR3NotifyPhysRomRegister(pVM, GCPhys, cbRange, pvCopy, fShadow);
339 return rc; /* we're sloppy with error cleanup here, but we're toast anyway if this fails. */
340}
341
342
343/**
344 * Reserve physical address space for ROM and MMIO ranges.
345 *
346 * @returns VBox status code.
347 * @param pVM VM Handle.
348 * @param GCPhys Start physical address.
349 * @param cbRange The size of the range.
350 * @param pszDesc Description string.
351 */
352VMMR3DECL(int) MMR3PhysReserve(PVM pVM, RTGCPHYS GCPhys, RTUINT cbRange, const char *pszDesc)
353{
354 /*
355 * Validate input.
356 */
357 AssertReturn(RT_ALIGN_T(GCPhys, PAGE_SIZE, RTGCPHYS) == GCPhys, VERR_INVALID_PARAMETER);
358 AssertReturn(RT_ALIGN(cbRange, PAGE_SIZE) == cbRange, VERR_INVALID_PARAMETER);
359 RTGCPHYS GCPhysLast = GCPhys + (cbRange - 1);
360 AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
361
362 /*
363 * Do we have an existing physical address range for the request?
364 */
365 PMMLOCKEDMEM pCur = pVM->mm.s.pLockedMem;
366 for ( ; pCur; pCur = pCur->pNext)
367 if ( pCur->eType == MM_LOCKED_TYPE_PHYS
368 && GCPhys - pCur->u.phys.GCPhys < pCur->cb)
369 break;
370 if (!pCur)
371 {
372 /*
373 * No range, we'll just allocate backing pages and register
374 * them as reserved using the Ram interface.
375 */
376 void *pvPages;
377 int rc = SUPPageAlloc(cbRange >> PAGE_SHIFT, &pvPages);
378 if (VBOX_SUCCESS(rc))
379 {
380 rc = MMR3PhysRegister(pVM, pvPages, GCPhys, cbRange, MM_RAM_FLAGS_RESERVED, pszDesc);
381 if (VBOX_FAILURE(rc))
382 SUPPageFree(pvPages, cbRange >> PAGE_SHIFT);
383 }
384 return rc;
385 }
386 if (GCPhysLast - pCur->u.phys.GCPhys >= pCur->cb)
387 {
388 AssertMsgFailed(("The reserved range (%#VGp LB%#x) was crossing the end of the physical range (%#VGp LB%#x)\n",
389 GCPhys, cbRange, pCur->u.phys.GCPhys, pCur->cb));
390 return VERR_INVALID_PARAMETER;
391 }
392
393 /*
394 * Update the flags.
395 */
396 unsigned iPage = (GCPhys - pCur->u.phys.GCPhys) >> PAGE_SHIFT;
397 unsigned iPageEnd = cbRange >> PAGE_SHIFT;
398 for (; iPage < iPageEnd; iPage++)
399 pCur->aPhysPages[iPage].Phys |= MM_RAM_FLAGS_RESERVED;
400 int rc = PGMR3PhysSetFlags(pVM, GCPhys, cbRange, MM_RAM_FLAGS_RESERVED, ~0);
401 AssertRC(rc);
402
403 REMR3NotifyPhysReserve(pVM, GCPhys, cbRange);
404 return rc;
405}
406
407
408/**
409 * Get the size of the base RAM.
410 * This usually means the size of the first contigous block of physical memory.
411 *
412 * @returns The guest base RAM size.
413 * @param pVM The VM handle.
414 * @thread Any.
415 */
416VMMR3DECL(uint64_t) MMR3PhysGetRamSize(PVM pVM)
417{
418 return pVM->mm.s.cbRamBase;
419}
420
421
422/**
423 * Called by MMR3Reset to reset the shadow ROM.
424 *
425 * Resetting involves reloading the ROM into RAM and make it
426 * wriable again (as it was made read only at the end of the POST).
427 *
428 * @param pVM The VM handle.
429 */
430void mmR3PhysRomReset(PVM pVM)
431{
432 for (PMMROMRANGE pCur = pVM->mm.s.pRomHead; pCur; pCur = pCur->pNext)
433 if (pCur->fShadow)
434 {
435 memcpy(pCur->pvCopy, pCur->pvBinary, pCur->cbRange);
436 if (!pCur->fWritable)
437 {
438 int rc = PGMHandlerPhysicalDeregister(pVM, pCur->GCPhys);
439 AssertRC(rc);
440 pCur->fWritable = true;
441
442 rc = PGMR3PhysSetFlags(pVM, pCur->GCPhys, pCur->cbRange, MM_RAM_FLAGS_MMIO2, ~0); /* ROM -> ROM + MMIO2 */
443 AssertRC(rc);
444
445 REMR3NotifyPhysRomRegister(pVM, pCur->GCPhys, pCur->cbRange, pCur->pvCopy, true /* read-write now */);
446 }
447 }
448}
449
450
451/**
452 * Write-protects a shadow ROM range.
453 *
454 * This is called late in the POST for shadow ROM ranges.
455 *
456 * @returns VBox status code.
457 * @param pVM The VM handle.
458 * @param GCPhys Start of the registered shadow ROM range
459 * @param cbRange The length of the registered shadow ROM range.
460 * This can be NULL (not sure about the BIOS interface yet).
461 */
462VMMR3DECL(int) MMR3PhysRomProtect(PVM pVM, RTGCPHYS GCPhys, RTUINT cbRange)
463{
464 for (PMMROMRANGE pCur = pVM->mm.s.pRomHead; pCur; pCur = pCur->pNext)
465 if ( pCur->GCPhys == GCPhys
466 && ( pCur->cbRange == cbRange
467 || !cbRange))
468 {
469 if (pCur->fWritable)
470 {
471 cbRange = pCur->cbRange;
472 int rc = PGMR3HandlerPhysicalRegister(pVM, PGMPHYSHANDLERTYPE_PHYSICAL_WRITE, GCPhys, GCPhys + cbRange - 1,
473 NULL, NULL,
474 NULL, "pgmPhysRomWriteHandler", 0,
475 NULL, "pgmPhysRomWriteHandler", 0, pCur->pszDesc);
476 AssertRCReturn(rc, rc);
477 pCur->fWritable = false;
478
479 rc = PGMR3PhysSetFlags(pVM, GCPhys, cbRange, 0, ~MM_RAM_FLAGS_MMIO2); /* ROM + MMIO2 -> ROM */
480 AssertRCReturn(rc, rc);
481 /* Don't bother with the MM page flags here because I don't think they are
482 really used beyond conflict checking at ROM, RAM, Reservation, etc. */
483
484 REMR3NotifyPhysRomRegister(pVM, GCPhys, cbRange, pCur->pvCopy, false /* read-only now */);
485 }
486 return VINF_SUCCESS;
487 }
488 AssertMsgFailed(("GCPhys=%VGp cbRange=%#x\n", GCPhys, cbRange));
489 return VERR_INVALID_PARAMETER;
490}
491
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use