|
1 | | -/* $Id: DevVGA-SVGA.cpp 114638 2026-07-07 17:03:05Z vitali.pelenjow@oracle.com $ */ |
| 1 | +/* $Id: DevVGA-SVGA.cpp 114699 2026-07-14 12:53:14Z vitali.pelenjow@oracle.com $ */ |
2 | 2 | /** @file |
3 | 3 | * VMware SVGA device. |
4 | 4 | * |
@@ -2039,6 +2039,42 @@ static void vmsvgaR3CursorMobId(PVGASTATE pThis, PVGASTATECC pThisCC) |
2039 | 2039 | } |
2040 | 2040 | # endif /* VBOX_WITH_VMSVGA3D */ |
2041 | 2041 |
|
| 2042 | + |
| 2043 | +/** Defines or frees a GMR. |
| 2044 | + * |
| 2045 | + * @param pThis The shared VGA/VMSVGA instance data. |
| 2046 | + * @param pThisCC The VGA/VMSVGA state for the current context. |
| 2047 | + * @param pGMRInfo The GMR description. |
| 2048 | + * @thread FIFO |
| 2049 | + */ |
| 2050 | +static void vmsvgaR3GMRDescriptor(PVGASTATE pThis, PVGASTATECC pThisCC, VMSVGAGMRINFO const *pGMRInfo) |
| 2051 | +{ |
| 2052 | + PVMSVGAR3STATE pSVGAState = pThisCC->svga.pSvgaR3State; |
| 2053 | + |
| 2054 | + uint32_t const idGMR = pGMRInfo->u32GMRId; |
| 2055 | + AssertReturnVoid(idGMR < pThis->svga.cGMR); |
| 2056 | + RT_UNTRUSTED_VALIDATED_FENCE(); |
| 2057 | + |
| 2058 | + /* Free the old GMR if present. */ |
| 2059 | + vmsvgaR3GmrFree(pThisCC, idGMR); |
| 2060 | + |
| 2061 | + if (pGMRInfo->cDescriptors != 0) |
| 2062 | + { |
| 2063 | + /* Commit the GMR. */ |
| 2064 | + size_t const cbAlloc = pGMRInfo->cDescriptors * sizeof(VMSVGAGMRDESCRIPTOR); |
| 2065 | + pSVGAState->paGMR[idGMR].paDesc = (PVMSVGAGMRDESCRIPTOR)RTMemAlloc(cbAlloc); |
| 2066 | + AssertReturnVoid(pSVGAState->paGMR[idGMR].paDesc); |
| 2067 | + memcpy(pSVGAState->paGMR[idGMR].paDesc, pGMRInfo->paDescs, cbAlloc); |
| 2068 | + |
| 2069 | + pSVGAState->paGMR[idGMR].numDescriptors = pGMRInfo->cDescriptors; |
| 2070 | + pSVGAState->paGMR[idGMR].cMaxPages = pGMRInfo->cPagesTotal; |
| 2071 | + pSVGAState->paGMR[idGMR].cbTotal = pGMRInfo->cPagesTotal * GUEST_PAGE_SIZE; |
| 2072 | + Assert((pSVGAState->paGMR[idGMR].cbTotal >> GUEST_PAGE_SHIFT) == pGMRInfo->cPagesTotal); |
| 2073 | + Log(("Defined new gmrid = %u: numDescriptors=%u cbTotal=%#x (%#x pages)\n", |
| 2074 | + idGMR, pGMRInfo->cDescriptors, pSVGAState->paGMR[idGMR].cbTotal, pGMRInfo->cPagesTotal)); |
| 2075 | + } |
| 2076 | +} |
| 2077 | + |
2042 | 2078 | #endif /* IN_RING3 */ |
2043 | 2079 |
|
2044 | 2080 |
|
@@ -2377,77 +2413,97 @@ static VBOXSTRICTRC vmsvgaWritePort(PPDMDEVINS pDevIns, PVGASTATE pThis, PVGASTA |
2377 | 2413 | AssertBreak(idGMR < pThis->svga.cGMR); |
2378 | 2414 | RT_UNTRUSTED_VALIDATED_FENCE(); |
2379 | 2415 |
|
2380 | | - /* Free the old GMR if present. */ |
2381 | | - vmsvgaR3GmrFree(pThisCC, idGMR); |
| 2416 | + /* GMRs must be modified from FIFO thread. Fetch the data and forward it to the FIFO thread. */ |
| 2417 | + VMSVGAGMRINFO *pGMRInfo = (VMSVGAGMRINFO *)RTMemAlloc(RT_UOFFSETOF(VMSVGAGMRINFO, paDescs)); |
| 2418 | + if (!pGMRInfo) |
| 2419 | + { |
| 2420 | + STAM_REL_COUNTER_INC(&pSVGAState->StatR3RegGmrDescriptorWrErrors); |
| 2421 | + break; |
| 2422 | + } |
| 2423 | + |
| 2424 | + pGMRInfo->u32GMRId = idGMR; |
| 2425 | + pGMRInfo->cDescriptors = 0; |
| 2426 | + pGMRInfo->cPagesTotal = 0; |
| 2427 | + pGMRInfo->u32Reserved = 0; |
| 2428 | + |
| 2429 | + int rc2 = VINF_SUCCESS; |
2382 | 2430 |
|
2383 | | - /* Just undefine the GMR? */ |
2384 | 2431 | RTGCPHYS GCPhys = (RTGCPHYS)u32 << GUEST_PAGE_SHIFT; |
2385 | 2432 | if (GCPhys == 0) |
2386 | 2433 | { |
2387 | 2434 | STAM_REL_COUNTER_INC(&pSVGAState->StatR3RegGmrDescriptorWrFree); |
2388 | | - break; |
2389 | 2435 | } |
2390 | | - |
2391 | | - |
2392 | | - /* Never cross a page boundary automatically. */ |
2393 | | - const uint32_t cMaxPages = RT_MIN(VMSVGA_MAX_GMR_PAGES, UINT32_MAX / X86_PAGE_SIZE); |
2394 | | - uint32_t cPagesTotal = 0; |
2395 | | - uint32_t iDesc = 0; |
2396 | | - PVMSVGAGMRDESCRIPTOR paDescs = NULL; |
2397 | | - uint32_t cLoops = 0; |
2398 | | - RTGCPHYS GCPhysBase = GCPhys; |
2399 | | - while ((GCPhys >> GUEST_PAGE_SHIFT) == (GCPhysBase >> GUEST_PAGE_SHIFT)) |
| 2436 | + else |
2400 | 2437 | { |
2401 | | - /* Read descriptor. */ |
2402 | | - SVGAGuestMemDescriptor desc; |
2403 | | - rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, &desc, sizeof(desc)); |
2404 | | - AssertRCBreak(VBOXSTRICTRC_VAL(rc)); |
2405 | | - |
2406 | | - if (desc.numPages != 0) |
| 2438 | + /* Never cross a page boundary automatically. */ |
| 2439 | + const uint32_t cMaxPages = RT_MIN(VMSVGA_MAX_GMR_PAGES, UINT32_MAX / X86_PAGE_SIZE); |
| 2440 | + uint32_t cLoops = 0; |
| 2441 | + RTGCPHYS GCPhysBase = GCPhys; |
| 2442 | + while ((GCPhys >> GUEST_PAGE_SHIFT) == (GCPhysBase >> GUEST_PAGE_SHIFT)) |
2407 | 2443 | { |
2408 | | - AssertBreakStmt(desc.numPages <= cMaxPages, rc = VERR_OUT_OF_RANGE); |
2409 | | - cPagesTotal += desc.numPages; |
2410 | | - AssertBreakStmt(cPagesTotal <= cMaxPages, rc = VERR_OUT_OF_RANGE); |
| 2444 | + /* Read descriptor. */ |
| 2445 | + SVGAGuestMemDescriptor desc; |
| 2446 | + rc2 = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, &desc, sizeof(desc)); |
| 2447 | + AssertRCBreak(rc2); |
2411 | 2448 |
|
2412 | | - if ((iDesc & 15) == 0) |
| 2449 | + if (desc.numPages != 0) |
2413 | 2450 | { |
2414 | | - void *pvNew = RTMemRealloc(paDescs, (iDesc + 16) * sizeof(VMSVGAGMRDESCRIPTOR)); |
2415 | | - AssertBreakStmt(pvNew, rc = VERR_NO_MEMORY); |
2416 | | - paDescs = (PVMSVGAGMRDESCRIPTOR)pvNew; |
2417 | | - } |
| 2451 | + AssertBreakStmt(desc.numPages <= cMaxPages, rc2 = VERR_OUT_OF_RANGE); |
| 2452 | + pGMRInfo->cPagesTotal += desc.numPages; |
| 2453 | + AssertBreakStmt(pGMRInfo->cPagesTotal <= cMaxPages, rc2 = VERR_OUT_OF_RANGE); |
2418 | 2454 |
|
2419 | | - paDescs[iDesc].GCPhys = (RTGCPHYS)desc.ppn << GUEST_PAGE_SHIFT; |
2420 | | - paDescs[iDesc++].numPages = desc.numPages; |
| 2455 | + if ((pGMRInfo->cDescriptors & 15) == 0) |
| 2456 | + { |
| 2457 | + size_t const cbAlloc = RT_UOFFSETOF(VMSVGAGMRINFO, paDescs) |
| 2458 | + + (pGMRInfo->cDescriptors + 16) * sizeof(VMSVGAGMRDESCRIPTOR); |
| 2459 | + void *pvNew = RTMemRealloc(pGMRInfo, cbAlloc); |
| 2460 | + AssertBreakStmt(pvNew, rc2 = VERR_NO_MEMORY); |
| 2461 | + pGMRInfo = (VMSVGAGMRINFO *)pvNew; |
| 2462 | + } |
| 2463 | + |
| 2464 | + pGMRInfo->paDescs[pGMRInfo->cDescriptors].GCPhys = (RTGCPHYS)desc.ppn << GUEST_PAGE_SHIFT; |
| 2465 | + pGMRInfo->paDescs[pGMRInfo->cDescriptors++].numPages = desc.numPages; |
| 2466 | + |
| 2467 | + /* Continue with the next descriptor. */ |
| 2468 | + GCPhys += sizeof(desc); |
| 2469 | + } |
| 2470 | + else if (desc.ppn == 0) |
| 2471 | + break; /* terminator */ |
| 2472 | + else /* Pointer to the next physical page of descriptors. */ |
| 2473 | + GCPhys = GCPhysBase = (RTGCPHYS)desc.ppn << GUEST_PAGE_SHIFT; |
2421 | 2474 |
|
2422 | | - /* Continue with the next descriptor. */ |
2423 | | - GCPhys += sizeof(desc); |
| 2475 | + cLoops++; |
| 2476 | + AssertBreakStmt(cLoops < VMSVGA_MAX_GMR_DESC_LOOP_COUNT, rc2 = VERR_OUT_OF_RANGE); |
2424 | 2477 | } |
2425 | | - else if (desc.ppn == 0) |
2426 | | - break; /* terminator */ |
2427 | | - else /* Pointer to the next physical page of descriptors. */ |
2428 | | - GCPhys = GCPhysBase = (RTGCPHYS)desc.ppn << GUEST_PAGE_SHIFT; |
2429 | 2478 |
|
2430 | | - cLoops++; |
2431 | | - AssertBreakStmt(cLoops < VMSVGA_MAX_GMR_DESC_LOOP_COUNT, rc = VERR_OUT_OF_RANGE); |
| 2479 | + AssertStmt(pGMRInfo->cDescriptors > 0 || RT_FAILURE_NP(rc2), rc2 = VERR_OUT_OF_RANGE); |
2432 | 2480 | } |
2433 | 2481 |
|
2434 | | - AssertStmt(iDesc > 0 || RT_FAILURE_NP(rc), rc = VERR_OUT_OF_RANGE); |
2435 | | - if (RT_SUCCESS(rc)) |
| 2482 | + if (RT_SUCCESS(rc2)) |
2436 | 2483 | { |
2437 | | - /* Commit the GMR. */ |
2438 | | - pSVGAState->paGMR[idGMR].paDesc = paDescs; |
2439 | | - pSVGAState->paGMR[idGMR].numDescriptors = iDesc; |
2440 | | - pSVGAState->paGMR[idGMR].cMaxPages = cPagesTotal; |
2441 | | - pSVGAState->paGMR[idGMR].cbTotal = cPagesTotal * GUEST_PAGE_SIZE; |
2442 | | - Assert((pSVGAState->paGMR[idGMR].cbTotal >> GUEST_PAGE_SHIFT) == cPagesTotal); |
2443 | | - Log(("Defined new gmr %x numDescriptors=%d cbTotal=%x (%#x pages)\n", |
2444 | | - idGMR, iDesc, pSVGAState->paGMR[idGMR].cbTotal, cPagesTotal)); |
| 2484 | + /* Forward to the FIFO thread. */ |
| 2485 | + PVMSVGACMDBUFCTX pCmdBufCtx = pThisCC->svga.pSvgaR3State->apCmdBufCtxs[0]; |
| 2486 | + PVMSVGACMDBUF pCmdBuf = vmsvgaR3CmdBufAlloc(pCmdBufCtx, VMSVGACMDBUFTYPE_HOST); |
| 2487 | + if (RT_LIKELY(pCmdBuf)) |
| 2488 | + { |
| 2489 | + pCmdBuf->idHostCommand = VMSVGACMDBUF_HOSTCOMMAND_GMR_DESCRIPTOR; |
| 2490 | + pCmdBuf->cbHostCommandData = RT_UOFFSETOF(VMSVGAGMRINFO, paDescs) |
| 2491 | + + pGMRInfo->cDescriptors * sizeof(VMSVGAGMRDESCRIPTOR); |
| 2492 | + pCmdBuf->pvHostCommandData = pGMRInfo; |
| 2493 | + vmsvgaR3CmdBufSubmitHostCommand(pDevIns, pThis, pThisCC, pCmdBuf); |
| 2494 | + Log(("Defining gmrid = %u: numDescriptors=%u, %#x pages\n", |
| 2495 | + idGMR, pGMRInfo->cDescriptors, pGMRInfo->cPagesTotal)); |
| 2496 | + } |
| 2497 | + else |
| 2498 | + rc2 = VERR_NO_MEMORY; |
2445 | 2499 | } |
2446 | | - else |
| 2500 | + |
| 2501 | + if (RT_FAILURE(rc2)) |
2447 | 2502 | { |
2448 | | - RTMemFree(paDescs); |
| 2503 | + RTMemFree(pGMRInfo); |
2449 | 2504 | STAM_REL_COUNTER_INC(&pSVGAState->StatR3RegGmrDescriptorWrErrors); |
2450 | 2505 | } |
| 2506 | + |
2451 | 2507 | break; |
2452 | 2508 | } |
2453 | 2509 | # endif /* IN_RING3 */ |
@@ -4599,6 +4655,8 @@ static void vmsvgaR3CmdBufProcessBuffers(PPDMDEVINS pDevIns, PVGASTATE pThis, PV |
4599 | 4655 | #else |
4600 | 4656 | ; /* Nothing. */ |
4601 | 4657 | #endif |
| 4658 | + else if (pCmdBuf->idHostCommand == VMSVGACMDBUF_HOSTCOMMAND_GMR_DESCRIPTOR) |
| 4659 | + vmsvgaR3GMRDescriptor(pThis, pThisCC, (VMSVGAGMRINFO *)pCmdBuf->pvHostCommandData); |
4602 | 4660 | else |
4603 | 4661 | AssertFailed(); |
4604 | 4662 | vmsvgaR3CmdBufFree(pCmdBuf); |
|
0 commit comments