VirtualBox

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


Ignore:
Timestamp:
May 23, 2016 10:16:26 PM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
107425
Message:

CPUM,HM,GVMM,TRPM,VMM: Next part of the FPU state handling for IEM. This is a little bit risky change as we now leave CR0.TS+EM cleared after saving the host state, they only get restored when we restore the host state. On Windows, Darwin, and later on Linux (needs testing) we will rely on #NM handling of the host OS and not our own CR.TS/EM handy work. This means we won't be saving the host state but rather the ring-3 state of our own thread. This change also introduces a CPUM force flag that we're using for restoring CR0.TS/EM in raw-mode (it may be extended with other uses later if we need to).

Location:
trunk/src/VBox/VMM
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR0/CPUMR0A.asm

    r61068 r61144  
    3131
    3232
    33 ;*******************************************************************************
    34 ;*      Defined Constants And Macros                                           *
    35 ;*******************************************************************************
    36 ;; The offset of the XMM registers in X86FXSTATE.
    37 ; Use define because I'm too lazy to convert the struct.
    38 %define XMM_OFF_IN_X86FXSTATE   160
    39 
    40 
    41 
    4233BEGINCODE
    4334
     35;;
     36; Makes sure the EMTs have a FPU state associated with them on hosts where we're
     37; allowed to use it in ring-0 too.
     38;
     39; This ensure that we don't have to allocate the state lazily while trying to execute
     40; guest code with preemption disabled or worse.
     41;
     42; @cproto VMMR0_INT_DECL(void) CPUMR0RegisterVCpuThread(PVMCPU pVCpu);
     43;
     44BEGINPROC CPUMR0RegisterVCpuThread
     45        push    xBP
     46        SEH64_PUSH_xBP
     47        mov     xBP, xSP
     48        SEH64_SET_FRAME_xBP 0
     49SEH64_END_PROLOGUE
     50
     51%ifdef CPUM_CAN_USE_FPU_IN_R0
     52        movaps  xmm0, xmm0
     53%endif
     54
     55.return:
     56        xor     eax, eax                ; paranoia
     57        leave
     58        ret
     59ENDPROC   CPUMR0RegisterVCpuThread
    4460
    4561
     
    7995        cli                             ; interrupt occurs while we're doing fxsave/fxrstor/cr0.
    8096
    81 %ifdef VBOX_WITH_KERNEL_USING_XMM
    82         movaps  xmm0, xmm0              ; Make 100% sure it's used before we save it or mess with CR0/XCR0.
    83 %endif
    84         SAVE_CR0_CLEAR_FPU_TRAPS xCX, xAX ; xCX is now old CR0 value, don't use!
    85 
    8697        ;
    8798        ; Save the host state.
     
    89100        test    dword [pCpumCpu + CPUMCPU.fUseFlags], CPUM_USED_FPU_HOST
    90101        jnz     .already_saved_host
     102
     103%ifndef CPUM_CAN_USE_FPU_IN_R0
     104        ; On systems where the kernel doesn't necessarily allow us to use the FPU
     105        ; in ring-0 context, we have to disable FPU traps before doing fxsave/xsave
     106        ; here.  (xCX is 0 if no CR0 was necessary.)  We leave it like that so IEM
     107        ; can use the FPU/SSE/AVX host CPU features directly.
     108        SAVE_CR0_CLEAR_FPU_TRAPS xCX, xAX
     109        mov     [pCpumCpu + CPUMCPU.Host.cr0Fpu], xCX
     110        ;; @todo What about XCR0?
     111%endif
     112
    91113        CPUMR0_SAVE_HOST
     114
    92115%ifdef VBOX_WITH_KERNEL_USING_XMM
    93116        jmp     .load_guest
     
    130153%endif
    131154
    132         ;; @todo Save CR0 + XCR0 bits related to FPU, SSE and AVX*, leaving these register sets accessible to IEM.
    133         RESTORE_CR0 xCX
    134155        or      dword [pCpumCpu + CPUMCPU.fUseFlags], (CPUM_USED_FPU_GUEST | CPUM_USED_FPU_SINCE_REM | CPUM_USED_FPU_HOST)
    135156        popf
     
    177198        pushf                           ; The darwin kernel can get upset or upset things if an
    178199        cli                             ; interrupt occurs while we're doing fxsave/fxrstor/cr0.
    179         SAVE_CR0_CLEAR_FPU_TRAPS xCX, xAX ; xCX is now old CR0 value, don't use!
    180 
    181200
    182201 %ifdef VBOX_WITH_KERNEL_USING_XMM
     
    232251        CPUMR0_LOAD_HOST
    233252
    234         ;; @todo Restore CR0 + XCR0 bits related to FPU, SSE and AVX* (for IEM).
     253%ifndef CPUM_CAN_USE_FPU_IN_R0
     254        ; Restore the CR0 value we saved in cpumR0SaveHostRestoreGuestFPUState or
     255        ; in cpumRZSaveHostFPUState.
     256        mov     xCX, [pCpumCpu + CPUMCPU.Host.cr0Fpu]
    235257        RESTORE_CR0 xCX
     258%endif
    236259        and     dword [pCpumCpu + CPUMCPU.fUseFlags], ~(CPUM_USED_FPU_GUEST | CPUM_USED_FPU_HOST)
    237260
     
    273296        pushf                           ; The darwin kernel can get upset or upset things if an
    274297        cli                             ; interrupt occurs while we're doing fxsave/fxrstor/cr0.
    275         SAVE_CR0_CLEAR_FPU_TRAPS xCX, xAX ; xCX is now old CR0 value, don't use!
    276298
    277299        CPUMR0_LOAD_HOST
    278300
     301%ifndef CPUM_CAN_USE_FPU_IN_R0
     302        ; Restore the CR0 value we saved in cpumR0SaveHostRestoreGuestFPUState or
     303        ; in cpumRZSaveHostFPUState.
     304        ;; @todo What about XCR0?
     305        mov     xCX, [pCpumCpu + CPUMCPU.Host.cr0Fpu]
    279306        RESTORE_CR0 xCX
     307%endif
    280308        and     dword [pCpumCpu + CPUMCPU.fUseFlags], ~CPUM_USED_FPU_HOST
    281309        popf
  • trunk/src/VBox/VMM/VMMR0/GVMMR0.cpp

    r59747 r61144  
    968968                                            gvmmR0CreateDestroyUnlock(pGVMM);
    969969
     970                                            CPUMR0RegisterVCpuThread(&pVM->aCpus[0]);
     971
    970972                                            *ppVM = pVM;
    971973                                            Log(("GVMMR0CreateVM: pVM=%p pVMR3=%p pGVM=%p hGVM=%d\n", pVM, pVM->pVMR3, pGVM, iHandle));
     
    14261428    pVM->aCpus[idCpu].hNativeThreadR0 = pGVM->aCpus[idCpu].hEMT = RTThreadNativeSelf();
    14271429
    1428     return VMMR0ThreadCtxHookCreateForEmt(&pVM->aCpus[idCpu]);
     1430    rc = VMMR0ThreadCtxHookCreateForEmt(&pVM->aCpus[idCpu]);
     1431    if (RT_SUCCESS(rc))
     1432        CPUMR0RegisterVCpuThread(&pVM->aCpus[idCpu]);
     1433    return rc;
    14291434}
    14301435
  • trunk/src/VBox/VMM/VMMR0/HMR0.cpp

    r60850 r61144  
    15051505    return VBOXSTRICTRC_VAL(rcStrict);
    15061506}
     1507
     1508
     1509/**
     1510 * Notification from CPUM that it has unloaded the guest FPU/SSE/AVX state from
     1511 * the host CPU and that guest access to it must be intercepted.
     1512 *
     1513 * @param   pVCpu   The cross context virtual CPU structure of the calling EMT.
     1514 */
     1515VMMR0_INT_DECL(void) HMR0NotifyCpumUnloadedGuestFpuState(PVMCPU pVCpu)
     1516{
     1517    HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_CR0);
     1518}
     1519
    15071520
    15081521#if HC_ARCH_BITS == 32 && defined(VBOX_ENABLE_64_BITS_GUESTS)
  • trunk/src/VBox/VMM/VMMR3/VMM.cpp

    r60847 r61144  
    28742874        PRINT_FLAG(VMCPU_FF_,CSAM_SCAN_PAGE);
    28752875        PRINT_FLAG(VMCPU_FF_,CSAM_PENDING_ACTION);
     2876        PRINT_FLAG(VMCPU_FF_,CPUM);
    28762877#endif
    28772878        if (f)
  • trunk/src/VBox/VMM/VMMRC/CPUMRC.cpp

    r58123 r61144  
    3131#include <iprt/assert.h>
    3232#include <VBox/log.h>
     33#include <iprt/asm-amd64-x86.h>
    3334
    3435
     
    220221#endif /* VBOX_WITH_RAW_RING1 */
    221222
     223
     224/**
     225 * Called by trpmGCExitTrap when VMCPU_FF_CPUM is set (by CPUMRZ.cpp).
     226 *
     227 * We can be called unecessarily here if we returned to ring-3 for some other
     228 * reason before we tried to resume executed guest code.  This is detected and
     229 * ignored.
     230 *
     231 * @param   pVCpu   The cross context CPU structure for the calling EMT.
     232 */
     233VMMRCDECL(void) CPUMRCProcessForceFlag(PVMVCPU pVCpu)
     234{
     235    /* Only modify CR0 if we're in the post IEM state (host state saved, guest no longer active). */
     236    if ((pVCpu->cpum.s.fUseFlags & (CPUM_USED_FPU_GUEST | CPUM_USED_FPU_HOST)) == CPUM_USED_FPU_HOST)
     237    {
     238        /*
     239         * Doing the same CR0 calculation as in AMD64andLegacy.mac so that we'll
     240         * catch guest FPU accesses and load the FPU/SSE/AVX register state as needed.
     241         */
     242        uint32_t cr0 = ASMGetCR0();
     243        cr0 |= pVCpu->cpum.s.Guest.cr0 & X86_CR0_EM;
     244        cr0 |= X86_CR0_TS | X86_CR0_MP;
     245        ASMSetCR0(cr0);
     246    }
     247}
     248
  • trunk/src/VBox/VMM/VMMRC/TRPMRCHandlers.cpp

    r61015 r61144  
    219219                                          | VMCPU_FF_PDM_CRITSECT  | VMCPU_FF_IEM            | VMCPU_FF_SELM_SYNC_GDT
    220220                                          | VMCPU_FF_SELM_SYNC_LDT | VMCPU_FF_SELM_SYNC_TSS  | VMCPU_FF_TRPM_SYNC_IDT
    221                                           | VMCPU_FF_IOM
     221                                          | VMCPU_FF_IOM           | VMCPU_FF_CPUM
    222222                                   )
    223223            )
     
    234234                APICUpdatePendingInterrupts(pVCpu);
    235235#endif
     236            if (VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_CPUM))
     237                CPUMRCProcessForceFlag(pVCpu);
     238
    236239            /* Pending Ring-3 action. */
    237240            if (VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_TO_R3 | VMCPU_FF_PDM_CRITSECT | VMCPU_FF_IEM | VMCPU_FF_IOM))
  • trunk/src/VBox/VMM/VMMRZ/CPUMRZ.cpp

    r61068 r61144  
    5050        case 0:
    5151            cpumRZSaveHostFPUState(&pVCpu->cpum.s);
     52#ifdef IN_RC
     53            VMCPU_FF_SET(pVCpu, VMCPU_FF_CPUM); /* Must recalc CR0 before executing more code! */
     54#endif
    5255            break;
    5356
     
    5760            {
    5861                pVCpu->cpum.s.fUseFlags &= ~CPUM_SYNC_FPU_STATE;
    59 /** @todo tell HM! */
     62                HMR0NotifyCpumUnloadedGuestFpuState(pVCpu);
    6063            }
    6164#endif
     
    6366
    6467        case CPUM_USED_FPU_GUEST | CPUM_USED_FPU_HOST:
    65 /** @todo tell HM! */
    6668#if defined(IN_RING0) && ARCH_BITS == 32 && defined(VBOX_WITH_64_BITS_GUESTS)
    6769            Assert(!(pVCpu->cpum.s.fUseFlags & CPUM_SYNC_FPU_STATE));
     
    7072            else
    7173#endif
    72                 cpumRZSaveGuestFpuState(&pVCpu->cpum.s);
    73 
     74                cpumRZSaveGuestFpuState(&pVCpu->cpum.s, true /*fLeaveFpuAccessible*/);
     75#ifdef IN_RING0
     76            HMR0NotifyCpumUnloadedGuestFpuState(pVCpu);
     77#endif
    7478            break;
    7579
     
    112116        else
    113117#endif
    114             cpumRZSaveGuestFpuState(&pVCpu->cpum.s);
     118            cpumRZSaveGuestFpuState(&pVCpu->cpum.s, false /*fLeaveFpuAccessible*/);
    115119        pVCpu->cpum.s.fUseFlags |= CPUM_USED_FPU_GUEST;
    116120    }
     
    129133#if defined(VBOX_WITH_KERNEL_USING_XMM) && HC_ARCH_BITS == 64
    130134    NOREF(pVCpu);
     135#error "do NOT commit this"
    131136#else
    132137    if (pVCpu->cpum.s.fUseFlags & CPUM_USED_FPU_GUEST)
     
    141146        else
    142147# endif
     148        {
     149RTLogPrintf("calling cpumRZSaveGuestSseRegisters\n");
    143150            cpumRZSaveGuestSseRegisters(&pVCpu->cpum.s);
     151        }
    144152    }
    145153#endif
  • trunk/src/VBox/VMM/VMMRZ/CPUMRZA.asm

    r61112 r61144  
    3434; Saves the host FPU/SSE/AVX state.
    3535;
     36; Will return with CR0.EM and CR0.TS cleared!  This is the normal state in
     37; ring-0, whereas in raw-mode the caller will probably set VMCPU_FF_CPUM to
     38; re-evaluate the situation before executing more guest code.
     39;
    3640; @returns  VINF_SUCCESS (0) in EAX
    3741; @param    pCpumCpu  x86:[ebp+8] gcc:rdi msc:rcx     CPUMCPU pointer
     
    6670        pushf                           ; The darwin kernel can get upset or upset things if an
    6771        cli                             ; interrupt occurs while we're doing fxsave/fxrstor/cr0.
    68 %ifdef VBOX_WITH_KERNEL_USING_XMM
     72
     73%ifndef CPUM_CAN_USE_FPU_IN_R0
     74        ;
     75        ; In raw-mode context and on systems where the kernel doesn't necessarily
     76        ; allow us to use the FPU in ring-0 context, we have to disable FPU traps
     77        ; before doing fxsave/xsave here.  (xCX is 0 if no CR0 was necessary.)  We
     78        ; leave it like that so IEM can use the FPU/SSE/AVX host CPU features directly.
     79        ;
     80        SAVE_CR0_CLEAR_FPU_TRAPS xCX, xAX
     81        ;; @todo What about XCR0?
    6982 %ifdef IN_RING0
    70         movaps  xmm0, xmm0              ; Make 100% sure it's used before we save it or mess with CR0/XCR0.
    71  %endif
    72 %endif
    73         SAVE_CR0_CLEAR_FPU_TRAPS xCX, xAX ; xCX is now old CR0 value, don't use!
    74 
     83        mov     [pCpumCpu + CPUMCPU.Host.cr0Fpu], xCX
     84 %else
     85  %error "Huh?"
     86 %endif
     87%endif
     88        ;
     89        ; Save the host state (xsave/fxsave will cause thread FPU state to be
     90        ; loaded on systems where we are allowed to use it in ring-0.
     91        ;
    7592        CPUMR0_SAVE_HOST
    76         ;; @todo Save CR0 + XCR0 bits related to FPU, SSE and AVX*, leaving these register sets accessible to IEM.
    77 
    78         RESTORE_CR0 xCX
     93
    7994        or      dword [pCpumCpu + CPUMCPU.fUseFlags], (CPUM_USED_FPU_HOST | CPUM_USED_FPU_SINCE_REM) ; Latter is not necessarily true, but normally yes.
    8095        popf
     
    95110;
    96111; @param    pCpumCpu  x86:[ebp+8] gcc:rdi msc:rcx     CPUMCPU pointer
     112; @param    fLeaveFpuAccessible  x86:[ebp+c] gcc:sil msc:dl      Whether to restore CR0 and XCR0 on
     113;                                                                the way out. Only really applicable to RC.
    97114;
    98115align 16
     
    124141        pushf                           ; The darwin kernel can get upset or upset things if an
    125142        cli                             ; interrupt occurs while we're doing fxsave/fxrstor/cr0.
    126         SAVE_CR0_CLEAR_FPU_TRAPS xCX, xAX ; xCX is now old CR0 value, don't use!
    127 
     143
     144 %ifdef IN_RC
     145        SAVE_CR0_CLEAR_FPU_TRAPS xCX, xAX ; xCX must be preserved until CR0 is restored!
     146 %endif
    128147
    129148 %ifndef VBOX_WITH_KERNEL_USING_XMM
     
    185204 %endif
    186205
     206        and     dword [pCpumCpu + CPUMCPU.fUseFlags], ~CPUM_USED_FPU_GUEST
     207 %ifdef IN_RC
     208        test    byte [ebp + 0ch], 1     ; fLeaveFpuAccessible
     209        jz      .no_cr0_restore
    187210        RESTORE_CR0 xCX
    188         and     dword [pCpumCpu + CPUMCPU.fUseFlags], ~CPUM_USED_FPU_GUEST
    189 
     211.no_cr0_restore:
     212 %endif
    190213        popf
    191214%ifdef RT_ARCH_X86
     
    202225;;
    203226; Saves the guest XMM0..15 registers.
     227;
     228; The purpose is to actualize the register state for read-only use, so CR0 is
     229; restored in raw-mode context (so, the FPU/SSE/AVX CPU features can be
     230; inaccessible upon return).
    204231;
    205232; @param    pCpumCpu  x86:[ebp+8] gcc:rdi msc:rcx     CPUMCPU pointer
     
    228255 %else
    229256  %error "Invalid context!"
     257 %endif
     258
     259 %ifdef IN_RC
     260        ; Temporarily grant access to the SSE state. xDX must be preserved until CR0 is restored!
     261        SAVE_CR0_CLEAR_FPU_TRAPS xDX, xAX
    230262 %endif
    231263
     
    251283        movdqa  [xCX + X86FXSTATE.xmm15], xmm15
    252284 %endif
     285
     286 %ifdef IN_RC
     287        RESTORE_CR0 xDX                 ; Restore CR0 if we changed it above.
     288 %endif
     289
    253290%endif ; !VBOX_WITH_KERNEL_USING_XMM
    254291
  • trunk/src/VBox/VMM/include/CPUMInternal.h

    r61068 r61144  
    262262    uint32_t        cr3;
    263263    uint32_t        cr4;
     264    /** The CR0 FPU state in HM mode.  Can't use cr0 here because the
     265     *  64-bit-on-32-bit-host world switches is using it. */
     266    uint32_t        cr0Fpu;
    264267    /** @} */
    265268
     
    286289    RTSEL           tr;
    287290    RTSEL           trPadding;
    288     uint32_t        SysEnterPadding;
    289291
    290292    /** The sysenter msr registers.
     
    304306    /** Control registers.
    305307     * @{ */
     308    /** The CR0 FPU state in HM mode.  */
    306309    uint64_t        cr0;
    307310    /*uint64_t        cr2; - scratch*/
     
    342345    /** @} */
    343346
    344     /* padding to get 32byte aligned size */
     347    /* padding to get 64byte aligned size */
    345348    uint8_t         auPadding[4];
    346349
     
    546549# if defined(IN_RC) || defined(IN_RING0)
    547550DECLASM(void)       cpumRZSaveHostFPUState(PCPUMCPU pCPUM);
    548 DECLASM(void)       cpumRZSaveGuestFpuState(PCPUMCPU pCPUM);
     551DECLASM(void)       cpumRZSaveGuestFpuState(PCPUMCPU pCPUM, bool fLeaveFpuAccessible);
    549552DECLASM(void)       cpumRZSaveGuestSseRegisters(PCPUMCPU pCPUM);
    550553# endif
  • trunk/src/VBox/VMM/include/CPUMInternal.mac

    r61109 r61144  
    3232 %define CPUM_IS_AMD64      0
    3333%endif
     34
     35;; @def CPUM_CAN_USE_FPU_IN_R0
     36; Indicates that we can use the FPU directly in ring-0.
     37; Only defined in ring-0.
     38%ifdef VBOX_WITH_KERNEL_USING_XMM
     39 ; Systems using XMM registers as part of their kernel calling convention must
     40 ; support saving and restoring the state while in ring-0.  64-bit Windows will
     41 ; always switch the FPU state when context switching.
     42 %define CPUM_CAN_USE_FPU_IN_R0 1
     43%endif
     44%ifdef RT_OS_WINDOWS
     45 ; 32-bit Windows will load the FPU context of the current thread (user land).
     46 %define CPUM_CAN_USE_FPU_IN_R0 1
     47%endif
     48%ifdef RT_OS_DARWIN
     49 ; Intel Darwin kernels will load the FPU context of the current thread (user land).
     50 %define CPUM_CAN_USE_FPU_IN_R0 1
     51%endif
     52%ifdef RT_OS_LINUX
     53 ; Intel Linux kernels will load the FPU context of the current thread (user land),
     54 ; at least that what my LXR research on 2.6.18+ indicates.  It's possible this was
     55 ; done differently at some point, I seems to recall issues with it ages and ages ago.
     56; %define CPUM_CAN_USE_FPU_IN_R0 1 - test me first
     57%endif
     58%ifndef IN_RING0
     59 %undef CPUM_CAN_USE_FPU_IN_R0
     60%endif
     61
    3462
    3563
     
    308336    .Host.cr3            resd    1
    309337    .Host.cr4            resd    1
     338    .Host.cr0Fpu         resd    1
    310339
    311340    .Host.dr0            resd    1
     
    325354    .Host.trPadding      resw    1
    326355
    327     .Host.SysEnterPadding resd   1
     356    alignb 8
    328357    .Host.SysEnter.cs    resq    1
    329358    .Host.SysEnter.eip   resq    1
     
    334363%else ; 64-bit
    335364
     365    .Host.cr0Fpu:
    336366    .Host.cr0            resq    1
    337367    ;.Host.cr2            resq    1 - scratch
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