Changeset 14362 in vbox
- Timestamp:
- Nov 19, 2008 5:04:25 PM (16 years ago)
- svn:sync-xref-src-repo-rev:
- 39582
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR0/PGMR0DynMap.cpp
r14244 r14362 152 152 153 153 154 155 154 /** 156 155 * Terminates the ring-0 dynamic mapping cache. … … 159 158 { 160 159 } 161 162 160 163 161 … … 183 181 { 184 182 NOREF(pVM); 183 } 184 185 186 /** 187 * Release references to a page, caller owns the spin lock. 188 * 189 * @param pThis The dynamic mapping cache instance. 190 * @param iPage The page. 191 * @param cRefs The number of references to release. 192 */ 193 DECLINLINE(void) pgmR0DynMapReleasePageLocked(PPGMR0DYNMAP pThis, uint32_t iPage, int32_t cRefs) 194 { 195 cRefs = ASMAtomicSubS32(&pThis->paPages[iPage].cRefs, cRefs); 196 AssertMsg(cRefs >= 0, ("%d\n", cRefs)); 197 if (!cRefs) 198 pThis->cLoad--; 199 } 200 201 202 /** 203 * Release references to a page, caller does not own the spin lock. 204 * 205 * @param pThis The dynamic mapping cache instance. 206 * @param iPage The page. 207 * @param cRefs The number of references to release. 208 */ 209 static void pgmR0DynMapReleasePage(PPGMR0DYNMAP pThis, uint32_t iPage, uint32_t cRefs) 210 { 211 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 212 RTSpinlockAcquire(pThis->hSpinlock, &Tmp); 213 pgmR0DynMapReleasePageLocked(pThis, iPage, cRefs); 214 RTSpinlockRelease(pThis->hSpinlock, &Tmp); 215 } 216 217 218 /** 219 * pgmR0DynMapPage worker that deals with the tedious bits. 220 * 221 * @returns The page index on success, UINT32_MAX on failure. 222 * @param pThis The dynamic mapping cache instance. 223 * @param HCPhys The address of the page to be mapped. 224 * @param iPage The page index pgmR0DynMapPage hashed HCPhys to. 225 */ 226 static uint32_t pgmR0DynMapPageSlow(PPGMR0DYNMAP pThis, RTHCPHYS HCPhys, uint32_t iPage) 227 { 228 /* 229 * Check if any of the first 5 pages are unreferenced since the caller 230 * already has made sure they aren't matching. 231 */ 232 uint32_t const cPages = cPages; 233 PPGMR0DYNMAPENTRY paPages = pThis->paPages; 234 uint32_t iFreePage; 235 if (!paPages[iPage].cRefs) 236 iFreePage = iPage; 237 else if (!paPages[(iPage + 1) % cPages].cRefs) 238 iFreePage = iPage; 239 else if (!paPages[(iPage + 2) % cPages].cRefs) 240 iFreePage = iPage; 241 else if (!paPages[(iPage + 3) % cPages].cRefs) 242 iFreePage = iPage; 243 else if (!paPages[(iPage + 4) % cPages].cRefs) 244 iFreePage = iPage; 245 else 246 { 247 /* 248 * Search for an unused or matching entry. 249 */ 250 iFreePage = (iPage + 5) % pThis->cPages; 251 for (;;) 252 { 253 if (paPages[iFreePage].HCPhys == HCPhys) 254 return iFreePage; 255 if (!paPages[iFreePage].cRefs) 256 break; 257 258 /* advance */ 259 iFreePage = (iFreePage + 1) % cPages; 260 if (RT_UNLIKELY(iFreePage != iPage)) 261 return UINT32_MAX; 262 } 263 } 264 265 /* 266 * Setup the new entry. 267 */ 268 paPages[iFreePage].HCPhys = HCPhys; 269 RTCpuSetFill(&paPages[iFreePage].PendingSet); 270 if (pThis->fLegacyMode) 271 paPages[iFreePage].uPte.pLegacy->u = (paPages[iFreePage].uPte.pLegacy->u & X86_PTE_G | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT) 272 | X86_PTE_P | X86_PTE_A | X86_PTE_D 273 | (HCPhys & X86_PTE_PG_MASK); 274 else 275 paPages[iFreePage].uPte.pPae->u = (paPages[iFreePage].uPte.pPae->u & X86_PTE_G | X86_PTE_PAT | X86_PTE_PCD | X86_PTE_PWT) 276 | X86_PTE_P | X86_PTE_A | X86_PTE_D 277 | (HCPhys & X86_PTE_PAE_PG_MASK); 278 return iFreePage; 279 } 280 281 282 /** 283 * Maps a page into the pool. 284 * 285 * @returns Pointer to the mapping. 286 * @param pThis The dynamic mapping cache instance. 287 * @param HCPhys The address of the page to be mapped. 288 * @param piPage Where to store the page index. 289 */ 290 DECLINLINE(void *) pgmR0DynMapPage(PPGMR0DYNMAP pThis, RTHCPHYS HCPhys, uint32_t *piPage) 291 { 292 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 293 RTSpinlockAcquire(pThis->hSpinlock, &Tmp); 294 AssertMsg(!(HCPhys & PAGE_OFFSET_MASK), ("HCPhys=%RHp\n", HCPhys)); 295 296 /* 297 * Find an entry, if possible a matching one. The HCPhys address is hashed 298 * down to a page index, collisions are handled by linear searching. Optimize 299 * for a hit in the first 5 pages. 300 * 301 * To the cheap hits here and defer the tedious searching and inserting 302 * to a helper function. 303 */ 304 uint32_t const cPages = cPages; 305 uint32_t iPage = (HCPhys >> PAGE_SHIFT) % cPages; 306 PPGMR0DYNMAPENTRY paPages = pThis->paPages; 307 if (paPages[iPage].HCPhys != HCPhys) 308 { 309 uint32_t iPage2 = (iPage + 1) % cPages; 310 if (paPages[iPage2].HCPhys != HCPhys) 311 { 312 iPage2 = (iPage + 2) % cPages; 313 if (paPages[iPage2].HCPhys != HCPhys) 314 { 315 iPage2 = (iPage + 3) % cPages; 316 if (paPages[iPage2].HCPhys != HCPhys) 317 { 318 iPage2 = (iPage + 4) % cPages; 319 if (paPages[iPage2].HCPhys != HCPhys) 320 { 321 iPage = pgmR0DynMapPageSlow(pThis, HCPhys, iPage); 322 if (RT_UNLIKELY(iPage == UINT32_MAX)) 323 { 324 RTSpinlockRelease(pThis->hSpinlock, &Tmp); 325 return NULL; 326 } 327 } 328 else 329 iPage = iPage2; 330 } 331 else 332 iPage = iPage2; 333 } 334 else 335 iPage = iPage2; 336 } 337 else 338 iPage = iPage2; 339 } 340 341 /* 342 * Reference it, update statistics and get the return address. 343 */ 344 if (ASMAtomicIncS32(&paPages[iPage].cRefs) == 1) 345 { 346 pThis->cLoad++; 347 if (pThis->cLoad > pThis->cMaxLoad) 348 pThis->cMaxLoad = pThis->cLoad; 349 Assert(pThis->cLoad <= pThis->cPages); 350 } 351 void *pvPage = paPages[iPage].pvPage; 352 353 /* 354 * Invalidate the entry? 355 */ 356 RTCPUID idRealCpu = RTMpCpuId(); 357 bool fInvalidateIt = RTCpuSetIsMember(&paPages[iPage].PendingSet, idRealCpu); 358 if (fInvalidateIt) 359 RTCpuSetDel(&paPages[iPage].PendingSet, idRealCpu); 360 361 RTSpinlockRelease(pThis->hSpinlock, &Tmp); 362 363 /* 364 * Do the actual invalidation outside the spinlock. 365 */ 366 ASMInvalidatePage(pvPage); 367 368 *piPage = iPage; 369 return pvPage; 185 370 } 186 371 … … 229 414 int32_t cRefs = pSet->aEntries[i].cRefs; 230 415 Assert(cRefs > 0); 231 cRefs = ASMAtomicSubS32(&pThis->paPages[iPage].cRefs, cRefs); 232 AssertMsg(cRefs >= 0, ("%d\n", cRefs)); NOREF(cRefs); 416 pgmR0DynMapReleasePageLocked(pThis, iPage, cRefs); 233 417 } 234 418 419 Assert(pThis->cLoad <= pThis->cPages); 235 420 RTSpinlockRelease(pThis->hSpinlock, &Tmp); 236 421 } … … 275 460 276 461 277 DECLINLINE(void *) pgmR0DynMapHCPhys(PPGMR0DYNMAP pThis, RTHCPHYS HCPhys) 278 { 279 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 280 RTSpinlockAcquire(pThis->hSpinlock, &Tmp); 281 282 /* 283 * Find an entry, if possible a matching one. 284 */ 285 286 /* First hash. */ 287 uint32_t iPage = (HCPhys >> PAGE_SHIFT) % pThis->cPages; 288 if (pThis->paPages[iPage].HCPhys != HCPhys) 289 { 290 291 // uint32_t iPage2 = 292 // if (pThis->paPages[iPage].cRefs) 293 294 } 295 296 /* 297 * Invalidate the entry? 298 */ 299 RTCPUID idRealCpu = RTMpCpuId(); 300 if (RTCpuSetIsMember(&pThis->paPages[iPage].PendingSet, idRealCpu)) 301 { 302 RTCpuSetDel(&pThis->paPages[iPage].PendingSet, idRealCpu); 303 ASMInvalidatePage(pThis->paPages[iPage].pvPage); 304 } 305 306 /* 307 * Reference it and get the return address. 308 */ 309 ASMAtomicIncS32(&pThis->paPages[iPage].cRefs); 310 void *pvPage = pThis->paPages[iPage].pvPage; 311 312 RTSpinlockRelease(pThis->hSpinlock, &Tmp); 313 314 return pvPage; 462 /** 463 * As a final resort for a full auto set, try merge duplicate entries. 464 * 465 * @param pSet The set. 466 */ 467 static void pgmDynMapOptimizeAutoSet(PPGMMAPSET pSet) 468 { 469 for (uint32_t i = 0 ; i < pSet->cEntries; i++) 470 { 471 uint16_t const iPage = pSet->aEntries[i].iPage; 472 uint32_t j = i + 1; 473 while (j < pSet->cEntries) 474 { 475 if (pSet->aEntries[j].iPage != iPage) 476 j++; 477 else 478 { 479 /* merge j with i removing j. */ 480 pSet->aEntries[i].cRefs += pSet->aEntries[j].cRefs; 481 pSet->cEntries--; 482 if (j < pSet->cEntries) 483 { 484 pSet->aEntries[j] = pSet->aEntries[pSet->cEntries]; 485 pSet->aEntries[pSet->cEntries].iPage = UINT16_MAX; 486 pSet->aEntries[pSet->cEntries].cRefs = 0; 487 } 488 else 489 { 490 pSet->aEntries[j].iPage = UINT16_MAX; 491 pSet->aEntries[j].cRefs = 0; 492 } 493 } 494 } 495 } 315 496 } 316 497 … … 320 501 { 321 502 AssertMsg(!(HCPhys & PAGE_OFFSET_MASK), ("HCPhys=%RHp\n", HCPhys)); 322 PVMCPU pVCpu = VMMGetCpu(pVM); 323 PPGMMAPSET pSet = &pVCpu->pgm.s.AutoSet; 503 504 /* 505 * Map it. 506 */ 507 uint32_t iPage; 508 void *pvPage = pgmR0DynMapPage(g_pPGMR0DynMap, HCPhys, &iPage); 509 if (RT_UNLIKELY(!pvPage)) 510 { 511 static uint32_t s_cBitched = 0; 512 if (++s_cBitched < 10) 513 LogRel(("PGMDynMapHCPage: cLoad=%u/%u cPages=%u\n", 514 g_pPGMR0DynMap->cLoad, g_pPGMR0DynMap->cMaxLoad, g_pPGMR0DynMap->cPages)); 515 return VERR_PGM_DYNMAP_FAILED; 516 } 324 517 325 518 /* 326 519 * Add the page to the auto reference set. 327 */ 520 * If it's less than half full, don't bother looking for duplicates. 521 */ 522 PVMCPU pVCpu = VMMGetCpu(pVM); 523 PPGMMAPSET pSet = &pVCpu->pgm.s.AutoSet; 524 if (pSet->cEntries < RT_ELEMENTS(pSet->aEntries) / 2) 525 { 526 pSet->aEntries[pSet->cEntries].cRefs = 1; 527 pSet->aEntries[pSet->cEntries].iPage = iPage; 528 } 529 else 530 { 531 Assert(pSet->cEntries <= RT_ELEMENTS(pSet->aEntries)); 532 int32_t i = pSet->cEntries; 533 while (i-- > 0) 534 if (pSet->aEntries[i].iPage) 535 { 536 pSet->aEntries[i].cRefs++; 537 break; 538 } 539 if (i < 0) 540 { 541 if (RT_UNLIKELY(pSet->cEntries >= RT_ELEMENTS(pSet->aEntries))) 542 pgmDynMapOptimizeAutoSet(pSet); 543 if (RT_LIKELY(pSet->cEntries < RT_ELEMENTS(pSet->aEntries))) 544 { 545 pSet->aEntries[pSet->cEntries].cRefs = 1; 546 pSet->aEntries[pSet->cEntries].iPage = iPage; 547 } 548 else 549 { 550 /* We're screwed. */ 551 pgmR0DynMapReleasePage(g_pPGMR0DynMap, iPage, 1); 552 553 static uint32_t s_cBitched = 0; 554 if (++s_cBitched < 10) 555 LogRel(("PGMDynMapHCPage: set is full!\n")); 556 return VERR_PGM_DYNMAP_FULL_SET; 557 } 558 } 559 } 328 560 329 561 return VINF_SUCCESS;
Note:
See TracChangeset
for help on using the changeset viewer.