VirtualBox

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

Last change on this file since 17698 was 17372, checked in by vboxsync, 16 years ago

PGM,MM: Made VBOX_WITH_NEW_PHYS_CODE compile and link.

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