VirtualBox

Changeset 49227 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
Oct 22, 2013 11:57:45 AM (11 years ago)
Author:
vboxsync
Message:

VMM/HMVMXR0: Adding functions for dynamic MSR swapping.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp

    r49209 r49227  
    6363/** Use the function table. */
    6464#define HMVMX_USE_FUNCTION_TABLE
     65
     66/**
     67 * The maximum number of MSRs we are willing to swap during a world-switch.
     68 * Intel claims 512/check capability MSR, we don't want to do anywhere close
     69 * to that. See Intel spec. 24.7.2 "VM-Exit Controls for MSRs"
     70 *
     71 * Bump this count as and when required, there's no backward compatibility
     72 * requirement.
     73 */
     74#define HMVMX_MAX_SWAP_MSR_COUNT                  5
    6575
    6676/** Determine which tagged-TLB flush handler to use. */
     
    11501160        ASMBitClear(pbMsrBitmap + 0x800, iBit);
    11511161}
     1162
     1163
     1164#ifdef VBOX_WITH_AUTO_MSR_LOAD_RESTORE
     1165/**
     1166 * Updates the VMCS with the number of effective MSRs in the auto-load/store MSR
     1167 * area.
     1168 *
     1169 * @returns VBox status code.
     1170 * @param   pVCpu       Pointer to the VMCPU.
     1171 * @param   cMsrs       The number of MSRs.
     1172 */
     1173DECLINLINE(int) hmR0VmxSetAutoLoadStoreMsrCount(PVMCPU pVCpu, uint32_t cMsrs)
     1174{
     1175    /* Update the VCPU's copy of the guest MSR count. */
     1176    pVCpu->hm.s.vmx.cGuestMsrs = cMsrs;
     1177
     1178    /* Update number of guest MSRs to load/store across the world-switch. */
     1179    int rc = VMXWriteVmcs32(VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT, cMsrs);  AssertRCReturn(rc, rc);
     1180    rc     = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT, cMsrs);  AssertRCReturn(rc, rc);
     1181
     1182    /* Update number of host MSRs to load after the world-switch. Identical to guest-MSR count as it's always paired. */
     1183    rc     = VMXWriteVmcs32(VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT,  cMsrs);  AssertRCReturn(rc, rc);
     1184    return VINF_SUCCESS;
     1185}
     1186
     1187
     1188/**
     1189 * Adds a guest/host MSR pair to be swapped during the world-switch as
     1190 * part of the auto-load/store MSR area in the VMCS.
     1191 *
     1192 * @returns VBox status code.
     1193 * @param   pVCpu       Pointer to the VMCPU.
     1194 * @param   uMsr        The MSR.
     1195 * @param   uGuestMsr   Value of the guest MSR.
     1196 * @param   uHostMsr    Value of the host MSR.
     1197 */
     1198static int hmR0VmxAddAutoLoadStoreMsr(PVMCPU pVCpu, uint32_t uMsr, uint64_t uGuestMsrValue, uint64_t uHostMsrValue)
     1199{
     1200    AssertMsg(HMVMX_MAX_SWAP_MSR_COUNT < MSR_IA32_VMX_MISC_MAX_MSR(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.u64Misc),
     1201              ("MSR swap count exceeded. Cpu reports %#RX32, our limit %#RX32\n",
     1202               MSR_IA32_VMX_MISC_MAX_MSR(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.u64Misc), HMVMX_MAX_SWAP_MSR_COUNT));
     1203
     1204    PVMXAUTOMSR pGuestMsr  = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
     1205    uint32_t    cGuestMsrs = pVCpu->hm.s.vmx.cGuestMsrs;
     1206    uint32_t    i;
     1207    for (i = 0; i < cGuestMsrs; i++)
     1208    {
     1209        if (pGuestMsr->u32Msr == uMsr)
     1210            break;
     1211        pGuestMsr++;
     1212    }
     1213
     1214    AssertReturn(i < HMVMX_MAX_SWAP_MSR_COUNT, VERR_HM_MSR_SWAP_COUNT_EXCEEDED);
     1215    if (i == cGuestMsrs)
     1216    {
     1217        ++cGuestMsrs;
     1218        /* Shouldn't ever happen but there -is- a number. We're well within the recommended 512. */
     1219        if (RT_UNLIKELY(cGuestMsrs > MSR_IA32_VMX_MISC_MAX_MSR(pVCpu->CTX_SUFF(pVM)->hm.s.vmx.Msrs.u64Misc)))
     1220        {
     1221            LogRel(("CPU autoload/store MSR count in VMCS exceeded cGuestMsrs=%u.\n", cGuestMsrs));
     1222            pVCpu->hm.s.u32HMError = VMX_UFC_INSUFFICIENT_GUEST_MSR_STORAGE;
     1223            return VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO;
     1224        }
     1225
     1226        int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, cGuestMsrs);
     1227        AssertRCReturn(rc, rc);
     1228    }
     1229
     1230    /* Update the MSR values in the auto-load/store MSR area. */
     1231    pGuestMsr->u32Msr    = uMsr;
     1232    pGuestMsr->u64Value  = uGuestMsrValue;
     1233
     1234    PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
     1235    pHostMsr += i;
     1236    pHostMsr->u32Msr     = uMsr;
     1237    pHostMsr->u64Value   = uHostMsrValue;
     1238
     1239    /* Now that we're swapping MSRs during the world-switch, allow the guest to read/write them without causing VM-exits. */
     1240    Assert(pVCpu->hm.s.vmx.u32ProcCtls & VMX_VMCS_CTRL_PROC_EXEC_USE_MSR_BITMAPS);
     1241    hmR0VmxSetMsrPermission(pVCpu, uMsr, VMXMSREXIT_PASSTHRU_READ, VMXMSREXIT_PASSTHRU_WRITE);
     1242    return VINF_SUCCESS;
     1243}
     1244
     1245
     1246/**
     1247 * Removes a guest/shost MSR pair to be swapped during the world-switch from the
     1248 * auto-load/store MSR area in the VMCS.
     1249 *
     1250 * Does not fail if the MSR in @a uMsr is not found in the auto-load/store MSR
     1251 * area.
     1252 *
     1253 * @returns VBox status code.
     1254 * @param   pVCpu       Pointer to the VMCPU.
     1255 * @param   uMsr        The MSR.
     1256 */
     1257static int hmR0VmxRemoveAutoLoadStoreMsr(PVMCPU pVCpu, uint32_t uMsr)
     1258{
     1259    PVMXAUTOMSR pGuestMsr  = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
     1260    uint32_t    cGuestMsrs = pVCpu->hm.s.vmx.cGuestMsrs;
     1261    uint32_t    i;
     1262    for (i = 0; i < cGuestMsrs; i++)
     1263    {
     1264        /* Find the MSR. */
     1265        if (pGuestMsr->u32Msr == uMsr)
     1266        {
     1267            /* If it's the last MSR, simply reduce the count. */
     1268            if (i == cGuestMsrs - 1)
     1269            {
     1270                --cGuestMsrs;
     1271                break;
     1272            }
     1273
     1274            /* Remove it by swapping the last MSR in place of it, and reducing the count. */
     1275            PVMXAUTOMSR pLastGuestMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvGuestMsr;
     1276            pLastGuestMsr            += cGuestMsrs;
     1277            pGuestMsr->u32Msr         = pLastGuestMsr->u32Msr;
     1278            pGuestMsr->u64Value       = pLastGuestMsr->u64Value;
     1279
     1280            PVMXAUTOMSR pHostMsr     = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
     1281            PVMXAUTOMSR pLastHostMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
     1282            pLastHostMsr            += cGuestMsrs;
     1283            pHostMsr->u32Msr         = pLastHostMsr->u32Msr;
     1284            pHostMsr->u64Value       = pLastHostMsr->u64Value;
     1285            --cGuestMsrs;
     1286            break;
     1287        }
     1288        pGuestMsr++;
     1289    }
     1290
     1291    /* Update the VMCS if the count changed (meaning the MSR was found). */
     1292    if (cGuestMsrs != pVCpu->hm.s.vmx.cGuestMsrs)
     1293    {
     1294        int rc = hmR0VmxSetAutoLoadStoreMsrCount(pVCpu, cGuestMsrs);
     1295        AssertRCReturn(rc, rc);
     1296    }
     1297
     1298    /* We're no longer swapping MSRs during the world-switch, intercept guest read/writes to them. */
     1299    hmR0VmxSetMsrPermission(pVCpu, uMsr, VMXMSREXIT_INTERCEPT_READ, VMXMSREXIT_INTERCEPT_WRITE);
     1300    return VINF_SUCCESS;
     1301}
     1302
     1303
     1304/**
     1305 * Updates the value of a host MSR in the auto-load/store area in the VMCS.
     1306 *
     1307 * @returns VBox status code.
     1308 * @param   pVCpu               Pointer to the VMCPU.
     1309 * @param   uMsr                The MSR.
     1310 */
     1311static int hmR0VmxUpdateAutoLoadStoreHostMsr(PVMCPU pVCpu, uint32_t uMsr)
     1312{
     1313    PVMXAUTOMSR pHostMsr = (PVMXAUTOMSR)pVCpu->hm.s.vmx.pvHostMsr;
     1314    uint32_t    cMsrs    = pVCpu->hm.s.vmx.cGuestMsrs;
     1315
     1316    for (uint32_t i = 0; i < cMsrs; i++)
     1317    {
     1318        if (pHostMsr->u32Msr == uMsr)
     1319        {
     1320            pHostMsr->u64Value = ASMRdMsr(pHostMsr->u32Msr);
     1321            return VINF_SUCCESS;
     1322        }
     1323    }
     1324
     1325    return VERR_NOT_FOUND;
     1326}
     1327
     1328#endif /* VBOX_WITH_AUTO_MSR_LOAD_RESTORE */
    11521329
    11531330
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette