VirtualBox

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

Last change on this file since 28 was 23, checked in by vboxsync, 18 years ago

string.h & stdio.h + header cleanups.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 16.9 KB
Line 
1/* $Id: MMPhys.cpp 23 2007-01-15 14:08:28Z vboxsync $ */
2/** @file
3 * MM - Memory Monitor(/Manager) - Physical Memory.
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung 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 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#define LOG_GROUP LOG_GROUP_MM_PHYS
27#include <VBox/mm.h>
28#include <VBox/pgm.h>
29#include <VBox/rem.h>
30#include "MMInternal.h"
31#include <VBox/vm.h>
32
33#include <VBox/log.h>
34#include <VBox/param.h>
35#include <VBox/err.h>
36#include <iprt/alloc.h>
37#include <iprt/assert.h>
38#include <iprt/string.h>
39
40
41/**
42 * Register externally allocated RAM for the virtual machine.
43 *
44 * The memory registered with the VM thru this interface must not be freed
45 * before the virtual machine has been destroyed. Bad things may happen... :-)
46 *
47 * @return VBox status code.
48 * @param pVM VM handle.
49 * @param pvRam Virtual address of the guest's physical memory range Must be page aligned.
50 * @param GCPhys The physical address the ram shall be registered at.
51 * @param cb Size of the memory. Must be page aligend.
52 * @param fFlags Flags of the MM_RAM_FLAGS_* defines.
53 * @param pszDesc Description of the memory.
54 */
55MMR3DECL(int) MMR3PhysRegister(PVM pVM, void *pvRam, RTGCPHYS GCPhys, unsigned cb, unsigned fFlags, const char *pszDesc)
56{
57 return MMR3PhysRegisterEx(pVM, pvRam, GCPhys, cb, fFlags, MM_PHYS_TYPE_NORMAL, pszDesc);
58}
59
60
61/**
62 * Register externally allocated RAM for the virtual machine.
63 *
64 * The memory registered with the VM thru this interface must not be freed
65 * before the virtual machine has been destroyed. Bad things may happen... :-)
66 *
67 * @return VBox status code.
68 * @param pVM VM handle.
69 * @param pvRam Virtual address of the guest's physical memory range Must be page aligned.
70 * @param GCPhys The physical address the ram shall be registered at.
71 * @param cb Size of the memory. Must be page aligend.
72 * @param fFlags Flags of the MM_RAM_FLAGS_* defines.
73 * @param enmType Physical range type (MM_PHYS_TYPE_*)
74 * @param pszDesc Description of the memory.
75 * @thread The Emulation Thread.
76 */
77/** @todo this function description is not longer up-to-date */
78MMR3DECL(int) MMR3PhysRegisterEx(PVM pVM, void *pvRam, RTGCPHYS GCPhys, unsigned cb, unsigned fFlags, MMPHYSREG enmType, const char *pszDesc)
79{
80 int rc = VINF_SUCCESS;
81
82 Log(("MMR3PhysRegister: pvRam=%p GCPhys=%VGp cb=%#x fFlags=%#x\n", pvRam, GCPhys, cb, fFlags));
83
84 /*
85 * Validate input.
86 */
87 AssertMsg(pVM, ("Invalid VM pointer\n"));
88 if (pvRam)
89 AssertReturn(ALIGNP(pvRam, PAGE_SIZE) == pvRam, VERR_INVALID_PARAMETER);
90 else
91 AssertReturn(fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC, VERR_INVALID_PARAMETER);
92 AssertReturn(RT_ALIGN_T(GCPhys, PAGE_SIZE, RTGCPHYS) == GCPhys, VERR_INVALID_PARAMETER);
93 AssertReturn(RT_ALIGN_Z(cb, PAGE_SIZE) == cb, VERR_INVALID_PARAMETER);
94 AssertReturn(enmType == MM_PHYS_TYPE_NORMAL || enmType == MM_PHYS_TYPE_DYNALLOC_CHUNK, VERR_INVALID_PARAMETER);
95 RTGCPHYS GCPhysLast = GCPhys + (cb - 1);
96 AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
97
98
99 /*
100 * Check for conflicts.
101 *
102 * We do not support overlapping physical memory regions yet,
103 * even if that's what the MM_RAM_FLAGS_MMIO2 flags is trying to
104 * tell us to do. Provided that all MMIO2 addresses are very high
105 * there is no real danger we'll be able to assign so much memory
106 * for a guest that it'll ever be a problem.
107 */
108 AssertMsg(!(fFlags & MM_RAM_FLAGS_MMIO2) || GCPhys > 0xc0000000,
109 ("MMIO2 addresses should be above 3GB for avoiding conflicts with real RAM.\n"));
110 PMMLOCKEDMEM pCur = pVM->mm.s.pLockedMem;
111 while (pCur)
112 {
113 if ( pCur->eType == MM_LOCKED_TYPE_PHYS
114 && ( GCPhys - pCur->u.phys.GCPhys < pCur->cb
115 || pCur->u.phys.GCPhys - GCPhys < cb)
116 )
117 {
118 AssertMsgFailed(("Conflicting RAM range. Existing %#x LB%#x, Req %#x LB%#x\n",
119 pCur->u.phys.GCPhys, pCur->cb, GCPhys, cb));
120 return VERR_MM_RAM_CONFLICT;
121 }
122
123 /* next */
124 pCur = pCur->pNext;
125 }
126
127
128 /* Dynamic/on-demand allocation of backing memory? */
129 if (fFlags & MM_RAM_FLAGS_DYNAMIC_ALLOC)
130 {
131 /*
132 * Register the ram with PGM.
133 */
134 rc = PGMR3PhysRegister(pVM, pvRam, GCPhys, cb, fFlags, NULL, pszDesc);
135 if (VBOX_SUCCESS(rc))
136 {
137 if (fFlags == MM_RAM_FLAGS_DYNAMIC_ALLOC)
138 pVM->mm.s.cbRAMSize += cb;
139
140 REMR3NotifyPhysRamRegister(pVM, GCPhys, cb, pvRam, fFlags);
141 return rc;
142 }
143 }
144 else
145 {
146 /*
147 * Lock the memory. (fully allocated by caller)
148 */
149 PMMLOCKEDMEM pLockedMem;
150 rc = mmr3LockMem(pVM, pvRam, cb, MM_LOCKED_TYPE_PHYS, &pLockedMem);
151 if (VBOX_SUCCESS(rc))
152 {
153 pLockedMem->u.phys.GCPhys = GCPhys;
154
155 /*
156 * We set any page flags specified.
157 */
158 if (fFlags)
159 for (unsigned i = 0; i < cb >> PAGE_SHIFT; i++)
160 pLockedMem->aPhysPages[i].Phys |= fFlags;
161
162 /*
163 * Register the ram with PGM.
164 */
165 if (enmType == MM_PHYS_TYPE_NORMAL)
166 {
167 rc = PGMR3PhysRegister(pVM, pvRam, pLockedMem->u.phys.GCPhys, cb, fFlags, &pLockedMem->aPhysPages[0], pszDesc);
168 if (VBOX_SUCCESS(rc))
169 {
170 if (!fFlags)
171 pVM->mm.s.cbRAMSize += cb;
172
173 REMR3NotifyPhysRamRegister(pVM, GCPhys, cb, pvRam, fFlags);
174 return rc;
175 }
176 }
177 else
178 {
179 Assert(enmType == MM_PHYS_TYPE_DYNALLOC_CHUNK);
180 return PGMR3PhysRegisterChunk(pVM, pvRam, pLockedMem->u.phys.GCPhys, cb, fFlags, &pLockedMem->aPhysPages[0], pszDesc);
181 }
182 }
183 /* Cleanup is done in VM destruction to which failure of this function will lead. */
184 }
185
186 return rc;
187}
188
189
190/**
191 * Relocate previously registered externally allocated RAM for the virtual machine.
192 *
193 * Use this only for MMIO ranges or the guest will become very confused.
194 * The memory registered with the VM thru this interface must not be freed
195 * before the virtual machine has been destroyed. Bad things may happen... :-)
196 *
197 * @return VBox status code.
198 * @param pVM VM handle.
199 * @param GCPhysOld The physical address the ram was registered at.
200 * @param GCPhysNew The physical address the ram shall be registered at.
201 * @param cb Size of the memory. Must be page aligend.
202 */
203MMR3DECL(int) MMR3PhysRelocate(PVM pVM, RTGCPHYS GCPhysOld, RTGCPHYS GCPhysNew, unsigned cb)
204{
205 Log(("MMR3PhysRelocate: GCPhysOld=%VGp GCPhysNew=%VGp cb=%#x\n", GCPhysOld, GCPhysNew, cb));
206
207 /*
208 * Validate input.
209 */
210 AssertMsg(pVM, ("Invalid VM pointer\n"));
211 AssertReturn(RT_ALIGN_T(GCPhysOld, PAGE_SIZE, RTGCPHYS) == GCPhysOld, VERR_INVALID_PARAMETER);
212 AssertReturn(RT_ALIGN_T(GCPhysNew, PAGE_SIZE, RTGCPHYS) == GCPhysNew, VERR_INVALID_PARAMETER);
213 AssertReturn(RT_ALIGN(cb, PAGE_SIZE) == cb, VERR_INVALID_PARAMETER);
214 RTGCPHYS GCPhysLast;
215 GCPhysLast = GCPhysOld + (cb - 1);
216 AssertReturn(GCPhysLast > GCPhysOld, VERR_INVALID_PARAMETER);
217 GCPhysLast = GCPhysNew + (cb - 1);
218 AssertReturn(GCPhysLast > GCPhysNew, VERR_INVALID_PARAMETER);
219
220 /*
221 * Find the old memory region.
222 */
223 PMMLOCKEDMEM pCur = pVM->mm.s.pLockedMem;
224 while (pCur)
225 {
226 if ( pCur->eType == MM_LOCKED_TYPE_PHYS
227 && GCPhysOld == pCur->u.phys.GCPhys
228 && cb == pCur->cb)
229 break;
230
231 /* next */
232 pCur = pCur->pNext;
233 }
234 if (!pCur)
235 {
236 AssertMsgFailed(("Unknown old region! %VGp LB%#x\n", GCPhysOld, cb));
237 return VERR_INVALID_PARAMETER;
238 }
239
240 /*
241 * Region is already locked, just need to change GC address.
242 */
243/** @todo r=bird: check for conflicts? */
244 pCur->u.phys.GCPhys = GCPhysNew;
245
246 /*
247 * Relocate the registered RAM range with PGM.
248 */
249 int rc = PGMR3PhysRelocate(pVM, GCPhysOld, GCPhysNew, cb);
250 if (VBOX_SUCCESS(rc))
251 {
252 /* Somewhat hackish way to relocate the region with REM. There
253 * is unfortunately no official way to unregister anything with
254 * REM, as there is no way to unregister memory with QEMU.
255 * This implementation seems to work, but is not very pretty. */
256 /// @todo one day provide a proper MMIO relocation operation
257 REMR3NotifyPhysReserve(pVM, GCPhysOld, cb);
258 REMR3NotifyPhysRamRegister(pVM, GCPhysNew, cb, pCur->pv,
259 pCur->aPhysPages[0].Phys & (MM_RAM_FLAGS_RESERVED | MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO | MM_RAM_FLAGS_MMIO2));
260 }
261
262 return rc;
263}
264
265
266/**
267 * Register a ROM (BIOS) region.
268 *
269 * It goes without saying that this is read-only memory. The memory region must be
270 * in unassigned memory. I.e. from the top of the address space or on the PC in
271 * the 0xa0000-0xfffff range.
272 *
273 * @returns VBox status.
274 * @param pVM VM Handle.
275 * @param pDevIns The device instance owning the ROM region.
276 * @param GCPhys First physical address in the range.
277 * Must be page aligned!
278 * @param cbRange The size of the range (in bytes).
279 * Must be page aligned!
280 * @param pvBinary Pointer to the binary data backing the ROM image.
281 * This must be cbRange bytes big.
282 * It will be copied and doesn't have to stick around.
283 * @param pszDesc Pointer to description string. This must not be freed.
284 * @remark There is no way to remove the rom, automatically on device cleanup or
285 * manually from the device yet. At present I doubt we need such features...
286 */
287MMR3DECL(int) MMR3PhysRomRegister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTUINT cbRange, const void *pvBinary, const char *pszDesc)
288{
289 /*
290 * Validate input.
291 */
292 AssertPtrReturn(pDevIns, VERR_INVALID_PARAMETER);
293 AssertReturn(RT_ALIGN_T(GCPhys, PAGE_SIZE, RTGCPHYS) == GCPhys, VERR_INVALID_PARAMETER);
294 AssertReturn(RT_ALIGN(cbRange, PAGE_SIZE) == cbRange, VERR_INVALID_PARAMETER);
295 RTGCPHYS GCPhysLast = GCPhys + (cbRange - 1);
296 AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
297 AssertPtrReturn(pvBinary, VERR_INVALID_PARAMETER);
298
299
300 /*
301 * Check if this can fit in an existing range.
302 *
303 * We do not handle the case where a new chunk of locked memory is
304 * required to accommodate the ROM since we assume MMR3PhysReserve()
305 * have been called to reserve the memory first.
306 *
307 * To make things even simpler, the pages in question must be
308 * marked as reserved.
309 */
310 PMMLOCKEDMEM pCur = pVM->mm.s.pLockedMem;
311 for ( ; pCur; pCur = pCur->pNext)
312 if ( pCur->eType == MM_LOCKED_TYPE_PHYS
313 && GCPhys - pCur->u.phys.GCPhys < pCur->cb)
314 break;
315 if (!pCur)
316 {
317 AssertMsgFailed(("No physical range was found matching the ROM location (%#VGp LB%#x)\n", GCPhys, cbRange));
318 return VERR_INVALID_PARAMETER;
319 }
320 if (GCPhysLast - pCur->u.phys.GCPhys >= pCur->cb)
321 {
322 AssertMsgFailed(("The ROM range (%#VGp LB%#x) was crossing the end of the physical range (%#VGp LB%#x)\n",
323 GCPhys, cbRange, pCur->u.phys.GCPhys, pCur->cb));
324 return VERR_INVALID_PARAMETER;
325 }
326
327 /* flags must be all reserved. */
328 unsigned iPage = (GCPhys - pCur->u.phys.GCPhys) >> PAGE_SHIFT;
329 unsigned iPageEnd = cbRange >> PAGE_SHIFT;
330 for (; iPage < iPageEnd; iPage++)
331 if ( (pCur->aPhysPages[iPage].Phys & (MM_RAM_FLAGS_RESERVED | MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO | MM_RAM_FLAGS_MMIO2))
332 != MM_RAM_FLAGS_RESERVED)
333 {
334 AssertMsgFailed(("Flags conflict at %VGp, HCPhys=%VHp.\n", pCur->u.phys.GCPhys + (iPage << PAGE_SHIFT), pCur->aPhysPages[iPage].Phys));
335 return VERR_INVALID_PARAMETER;
336 }
337
338 /*
339 * Copy the ram and update the flags.
340 */
341 iPage = (GCPhys - pCur->u.phys.GCPhys) >> PAGE_SHIFT;
342 void *pvCopy = (char *)pCur->pv + (iPage << PAGE_SHIFT);
343 memcpy(pvCopy, pvBinary, cbRange);
344
345 /** @note we rely on the MM_RAM_FLAGS_ROM flag in PGMPhysRead now. Don't change to reserved! */
346 /** @todo r=bird: Noone ever talked about changing *to* _RESERVED. The question is whether
347 * we should *clear* _RESERVED. I've no idea what the state of that flag is for ROM areas right
348 * now, but I will find out later. */
349 for (; iPage < iPageEnd; iPage++)
350 pCur->aPhysPages[iPage].Phys |= MM_RAM_FLAGS_ROM; /** @todo should be clearing _RESERVED? */
351 int rc = PGMR3PhysSetFlags(pVM, GCPhys, cbRange, MM_RAM_FLAGS_ROM, ~0); /** @todo should be clearing _RESERVED? */
352 AssertRC(rc);
353 if (VBOX_SUCCESS(rc))
354 {
355 /*
356 * Prevent changes to the ROM memory when executing in raw mode by
357 * registering a GC only write access handler.
358 *
359 * ASSUMES that REMR3NotifyPhysRomRegister doesn't call cpu_register_physical_memory
360 * when there is no HC handler. The result would probably be immediate boot failure.
361 */
362 rc = PGMR3HandlerPhysicalRegister(pVM, PGMPHYSHANDLERTYPE_PHYSICAL_WRITE, GCPhys, GCPhys + cbRange - 1,
363 NULL, NULL,
364 NULL, "pgmGuestROMWriteHandler", 0,
365 NULL, "pgmGuestROMWriteHandler", 0, "ROM Write Access Handler");
366 AssertRC(rc);
367 }
368
369 REMR3NotifyPhysRomRegister(pVM, GCPhys, cbRange, pvCopy);
370 return rc; /* we're sloppy with error cleanup here, but we're toast anyway if this fails. */
371}
372
373
374/**
375 * Reserve physical address space for ROM and MMIO ranges.
376 *
377 * @returns VBox status code.
378 * @param pVM VM Handle.
379 * @param GCPhys Start physical address.
380 * @param cbRange The size of the range.
381 * @param pszDesc Description string.
382 */
383MMR3DECL(int) MMR3PhysReserve(PVM pVM, RTGCPHYS GCPhys, RTUINT cbRange, const char *pszDesc)
384{
385 /*
386 * Validate input.
387 */
388 AssertReturn(RT_ALIGN_T(GCPhys, PAGE_SIZE, RTGCPHYS) == GCPhys, VERR_INVALID_PARAMETER);
389 AssertReturn(RT_ALIGN(cbRange, PAGE_SIZE) == cbRange, VERR_INVALID_PARAMETER);
390 RTGCPHYS GCPhysLast = GCPhys + (cbRange - 1);
391 AssertReturn(GCPhysLast > GCPhys, VERR_INVALID_PARAMETER);
392
393 /*
394 * Do we have an existing physical address range for the request?
395 */
396 PMMLOCKEDMEM pCur = pVM->mm.s.pLockedMem;
397 for ( ; pCur; pCur = pCur->pNext)
398 if ( pCur->eType == MM_LOCKED_TYPE_PHYS
399 && GCPhys - pCur->u.phys.GCPhys < pCur->cb)
400 break;
401 if (!pCur)
402 {
403 /*
404 * No range, we'll just allocate backing pages and register
405 * them as reserved using the Ram interface.
406 */
407 void *pvPages;
408 int rc = SUPPageAlloc(cbRange >> PAGE_SHIFT, &pvPages);
409 if (VBOX_SUCCESS(rc))
410 {
411 rc = MMR3PhysRegister(pVM, pvPages, GCPhys, cbRange, MM_RAM_FLAGS_RESERVED, pszDesc);
412 if (VBOX_FAILURE(rc))
413 SUPPageFree(pvPages);
414 }
415 return rc;
416 }
417 if (GCPhysLast - pCur->u.phys.GCPhys >= pCur->cb)
418 {
419 AssertMsgFailed(("The reserved range (%#VGp LB%#x) was crossing the end of the physical range (%#VGp LB%#x)\n",
420 GCPhys, cbRange, pCur->u.phys.GCPhys, pCur->cb));
421 return VERR_INVALID_PARAMETER;
422 }
423
424 /*
425 * Update the flags.
426 */
427 unsigned iPage = (GCPhys - pCur->u.phys.GCPhys) >> PAGE_SHIFT;
428 unsigned iPageEnd = cbRange >> PAGE_SHIFT;
429 for (; iPage < iPageEnd; iPage++)
430 pCur->aPhysPages[iPage].Phys |= MM_RAM_FLAGS_RESERVED;
431 int rc = PGMR3PhysSetFlags(pVM, GCPhys, cbRange, MM_RAM_FLAGS_RESERVED, ~0);
432 AssertRC(rc);
433
434 REMR3NotifyPhysReserve(pVM, GCPhys, cbRange);
435 return rc;
436}
437
438
439/**
440 * Get the size of the base RAM.
441 * This usually means the size of the first contigous block of physical memory.
442 *
443 * @returns
444 * @param pVM
445 * @thread Any.
446 */
447MMR3DECL(uint64_t) MMR3PhysGetRamSize(PVM pVM)
448{
449 return pVM->mm.s.cbRamBase;
450}
451
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