VirtualBox

Changeset 5142

Show
Ignore:
Timestamp:
10/02/07 15:58:35 (1 year ago)
Author:
vboxsync
Message:

More GMM code.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/include/VBox/err.h

    r5135 r5142  
    11371137/** The page to be updated or freed was noted owned by the caller. */ 
    11381138#define VERR_GMM_NOT_PAGE_OWNER                     (-4160) 
     1139/** The specified chunk was not found. */ 
     1140#define VERR_GMM_CHUNK_NOT_FOUND                    (-4161) 
     1141/** The chunk has already been mapped into the process. */ 
     1142#define VERR_GMM_CHUNK_ALREADY_MAPPED               (-4162) 
     1143/** The chunk to be unmapped isn't actually mapped into the process. */ 
     1144#define VERR_GMM_CHUNK_NOT_MAPPED                   (-4163) 
    11391145/** The reservation or reservation update was declined - too many VMs, too 
    11401146 * little memory, and/or too low GMM configuration. */ 
  • trunk/include/VBox/gmm.h

    r5135 r5142  
    222222GMMR0DECL(int)  GMMR0BalloonedPages(PVM pVM, uint32_t cBalloonedPages, uint32_t cPagesToFree, PGMMFREEPAGEDESC paPages, bool fCompleted); 
    223223GMMR0DECL(int)  GMMR0DeflatedBalloon(PVM pVM, uint32_t cPages); 
    224 GMMR0DECL(int)  GMMR0FreeMapUnmapChunk(PVM pVM, uint32_t idChunkMap, uint32_t idChunkUnmap, PRTR3PTR pvR3); 
     224GMMR0DECL(int)  GMMR0MapUnmapChunk(PVM pVM, uint32_t idChunkMap, uint32_t idChunkUnmap, PRTR3PTR ppvR3); 
    225225GMMR0DECL(int)  GMMR0SeedChunk(PVM pVM, RTR3PTR pvR3); 
    226226 
     
    330330 
    331331/** 
    332  * Request buffer for GMMR0FreeMapUnmapChunkReq / VMMR0_DO_GMM_MAP_UNMAP_CHUNK. 
    333  * @see GMMR0FreeMapUnmapChunk 
     332 * Request buffer for GMMR0MapUnmapChunkReq / VMMR0_DO_GMM_MAP_UNMAP_CHUNK. 
     333 * @see GMMR0MapUnmapChunk 
    334334 */ 
    335335typedef struct GMMMAPUNMAPCHUNKREQ 
     
    344344    RTR3PTR         pvR3; 
    345345} GMMMAPUNMAPCHUNKREQ; 
    346 /** Pointer to a GMMR0FreeMapUnmapChunkReq / VMMR0_DO_GMM_MAP_UNMAP_CHUNK request buffer. */ 
     346/** Pointer to a GMMR0MapUnmapChunkReq / VMMR0_DO_GMM_MAP_UNMAP_CHUNK request buffer. */ 
    347347typedef GMMMAPUNMAPCHUNKREQ *PGMMMAPUNMAPCHUNKREQ; 
    348348 
    349 GMMR0DECL(int)  GMMR0FreeMapUnmapChunkReq(PVM pVM, PGMMMAPUNMAPCHUNKREQ pReq); 
     349GMMR0DECL(int)  GMMR0MapUnmapChunkReq(PVM pVM, PGMMMAPUNMAPCHUNKREQ pReq); 
    350350 
    351351 
  • trunk/src/VBox/VMM/VMMR0/GMMR0.cpp

    r5135 r5142  
    348348    RTR0MEMOBJ      MapObj; 
    349349    /** The VM owning the mapping. */ 
    350     PVM             pVM; 
     350    PGVM            pGVM; 
    351351} GMMCHUNKMAP; 
    352352/** Pointer to a GMM allocation chunk mapping. */ 
     
    11721172 
    11731173/** 
    1174  * Allocate one new chunk and add it to the specified free set. 
     1174 * Registers a new chunk of memory. 
     1175 * 
     1176 * This is called by both gmmR0AllocateOneChunk and GMMR0SeedChunk. 
    11751177 * 
    11761178 * @returns VBox status code. 
    11771179 * @param   pGMM        Pointer to the GMM instance. 
    11781180 * @param   pSet        Pointer to the set. 
    1179  */ 
    1180 static int gmmR0AllocateOneChunk(PGMM pGMM, PGMMCHUNKFREESET pSet) 
    1181 
    1182     /* 
    1183      * Allocate the memory. 
    1184      */ 
    1185     RTR0MEMOBJ MemObj; 
    1186     int rc = RTR0MemObjAllocPhysNC(&MemObj, GMM_CHUNK_SIZE, NIL_RTHCPHYS); 
    1187     if (RT_FAILURE(rc)) 
    1188         return rc; 
    1189  
     1181 * @param   MemObj      The memory object for the chunk. 
     1182 * @param   hGVM        The hGVM value. (Only used by GMMR0SeedChunk.) 
     1183 */ 
     1184static int gmmR0RegisterChunk(PGMM pGMM, PGMMCHUNKFREESET pSet, RTR0MEMOBJ MemObj, uint16_t hGVM) 
     1185
     1186    int rc; 
    11901187    PGMMCHUNK pChunk = (PGMMCHUNK)RTMemAllocZ(sizeof(*pChunk)); 
    11911188    if (pChunk) 
     
    11961193        pChunk->MemObj = MemObj; 
    11971194        pChunk->cFree = GMM_CHUNK_NUM_PAGES; 
    1198         pChunk->hGVM = NIL_GVM_HANDLE
     1195        pChunk->hGVM = hGVM
    11991196        pChunk->iFreeHead = 0; 
    12001197        for (unsigned iPage = 0; iPage < RT_ELEMENTS(pChunk->aPages) - 1; iPage++) 
     
    12251222    else 
    12261223        rc = VERR_NO_MEMORY; 
    1227     RTR0MemObjFree(MemObj, false /* fFreeMappings */); 
     1224    return rc; 
     1225
     1226 
     1227 
     1228/** 
     1229 * Allocate one new chunk and add it to the specified free set. 
     1230 * 
     1231 * @returns VBox status code. 
     1232 * @param   pGMM        Pointer to the GMM instance. 
     1233 * @param   pSet        Pointer to the set. 
     1234 */ 
     1235static int gmmR0AllocateOneChunk(PGMM pGMM, PGMMCHUNKFREESET pSet) 
     1236
     1237    /* 
     1238     * Allocate the memory. 
     1239     */ 
     1240    RTR0MEMOBJ MemObj; 
     1241    int rc = RTR0MemObjAllocPhysNC(&MemObj, GMM_CHUNK_SIZE, NIL_RTHCPHYS); 
     1242    if (RT_SUCCESS(rc)) 
     1243    { 
     1244        rc = gmmR0RegisterChunk(pGMM, pSet, MemObj, NIL_GVM_HANDLE); 
     1245        if (RT_FAILURE(rc)) 
     1246            RTR0MemObjFree(MemObj, false /* fFreeMappings */); 
     1247    } 
    12281248    return rc; 
    12291249} 
     
    22602280        } 
    22612281        else 
    2262         { 
    22632282            Log(("GMMR0BalloonedPages: -%#x - Global=%#llx / VM: Total=%#llx\n", cPages, 
    22642283                 pGMM->cBalloonedPages, pGVM->gmm.s.cBalloonedPages)); 
    2265         } 
    22662284    } 
    22672285    else 
     
    22772295 
    22782296 
    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 */ 
     2305static 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 */ 
     2346static 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 */ 
     2409GMMR0DECL(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. 
    22892496 * @param   pVM             Pointer to the shared VM structure. 
    22902497 * @param   pReq            The request packet. 
    22912498 */ 
    2292 GMMR0DECL(int)  GMMR0FreeMapUnmapChunkReq(PVM pVM, PGMMMAPUNMAPCHUNKREQ pReq) 
     2499GMMR0DECL(int)  GMMR0MapUnmapChunkReq(PVM pVM, PGMMMAPUNMAPCHUNKREQ pReq) 
    22932500{ 
    22942501    /* 
     
    22992506    AssertMsgReturn(pReq->Hdr.cbReq == sizeof(*pReq), ("%#x != %#x\n", pReq->Hdr.cbReq, sizeof(*pReq)), VERR_INVALID_PARAMETER); 
    23002507 
    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 */ 
     2522GMMR0DECL(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 
  • trunk/src/VBox/VMM/VMMR0/VMMR0.cpp

    r5135 r5142  
    751751 
    752752        case VMMR0_DO_GMM_MAP_UNMAP_CHUNK: 
    753             return GMMR0FreeMapUnmapChunkReq(pVM, (PGMMMAPUNMAPCHUNKREQ)pReqHdr); 
     753            return GMMR0MapUnmapChunkReq(pVM, (PGMMMAPUNMAPCHUNKREQ)pReqHdr); 
    754754        case VMMR0_DO_GMM_SEED_CHUNK: 
    755755            return GMMR0SeedChunk(pVM, (RTR3PTR)u64Arg); 

© 2008 Sun Microsystems, Inc.
ContactPrivacy policy