Changeset 23524 in vbox
- Timestamp:
- Oct 3, 2009 3:23:42 PM (16 years ago)
- svn:sync-xref-src-repo-rev:
- 53167
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/PGMSavedState.cpp
r23523 r23524 175 175 176 176 /** 177 * Prepare for a live save operation. 178 * 179 * This will attempt to allocate and initialize the tracking structures. It 180 * will also prepare for write monitoring of pages and initialize PGM::LiveSave. 181 * pgmR3SaveDone will do the cleanups. 177 * Prepares the ROM pages for a live save. 182 178 * 183 179 * @returns VBox status code. 184 * 185 * @param pVM The VM handle. 186 * @param pSSM The SSM handle. 187 */ 188 static DECLCALLBACK(int) pgmR3LivePrep(PVM pVM, PSSMHANDLE pSSM) 189 { 190 /* 191 * Indicate that we will be using the write monitoring. 192 */ 193 pgmLock(pVM); 194 /** @todo find a way of mediating this when more users are added. */ 195 if (pVM->pgm.s.fPhysWriteMonitoringEngaged) 196 { 197 pgmUnlock(pVM); 198 AssertLogRelFailedReturn(VERR_INTERNAL_ERROR_2); 199 } 200 pVM->pgm.s.fPhysWriteMonitoringEngaged = true; 201 pgmUnlock(pVM); 202 203 /* 204 * Initialize the statistics. 205 */ 206 pVM->pgm.s.LiveSave.cReadyPages = 0; 207 pVM->pgm.s.LiveSave.cDirtyPages = 0; 208 pVM->pgm.s.LiveSave.cIgnoredPages = 0; 209 pVM->pgm.s.LiveSave.cDirtyMmio2Pages = 0; 210 pVM->pgm.s.LiveSave.fActive = true; 211 212 /* 213 * Initialize the live save tracking in the MMIO2 ranges. 214 * ASSUME nothing changes here. 215 */ 216 pgmLock(pVM); 217 for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3) 218 { 219 uint32_t const cPages = pMmio2->RamRange.cb >> PAGE_SHIFT; 220 pgmUnlock(pVM); 221 222 PPGMLIVESAVEMMIO2PAGE paLSPages = (PPGMLIVESAVEMMIO2PAGE)MMR3HeapAllocZ(pVM, MM_TAG_PGM, sizeof(PGMLIVESAVEMMIO2PAGE) * cPages); 223 if (!paLSPages) 224 return VERR_NO_MEMORY; 225 for (uint32_t iPage = 0; iPage < cPages; iPage++) 226 { 227 /* Initialize it as a dirty zero page. */ 228 paLSPages[iPage].fDirty = true; 229 paLSPages[iPage].cUnchangedScans = 0; 230 paLSPages[iPage].fZero = true; 231 paLSPages[iPage].u32CrcH1 = PGM_STATE_CRC32_ZERO_HALF_PAGE; 232 paLSPages[iPage].u32CrcH2 = PGM_STATE_CRC32_ZERO_HALF_PAGE; 233 } 234 235 pgmLock(pVM); 236 pMmio2->paLSPages = paLSPages; 237 pVM->pgm.s.LiveSave.cDirtyMmio2Pages += cPages; 238 } 239 pgmUnlock(pVM); 240 180 * @param pVM The VM handle. 181 */ 182 static int pgmR3PrepRomPages(PVM pVM) 183 { 241 184 /* 242 185 * Initialize the live save tracking in the ROM page descriptors. … … 277 220 } 278 221 pgmUnlock(pVM); 222 223 return VINF_SUCCESS; 224 } 225 226 227 /** 228 * Assigns IDs to the ROM ranges and saves them. 229 * 230 * @returns VBox status code. 231 * @param pVM The VM handle. 232 * @param pSSM Saved state handle. 233 */ 234 static int pgmR3SaveRomRanges(PVM pVM, PSSMHANDLE pSSM) 235 { 236 pgmLock(pVM); 237 uint8_t id = 1; 238 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3, id++) 239 { 240 pRom->idSavedState = id; 241 SSMR3PutU8(pSSM, id); 242 SSMR3PutStrZ(pSSM, ""); /* device name */ 243 SSMR3PutU32(pSSM, 0); /* device instance */ 244 SSMR3PutU8(pSSM, 0); /* region */ 245 SSMR3PutStrZ(pSSM, pRom->pszDesc); 246 SSMR3PutGCPhys(pSSM, pRom->GCPhys); 247 int rc = SSMR3PutGCPhys(pSSM, pRom->cb); 248 if (RT_FAILURE(rc)) 249 break; 250 } 251 pgmUnlock(pVM); 252 return SSMR3PutU8(pSSM, UINT8_MAX); 253 } 254 255 256 /** 257 * Loads the ROM range ID assignments. 258 * 259 * @returns VBox status code. 260 * 261 * @param pVM The VM handle. 262 * @param pSSM The saved state handle. 263 */ 264 static int pgmR3LoadRomRanges(PVM pVM, PSSMHANDLE pSSM) 265 { 266 Assert(PGMIsLockOwner(pVM)); 267 268 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3) 269 pRom->idSavedState = UINT8_MAX; 270 271 for (;;) 272 { 273 /* 274 * Read the data. 275 */ 276 uint8_t id; 277 int rc = SSMR3GetU8(pSSM, &id); 278 if (RT_FAILURE(rc)) 279 return rc; 280 if (id == UINT8_MAX) 281 { 282 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3) 283 AssertLogRelMsg(pRom->idSavedState != UINT8_MAX, ("%s\n", pRom->pszDesc)); 284 return VINF_SUCCESS; /* the end */ 285 } 286 AssertLogRelReturn(id != 0, VERR_SSM_DATA_UNIT_FORMAT_CHANGED); 287 288 char szDevName[RT_SIZEOFMEMB(PDMDEVREG, szDeviceName)]; 289 rc = SSMR3GetStrZ(pSSM, szDevName, sizeof(szDevName)); 290 AssertLogRelRCReturn(rc, rc); 291 292 uint32_t uInstance; 293 SSMR3GetU32(pSSM, &uInstance); 294 uint8_t iRegion; 295 SSMR3GetU8(pSSM, &iRegion); 296 297 char szDesc[64]; 298 rc = SSMR3GetStrZ(pSSM, szDesc, sizeof(szDesc)); 299 AssertLogRelRCReturn(rc, rc); 300 301 RTGCPHYS GCPhys; 302 SSMR3GetGCPhys(pSSM, &GCPhys); 303 RTGCPHYS cb; 304 rc = SSMR3GetGCPhys(pSSM, &cb); 305 if (RT_FAILURE(rc)) 306 return rc; 307 AssertLogRelMsgReturn(!(GCPhys & PAGE_OFFSET_MASK), ("GCPhys=%RGp %s\n", GCPhys, szDesc), VERR_SSM_DATA_UNIT_FORMAT_CHANGED); 308 AssertLogRelMsgReturn(!(cb & PAGE_OFFSET_MASK), ("cb=%RGp %s\n", cb, szDesc), VERR_SSM_DATA_UNIT_FORMAT_CHANGED); 309 310 /* 311 * Locate a matching ROM range. 312 */ 313 AssertLogRelMsgReturn( uInstance == 0 314 && iRegion == 0 315 && szDevName[0] == '\0', 316 ("GCPhys=%RGp %s\n", GCPhys, szDesc), 317 VERR_SSM_DATA_UNIT_FORMAT_CHANGED); 318 PPGMROMRANGE pRom; 319 for (pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3) 320 { 321 if ( pRom->idSavedState == UINT8_MAX 322 && !strcmp(pRom->pszDesc, szDesc)) 323 { 324 pRom->idSavedState = id; 325 break; 326 } 327 } 328 AssertLogRelMsgReturn(pRom, ("GCPhys=%RGp %s\n", GCPhys, szDesc), VERR_SSM_LOAD_CONFIG_MISMATCH); 329 } /* forever */ 330 } 331 332 333 /** 334 * Scan ROM pages. 335 * 336 * @param pVM The VM handle. 337 */ 338 static void pgmR3ScanRomPages(PVM pVM) 339 { 340 /* 341 * The shadow ROMs. 342 */ 343 pgmLock(pVM); 344 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3) 345 { 346 if (pRom->fFlags & PGMPHYS_ROM_FLAGS_SHADOWED) 347 { 348 uint32_t const cPages = pRom->cb >> PAGE_SHIFT; 349 for (uint32_t iPage = 0; iPage < cPages; iPage++) 350 { 351 PPGMROMPAGE pRomPage = &pRom->aPages[iPage]; 352 if (pRomPage->LiveSave.fWrittenTo) 353 { 354 pRomPage->LiveSave.fWrittenTo = false; 355 if (!pRomPage->LiveSave.fDirty) 356 { 357 pRomPage->LiveSave.fDirty = true; 358 pVM->pgm.s.LiveSave.cReadyPages--; 359 pVM->pgm.s.LiveSave.cDirtyPages++; 360 } 361 pRomPage->LiveSave.fDirtiedRecently = true; 362 } 363 else 364 pRomPage->LiveSave.fDirtiedRecently = false; 365 } 366 } 367 } 368 pgmUnlock(pVM); 369 } 370 371 372 /** 373 * Takes care of the virgin ROM pages in the first pass. 374 * 375 * This is an attempt at simplifying the handling of ROM pages a little bit. 376 * This ASSUMES that no new ROM ranges will be added and that they won't be 377 * relinked in any way. 378 * 379 * @param pVM The VM handle. 380 * @param pSSM The SSM handle. 381 * @param fLiveSave Whether we're in a live save or not. 382 */ 383 static int pgmR3SaveRomVirginPages(PVM pVM, PSSMHANDLE pSSM, bool fLiveSave) 384 { 385 pgmLock(pVM); 386 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3) 387 { 388 uint32_t const cPages = pRom->cb >> PAGE_SHIFT; 389 for (uint32_t iPage = 0; iPage < cPages; iPage++) 390 { 391 RTGCPHYS GCPhys = pRom->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT); 392 PGMROMPROT enmProt = pRom->aPages[iPage].enmProt; 393 394 /* Get the virgin page descriptor. */ 395 PPGMPAGE pPage; 396 if (PGMROMPROT_IS_ROM(enmProt)) 397 pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys); 398 else 399 pPage = &pRom->aPages[iPage].Virgin; 400 401 /* Get the page bits. (Cannot use pgmPhysGCPhys2CCPtrInternalReadOnly here!) */ 402 int rc = VINF_SUCCESS; 403 char abPage[PAGE_SIZE]; 404 if (!PGM_PAGE_IS_ZERO(pPage)) 405 { 406 void const *pvPage; 407 rc = pgmPhysPageMapReadOnly(pVM, pPage, GCPhys, &pvPage); 408 if (RT_SUCCESS(rc)) 409 memcpy(abPage, pvPage, PAGE_SIZE); 410 } 411 else 412 ASMMemZeroPage(abPage); 413 pgmUnlock(pVM); 414 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc GCPhys=%RGp\n", rc, GCPhys), rc); 415 416 /* Save it. */ 417 if (iPage > 0) 418 SSMR3PutU8(pSSM, PGM_STATE_REC_ROM_VIRGIN); 419 else 420 { 421 SSMR3PutU8(pSSM, PGM_STATE_REC_ROM_VIRGIN | PGM_STATE_REC_FLAG_ADDR); 422 SSMR3PutU8(pSSM, pRom->idSavedState); 423 SSMR3PutU32(pSSM, iPage); 424 } 425 SSMR3PutU8(pSSM, (uint8_t)enmProt); 426 rc = SSMR3PutMem(pSSM, abPage, PAGE_SIZE); 427 if (RT_FAILURE(rc)) 428 return rc; 429 430 /* Update state. */ 431 pgmLock(pVM); 432 pRom->aPages[iPage].LiveSave.u8Prot = (uint8_t)enmProt; 433 if (fLiveSave) 434 { 435 pVM->pgm.s.LiveSave.cDirtyPages--; 436 pVM->pgm.s.LiveSave.cReadyPages++; 437 } 438 } 439 } 440 pgmUnlock(pVM); 441 return VINF_SUCCESS; 442 } 443 444 445 /** 446 * Saves dirty pages in the shadowed ROM ranges. 447 * 448 * Used by pgmR3LiveExecPart2 and pgmR3SaveExecMemory. 449 * 450 * @returns VBox status code. 451 * @param pVM The VM handle. 452 * @param pSSM The SSM handle. 453 * @param fLiveSave Whether it's a live save or not. 454 * @param fFinalPass Whether this is the final pass or not. 455 */ 456 static int pgmR3SaveShadowedRomPages(PVM pVM, PSSMHANDLE pSSM, bool fLiveSave, bool fFinalPass) 457 { 458 /* 459 * The Shadowed ROMs. 460 * 461 * ASSUMES that the ROM ranges are fixed. 462 * ASSUMES that all the ROM ranges are mapped. 463 */ 464 pgmLock(pVM); 465 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3) 466 { 467 if (pRom->fFlags & PGMPHYS_ROM_FLAGS_SHADOWED) 468 { 469 uint32_t const cPages = pRom->cb >> PAGE_SHIFT; 470 uint32_t iPrevPage = cPages; 471 for (uint32_t iPage = 0; iPage < cPages; iPage++) 472 { 473 PPGMROMPAGE pRomPage = &pRom->aPages[iPage]; 474 if ( !fLiveSave 475 || ( pRomPage->LiveSave.fDirty 476 && ( ( !pRomPage->LiveSave.fDirtiedRecently 477 && !pRomPage->LiveSave.fWrittenTo) 478 || fFinalPass 479 ) 480 ) 481 ) 482 { 483 uint8_t abPage[PAGE_SIZE]; 484 PGMROMPROT enmProt = pRomPage->enmProt; 485 RTGCPHYS GCPhys = pRom->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT); 486 PPGMPAGE pPage = PGMROMPROT_IS_ROM(enmProt) ? &pRomPage->Shadow : pgmPhysGetPage(&pVM->pgm.s, GCPhys); 487 bool fZero = PGM_PAGE_IS_ZERO(pPage); 488 int rc = VINF_SUCCESS; 489 if (!fZero) 490 { 491 void const *pvPage; 492 rc = pgmPhysPageMapReadOnly(pVM, pPage, GCPhys, &pvPage); 493 if (RT_SUCCESS(rc)) 494 memcpy(abPage, pvPage, PAGE_SIZE); 495 } 496 if (fLiveSave && RT_SUCCESS(rc)) 497 { 498 pRomPage->LiveSave.u8Prot = (uint8_t)enmProt; 499 pRomPage->LiveSave.fDirty = false; 500 pVM->pgm.s.LiveSave.cReadyPages++; 501 pVM->pgm.s.LiveSave.cDirtyPages--; 502 } 503 pgmUnlock(pVM); 504 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc GCPhys=%RGp\n", rc, GCPhys), rc); 505 506 if (iPage - 1U == iPrevPage && iPage > 0) 507 SSMR3PutU8(pSSM, (fZero ? PGM_STATE_REC_ROM_SHW_ZERO : PGM_STATE_REC_ROM_SHW_RAW)); 508 else 509 { 510 SSMR3PutU8(pSSM, (fZero ? PGM_STATE_REC_ROM_SHW_ZERO : PGM_STATE_REC_ROM_SHW_RAW) | PGM_STATE_REC_FLAG_ADDR); 511 SSMR3PutU8(pSSM, pRom->idSavedState); 512 SSMR3PutU32(pSSM, iPage); 513 } 514 rc = SSMR3PutU8(pSSM, (uint8_t)enmProt); 515 if (!fZero) 516 rc = SSMR3PutMem(pSSM, abPage, PAGE_SIZE); 517 if (RT_FAILURE(rc)) 518 return rc; 519 520 pgmLock(pVM); 521 iPrevPage = iPage; 522 } 523 /* 524 * In the final pass, make sure the protection is in sync. 525 */ 526 else if ( fFinalPass 527 && pRomPage->LiveSave.u8Prot != pRomPage->enmProt) 528 { 529 PGMROMPROT enmProt = pRomPage->enmProt; 530 pRomPage->LiveSave.u8Prot = (uint8_t)enmProt; 531 pgmUnlock(pVM); 532 533 if (iPage - 1U == iPrevPage && iPage > 0) 534 SSMR3PutU8(pSSM, PGM_STATE_REC_ROM_PROT); 535 else 536 { 537 SSMR3PutU8(pSSM, PGM_STATE_REC_ROM_PROT | PGM_STATE_REC_FLAG_ADDR); 538 SSMR3PutU8(pSSM, pRom->idSavedState); 539 SSMR3PutU32(pSSM, iPage); 540 } 541 int rc = SSMR3PutU8(pSSM, (uint8_t)enmProt); 542 if (RT_FAILURE(rc)) 543 return rc; 544 545 pgmLock(pVM); 546 iPrevPage = iPage; 547 } 548 } 549 } 550 } 551 pgmUnlock(pVM); 552 return VINF_SUCCESS; 553 } 554 555 556 /** 557 * Cleans up ROM pages after a live save. 558 * 559 * @param pVM The VM handle. 560 */ 561 static void pgmR3DoneRomPages(PVM pVM) 562 { 563 NOREF(pVM); 564 } 565 566 567 /** 568 * Prepares the MMIO2 pages for a live save. 569 * 570 * @returns VBox status code. 571 * @param pVM The VM handle. 572 */ 573 static int pgmR3PrepMmio2Pages(PVM pVM) 574 { 575 /* 576 * Initialize the live save tracking in the MMIO2 ranges. 577 * ASSUME nothing changes here. 578 */ 579 pgmLock(pVM); 580 for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3) 581 { 582 uint32_t const cPages = pMmio2->RamRange.cb >> PAGE_SHIFT; 583 pgmUnlock(pVM); 584 585 PPGMLIVESAVEMMIO2PAGE paLSPages = (PPGMLIVESAVEMMIO2PAGE)MMR3HeapAllocZ(pVM, MM_TAG_PGM, sizeof(PGMLIVESAVEMMIO2PAGE) * cPages); 586 if (!paLSPages) 587 return VERR_NO_MEMORY; 588 for (uint32_t iPage = 0; iPage < cPages; iPage++) 589 { 590 /* Initialize it as a dirty zero page. */ 591 paLSPages[iPage].fDirty = true; 592 paLSPages[iPage].cUnchangedScans = 0; 593 paLSPages[iPage].fZero = true; 594 paLSPages[iPage].u32CrcH1 = PGM_STATE_CRC32_ZERO_HALF_PAGE; 595 paLSPages[iPage].u32CrcH2 = PGM_STATE_CRC32_ZERO_HALF_PAGE; 596 } 597 598 pgmLock(pVM); 599 pMmio2->paLSPages = paLSPages; 600 pVM->pgm.s.LiveSave.cDirtyMmio2Pages += cPages; 601 } 602 pgmUnlock(pVM); 603 return VINF_SUCCESS; 604 } 605 606 607 /** 608 * Assigns IDs to the MMIO2 ranges and saves them. 609 * 610 * @returns VBox status code. 611 * @param pVM The VM handle. 612 * @param pSSM Saved state handle. 613 */ 614 static int pgmR3SaveMmio2Ranges(PVM pVM, PSSMHANDLE pSSM) 615 { 616 pgmLock(pVM); 617 uint8_t id = 1; 618 for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3, id++) 619 { 620 pMmio2->idSavedState = id; 621 SSMR3PutU8(pSSM, id); 622 SSMR3PutStrZ(pSSM, pMmio2->pDevInsR3->pDevReg->szDeviceName); 623 SSMR3PutU32(pSSM, pMmio2->pDevInsR3->iInstance); 624 SSMR3PutU8(pSSM, pMmio2->iRegion); 625 SSMR3PutStrZ(pSSM, pMmio2->RamRange.pszDesc); 626 int rc = SSMR3PutGCPhys(pSSM, pMmio2->RamRange.cb); 627 if (RT_FAILURE(rc)) 628 break; 629 } 630 pgmUnlock(pVM); 631 return SSMR3PutU8(pSSM, UINT8_MAX); 632 } 633 634 635 /** 636 * Loads the MMIO2 range ID assignments. 637 * 638 * @returns VBox status code. 639 * 640 * @param pVM The VM handle. 641 * @param pSSM The saved state handle. 642 */ 643 static int pgmR3LoadMmio2Ranges(PVM pVM, PSSMHANDLE pSSM) 644 { 645 Assert(PGMIsLockOwner(pVM)); 646 647 for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3) 648 pMmio2->idSavedState = UINT8_MAX; 649 650 for (;;) 651 { 652 /* 653 * Read the data. 654 */ 655 uint8_t id; 656 int rc = SSMR3GetU8(pSSM, &id); 657 if (RT_FAILURE(rc)) 658 return rc; 659 if (id == UINT8_MAX) 660 { 661 for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3) 662 AssertLogRelMsg(pMmio2->idSavedState != UINT8_MAX, ("%s\n", pMmio2->RamRange.pszDesc)); 663 return VINF_SUCCESS; /* the end */ 664 } 665 AssertLogRelReturn(id != 0, VERR_SSM_DATA_UNIT_FORMAT_CHANGED); 666 667 char szDevName[RT_SIZEOFMEMB(PDMDEVREG, szDeviceName)]; 668 rc = SSMR3GetStrZ(pSSM, szDevName, sizeof(szDevName)); 669 AssertLogRelRCReturn(rc, rc); 670 671 uint32_t uInstance; 672 SSMR3GetU32(pSSM, &uInstance); 673 uint8_t iRegion; 674 SSMR3GetU8(pSSM, &iRegion); 675 676 char szDesc[64]; 677 rc = SSMR3GetStrZ(pSSM, szDesc, sizeof(szDesc)); 678 AssertLogRelRCReturn(rc, rc); 679 680 RTGCPHYS cb; 681 rc = SSMR3GetGCPhys(pSSM, &cb); 682 AssertLogRelMsgReturn(!(cb & PAGE_OFFSET_MASK), ("cb=%RGp %s\n", cb, szDesc), VERR_SSM_DATA_UNIT_FORMAT_CHANGED); 683 684 /* 685 * Locate a matching MMIO2 range. 686 */ 687 PPGMMMIO2RANGE pMmio2; 688 for (pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3) 689 { 690 if ( pMmio2->idSavedState == UINT8_MAX 691 && pMmio2->iRegion == iRegion 692 && pMmio2->pDevInsR3->iInstance == uInstance 693 && !strcmp(pMmio2->pDevInsR3->pDevReg->szDeviceName, szDevName)) 694 { 695 pMmio2->idSavedState = id; 696 break; 697 } 698 } 699 AssertLogRelMsgReturn(pMmio2, ("%s/%u/%u: %s\n", szDevName, uInstance, iRegion, szDesc), VERR_SSM_LOAD_CONFIG_MISMATCH); 700 } /* forever */ 701 } 702 703 704 /** 705 * Scans one MMIO2 page. 706 * 707 * @returns True if changed, false if unchanged. 708 * 709 * @param pVM The VM handle 710 * @param pbPage The page bits. 711 * @param pLSPage The live save tracking structure for the page. 712 * 713 */ 714 DECLINLINE(bool) pgmR3ScanMmio2Page(PVM pVM, uint8_t const *pbPage, PPGMLIVESAVEMMIO2PAGE pLSPage) 715 { 716 /* 717 * Special handling of zero pages. 718 */ 719 if (pLSPage->fZero) 720 { 721 if (ASMMemIsZeroPage(pbPage)) 722 { 723 /* Not modified. */ 724 if (pLSPage->fDirty) 725 pLSPage->cUnchangedScans++; 726 return false; 727 } 728 729 pLSPage->fZero = false; 730 pLSPage->u32CrcH1 = RTCrc32(pbPage, PAGE_SIZE / 2); 731 } 732 else 733 { 734 /* 735 * CRC the first half, if it doesn't match the page is dirty and 736 * we won't check the 2nd half (we'll do that next time). 737 */ 738 uint32_t u32CrcH1 = RTCrc32(pbPage, PAGE_SIZE / 2); 739 if (u32CrcH1 == pLSPage->u32CrcH1) 740 { 741 uint32_t u32CrcH2 = RTCrc32(pbPage + PAGE_SIZE / 2, PAGE_SIZE / 2); 742 if (u32CrcH2 == pLSPage->u32CrcH2) 743 { 744 /* Probably not modified. */ 745 if (pLSPage->fDirty) 746 pLSPage->cUnchangedScans++; 747 return false; 748 } 749 750 pLSPage->u32CrcH2 = u32CrcH2; 751 } 752 else 753 { 754 pLSPage->u32CrcH1 = u32CrcH1; 755 if ( u32CrcH1 == PGM_STATE_CRC32_ZERO_HALF_PAGE 756 && ASMMemIsZeroPage(pbPage)) 757 { 758 pLSPage->u32CrcH2 = PGM_STATE_CRC32_ZERO_HALF_PAGE; 759 pLSPage->fZero = true; 760 } 761 } 762 } 763 764 /* dirty page path */ 765 pLSPage->cUnchangedScans = 0; 766 if (!pLSPage->fDirty) 767 { 768 pLSPage->fDirty = true; 769 pVM->pgm.s.LiveSave.cReadyPages--; 770 pVM->pgm.s.LiveSave.cDirtyMmio2Pages++; 771 } 772 return true; 773 } 774 775 776 /** 777 * Scan for MMIO2 page modifications. 778 * 779 * @param pVM The VM handle. 780 * @param uPass The pass number. 781 */ 782 static void pgmR3ScanMmio2Pages(PVM pVM, uint32_t uPass) 783 { 784 /* 785 * Only do this every 4th time as it's a little bit expensive. 786 */ 787 if ( (uPass & 3) != 0 788 || uPass == SSM_PASS_FINAL) 789 return; 790 791 pgmLock(pVM); /* paranoia */ 792 for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3) 793 { 794 PPGMLIVESAVEMMIO2PAGE paLSPages = pMmio2->paLSPages; 795 uint8_t const *pbPage = (uint8_t const *)pMmio2->RamRange.pvR3; 796 uint32_t cPages = pMmio2->RamRange.cb >> PAGE_SHIFT; 797 pgmUnlock(pVM); 798 799 for (uint32_t iPage = 0; iPage < cPages; iPage++, pbPage += PAGE_SIZE) 800 { 801 uint8_t const *pbPage = (uint8_t const *)pMmio2->pvR3 + iPage * PAGE_SIZE; 802 pgmR3ScanMmio2Page(pVM,pbPage, &paLSPages[iPage]); 803 } 804 805 pgmLock(pVM); 806 } 807 pgmUnlock(pVM); 808 809 } 810 811 812 /** 813 * Save quiescent MMIO2 pages. 814 * 815 * @returns VBox status code. 816 * @param pVM The VM handle. 817 * @param pSSM The SSM handle. 818 * @param fLiveSave Whether it's a live save or not. 819 * @param uPass The pass number. 820 */ 821 static int pgmR3SaveMmio2Pages(PVM pVM, PSSMHANDLE pSSM, bool fLiveSave, uint32_t uPass) 822 { 823 /** @todo implement live saving of MMIO2 pages. (Need some way of telling the 824 * device that we wish to know about changes.) */ 825 826 int rc = VINF_SUCCESS; 827 if (uPass == SSM_PASS_FINAL) 828 { 829 /* 830 * The mop up round. 831 */ 832 pgmLock(pVM); 833 for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; 834 pMmio2 && RT_SUCCESS(rc); 835 pMmio2 = pMmio2->pNextR3) 836 { 837 PPGMLIVESAVEMMIO2PAGE paLSPages = pMmio2->paLSPages; 838 uint8_t const *pbPage = (uint8_t const *)pMmio2->RamRange.pvR3; 839 uint32_t cPages = pMmio2->RamRange.cb >> PAGE_SHIFT; 840 uint32_t iPageLast = cPages; 841 for (uint32_t iPage = 0; iPage < cPages; iPage++, pbPage += PAGE_SIZE) 842 { 843 uint8_t u8Type; 844 if (!fLiveSave) 845 u8Type = ASMMemIsZeroPage(pbPage) ? PGM_STATE_REC_MMIO2_ZERO : PGM_STATE_REC_MMIO2_RAW; 846 else 847 { 848 /* Try figure if it's a clean page, compare the SHA-1 to be really sure. */ 849 if ( !paLSPages[iPage].fDirty 850 && !pgmR3ScanMmio2Page(pVM, pbPage, &paLSPages[iPage])) 851 { 852 if (paLSPages[iPage].fZero) 853 continue; 854 855 uint8_t abSha1Hash[RTSHA1_HASH_SIZE]; 856 RTSha1(pbPage, PAGE_SIZE, abSha1Hash); 857 if (!memcmp(abSha1Hash, paLSPages[iPage].abSha1Saved, sizeof(abSha1Hash))) 858 continue; 859 } 860 u8Type = paLSPages[iPage].fZero ? PGM_STATE_REC_MMIO2_ZERO : PGM_STATE_REC_MMIO2_RAW; 861 } 862 863 if (iPage != 0 && iPage == iPageLast + 1) 864 rc = SSMR3PutU8(pSSM, u8Type); 865 else 866 { 867 SSMR3PutU8(pSSM, u8Type | PGM_STATE_REC_FLAG_ADDR); 868 SSMR3PutU8(pSSM, pMmio2->idSavedState); 869 rc = SSMR3PutU32(pSSM, iPage); 870 } 871 if (u8Type == PGM_STATE_REC_MMIO2_RAW) 872 rc = SSMR3PutMem(pSSM, pbPage, PAGE_SIZE); 873 if (RT_FAILURE(rc)) 874 break; 875 iPageLast = iPage; 876 } 877 } 878 pgmUnlock(pVM); 879 } 880 /* 881 * Only do this every 4rd time since it's kind of expense. 882 * We position it two passes after the scan pass to avoid saving busy pages. 883 */ 884 else if ((uPass & 3) == 2) 885 { 886 pgmLock(pVM); 887 for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; 888 pMmio2 && RT_SUCCESS(rc); 889 pMmio2 = pMmio2->pNextR3) 890 { 891 PPGMLIVESAVEMMIO2PAGE paLSPages = pMmio2->paLSPages; 892 uint8_t const *pbPage = (uint8_t const *)pMmio2->RamRange.pvR3; 893 uint32_t cPages = pMmio2->RamRange.cb >> PAGE_SHIFT; 894 uint32_t iPageLast = cPages; 895 pgmUnlock(pVM); 896 897 for (uint32_t iPage = 0; iPage < cPages; iPage++, pbPage += PAGE_SIZE) 898 { 899 /* Skip clean pages and pages which hasn't quiesced. */ 900 if (!paLSPages[iPage].fDirty) 901 continue; 902 if (paLSPages[iPage].cUnchangedScans < 3) 903 continue; 904 if (pgmR3ScanMmio2Page(pVM, pbPage, &paLSPages[iPage])) 905 continue; 906 907 /* Save it. */ 908 if (!paLSPages[iPage].fZero) 909 RTSha1(pbPage, PAGE_SIZE, paLSPages[iPage].abSha1Saved); 910 uint8_t u8Type = paLSPages[iPage].fZero ? PGM_STATE_REC_MMIO2_ZERO : PGM_STATE_REC_MMIO2_RAW; 911 if (iPage != 0 && iPage == iPageLast + 1) 912 rc = SSMR3PutU8(pSSM, u8Type); 913 else 914 { 915 SSMR3PutU8(pSSM, u8Type | PGM_STATE_REC_FLAG_ADDR); 916 SSMR3PutU8(pSSM, pMmio2->idSavedState); 917 rc = SSMR3PutU32(pSSM, iPage); 918 } 919 if (u8Type == PGM_STATE_REC_MMIO2_RAW) 920 rc = SSMR3PutMem(pSSM, pbPage, PAGE_SIZE); 921 if (RT_FAILURE(rc)) 922 break; 923 iPageLast = iPage; 924 } 925 926 pgmLock(pVM); 927 } 928 pgmUnlock(pVM); 929 } 930 931 return rc; 932 } 933 934 935 /** 936 * Cleans up MMIO2 pages after a live save. 937 * 938 * @param pVM The VM handle. 939 */ 940 static void pgmR3DoneMmio2Pages(PVM pVM) 941 { 942 /* 943 * Free the tracking structures for the MMIO2 pages. 944 * We do the freeing outside the lock in case the VM is running. 945 */ 946 pgmLock(pVM); 947 for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3) 948 { 949 void *pvMmio2ToFree = pMmio2->paLSPages; 950 if (pvMmio2ToFree) 951 { 952 pMmio2->paLSPages = NULL; 953 pgmUnlock(pVM); 954 MMR3HeapFree(pvMmio2ToFree); 955 pgmLock(pVM); 956 } 957 } 958 pgmUnlock(pVM); 959 } 960 961 962 /** 963 * Prepares the RAM pages for a live save. 964 * 965 * @returns VBox status code. 966 * @param pVM The VM handle. 967 */ 968 static int pgmR3PrepRamPages(PVM pVM) 969 { 279 970 280 971 /* … … 386 1077 387 1078 return VINF_SUCCESS; 388 }389 390 391 /**392 * Assigns IDs to the ROM ranges and saves them.393 *394 * @returns VBox status code.395 * @param pVM The VM handle.396 * @param pSSM Saved state handle.397 */398 static int pgmR3SaveRomRanges(PVM pVM, PSSMHANDLE pSSM)399 {400 pgmLock(pVM);401 uint8_t id = 1;402 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3, id++)403 {404 pRom->idSavedState = id;405 SSMR3PutU8(pSSM, id);406 SSMR3PutStrZ(pSSM, ""); /* device name */407 SSMR3PutU32(pSSM, 0); /* device instance */408 SSMR3PutU8(pSSM, 0); /* region */409 SSMR3PutStrZ(pSSM, pRom->pszDesc);410 SSMR3PutGCPhys(pSSM, pRom->GCPhys);411 int rc = SSMR3PutGCPhys(pSSM, pRom->cb);412 if (RT_FAILURE(rc))413 break;414 }415 pgmUnlock(pVM);416 return SSMR3PutU8(pSSM, UINT8_MAX);417 }418 419 420 /**421 * Loads the ROM range ID assignments.422 *423 * @returns VBox status code.424 *425 * @param pVM The VM handle.426 * @param pSSM The saved state handle.427 */428 static int pgmR3LoadRomRanges(PVM pVM, PSSMHANDLE pSSM)429 {430 Assert(PGMIsLockOwner(pVM));431 432 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3)433 pRom->idSavedState = UINT8_MAX;434 435 for (;;)436 {437 /*438 * Read the data.439 */440 uint8_t id;441 int rc = SSMR3GetU8(pSSM, &id);442 if (RT_FAILURE(rc))443 return rc;444 if (id == UINT8_MAX)445 {446 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3)447 AssertLogRelMsg(pRom->idSavedState != UINT8_MAX, ("%s\n", pRom->pszDesc));448 return VINF_SUCCESS; /* the end */449 }450 AssertLogRelReturn(id != 0, VERR_SSM_DATA_UNIT_FORMAT_CHANGED);451 452 char szDevName[RT_SIZEOFMEMB(PDMDEVREG, szDeviceName)];453 rc = SSMR3GetStrZ(pSSM, szDevName, sizeof(szDevName));454 AssertLogRelRCReturn(rc, rc);455 456 uint32_t uInstance;457 SSMR3GetU32(pSSM, &uInstance);458 uint8_t iRegion;459 SSMR3GetU8(pSSM, &iRegion);460 461 char szDesc[64];462 rc = SSMR3GetStrZ(pSSM, szDesc, sizeof(szDesc));463 AssertLogRelRCReturn(rc, rc);464 465 RTGCPHYS GCPhys;466 SSMR3GetGCPhys(pSSM, &GCPhys);467 RTGCPHYS cb;468 rc = SSMR3GetGCPhys(pSSM, &cb);469 if (RT_FAILURE(rc))470 return rc;471 AssertLogRelMsgReturn(!(GCPhys & PAGE_OFFSET_MASK), ("GCPhys=%RGp %s\n", GCPhys, szDesc), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);472 AssertLogRelMsgReturn(!(cb & PAGE_OFFSET_MASK), ("cb=%RGp %s\n", cb, szDesc), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);473 474 /*475 * Locate a matching ROM range.476 */477 AssertLogRelMsgReturn( uInstance == 0478 && iRegion == 0479 && szDevName[0] == '\0',480 ("GCPhys=%RGp %s\n", GCPhys, szDesc),481 VERR_SSM_DATA_UNIT_FORMAT_CHANGED);482 PPGMROMRANGE pRom;483 for (pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3)484 {485 if ( pRom->idSavedState == UINT8_MAX486 && !strcmp(pRom->pszDesc, szDesc))487 {488 pRom->idSavedState = id;489 break;490 }491 }492 AssertLogRelMsgReturn(pRom, ("GCPhys=%RGp %s\n", GCPhys, szDesc), VERR_SSM_LOAD_CONFIG_MISMATCH);493 } /* forever */494 }495 496 497 /**498 * Scan ROM pages.499 *500 * @param pVM The VM handle.501 */502 static void pgmR3ScanRomPages(PVM pVM)503 {504 /*505 * The shadow ROMs.506 */507 pgmLock(pVM);508 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3)509 {510 if (pRom->fFlags & PGMPHYS_ROM_FLAGS_SHADOWED)511 {512 uint32_t const cPages = pRom->cb >> PAGE_SHIFT;513 for (uint32_t iPage = 0; iPage < cPages; iPage++)514 {515 PPGMROMPAGE pRomPage = &pRom->aPages[iPage];516 if (pRomPage->LiveSave.fWrittenTo)517 {518 pRomPage->LiveSave.fWrittenTo = false;519 if (!pRomPage->LiveSave.fDirty)520 {521 pRomPage->LiveSave.fDirty = true;522 pVM->pgm.s.LiveSave.cReadyPages--;523 pVM->pgm.s.LiveSave.cDirtyPages++;524 }525 pRomPage->LiveSave.fDirtiedRecently = true;526 }527 else528 pRomPage->LiveSave.fDirtiedRecently = false;529 }530 }531 }532 pgmUnlock(pVM);533 }534 535 536 /**537 * Takes care of the virgin ROM pages in the first pass.538 *539 * This is an attempt at simplifying the handling of ROM pages a little bit.540 * This ASSUMES that no new ROM ranges will be added and that they won't be541 * relinked in any way.542 *543 * @param pVM The VM handle.544 * @param pSSM The SSM handle.545 * @param fLiveSave Whether we're in a live save or not.546 */547 static int pgmR3SaveRomVirginPages(PVM pVM, PSSMHANDLE pSSM, bool fLiveSave)548 {549 pgmLock(pVM);550 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3)551 {552 uint32_t const cPages = pRom->cb >> PAGE_SHIFT;553 for (uint32_t iPage = 0; iPage < cPages; iPage++)554 {555 RTGCPHYS GCPhys = pRom->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT);556 PGMROMPROT enmProt = pRom->aPages[iPage].enmProt;557 558 /* Get the virgin page descriptor. */559 PPGMPAGE pPage;560 if (PGMROMPROT_IS_ROM(enmProt))561 pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);562 else563 pPage = &pRom->aPages[iPage].Virgin;564 565 /* Get the page bits. (Cannot use pgmPhysGCPhys2CCPtrInternalReadOnly here!) */566 int rc = VINF_SUCCESS;567 char abPage[PAGE_SIZE];568 if (!PGM_PAGE_IS_ZERO(pPage))569 {570 void const *pvPage;571 rc = pgmPhysPageMapReadOnly(pVM, pPage, GCPhys, &pvPage);572 if (RT_SUCCESS(rc))573 memcpy(abPage, pvPage, PAGE_SIZE);574 }575 else576 ASMMemZeroPage(abPage);577 pgmUnlock(pVM);578 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc GCPhys=%RGp\n", rc, GCPhys), rc);579 580 /* Save it. */581 if (iPage > 0)582 SSMR3PutU8(pSSM, PGM_STATE_REC_ROM_VIRGIN);583 else584 {585 SSMR3PutU8(pSSM, PGM_STATE_REC_ROM_VIRGIN | PGM_STATE_REC_FLAG_ADDR);586 SSMR3PutU8(pSSM, pRom->idSavedState);587 SSMR3PutU32(pSSM, iPage);588 }589 SSMR3PutU8(pSSM, (uint8_t)enmProt);590 rc = SSMR3PutMem(pSSM, abPage, PAGE_SIZE);591 if (RT_FAILURE(rc))592 return rc;593 594 /* Update state. */595 pgmLock(pVM);596 pRom->aPages[iPage].LiveSave.u8Prot = (uint8_t)enmProt;597 if (fLiveSave)598 {599 pVM->pgm.s.LiveSave.cDirtyPages--;600 pVM->pgm.s.LiveSave.cReadyPages++;601 }602 }603 }604 pgmUnlock(pVM);605 return VINF_SUCCESS;606 }607 608 609 /**610 * Saves dirty pages in the shadowed ROM ranges.611 *612 * Used by pgmR3LiveExecPart2 and pgmR3SaveExecMemory.613 *614 * @returns VBox status code.615 * @param pVM The VM handle.616 * @param pSSM The SSM handle.617 * @param fLiveSave Whether it's a live save or not.618 * @param fFinalPass Whether this is the final pass or not.619 */620 static int pgmR3SaveShadowedRomPages(PVM pVM, PSSMHANDLE pSSM, bool fLiveSave, bool fFinalPass)621 {622 /*623 * The Shadowed ROMs.624 *625 * ASSUMES that the ROM ranges are fixed.626 * ASSUMES that all the ROM ranges are mapped.627 */628 pgmLock(pVM);629 for (PPGMROMRANGE pRom = pVM->pgm.s.pRomRangesR3; pRom; pRom = pRom->pNextR3)630 {631 if (pRom->fFlags & PGMPHYS_ROM_FLAGS_SHADOWED)632 {633 uint32_t const cPages = pRom->cb >> PAGE_SHIFT;634 uint32_t iPrevPage = cPages;635 for (uint32_t iPage = 0; iPage < cPages; iPage++)636 {637 PPGMROMPAGE pRomPage = &pRom->aPages[iPage];638 if ( !fLiveSave639 || ( pRomPage->LiveSave.fDirty640 && ( ( !pRomPage->LiveSave.fDirtiedRecently641 && !pRomPage->LiveSave.fWrittenTo)642 || fFinalPass643 )644 )645 )646 {647 uint8_t abPage[PAGE_SIZE];648 PGMROMPROT enmProt = pRomPage->enmProt;649 RTGCPHYS GCPhys = pRom->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT);650 PPGMPAGE pPage = PGMROMPROT_IS_ROM(enmProt) ? &pRomPage->Shadow : pgmPhysGetPage(&pVM->pgm.s, GCPhys);651 bool fZero = PGM_PAGE_IS_ZERO(pPage);652 int rc = VINF_SUCCESS;653 if (!fZero)654 {655 void const *pvPage;656 rc = pgmPhysPageMapReadOnly(pVM, pPage, GCPhys, &pvPage);657 if (RT_SUCCESS(rc))658 memcpy(abPage, pvPage, PAGE_SIZE);659 }660 if (fLiveSave && RT_SUCCESS(rc))661 {662 pRomPage->LiveSave.u8Prot = (uint8_t)enmProt;663 pRomPage->LiveSave.fDirty = false;664 pVM->pgm.s.LiveSave.cReadyPages++;665 pVM->pgm.s.LiveSave.cDirtyPages--;666 }667 pgmUnlock(pVM);668 AssertLogRelMsgRCReturn(rc, ("rc=%Rrc GCPhys=%RGp\n", rc, GCPhys), rc);669 670 if (iPage - 1U == iPrevPage && iPage > 0)671 SSMR3PutU8(pSSM, (fZero ? PGM_STATE_REC_ROM_SHW_ZERO : PGM_STATE_REC_ROM_SHW_RAW));672 else673 {674 SSMR3PutU8(pSSM, (fZero ? PGM_STATE_REC_ROM_SHW_ZERO : PGM_STATE_REC_ROM_SHW_RAW) | PGM_STATE_REC_FLAG_ADDR);675 SSMR3PutU8(pSSM, pRom->idSavedState);676 SSMR3PutU32(pSSM, iPage);677 }678 rc = SSMR3PutU8(pSSM, (uint8_t)enmProt);679 if (!fZero)680 rc = SSMR3PutMem(pSSM, abPage, PAGE_SIZE);681 if (RT_FAILURE(rc))682 return rc;683 684 pgmLock(pVM);685 iPrevPage = iPage;686 }687 /*688 * In the final pass, make sure the protection is in sync.689 */690 else if ( fFinalPass691 && pRomPage->LiveSave.u8Prot != pRomPage->enmProt)692 {693 PGMROMPROT enmProt = pRomPage->enmProt;694 pRomPage->LiveSave.u8Prot = (uint8_t)enmProt;695 pgmUnlock(pVM);696 697 if (iPage - 1U == iPrevPage && iPage > 0)698 SSMR3PutU8(pSSM, PGM_STATE_REC_ROM_PROT);699 else700 {701 SSMR3PutU8(pSSM, PGM_STATE_REC_ROM_PROT | PGM_STATE_REC_FLAG_ADDR);702 SSMR3PutU8(pSSM, pRom->idSavedState);703 SSMR3PutU32(pSSM, iPage);704 }705 int rc = SSMR3PutU8(pSSM, (uint8_t)enmProt);706 if (RT_FAILURE(rc))707 return rc;708 709 pgmLock(pVM);710 iPrevPage = iPage;711 }712 }713 }714 }715 pgmUnlock(pVM);716 return VINF_SUCCESS;717 }718 719 720 /**721 * Assigns IDs to the MMIO2 ranges and saves them.722 *723 * @returns VBox status code.724 * @param pVM The VM handle.725 * @param pSSM Saved state handle.726 */727 static int pgmR3SaveMmio2Ranges(PVM pVM, PSSMHANDLE pSSM)728 {729 pgmLock(pVM);730 uint8_t id = 1;731 for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3, id++)732 {733 pMmio2->idSavedState = id;734 SSMR3PutU8(pSSM, id);735 SSMR3PutStrZ(pSSM, pMmio2->pDevInsR3->pDevReg->szDeviceName);736 SSMR3PutU32(pSSM, pMmio2->pDevInsR3->iInstance);737 SSMR3PutU8(pSSM, pMmio2->iRegion);738 SSMR3PutStrZ(pSSM, pMmio2->RamRange.pszDesc);739 int rc = SSMR3PutGCPhys(pSSM, pMmio2->RamRange.cb);740 if (RT_FAILURE(rc))741 break;742 }743 pgmUnlock(pVM);744 return SSMR3PutU8(pSSM, UINT8_MAX);745 }746 747 748 /**749 * Loads the MMIO2 range ID assignments.750 *751 * @returns VBox status code.752 *753 * @param pVM The VM handle.754 * @param pSSM The saved state handle.755 */756 static int pgmR3LoadMmio2Ranges(PVM pVM, PSSMHANDLE pSSM)757 {758 Assert(PGMIsLockOwner(pVM));759 760 for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3)761 pMmio2->idSavedState = UINT8_MAX;762 763 for (;;)764 {765 /*766 * Read the data.767 */768 uint8_t id;769 int rc = SSMR3GetU8(pSSM, &id);770 if (RT_FAILURE(rc))771 return rc;772 if (id == UINT8_MAX)773 {774 for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3)775 AssertLogRelMsg(pMmio2->idSavedState != UINT8_MAX, ("%s\n", pMmio2->RamRange.pszDesc));776 return VINF_SUCCESS; /* the end */777 }778 AssertLogRelReturn(id != 0, VERR_SSM_DATA_UNIT_FORMAT_CHANGED);779 780 char szDevName[RT_SIZEOFMEMB(PDMDEVREG, szDeviceName)];781 rc = SSMR3GetStrZ(pSSM, szDevName, sizeof(szDevName));782 AssertLogRelRCReturn(rc, rc);783 784 uint32_t uInstance;785 SSMR3GetU32(pSSM, &uInstance);786 uint8_t iRegion;787 SSMR3GetU8(pSSM, &iRegion);788 789 char szDesc[64];790 rc = SSMR3GetStrZ(pSSM, szDesc, sizeof(szDesc));791 AssertLogRelRCReturn(rc, rc);792 793 RTGCPHYS cb;794 rc = SSMR3GetGCPhys(pSSM, &cb);795 AssertLogRelMsgReturn(!(cb & PAGE_OFFSET_MASK), ("cb=%RGp %s\n", cb, szDesc), VERR_SSM_DATA_UNIT_FORMAT_CHANGED);796 797 /*798 * Locate a matching MMIO2 range.799 */800 PPGMMMIO2RANGE pMmio2;801 for (pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3)802 {803 if ( pMmio2->idSavedState == UINT8_MAX804 && pMmio2->iRegion == iRegion805 && pMmio2->pDevInsR3->iInstance == uInstance806 && !strcmp(pMmio2->pDevInsR3->pDevReg->szDeviceName, szDevName))807 {808 pMmio2->idSavedState = id;809 break;810 }811 }812 AssertLogRelMsgReturn(pMmio2, ("%s/%u/%u: %s\n", szDevName, uInstance, iRegion, szDesc), VERR_SSM_LOAD_CONFIG_MISMATCH);813 } /* forever */814 }815 816 817 /**818 * Scans one MMIO2 page.819 *820 * @returns True if changed, false if unchanged.821 *822 * @param pVM The VM handle823 * @param pbPage The page bits.824 * @param pLSPage The live save tracking structure for the page.825 *826 */827 DECLINLINE(bool) pgmR3ScanMmio2Page(PVM pVM, uint8_t const *pbPage, PPGMLIVESAVEMMIO2PAGE pLSPage)828 {829 /*830 * Special handling of zero pages.831 */832 if (pLSPage->fZero)833 {834 if (ASMMemIsZeroPage(pbPage))835 {836 /* Not modified. */837 if (pLSPage->fDirty)838 pLSPage->cUnchangedScans++;839 return false;840 }841 842 pLSPage->fZero = false;843 pLSPage->u32CrcH1 = RTCrc32(pbPage, PAGE_SIZE / 2);844 }845 else846 {847 /*848 * CRC the first half, if it doesn't match the page is dirty and849 * we won't check the 2nd half (we'll do that next time).850 */851 uint32_t u32CrcH1 = RTCrc32(pbPage, PAGE_SIZE / 2);852 if (u32CrcH1 == pLSPage->u32CrcH1)853 {854 uint32_t u32CrcH2 = RTCrc32(pbPage + PAGE_SIZE / 2, PAGE_SIZE / 2);855 if (u32CrcH2 == pLSPage->u32CrcH2)856 {857 /* Probably not modified. */858 if (pLSPage->fDirty)859 pLSPage->cUnchangedScans++;860 return false;861 }862 863 pLSPage->u32CrcH2 = u32CrcH2;864 }865 else866 {867 pLSPage->u32CrcH1 = u32CrcH1;868 if ( u32CrcH1 == PGM_STATE_CRC32_ZERO_HALF_PAGE869 && ASMMemIsZeroPage(pbPage))870 {871 pLSPage->u32CrcH2 = PGM_STATE_CRC32_ZERO_HALF_PAGE;872 pLSPage->fZero = true;873 }874 }875 }876 877 /* dirty page path */878 pLSPage->cUnchangedScans = 0;879 if (!pLSPage->fDirty)880 {881 pLSPage->fDirty = true;882 pVM->pgm.s.LiveSave.cReadyPages--;883 pVM->pgm.s.LiveSave.cDirtyMmio2Pages++;884 }885 return true;886 }887 888 889 /**890 * Scan for MMIO2 page modifications.891 *892 * @param pVM The VM handle.893 * @param uPass The pass number.894 */895 static void pgmR3ScanMmio2Pages(PVM pVM, uint32_t uPass)896 {897 /*898 * Only do this every 4th time as it's a little bit expensive.899 */900 if ( (uPass & 3) != 0901 || uPass == SSM_PASS_FINAL)902 return;903 904 pgmLock(pVM); /* paranoia */905 for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3)906 {907 PPGMLIVESAVEMMIO2PAGE paLSPages = pMmio2->paLSPages;908 uint8_t const *pbPage = (uint8_t const *)pMmio2->RamRange.pvR3;909 uint32_t cPages = pMmio2->RamRange.cb >> PAGE_SHIFT;910 pgmUnlock(pVM);911 912 for (uint32_t iPage = 0; iPage < cPages; iPage++, pbPage += PAGE_SIZE)913 {914 uint8_t const *pbPage = (uint8_t const *)pMmio2->pvR3 + iPage * PAGE_SIZE;915 pgmR3ScanMmio2Page(pVM,pbPage, &paLSPages[iPage]);916 }917 918 pgmLock(pVM);919 }920 pgmUnlock(pVM);921 922 }923 924 925 /**926 * Save quiescent MMIO2 pages.927 *928 * @returns VBox status code.929 * @param pVM The VM handle.930 * @param pSSM The SSM handle.931 * @param fLiveSave Whether it's a live save or not.932 * @param uPass The pass number.933 */934 static int pgmR3SaveMmio2Pages(PVM pVM, PSSMHANDLE pSSM, bool fLiveSave, uint32_t uPass)935 {936 /** @todo implement live saving of MMIO2 pages. (Need some way of telling the937 * device that we wish to know about changes.) */938 939 int rc = VINF_SUCCESS;940 if (uPass == SSM_PASS_FINAL)941 {942 /*943 * The mop up round.944 */945 pgmLock(pVM);946 for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3;947 pMmio2 && RT_SUCCESS(rc);948 pMmio2 = pMmio2->pNextR3)949 {950 PPGMLIVESAVEMMIO2PAGE paLSPages = pMmio2->paLSPages;951 uint8_t const *pbPage = (uint8_t const *)pMmio2->RamRange.pvR3;952 uint32_t cPages = pMmio2->RamRange.cb >> PAGE_SHIFT;953 uint32_t iPageLast = cPages;954 for (uint32_t iPage = 0; iPage < cPages; iPage++, pbPage += PAGE_SIZE)955 {956 uint8_t u8Type;957 if (!fLiveSave)958 u8Type = ASMMemIsZeroPage(pbPage) ? PGM_STATE_REC_MMIO2_ZERO : PGM_STATE_REC_MMIO2_RAW;959 else960 {961 /* Try figure if it's a clean page, compare the SHA-1 to be really sure. */962 if ( !paLSPages[iPage].fDirty963 && !pgmR3ScanMmio2Page(pVM, pbPage, &paLSPages[iPage]))964 {965 if (paLSPages[iPage].fZero)966 continue;967 968 uint8_t abSha1Hash[RTSHA1_HASH_SIZE];969 RTSha1(pbPage, PAGE_SIZE, abSha1Hash);970 if (!memcmp(abSha1Hash, paLSPages[iPage].abSha1Saved, sizeof(abSha1Hash)))971 continue;972 }973 u8Type = paLSPages[iPage].fZero ? PGM_STATE_REC_MMIO2_ZERO : PGM_STATE_REC_MMIO2_RAW;974 }975 976 if (iPage != 0 && iPage == iPageLast + 1)977 rc = SSMR3PutU8(pSSM, u8Type);978 else979 {980 SSMR3PutU8(pSSM, u8Type | PGM_STATE_REC_FLAG_ADDR);981 SSMR3PutU8(pSSM, pMmio2->idSavedState);982 rc = SSMR3PutU32(pSSM, iPage);983 }984 if (u8Type == PGM_STATE_REC_MMIO2_RAW)985 rc = SSMR3PutMem(pSSM, pbPage, PAGE_SIZE);986 if (RT_FAILURE(rc))987 break;988 iPageLast = iPage;989 }990 }991 pgmUnlock(pVM);992 }993 /*994 * Only do this every 4rd time since it's kind of expense.995 * We position it two passes after the scan pass to avoid saving busy pages.996 */997 else if ((uPass & 3) == 2)998 {999 pgmLock(pVM);1000 for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3;1001 pMmio2 && RT_SUCCESS(rc);1002 pMmio2 = pMmio2->pNextR3)1003 {1004 PPGMLIVESAVEMMIO2PAGE paLSPages = pMmio2->paLSPages;1005 uint8_t const *pbPage = (uint8_t const *)pMmio2->RamRange.pvR3;1006 uint32_t cPages = pMmio2->RamRange.cb >> PAGE_SHIFT;1007 uint32_t iPageLast = cPages;1008 pgmUnlock(pVM);1009 1010 for (uint32_t iPage = 0; iPage < cPages; iPage++, pbPage += PAGE_SIZE)1011 {1012 /* Skip clean pages and pages which hasn't quiesced. */1013 if (!paLSPages[iPage].fDirty)1014 continue;1015 if (paLSPages[iPage].cUnchangedScans < 3)1016 continue;1017 if (pgmR3ScanMmio2Page(pVM, pbPage, &paLSPages[iPage]))1018 continue;1019 1020 /* Save it. */1021 if (!paLSPages[iPage].fZero)1022 RTSha1(pbPage, PAGE_SIZE, paLSPages[iPage].abSha1Saved);1023 uint8_t u8Type = paLSPages[iPage].fZero ? PGM_STATE_REC_MMIO2_ZERO : PGM_STATE_REC_MMIO2_RAW;1024 if (iPage != 0 && iPage == iPageLast + 1)1025 rc = SSMR3PutU8(pSSM, u8Type);1026 else1027 {1028 SSMR3PutU8(pSSM, u8Type | PGM_STATE_REC_FLAG_ADDR);1029 SSMR3PutU8(pSSM, pMmio2->idSavedState);1030 rc = SSMR3PutU32(pSSM, iPage);1031 }1032 if (u8Type == PGM_STATE_REC_MMIO2_RAW)1033 rc = SSMR3PutMem(pSSM, pbPage, PAGE_SIZE);1034 if (RT_FAILURE(rc))1035 break;1036 iPageLast = iPage;1037 }1038 1039 pgmLock(pVM);1040 }1041 pgmUnlock(pVM);1042 }1043 1044 return rc;1045 1079 } 1046 1080 … … 1375 1409 1376 1410 /** 1411 * Cleans up RAM pages after a live save. 1412 * 1413 * @param pVM The VM handle. 1414 */ 1415 static void pgmR3DoneRamPages(PVM pVM) 1416 { 1417 /* 1418 * Free the tracking arrays and disable write monitoring. 1419 * 1420 * Play nice with the PGM lock in case we're called while the VM is still 1421 * running. This means we have to delay the freeing since we wish to use 1422 * paLSPages as an indicator of which RAM ranges which we need to scan for 1423 * write monitored pages. 1424 */ 1425 void *pvToFree = NULL; 1426 PPGMRAMRANGE pCur; 1427 uint32_t cMonitoredPages = 0; 1428 pgmLock(pVM); 1429 do 1430 { 1431 for (pCur = pVM->pgm.s.pRamRangesR3; pCur; pCur = pCur->pNextR3) 1432 { 1433 if (pCur->paLSPages) 1434 { 1435 if (pvToFree) 1436 { 1437 uint32_t idRamRangesGen = pVM->pgm.s.idRamRangesGen; 1438 pgmUnlock(pVM); 1439 MMR3HeapFree(pvToFree); 1440 pvToFree = NULL; 1441 pgmLock(pVM); 1442 if (idRamRangesGen != pVM->pgm.s.idRamRangesGen) 1443 break; /* start over again. */ 1444 } 1445 1446 pvToFree = pCur->paLSPages; 1447 pCur->paLSPages = NULL; 1448 1449 uint32_t iPage = pCur->cb >> PAGE_SHIFT; 1450 while (iPage--) 1451 { 1452 PPGMPAGE pPage = &pCur->aPages[iPage]; 1453 PGM_PAGE_CLEAR_WRITTEN_TO(pPage); 1454 if (PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED) 1455 { 1456 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_ALLOCATED); 1457 cMonitoredPages++; 1458 } 1459 } 1460 } 1461 } 1462 } while (pCur); 1463 1464 Assert(pVM->pgm.s.cMonitoredPages >= cMonitoredPages); 1465 if (pVM->pgm.s.cMonitoredPages < cMonitoredPages) 1466 pVM->pgm.s.cMonitoredPages = 0; 1467 else 1468 pVM->pgm.s.cMonitoredPages -= cMonitoredPages; 1469 1470 pgmUnlock(pVM); 1471 1472 MMR3HeapFree(pvToFree); 1473 pvToFree = NULL; 1474 } 1475 1476 1477 /** 1377 1478 * Execute a live save pass. 1378 1479 * … … 1515 1616 #endif /* !VBOX_WITH_LIVE_MIGRATION */ 1516 1617 1618 1619 /** 1620 * Prepare for a live save operation. 1621 * 1622 * This will attempt to allocate and initialize the tracking structures. It 1623 * will also prepare for write monitoring of pages and initialize PGM::LiveSave. 1624 * pgmR3SaveDone will do the cleanups. 1625 * 1626 * @returns VBox status code. 1627 * 1628 * @param pVM The VM handle. 1629 * @param pSSM The SSM handle. 1630 */ 1631 static DECLCALLBACK(int) pgmR3LivePrep(PVM pVM, PSSMHANDLE pSSM) 1632 { 1633 /* 1634 * Indicate that we will be using the write monitoring. 1635 */ 1636 pgmLock(pVM); 1637 /** @todo find a way of mediating this when more users are added. */ 1638 if (pVM->pgm.s.fPhysWriteMonitoringEngaged) 1639 { 1640 pgmUnlock(pVM); 1641 AssertLogRelFailedReturn(VERR_INTERNAL_ERROR_2); 1642 } 1643 pVM->pgm.s.fPhysWriteMonitoringEngaged = true; 1644 pgmUnlock(pVM); 1645 1646 /* 1647 * Initialize the statistics. 1648 */ 1649 pVM->pgm.s.LiveSave.cReadyPages = 0; 1650 pVM->pgm.s.LiveSave.cDirtyPages = 0; 1651 pVM->pgm.s.LiveSave.cIgnoredPages = 0; 1652 pVM->pgm.s.LiveSave.cDirtyMmio2Pages = 0; 1653 pVM->pgm.s.LiveSave.fActive = true; 1654 1655 /* 1656 * Per page type. 1657 */ 1658 int rc = pgmR3PrepRomPages(pVM); 1659 if (RT_SUCCESS(rc)) 1660 rc = pgmR3PrepMmio2Pages(pVM); 1661 if (RT_SUCCESS(rc)) 1662 rc = pgmR3PrepRamPages(pVM); 1663 return rc; 1664 } 1665 1666 1517 1667 /** 1518 1668 * Execute state save operation. … … 1658 1808 { 1659 1809 /* 1660 * Free the tracking arrays and disable write monitoring. 1661 * 1662 * Play nice with the PGM lock in case we're called while the VM is still 1663 * running. This means we have to delay the freeing since we wish to use 1664 * paLSPages as an indicator of which RAM ranges which we need to scan for 1665 * write monitored pages. 1666 */ 1667 void *pvToFree = NULL; 1668 PPGMRAMRANGE pCur; 1669 uint32_t cMonitoredPages = 0; 1810 * Do per page type cleanups first. 1811 */ 1812 if (pVM->pgm.s.LiveSave.fActive) 1813 { 1814 pgmR3DoneRomPages(pVM); 1815 pgmR3DoneMmio2Pages(pVM); 1816 pgmR3DoneRamPages(pVM); 1817 } 1818 1819 /* 1820 * Clear the live save indicator and disengage write monitoring. 1821 */ 1670 1822 pgmLock(pVM); 1671 do1672 {1673 for (pCur = pVM->pgm.s.pRamRangesR3; pCur; pCur = pCur->pNextR3)1674 {1675 if (pCur->paLSPages)1676 {1677 if (pvToFree)1678 {1679 uint32_t idRamRangesGen = pVM->pgm.s.idRamRangesGen;1680 pgmUnlock(pVM);1681 MMR3HeapFree(pvToFree);1682 pvToFree = NULL;1683 pgmLock(pVM);1684 if (idRamRangesGen != pVM->pgm.s.idRamRangesGen)1685 break; /* start over again. */1686 }1687 1688 pvToFree = pCur->paLSPages;1689 pCur->paLSPages = NULL;1690 1691 uint32_t iPage = pCur->cb >> PAGE_SHIFT;1692 while (iPage--)1693 {1694 PPGMPAGE pPage = &pCur->aPages[iPage];1695 PGM_PAGE_CLEAR_WRITTEN_TO(pPage);1696 if (PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED)1697 {1698 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_ALLOCATED);1699 cMonitoredPages++;1700 }1701 }1702 }1703 }1704 } while (pCur);1705 1706 /* Ditto for MMIO2 (ASSUME no runtime MMIO2 changes). */1707 for (PPGMMMIO2RANGE pMmio2 = pVM->pgm.s.pMmio2RangesR3; pMmio2; pMmio2 = pMmio2->pNextR3)1708 {1709 void *pvMmio2ToFree = pMmio2->paLSPages;1710 if (pvMmio2ToFree)1711 {1712 pMmio2->paLSPages = NULL;1713 pgmUnlock(pVM);1714 MMR3HeapFree(pvMmio2ToFree);1715 pgmLock(pVM);1716 }1717 }1718 1719 /* Update PGM state. */1720 1823 pVM->pgm.s.LiveSave.fActive = false; 1721 1722 Assert(pVM->pgm.s.cMonitoredPages >= cMonitoredPages);1723 if (pVM->pgm.s.cMonitoredPages < cMonitoredPages)1724 pVM->pgm.s.cMonitoredPages = 0;1725 else1726 pVM->pgm.s.cMonitoredPages -= cMonitoredPages;1727 1728 1824 /** @todo this is blindly assuming that we're the only user of write 1729 1825 * monitoring. Fix this when more users are added. */ 1730 1826 pVM->pgm.s.fPhysWriteMonitoringEngaged = false; 1731 1827 pgmUnlock(pVM); 1732 1733 MMR3HeapFree(pvToFree);1734 pvToFree = NULL;1735 1828 1736 1829 return VINF_SUCCESS;
Note:
See TracChangeset
for help on using the changeset viewer.