Changeset 6906 in vbox
- Timestamp:
- Feb 11, 2008 6:17:52 PM (17 years ago)
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/PGMInternal.h
r6902 r6906 2479 2479 int pgmHandlerVirtualFindByPhysAddr(PVM pVM, RTGCPHYS GCPhys, PPGMVIRTHANDLER *ppVirt, unsigned *piPage); 2480 2480 DECLCALLBACK(int) pgmHandlerVirtualResetOne(PAVLROGCPTRNODECORE pNode, void *pvUser); 2481 #if def VBOX_STRICT2481 #if defined(VBOX_STRICT) || defined(LOG_ENABLED) 2482 2482 void pgmHandlerVirtualDumpPhysPages(PVM pVM); 2483 2483 #else -
trunk/src/VBox/VMM/VMMAll/PGMAll.cpp
r6905 r6906 779 779 780 780 /** 781 * Temporarily turns off the access monitoring of a page within a monitored782 * physical write/all page access handler region.783 *784 * Use this when no further \#PFs are required for that page. Be aware that785 * a page directory sync might reset the flags, and turn on access monitoring786 * for the page.787 *788 * The caller must do required page table modifications.789 *790 * @returns VBox status code.791 * @param pVM VM Handle792 * @param GCPhys Start physical address earlier passed to PGMR3HandlerPhysicalRegister().793 * This must be a fully page aligned range or we risk messing up other794 * handlers installed for the start and end pages.795 * @param GCPhysPage Physical address of the page to turn off access monitoring for.796 * @todo move to PGMAllHandler.cpp797 */798 PGMDECL(int) PGMHandlerPhysicalPageTempOff(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage)799 {800 /*801 * Validate the range.802 */803 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, GCPhys);804 if (pCur)805 {806 if ( GCPhysPage >= pCur->Core.Key807 && GCPhysPage <= pCur->Core.KeyLast)808 {809 Assert(!(pCur->Core.Key & PAGE_OFFSET_MASK));810 Assert((pCur->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);811 812 AssertReturn( pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_WRITE813 || pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_ALL,814 VERR_ACCESS_DENIED);815 816 /*817 * Change the page status.818 */819 PPGMPAGE pPage;820 int rc = pgmPhysGetPageEx(&pVM->pgm.s, GCPhysPage, &pPage);821 AssertRCReturn(rc, rc);822 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, PGM_PAGE_HNDL_PHYS_STATE_DISABLED);823 return VINF_SUCCESS;824 }825 826 AssertMsgFailed(("The page %#x is outside the range %#x-%#x\n",827 GCPhysPage, pCur->Core.Key, pCur->Core.KeyLast));828 return VERR_INVALID_PARAMETER;829 }830 831 AssertMsgFailed(("Specified physical handler start address %#x is invalid.\n", GCPhys));832 return VERR_PGM_HANDLER_NOT_FOUND;833 }834 835 836 /**837 * Turns access monitoring of a page within a monitored838 * physical write/all page access handler regio back on.839 *840 * The caller must do required page table modifications.841 *842 * @returns VBox status code.843 * @param pVM VM Handle844 * @param GCPhys Start physical address earlier passed to PGMR3HandlerPhysicalRegister().845 * This must be a fully page aligned range or we risk messing up other846 * handlers installed for the start and end pages.847 * @param GCPhysPage Physical address of the page to turn on access monitoring for.848 * @todo move to PGMAllHandler.cpp849 */850 PGMDECL(int) PGMHandlerPhysicalPageReset(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage)851 {852 /*853 * Validate the range.854 */855 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, GCPhys);856 if (pCur)857 {858 if ( GCPhysPage >= pCur->Core.Key859 && GCPhysPage <= pCur->Core.KeyLast)860 {861 Assert(!(pCur->Core.Key & PAGE_OFFSET_MASK));862 Assert((pCur->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);863 864 AssertReturn( pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_WRITE865 || pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_ALL,866 VERR_ACCESS_DENIED);867 868 /*869 * Change the page status.870 */871 PPGMPAGE pPage;872 int rc = pgmPhysGetPageEx(&pVM->pgm.s, GCPhysPage, &pPage);873 AssertRCReturn(rc, rc);874 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, pgmHandlerPhysicalCalcState(pCur));875 return VINF_SUCCESS;876 }877 878 AssertMsgFailed(("The page %#x is outside the range %#x-%#x\n",879 GCPhysPage, pCur->Core.Key, pCur->Core.KeyLast));880 return VERR_INVALID_PARAMETER;881 }882 883 AssertMsgFailed(("Specified physical handler start address %#x is invalid.\n", GCPhys));884 return VERR_PGM_HANDLER_NOT_FOUND;885 }886 887 888 /**889 * Checks if a physical range is handled890 *891 * @returns boolean892 * @param pVM VM Handle893 * @param GCPhys Start physical address earlier passed to PGMR3HandlerPhysicalRegister().894 * @todo move to PGMAllHandler.cpp895 */896 PGMDECL(bool) PGMHandlerPhysicalIsRegistered(PVM pVM, RTGCPHYS GCPhys)897 {898 /*899 * Find the handler.900 */901 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, GCPhys);902 if (pCur)903 {904 if ( GCPhys >= pCur->Core.Key905 && GCPhys <= pCur->Core.KeyLast)906 {907 Assert( pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_WRITE908 || pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_ALL909 || pCur->enmType == PGMPHYSHANDLERTYPE_MMIO);910 return true;911 }912 }913 914 return false;915 }916 917 918 #ifdef VBOX_STRICT919 DECLCALLBACK(int) pgmVirtHandlerDumpPhysRange(PAVLROGCPHYSNODECORE pNode, void *pvUser)920 {921 PPGMPHYS2VIRTHANDLER pCur = (PPGMPHYS2VIRTHANDLER)pNode;922 PPGMVIRTHANDLER pVirt = (PPGMVIRTHANDLER)((uintptr_t)pCur + pCur->offVirtHandler);923 Log(("PHYS2VIRT: Range %VGp-%VGp for virtual handler: %s\n", pCur->Core.Key, pCur->Core.KeyLast, pVirt->pszDesc));924 return 0;925 }926 927 928 void pgmHandlerVirtualDumpPhysPages(PVM pVM)929 {930 RTAvlroGCPhysDoWithAll(CTXSUFF(&pVM->pgm.s.pTrees)->PhysToVirtHandlers, true, pgmVirtHandlerDumpPhysRange, 0);931 }932 #endif /* VBOX_STRICT */933 934 935 /**936 781 * Gets the current CR3 register value for the shadow memory context. 937 782 * @returns CR3 value. … … 1376 1221 1377 1222 /** 1378 * State structure used by the PGMAssertHandlerAndFlagsInSync() function1379 * and its AVL enumerators.1380 */1381 typedef struct PGMAHAFIS1382 {1383 /** The VM handle. */1384 PVM pVM;1385 /** Number of errors. */1386 unsigned cErrors;1387 /** The flags we've found. */1388 unsigned fFlagsFound;1389 /** The flags we're matching up to.1390 * This is also on the stack as a const, thus only valid during enumeration. */1391 unsigned fFlags;1392 /** The current physical address. */1393 RTGCPHYS GCPhys;1394 } PGMAHAFIS, *PPGMAHAFIS;1395 1396 /**1397 * Verify virtual handler by matching physical address.1398 *1399 * @returns 01400 * @param pNode Pointer to a PGMVIRTHANDLER.1401 * @param pvUser Pointer to user parameter.1402 */1403 static DECLCALLBACK(int) pgmVirtHandlerVerifyOneByPhysAddr(PAVLROGCPTRNODECORE pNode, void *pvUser)1404 {1405 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)pNode;1406 PPGMAHAFIS pState = (PPGMAHAFIS)pvUser;1407 1408 for (unsigned iPage = 0; iPage < pCur->cPages; iPage++)1409 {1410 if ((pCur->aPhysToVirt[iPage].Core.Key & X86_PTE_PAE_PG_MASK) == pState->GCPhys)1411 {1412 switch (pCur->enmType)1413 {1414 case PGMVIRTHANDLERTYPE_EIP:1415 case PGMVIRTHANDLERTYPE_NORMAL: pState->fFlagsFound |= MM_RAM_FLAGS_VIRTUAL_HANDLER; break;1416 case PGMVIRTHANDLERTYPE_WRITE: pState->fFlagsFound |= MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_WRITE; break;1417 case PGMVIRTHANDLERTYPE_ALL: pState->fFlagsFound |= MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_ALL; break;1418 /* hypervisor handlers need no flags and wouldn't have nowhere to put them in any case. */1419 case PGMVIRTHANDLERTYPE_HYPERVISOR:1420 return 0;1421 }1422 if ( (pState->fFlags & (MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_WRITE | MM_RAM_FLAGS_VIRTUAL_ALL))1423 == pState->fFlagsFound)1424 break;1425 }1426 }1427 return 0;1428 }1429 1430 1431 /**1432 * Verify a virtual handler.1433 *1434 * @returns 01435 * @param pNode Pointer to a PGMVIRTHANDLER.1436 * @param pvUser Pointer to user parameter.1437 */1438 static DECLCALLBACK(int) pgmVirtHandlerVerifyOne(PAVLROGCPTRNODECORE pNode, void *pvUser)1439 {1440 PPGMVIRTHANDLER pVirt = (PPGMVIRTHANDLER)pNode;1441 PPGMAHAFIS pState = (PPGMAHAFIS)pvUser;1442 PVM pVM = pState->pVM;1443 1444 if ( pVirt->aPhysToVirt[0].Core.Key != NIL_RTGCPHYS1445 && (pVirt->aPhysToVirt[0].Core.Key & PAGE_OFFSET_MASK) != ((RTGCUINTPTR)pVirt->GCPtr & PAGE_OFFSET_MASK))1446 {1447 AssertMsgFailed(("virt handler phys out has incorrect key! %VGp %VGv %s\n",1448 pVirt->aPhysToVirt[0].Core.Key, pVirt->GCPtr, HCSTRING(pVirt->pszDesc)));1449 pState->cErrors++;1450 }1451 1452 /*1453 * Calc flags.1454 */1455 unsigned fFlags;1456 switch (pVirt->enmType)1457 {1458 case PGMVIRTHANDLERTYPE_EIP:1459 case PGMVIRTHANDLERTYPE_NORMAL: fFlags = MM_RAM_FLAGS_VIRTUAL_HANDLER; break;1460 case PGMVIRTHANDLERTYPE_WRITE: fFlags = MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_WRITE; break;1461 case PGMVIRTHANDLERTYPE_ALL: fFlags = MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_ALL; break;1462 /* hypervisor handlers need no flags and wouldn't have nowhere to put them in any case. */1463 case PGMVIRTHANDLERTYPE_HYPERVISOR:1464 return 0;1465 default:1466 AssertMsgFailed(("unknown enmType=%d\n", pVirt->enmType));1467 return 0;1468 }1469 1470 /*1471 * Check pages against flags.1472 */1473 RTGCUINTPTR GCPtr = (RTGCUINTPTR)pVirt->GCPtr;1474 for (unsigned iPage = 0; iPage < pVirt->cPages; iPage++, GCPtr += PAGE_SIZE)1475 {1476 RTGCPHYS GCPhysGst;1477 uint64_t fGst;1478 int rc = PGMGstGetPage(pVM, (RTGCPTR)GCPtr, &fGst, &GCPhysGst);1479 if ( rc == VERR_PAGE_NOT_PRESENT1480 || rc == VERR_PAGE_TABLE_NOT_PRESENT)1481 {1482 if (pVirt->aPhysToVirt[iPage].Core.Key != NIL_RTGCPHYS)1483 {1484 AssertMsgFailed(("virt handler phys out of sync. %VGp GCPhysNew=~0 iPage=%#x %VGv %s\n",1485 pVirt->aPhysToVirt[iPage].Core.Key, iPage, GCPtr, HCSTRING(pVirt->pszDesc)));1486 pState->cErrors++;1487 }1488 continue;1489 }1490 1491 AssertRCReturn(rc, 0);1492 if ((pVirt->aPhysToVirt[iPage].Core.Key & X86_PTE_PAE_PG_MASK) != GCPhysGst)1493 {1494 AssertMsgFailed(("virt handler phys out of sync. %VGp GCPhysGst=%VGp iPage=%#x %VGv %s\n",1495 pVirt->aPhysToVirt[iPage].Core.Key, GCPhysGst, iPage, GCPtr, HCSTRING(pVirt->pszDesc)));1496 pState->cErrors++;1497 continue;1498 }1499 1500 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhysGst);1501 if (!pPage)1502 {1503 AssertMsgFailed(("virt handler getting ram flags. GCPhysGst=%VGp iPage=%#x %VGv %s\n",1504 GCPhysGst, iPage, GCPtr, HCSTRING(pVirt->pszDesc)));1505 pState->cErrors++;1506 continue;1507 }1508 1509 if ((pPage->HCPhys & fFlags) != fFlags) /** @todo PAGE FLAGS */1510 {1511 AssertMsgFailed(("virt handler flags mismatch. HCPhys=%VHp fFlags=%#x GCPhysGst=%VGp iPage=%#x %VGv %s\n",1512 pPage->HCPhys, fFlags, GCPhysGst, iPage, GCPtr, HCSTRING(pVirt->pszDesc)));1513 pState->cErrors++;1514 continue;1515 }1516 } /* for pages in virtual mapping. */1517 1518 return 0;1519 }1520 1521 1522 /**1523 * Asserts that the handlers+guest-page-tables == ramrange-flags and1524 * that the physical addresses associated with virtual handlers are correct.1525 *1526 * @returns Number of mismatches.1527 * @param pVM The VM handle.1528 */1529 PGMDECL(unsigned) PGMAssertHandlerAndFlagsInSync(PVM pVM)1530 {1531 PPGM pPGM = &pVM->pgm.s;1532 PGMAHAFIS State;1533 State.cErrors = 0;1534 State.pVM = pVM;1535 1536 /*1537 * Check the RAM flags against the handlers.1538 */1539 for (PPGMRAMRANGE pRam = CTXALLSUFF(pPGM->pRamRanges); pRam; pRam = CTXALLSUFF(pRam->pNext))1540 {1541 const unsigned cPages = pRam->cb >> PAGE_SHIFT;1542 for (unsigned iPage = 0; iPage < cPages; iPage++)1543 {1544 PGMPAGE const *pPage = &pRam->aPages[iPage];1545 if (PGM_PAGE_HAVE_ANY_HANDLERS(pPage))1546 {1547 State.GCPhys = pRam->GCPhys + (iPage << PAGE_SHIFT);1548 State.fFlagsFound = 0; /* build flags and compare. */1549 1550 /*1551 * Physical first - calculate the state based on the handlers1552 * active on the page, then compare.1553 */1554 if (PGM_PAGE_HAVE_ANY_PHYSICAL_HANDLERS(pPage))1555 {1556 /* the first */1557 PPGMPHYSHANDLER pPhys = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pPGM->CTXSUFF(pTrees)->PhysHandlers, State.GCPhys);1558 if (!pPhys)1559 {1560 pPhys = (PPGMPHYSHANDLER)RTAvlroGCPhysGetBestFit(&pPGM->CTXSUFF(pTrees)->PhysHandlers, State.GCPhys, true);1561 if ( pPhys1562 && pPhys->Core.Key > (State.GCPhys + PAGE_SIZE - 1))1563 pPhys = NULL;1564 Assert(!pPhys || pPhys->Core.Key >= State.GCPhys);1565 }1566 if (pPhys)1567 {1568 unsigned uState = pgmHandlerPhysicalCalcState(pPhys);1569 1570 /* more? */1571 while (pPhys->Core.KeyLast < (State.GCPhys | PAGE_OFFSET_MASK))1572 {1573 PPGMPHYSHANDLER pPhys2 = (PPGMPHYSHANDLER)RTAvlroGCPhysGetBestFit(&pPGM->CTXSUFF(pTrees)->PhysHandlers,1574 pPhys->Core.KeyLast + 1, true);1575 if ( !pPhys21576 || pPhys2->Core.Key > (State.GCPhys | PAGE_OFFSET_MASK))1577 break;1578 unsigned uState2 = pgmHandlerPhysicalCalcState(pPhys2);1579 uState = RT_MAX(uState, uState2);1580 pPhys = pPhys2;1581 }1582 1583 /* compare.*/1584 if ( PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) != uState1585 && PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) != PGM_PAGE_HNDL_PHYS_STATE_DISABLED)1586 {1587 AssertMsgFailed(("ram range vs phys handler flags mismatch. GCPhys=%RGp state=%d expected=%d %s\n",1588 State.GCPhys, PGM_PAGE_GET_HNDL_PHYS_STATE(pPage), uState, pPhys->pszDesc));1589 State.cErrors++;1590 }1591 1592 #ifdef IN_RING31593 /* validate that REM is handling it. */1594 if ( !REMR3IsPageAccessHandled(pVM, State.GCPhys)1595 /* ignore shadowed ROM for the time being. */ /// @todo PAGE FLAGS1596 && (pPage->HCPhys & (MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO2)) != (MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO2))1597 {1598 AssertMsgFailed(("ram range vs phys handler REM mismatch. GCPhys=%RGp state=%d %s\n",1599 State.GCPhys, PGM_PAGE_GET_HNDL_PHYS_STATE(pPage), pPhys->pszDesc));1600 State.cErrors++;1601 }1602 #endif1603 }1604 else1605 {1606 AssertMsgFailed(("ram range vs phys handler mismatch. no handler for GCPhys=%RGp\n", State.GCPhys));1607 State.cErrors++;1608 }1609 }1610 1611 /* virtual flags. */1612 if (PGM_PAGE_HAVE_ACTIVE_VIRTUAL_HANDLERS(pPage))1613 {1614 State.fFlags = pPage->HCPhys & (MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_WRITE | MM_RAM_FLAGS_VIRTUAL_ALL); /// @todo PAGE FLAGS1615 RTAvlroGCPtrDoWithAll(CTXSUFF(&pVM->pgm.s.pTrees)->VirtHandlers, true, pgmVirtHandlerVerifyOneByPhysAddr, &State);1616 if (State.fFlags != State.fFlagsFound)1617 {1618 AssertMsgFailed(("ram range vs virt handler flags mismatch. GCPhys=%RGp fFlags=%#x fFlagsFound=%#x\n",1619 State.GCPhys, State.fFlags, State.fFlagsFound));1620 State.cErrors++;1621 }1622 1623 }1624 }1625 } /* foreach page in ram range. */1626 } /* foreach ram range. */1627 1628 /*1629 * Check that the physical addresses of the virtual handlers matches up.1630 */1631 RTAvlroGCPtrDoWithAll(CTXSUFF(&pVM->pgm.s.pTrees)->VirtHandlers, true, pgmVirtHandlerVerifyOne, &State);1632 1633 /*1634 * Do the reverse check for physical handlers.1635 */1636 /** @todo */1637 1638 return State.cErrors;1639 }1640 1641 1642 /**1643 1223 * Asserts that there are no mapping conflicts. 1644 1224 * -
trunk/src/VBox/VMM/VMMAll/PGMAllHandler.cpp
r6902 r6906 863 863 pgmUnlock(pVM); 864 864 return rc; 865 } 866 867 868 /** 869 * Temporarily turns off the access monitoring of a page within a monitored 870 * physical write/all page access handler region. 871 * 872 * Use this when no further \#PFs are required for that page. Be aware that 873 * a page directory sync might reset the flags, and turn on access monitoring 874 * for the page. 875 * 876 * The caller must do required page table modifications. 877 * 878 * @returns VBox status code. 879 * @param pVM VM Handle 880 * @param GCPhys Start physical address earlier passed to PGMR3HandlerPhysicalRegister(). 881 * This must be a fully page aligned range or we risk messing up other 882 * handlers installed for the start and end pages. 883 * @param GCPhysPage Physical address of the page to turn off access monitoring for. 884 */ 885 PGMDECL(int) PGMHandlerPhysicalPageTempOff(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage) 886 { 887 /* 888 * Validate the range. 889 */ 890 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, GCPhys); 891 if (pCur) 892 { 893 if ( GCPhysPage >= pCur->Core.Key 894 && GCPhysPage <= pCur->Core.KeyLast) 895 { 896 Assert(!(pCur->Core.Key & PAGE_OFFSET_MASK)); 897 Assert((pCur->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK); 898 899 AssertReturn( pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_WRITE 900 || pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_ALL, 901 VERR_ACCESS_DENIED); 902 903 /* 904 * Change the page status. 905 */ 906 PPGMPAGE pPage; 907 int rc = pgmPhysGetPageEx(&pVM->pgm.s, GCPhysPage, &pPage); 908 AssertRCReturn(rc, rc); 909 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, PGM_PAGE_HNDL_PHYS_STATE_DISABLED); 910 return VINF_SUCCESS; 911 } 912 913 AssertMsgFailed(("The page %#x is outside the range %#x-%#x\n", 914 GCPhysPage, pCur->Core.Key, pCur->Core.KeyLast)); 915 return VERR_INVALID_PARAMETER; 916 } 917 918 AssertMsgFailed(("Specified physical handler start address %#x is invalid.\n", GCPhys)); 919 return VERR_PGM_HANDLER_NOT_FOUND; 920 } 921 922 923 /** 924 * Turns access monitoring of a page within a monitored 925 * physical write/all page access handler regio back on. 926 * 927 * The caller must do required page table modifications. 928 * 929 * @returns VBox status code. 930 * @param pVM VM Handle 931 * @param GCPhys Start physical address earlier passed to PGMR3HandlerPhysicalRegister(). 932 * This must be a fully page aligned range or we risk messing up other 933 * handlers installed for the start and end pages. 934 * @param GCPhysPage Physical address of the page to turn on access monitoring for. 935 */ 936 PGMDECL(int) PGMHandlerPhysicalPageReset(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage) 937 { 938 /* 939 * Validate the range. 940 */ 941 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, GCPhys); 942 if (pCur) 943 { 944 if ( GCPhysPage >= pCur->Core.Key 945 && GCPhysPage <= pCur->Core.KeyLast) 946 { 947 Assert(!(pCur->Core.Key & PAGE_OFFSET_MASK)); 948 Assert((pCur->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK); 949 950 AssertReturn( pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_WRITE 951 || pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_ALL, 952 VERR_ACCESS_DENIED); 953 954 /* 955 * Change the page status. 956 */ 957 PPGMPAGE pPage; 958 int rc = pgmPhysGetPageEx(&pVM->pgm.s, GCPhysPage, &pPage); 959 AssertRCReturn(rc, rc); 960 PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, pgmHandlerPhysicalCalcState(pCur)); 961 return VINF_SUCCESS; 962 } 963 964 AssertMsgFailed(("The page %#x is outside the range %#x-%#x\n", 965 GCPhysPage, pCur->Core.Key, pCur->Core.KeyLast)); 966 return VERR_INVALID_PARAMETER; 967 } 968 969 AssertMsgFailed(("Specified physical handler start address %#x is invalid.\n", GCPhys)); 970 return VERR_PGM_HANDLER_NOT_FOUND; 971 } 972 973 974 /** 975 * Checks if a physical range is handled 976 * 977 * @returns boolean 978 * @param pVM VM Handle 979 * @param GCPhys Start physical address earlier passed to PGMR3HandlerPhysicalRegister(). 980 */ 981 PGMDECL(bool) PGMHandlerPhysicalIsRegistered(PVM pVM, RTGCPHYS GCPhys) 982 { 983 /* 984 * Find the handler. 985 */ 986 PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, GCPhys); 987 if (pCur) 988 { 989 if ( GCPhys >= pCur->Core.Key 990 && GCPhys <= pCur->Core.KeyLast) 991 { 992 Assert( pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_WRITE 993 || pCur->enmType == PGMPHYSHANDLERTYPE_PHYSICAL_ALL 994 || pCur->enmType == PGMPHYSHANDLERTYPE_MMIO); 995 return true; 996 } 997 } 998 999 return false; 865 1000 } 866 1001 … … 1027 1162 } 1028 1163 1164 1165 #if defined(VBOX_STRICT) || defined(LOG_ENABLED) 1166 /** 1167 * Worker for pgmHandlerVirtualDumpPhysPages. 1168 * 1169 * @returns 0 (continue enumeration). 1170 * @param pNode The virtual handler node. 1171 * @param pvUser User argument, unused. 1172 */ 1173 static DECLCALLBACK(int) pgmHandlerVirtualDumpPhysPagesCallback(PAVLROGCPHYSNODECORE pNode, void *pvUser) 1174 { 1175 PPGMPHYS2VIRTHANDLER pCur = (PPGMPHYS2VIRTHANDLER)pNode; 1176 PPGMVIRTHANDLER pVirt = (PPGMVIRTHANDLER)((uintptr_t)pCur + pCur->offVirtHandler); 1177 Log(("PHYS2VIRT: Range %VGp-%VGp for virtual handler: %s\n", pCur->Core.Key, pCur->Core.KeyLast, pVirt->pszDesc)); 1178 return 0; 1179 } 1180 1181 1182 /** 1183 * Assertion / logging helper for dumping all the 1184 * virtual handlers to the log. 1185 * 1186 * @param pVM Pointer to the shared VM structure. 1187 */ 1188 void pgmHandlerVirtualDumpPhysPages(PVM pVM) 1189 { 1190 RTAvlroGCPhysDoWithAll(CTXSUFF(&pVM->pgm.s.pTrees)->PhysToVirtHandlers, true /* from left */, 1191 pgmHandlerVirtualDumpPhysPagesCallback, 0); 1192 } 1193 #endif /* VBOX_STRICT || LOG_ENABLED */ 1194 1195 #ifdef VBOX_STRICT 1196 1197 /** 1198 * State structure used by the PGMAssertHandlerAndFlagsInSync() function 1199 * and its AVL enumerators. 1200 */ 1201 typedef struct PGMAHAFIS 1202 { 1203 /** The VM handle. */ 1204 PVM pVM; 1205 /** Number of errors. */ 1206 unsigned cErrors; 1207 /** The flags we've found. */ 1208 unsigned fFlagsFound; 1209 /** The flags we're matching up to. 1210 * This is also on the stack as a const, thus only valid during enumeration. */ 1211 unsigned fFlags; 1212 /** The current physical address. */ 1213 RTGCPHYS GCPhys; 1214 } PGMAHAFIS, *PPGMAHAFIS; 1215 1216 /** 1217 * Verify virtual handler by matching physical address. 1218 * 1219 * @returns 0 1220 * @param pNode Pointer to a PGMVIRTHANDLER. 1221 * @param pvUser Pointer to user parameter. 1222 */ 1223 static DECLCALLBACK(int) pgmVirtHandlerVerifyOneByPhysAddr(PAVLROGCPTRNODECORE pNode, void *pvUser) 1224 { 1225 PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)pNode; 1226 PPGMAHAFIS pState = (PPGMAHAFIS)pvUser; 1227 1228 for (unsigned iPage = 0; iPage < pCur->cPages; iPage++) 1229 { 1230 if ((pCur->aPhysToVirt[iPage].Core.Key & X86_PTE_PAE_PG_MASK) == pState->GCPhys) 1231 { 1232 switch (pCur->enmType) 1233 { 1234 case PGMVIRTHANDLERTYPE_EIP: 1235 case PGMVIRTHANDLERTYPE_NORMAL: pState->fFlagsFound |= MM_RAM_FLAGS_VIRTUAL_HANDLER; break; 1236 case PGMVIRTHANDLERTYPE_WRITE: pState->fFlagsFound |= MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_WRITE; break; 1237 case PGMVIRTHANDLERTYPE_ALL: pState->fFlagsFound |= MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_ALL; break; 1238 /* hypervisor handlers need no flags and wouldn't have nowhere to put them in any case. */ 1239 case PGMVIRTHANDLERTYPE_HYPERVISOR: 1240 return 0; 1241 } 1242 if ( (pState->fFlags & (MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_WRITE | MM_RAM_FLAGS_VIRTUAL_ALL)) 1243 == pState->fFlagsFound) 1244 break; 1245 } 1246 } 1247 return 0; 1248 } 1249 1250 1251 /** 1252 * Verify a virtual handler. 1253 * 1254 * @returns 0 1255 * @param pNode Pointer to a PGMVIRTHANDLER. 1256 * @param pvUser Pointer to user parameter. 1257 */ 1258 static DECLCALLBACK(int) pgmVirtHandlerVerifyOne(PAVLROGCPTRNODECORE pNode, void *pvUser) 1259 { 1260 PPGMVIRTHANDLER pVirt = (PPGMVIRTHANDLER)pNode; 1261 PPGMAHAFIS pState = (PPGMAHAFIS)pvUser; 1262 PVM pVM = pState->pVM; 1263 1264 if ( pVirt->aPhysToVirt[0].Core.Key != NIL_RTGCPHYS 1265 && (pVirt->aPhysToVirt[0].Core.Key & PAGE_OFFSET_MASK) != ((RTGCUINTPTR)pVirt->GCPtr & PAGE_OFFSET_MASK)) 1266 { 1267 AssertMsgFailed(("virt handler phys out has incorrect key! %VGp %VGv %s\n", 1268 pVirt->aPhysToVirt[0].Core.Key, pVirt->GCPtr, HCSTRING(pVirt->pszDesc))); 1269 pState->cErrors++; 1270 } 1271 1272 /* 1273 * Calc flags. 1274 */ 1275 unsigned fFlags; 1276 switch (pVirt->enmType) 1277 { 1278 case PGMVIRTHANDLERTYPE_EIP: 1279 case PGMVIRTHANDLERTYPE_NORMAL: fFlags = MM_RAM_FLAGS_VIRTUAL_HANDLER; break; 1280 case PGMVIRTHANDLERTYPE_WRITE: fFlags = MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_WRITE; break; 1281 case PGMVIRTHANDLERTYPE_ALL: fFlags = MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_ALL; break; 1282 /* hypervisor handlers need no flags and wouldn't have nowhere to put them in any case. */ 1283 case PGMVIRTHANDLERTYPE_HYPERVISOR: 1284 return 0; 1285 default: 1286 AssertMsgFailed(("unknown enmType=%d\n", pVirt->enmType)); 1287 return 0; 1288 } 1289 1290 /* 1291 * Check pages against flags. 1292 */ 1293 RTGCUINTPTR GCPtr = (RTGCUINTPTR)pVirt->GCPtr; 1294 for (unsigned iPage = 0; iPage < pVirt->cPages; iPage++, GCPtr += PAGE_SIZE) 1295 { 1296 RTGCPHYS GCPhysGst; 1297 uint64_t fGst; 1298 int rc = PGMGstGetPage(pVM, (RTGCPTR)GCPtr, &fGst, &GCPhysGst); 1299 if ( rc == VERR_PAGE_NOT_PRESENT 1300 || rc == VERR_PAGE_TABLE_NOT_PRESENT) 1301 { 1302 if (pVirt->aPhysToVirt[iPage].Core.Key != NIL_RTGCPHYS) 1303 { 1304 AssertMsgFailed(("virt handler phys out of sync. %VGp GCPhysNew=~0 iPage=%#x %VGv %s\n", 1305 pVirt->aPhysToVirt[iPage].Core.Key, iPage, GCPtr, HCSTRING(pVirt->pszDesc))); 1306 pState->cErrors++; 1307 } 1308 continue; 1309 } 1310 1311 AssertRCReturn(rc, 0); 1312 if ((pVirt->aPhysToVirt[iPage].Core.Key & X86_PTE_PAE_PG_MASK) != GCPhysGst) 1313 { 1314 AssertMsgFailed(("virt handler phys out of sync. %VGp GCPhysGst=%VGp iPage=%#x %VGv %s\n", 1315 pVirt->aPhysToVirt[iPage].Core.Key, GCPhysGst, iPage, GCPtr, HCSTRING(pVirt->pszDesc))); 1316 pState->cErrors++; 1317 continue; 1318 } 1319 1320 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhysGst); 1321 if (!pPage) 1322 { 1323 AssertMsgFailed(("virt handler getting ram flags. GCPhysGst=%VGp iPage=%#x %VGv %s\n", 1324 GCPhysGst, iPage, GCPtr, HCSTRING(pVirt->pszDesc))); 1325 pState->cErrors++; 1326 continue; 1327 } 1328 1329 if ((pPage->HCPhys & fFlags) != fFlags) /** @todo PAGE FLAGS */ 1330 { 1331 AssertMsgFailed(("virt handler flags mismatch. HCPhys=%VHp fFlags=%#x GCPhysGst=%VGp iPage=%#x %VGv %s\n", 1332 pPage->HCPhys, fFlags, GCPhysGst, iPage, GCPtr, HCSTRING(pVirt->pszDesc))); 1333 pState->cErrors++; 1334 continue; 1335 } 1336 } /* for pages in virtual mapping. */ 1337 1338 return 0; 1339 } 1340 1341 1342 /** 1343 * Asserts that the handlers+guest-page-tables == ramrange-flags and 1344 * that the physical addresses associated with virtual handlers are correct. 1345 * 1346 * @returns Number of mismatches. 1347 * @param pVM The VM handle. 1348 */ 1349 PGMDECL(unsigned) PGMAssertHandlerAndFlagsInSync(PVM pVM) 1350 { 1351 PPGM pPGM = &pVM->pgm.s; 1352 PGMAHAFIS State; 1353 State.cErrors = 0; 1354 State.pVM = pVM; 1355 1356 /* 1357 * Check the RAM flags against the handlers. 1358 */ 1359 for (PPGMRAMRANGE pRam = CTXALLSUFF(pPGM->pRamRanges); pRam; pRam = CTXALLSUFF(pRam->pNext)) 1360 { 1361 const unsigned cPages = pRam->cb >> PAGE_SHIFT; 1362 for (unsigned iPage = 0; iPage < cPages; iPage++) 1363 { 1364 PGMPAGE const *pPage = &pRam->aPages[iPage]; 1365 if (PGM_PAGE_HAVE_ANY_HANDLERS(pPage)) 1366 { 1367 State.GCPhys = pRam->GCPhys + (iPage << PAGE_SHIFT); 1368 State.fFlagsFound = 0; /* build flags and compare. */ 1369 1370 /* 1371 * Physical first - calculate the state based on the handlers 1372 * active on the page, then compare. 1373 */ 1374 if (PGM_PAGE_HAVE_ANY_PHYSICAL_HANDLERS(pPage)) 1375 { 1376 /* the first */ 1377 PPGMPHYSHANDLER pPhys = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pPGM->CTXSUFF(pTrees)->PhysHandlers, State.GCPhys); 1378 if (!pPhys) 1379 { 1380 pPhys = (PPGMPHYSHANDLER)RTAvlroGCPhysGetBestFit(&pPGM->CTXSUFF(pTrees)->PhysHandlers, State.GCPhys, true); 1381 if ( pPhys 1382 && pPhys->Core.Key > (State.GCPhys + PAGE_SIZE - 1)) 1383 pPhys = NULL; 1384 Assert(!pPhys || pPhys->Core.Key >= State.GCPhys); 1385 } 1386 if (pPhys) 1387 { 1388 unsigned uState = pgmHandlerPhysicalCalcState(pPhys); 1389 1390 /* more? */ 1391 while (pPhys->Core.KeyLast < (State.GCPhys | PAGE_OFFSET_MASK)) 1392 { 1393 PPGMPHYSHANDLER pPhys2 = (PPGMPHYSHANDLER)RTAvlroGCPhysGetBestFit(&pPGM->CTXSUFF(pTrees)->PhysHandlers, 1394 pPhys->Core.KeyLast + 1, true); 1395 if ( !pPhys2 1396 || pPhys2->Core.Key > (State.GCPhys | PAGE_OFFSET_MASK)) 1397 break; 1398 unsigned uState2 = pgmHandlerPhysicalCalcState(pPhys2); 1399 uState = RT_MAX(uState, uState2); 1400 pPhys = pPhys2; 1401 } 1402 1403 /* compare.*/ 1404 if ( PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) != uState 1405 && PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) != PGM_PAGE_HNDL_PHYS_STATE_DISABLED) 1406 { 1407 AssertMsgFailed(("ram range vs phys handler flags mismatch. GCPhys=%RGp state=%d expected=%d %s\n", 1408 State.GCPhys, PGM_PAGE_GET_HNDL_PHYS_STATE(pPage), uState, pPhys->pszDesc)); 1409 State.cErrors++; 1410 } 1411 1412 #ifdef IN_RING3 1413 /* validate that REM is handling it. */ 1414 if ( !REMR3IsPageAccessHandled(pVM, State.GCPhys) 1415 /* ignore shadowed ROM for the time being. */ /// @todo PAGE FLAGS 1416 && (pPage->HCPhys & (MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO2)) != (MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO2)) 1417 { 1418 AssertMsgFailed(("ram range vs phys handler REM mismatch. GCPhys=%RGp state=%d %s\n", 1419 State.GCPhys, PGM_PAGE_GET_HNDL_PHYS_STATE(pPage), pPhys->pszDesc)); 1420 State.cErrors++; 1421 } 1422 #endif 1423 } 1424 else 1425 { 1426 AssertMsgFailed(("ram range vs phys handler mismatch. no handler for GCPhys=%RGp\n", State.GCPhys)); 1427 State.cErrors++; 1428 } 1429 } 1430 1431 /* virtual flags. */ 1432 if (PGM_PAGE_HAVE_ACTIVE_VIRTUAL_HANDLERS(pPage)) 1433 { 1434 State.fFlags = pPage->HCPhys & (MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_WRITE | MM_RAM_FLAGS_VIRTUAL_ALL); /// @todo PAGE FLAGS 1435 RTAvlroGCPtrDoWithAll(CTXSUFF(&pVM->pgm.s.pTrees)->VirtHandlers, true, pgmVirtHandlerVerifyOneByPhysAddr, &State); 1436 if (State.fFlags != State.fFlagsFound) 1437 { 1438 AssertMsgFailed(("ram range vs virt handler flags mismatch. GCPhys=%RGp fFlags=%#x fFlagsFound=%#x\n", 1439 State.GCPhys, State.fFlags, State.fFlagsFound)); 1440 State.cErrors++; 1441 } 1442 1443 } 1444 } 1445 } /* foreach page in ram range. */ 1446 } /* foreach ram range. */ 1447 1448 /* 1449 * Check that the physical addresses of the virtual handlers matches up. 1450 */ 1451 RTAvlroGCPtrDoWithAll(CTXSUFF(&pVM->pgm.s.pTrees)->VirtHandlers, true, pgmVirtHandlerVerifyOne, &State); 1452 1453 /* 1454 * Do the reverse check for physical handlers. 1455 */ 1456 /** @todo */ 1457 1458 return State.cErrors; 1459 } 1460 1461 #endif /* VBOX_STRICT */ 1462
Note:
See TracChangeset
for help on using the changeset viewer.