| 2279 | | GMMR0DECL(int) GMMR0FreeMapUnmapChunk(PVM pVM, uint32_t idChunkMap, uint32_t idChunkUnmap, PRTR3PTR pvR3) |
|---|
| 2280 | | { |
|---|
| 2281 | | return VERR_NOT_IMPLEMENTED; |
|---|
| 2282 | | } |
|---|
| 2283 | | |
|---|
| 2284 | | |
|---|
| 2285 | | /** |
|---|
| 2286 | | * VMMR0 request wrapper for GMMR0FreeMapUnmapChunk. |
|---|
| 2287 | | * |
|---|
| 2288 | | * @returns see GMMR0FreeMapUnmapChunk. |
|---|
| | 2297 | /** |
|---|
| | 2298 | * Unmaps a chunk previously mapped into the address space of the current process. |
|---|
| | 2299 | * |
|---|
| | 2300 | * @returns VBox status code. |
|---|
| | 2301 | * @param pGMM Pointer to the GMM instance data. |
|---|
| | 2302 | * @param pGVM Pointer to the Global VM structure. |
|---|
| | 2303 | * @param pChunk Pointer to the chunk to be unmapped. |
|---|
| | 2304 | */ |
|---|
| | 2305 | static int gmmR0UnmapChunk(PGMM pGMM, PGVM pGVM, PGMMCHUNK pChunk) |
|---|
| | 2306 | { |
|---|
| | 2307 | /* |
|---|
| | 2308 | * Find the mapping and try unmapping it. |
|---|
| | 2309 | */ |
|---|
| | 2310 | for (uint32_t i = 0; i < pChunk->cMappings; i++) |
|---|
| | 2311 | { |
|---|
| | 2312 | Assert(pChunk->paMappings[i].pGVM && pChunk->paMappings[i].MapObj != NIL_RTR0MEMOBJ); |
|---|
| | 2313 | if (pChunk->paMappings[i].pGVM == pGVM) |
|---|
| | 2314 | { |
|---|
| | 2315 | /* unmap */ |
|---|
| | 2316 | int rc = RTR0MemObjFree(pChunk->paMappings[i].MapObj, false /* fFreeMappings */); |
|---|
| | 2317 | if (RT_SUCCESS(rc)) |
|---|
| | 2318 | { |
|---|
| | 2319 | /* update the record. */ |
|---|
| | 2320 | pChunk->cMappings--; |
|---|
| | 2321 | if (pChunk->cMappings > i) |
|---|
| | 2322 | pChunk->paMappings[i] = pChunk->paMappings[pChunk->cMappings]; |
|---|
| | 2323 | pChunk->paMappings[pChunk->cMappings].MapObj = NIL_RTR0MEMOBJ; |
|---|
| | 2324 | pChunk->paMappings[pChunk->cMappings].pGVM = NULL; |
|---|
| | 2325 | } |
|---|
| | 2326 | return rc; |
|---|
| | 2327 | } |
|---|
| | 2328 | } |
|---|
| | 2329 | |
|---|
| | 2330 | Log(("gmmR0MapChunk: Chunk %#x is not mapped into pGVM=%p/%#x\n", pChunk->Core.Key, pGVM, pGVM->hSelf)); |
|---|
| | 2331 | return VERR_GMM_CHUNK_NOT_MAPPED; |
|---|
| | 2332 | } |
|---|
| | 2333 | |
|---|
| | 2334 | |
|---|
| | 2335 | /** |
|---|
| | 2336 | * Maps a chunk into the user address space of the current process. |
|---|
| | 2337 | * |
|---|
| | 2338 | * @returns VBox status code. |
|---|
| | 2339 | * @param pGMM Pointer to the GMM instance data. |
|---|
| | 2340 | * @param pGVM Pointer to the Global VM structure. |
|---|
| | 2341 | * @param pChunk Pointer to the chunk to be mapped. |
|---|
| | 2342 | * @param ppvR3 Where to store the ring-3 address of the mapping. |
|---|
| | 2343 | * In the VERR_GMM_CHUNK_ALREADY_MAPPED case, this will be |
|---|
| | 2344 | * contain the address of the existing mapping. |
|---|
| | 2345 | */ |
|---|
| | 2346 | static int gmmR0MapChunk(PGMM pGMM, PGVM pGVM, PGMMCHUNK pChunk, PRTR3PTR ppvR3) |
|---|
| | 2347 | { |
|---|
| | 2348 | /* |
|---|
| | 2349 | * Check to see if the chunk is already mapped. |
|---|
| | 2350 | */ |
|---|
| | 2351 | for (uint32_t i = 0; i < pChunk->cMappings; i++) |
|---|
| | 2352 | { |
|---|
| | 2353 | Assert(pChunk->paMappings[i].pGVM && pChunk->paMappings[i].MapObj != NIL_RTR0MEMOBJ); |
|---|
| | 2354 | if (pChunk->paMappings[i].pGVM == pGVM) |
|---|
| | 2355 | { |
|---|
| | 2356 | *ppvR3 = RTR0MemObjAddressR3(pChunk->paMappings[i].MapObj); |
|---|
| | 2357 | Log(("gmmR0MapChunk: chunk %#x is already mapped at %p!\n", pChunk->Core.Key, *ppvR3)); |
|---|
| | 2358 | return VERR_GMM_CHUNK_ALREADY_MAPPED; |
|---|
| | 2359 | } |
|---|
| | 2360 | } |
|---|
| | 2361 | |
|---|
| | 2362 | /* |
|---|
| | 2363 | * Do the mapping. |
|---|
| | 2364 | */ |
|---|
| | 2365 | RTR0MEMOBJ MapObj; |
|---|
| | 2366 | int rc = RTR0MemObjMapUser(&MapObj, pChunk->MemObj, (RTR3PTR)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE, NIL_RTR0PROCESS); |
|---|
| | 2367 | if (RT_SUCCESS(rc)) |
|---|
| | 2368 | { |
|---|
| | 2369 | /* reallocate the array? */ |
|---|
| | 2370 | if ((pChunk->cMappings & 1 /*7*/) == 0) |
|---|
| | 2371 | { |
|---|
| | 2372 | void *pvMappings = RTMemRealloc(pChunk->paMappings, (pChunk->cMappings + 2 /*8*/) * sizeof(pChunk->paMappings[0])); |
|---|
| | 2373 | if (RT_UNLIKELY(pvMappings)) |
|---|
| | 2374 | { |
|---|
| | 2375 | rc = RTR0MemObjFree(MapObj, false /* fFreeMappings */); |
|---|
| | 2376 | AssertRC(rc); |
|---|
| | 2377 | return VERR_NO_MEMORY; |
|---|
| | 2378 | } |
|---|
| | 2379 | pChunk->paMappings = (PGMMCHUNKMAP)pvMappings; |
|---|
| | 2380 | } |
|---|
| | 2381 | |
|---|
| | 2382 | /* insert new entry */ |
|---|
| | 2383 | pChunk->paMappings[pChunk->cMappings].MapObj = MapObj; |
|---|
| | 2384 | pChunk->paMappings[pChunk->cMappings].pGVM = pGVM; |
|---|
| | 2385 | pChunk->cMappings++; |
|---|
| | 2386 | |
|---|
| | 2387 | *ppvR3 = RTR0MemObjAddressR3(MapObj); |
|---|
| | 2388 | } |
|---|
| | 2389 | |
|---|
| | 2390 | return rc; |
|---|
| | 2391 | } |
|---|
| | 2392 | |
|---|
| | 2393 | |
|---|
| | 2394 | /** |
|---|
| | 2395 | * Map a chunk and/or unmap another chunk. |
|---|
| | 2396 | * |
|---|
| | 2397 | * The mapping and unmapping applies to the current process. |
|---|
| | 2398 | * |
|---|
| | 2399 | * This API does two things because it saves a kernel call per mapping when |
|---|
| | 2400 | * when the ring-3 mapping cache is full. |
|---|
| | 2401 | * |
|---|
| | 2402 | * @returns VBox status code. |
|---|
| | 2403 | * @param pVM The VM. |
|---|
| | 2404 | * @param idChunkMap The chunk to map. NIL_GMM_CHUNKID if nothing to map. |
|---|
| | 2405 | * @param idChunkUnmap The chunk to unmap. NIL_GMM_CHUNKID if nothing to unmap. |
|---|
| | 2406 | * @param ppvR3 Where to store the address of the mapped chunk. NULL is ok if nothing to map. |
|---|
| | 2407 | * @thread EMT |
|---|
| | 2408 | */ |
|---|
| | 2409 | GMMR0DECL(int) GMMR0MapUnmapChunk(PVM pVM, uint32_t idChunkMap, uint32_t idChunkUnmap, PRTR3PTR ppvR3) |
|---|
| | 2410 | { |
|---|
| | 2411 | LogFlow(("GMMR0MapUnmapChunk: pVM=%p idChunkMap=%#x idChunkUnmap=%#x ppvR3=%p\n", |
|---|
| | 2412 | pVM, idChunkMap, idChunkUnmap, ppvR3)); |
|---|
| | 2413 | |
|---|
| | 2414 | /* |
|---|
| | 2415 | * Validate input and get the basics. |
|---|
| | 2416 | */ |
|---|
| | 2417 | PGMM pGMM; |
|---|
| | 2418 | GMM_GET_VALID_INSTANCE(pGMM, VERR_INTERNAL_ERROR); |
|---|
| | 2419 | PGVM pGVM = GVMMR0ByVM(pVM); |
|---|
| | 2420 | if (!pGVM) |
|---|
| | 2421 | return VERR_INVALID_PARAMETER; |
|---|
| | 2422 | if (pGVM->hEMT != RTThreadNativeSelf()) |
|---|
| | 2423 | return VERR_NOT_OWNER; |
|---|
| | 2424 | |
|---|
| | 2425 | AssertCompile(NIL_GMM_CHUNKID == 0); |
|---|
| | 2426 | AssertMsgReturn(idChunkMap <= GMM_CHUNKID_LAST, ("%#x\n", idChunkMap), VERR_INVALID_PARAMETER); |
|---|
| | 2427 | AssertMsgReturn(idChunkUnmap <= GMM_CHUNKID_LAST, ("%#x\n", idChunkUnmap), VERR_INVALID_PARAMETER); |
|---|
| | 2428 | |
|---|
| | 2429 | if ( idChunkMap == NIL_GMM_CHUNKID |
|---|
| | 2430 | && idChunkUnmap == NIL_GMM_CHUNKID) |
|---|
| | 2431 | return VERR_INVALID_PARAMETER; |
|---|
| | 2432 | |
|---|
| | 2433 | if (idChunkMap != NIL_GMM_CHUNKID) |
|---|
| | 2434 | { |
|---|
| | 2435 | AssertPtrReturn(ppvR3, VERR_INVALID_POINTER); |
|---|
| | 2436 | *ppvR3 = NIL_RTR3PTR; |
|---|
| | 2437 | } |
|---|
| | 2438 | |
|---|
| | 2439 | if (pGMM->fLegacyMode) |
|---|
| | 2440 | { |
|---|
| | 2441 | Log(("GMMR0MapUnmapChunk: legacy mode!\n")); |
|---|
| | 2442 | return VERR_NOT_SUPPORTED; |
|---|
| | 2443 | } |
|---|
| | 2444 | |
|---|
| | 2445 | /* |
|---|
| | 2446 | * Take the semaphore and do the work. |
|---|
| | 2447 | * |
|---|
| | 2448 | * The unmapping is done last since it's easier to undo a mapping than |
|---|
| | 2449 | * undoing an unmapping. The ring-3 mapping cache cannot not be so big |
|---|
| | 2450 | * that it pushes the user virtual address space to within a chunk of |
|---|
| | 2451 | * it it's limits, so, no problem here. |
|---|
| | 2452 | */ |
|---|
| | 2453 | int rc = RTSemFastMutexRequest(pGMM->Mtx); |
|---|
| | 2454 | AssertRC(rc); |
|---|
| | 2455 | |
|---|
| | 2456 | PGMMCHUNK pMap = NULL; |
|---|
| | 2457 | if (idChunkMap != NIL_GVM_HANDLE) |
|---|
| | 2458 | { |
|---|
| | 2459 | pMap = gmmR0GetChunk(pGMM, idChunkMap); |
|---|
| | 2460 | if (RT_LIKELY(pMap)) |
|---|
| | 2461 | rc = gmmR0MapChunk(pGMM, pGVM, pMap, ppvR3); |
|---|
| | 2462 | else |
|---|
| | 2463 | { |
|---|
| | 2464 | Log(("GMMR0MapUnmapChunk: idChunkMap=%#x\n", idChunkMap)); |
|---|
| | 2465 | rc = VERR_GMM_CHUNK_NOT_FOUND; |
|---|
| | 2466 | } |
|---|
| | 2467 | } |
|---|
| | 2468 | |
|---|
| | 2469 | if ( idChunkUnmap != NIL_GMM_CHUNKID |
|---|
| | 2470 | && RT_SUCCESS(rc)) |
|---|
| | 2471 | { |
|---|
| | 2472 | PGMMCHUNK pUnmap = gmmR0GetChunk(pGMM, idChunkUnmap); |
|---|
| | 2473 | if (RT_LIKELY(pUnmap)) |
|---|
| | 2474 | rc = gmmR0UnmapChunk(pGMM, pGVM, pUnmap); |
|---|
| | 2475 | else |
|---|
| | 2476 | { |
|---|
| | 2477 | Log(("GMMR0MapUnmapChunk: idChunkUnmap=%#x\n", idChunkUnmap)); |
|---|
| | 2478 | rc = VERR_GMM_CHUNK_NOT_FOUND; |
|---|
| | 2479 | } |
|---|
| | 2480 | |
|---|
| | 2481 | if (RT_FAILURE(rc) && pMap) |
|---|
| | 2482 | gmmR0UnmapChunk(pGMM, pGVM, pMap); |
|---|
| | 2483 | } |
|---|
| | 2484 | |
|---|
| | 2485 | RTSemFastMutexRelease(pGMM->Mtx); |
|---|
| | 2486 | |
|---|
| | 2487 | LogFlow(("GMMR0MapUnmapChunk: returns %Rrc\n", rc)); |
|---|
| | 2488 | return rc; |
|---|
| | 2489 | } |
|---|
| | 2490 | |
|---|
| | 2491 | |
|---|
| | 2492 | /** |
|---|
| | 2493 | * VMMR0 request wrapper for GMMR0MapUnmapChunk. |
|---|
| | 2494 | * |
|---|
| | 2495 | * @returns see GMMR0MapUnmapChunk. |
|---|
| 2301 | | return GMMR0FreeMapUnmapChunk(pVM, pReq->idChunkMap, pReq->idChunkUnmap, &pReq->pvR3); |
|---|
| 2302 | | } |
|---|
| 2303 | | |
|---|
| 2304 | | |
|---|
| 2305 | | GMMR0DECL(int) GMMR0SeedChunk(PVM pVM, RTR3PTR pvR3) |
|---|
| 2306 | | { |
|---|
| 2307 | | return VERR_NOT_IMPLEMENTED; |
|---|
| 2308 | | } |
|---|
| 2309 | | |
|---|
| | 2508 | return GMMR0MapUnmapChunk(pVM, pReq->idChunkMap, pReq->idChunkUnmap, &pReq->pvR3); |
|---|
| | 2509 | } |
|---|
| | 2510 | |
|---|
| | 2511 | |
|---|
| | 2512 | /** |
|---|
| | 2513 | * Legacy mode API for supplying pages. |
|---|
| | 2514 | * |
|---|
| | 2515 | * The specified user address points to a allocation chunk sized block that |
|---|
| | 2516 | * will be locked down and used by the GMM when the GM asks for pages. |
|---|
| | 2517 | * |
|---|
| | 2518 | * @returns VBox status code. |
|---|
| | 2519 | * @param pVM The VM. |
|---|
| | 2520 | * @param pvR3 Pointer to the chunk size memory block to lock down. |
|---|
| | 2521 | */ |
|---|
| | 2522 | GMMR0DECL(int) GMMR0SeedChunk(PVM pVM, RTR3PTR pvR3) |
|---|
| | 2523 | { |
|---|
| | 2524 | /* |
|---|
| | 2525 | * Validate input and get the basics. |
|---|
| | 2526 | */ |
|---|
| | 2527 | PGMM pGMM; |
|---|
| | 2528 | GMM_GET_VALID_INSTANCE(pGMM, VERR_INTERNAL_ERROR); |
|---|
| | 2529 | PGVM pGVM = GVMMR0ByVM(pVM); |
|---|
| | 2530 | if (!pGVM) |
|---|
| | 2531 | return VERR_INVALID_PARAMETER; |
|---|
| | 2532 | if (pGVM->hEMT != RTThreadNativeSelf()) |
|---|
| | 2533 | return VERR_NOT_OWNER; |
|---|
| | 2534 | |
|---|
| | 2535 | AssertPtrReturn(pvR3, VERR_INVALID_POINTER); |
|---|
| | 2536 | AssertReturn(!(PAGE_OFFSET_MASK & pvR3), VERR_INVALID_POINTER); |
|---|
| | 2537 | |
|---|
| | 2538 | if (!pGMM->fLegacyMode) |
|---|
| | 2539 | { |
|---|
| | 2540 | Log(("GMMR0MapUnmapChunk: not in legacy mode!\n")); |
|---|
| | 2541 | return VERR_NOT_SUPPORTED; |
|---|
| | 2542 | } |
|---|
| | 2543 | |
|---|
| | 2544 | /* |
|---|
| | 2545 | * Lock the memory before taking the semaphore. |
|---|
| | 2546 | */ |
|---|
| | 2547 | RTR0MEMOBJ MemObj; |
|---|
| | 2548 | int rc = RTR0MemObjLockUser(&MemObj, pvR3, GMM_CHUNK_SIZE, NIL_RTR0PROCESS); |
|---|
| | 2549 | if (RT_SUCCESS(rc)) |
|---|
| | 2550 | { |
|---|
| | 2551 | /* |
|---|
| | 2552 | * Take the semaphore and add a new chunk with our hGVM. |
|---|
| | 2553 | */ |
|---|
| | 2554 | int rc = RTSemFastMutexRequest(pGMM->Mtx); |
|---|
| | 2555 | AssertRC(rc); |
|---|
| | 2556 | |
|---|
| | 2557 | rc = gmmR0RegisterChunk(pGMM, &pGMM->Private, MemObj, pGVM->hSelf); |
|---|
| | 2558 | |
|---|
| | 2559 | RTSemFastMutexRelease(pGMM->Mtx); |
|---|
| | 2560 | |
|---|
| | 2561 | if (RT_FAILURE(rc)) |
|---|
| | 2562 | RTR0MemObjFree(MemObj, false /* fFreeMappings */); |
|---|
| | 2563 | } |
|---|
| | 2564 | |
|---|
| | 2565 | return rc; |
|---|
| | 2566 | } |
|---|
| | 2567 | |
|---|