| | 111 | /** |
|---|
| | 112 | * Lazily sync in the FPU/XMM state |
|---|
| | 113 | * |
|---|
| | 114 | * @returns VBox status code. |
|---|
| | 115 | * @param pVM VM handle. |
|---|
| | 116 | * @param pCtx CPU context |
|---|
| | 117 | */ |
|---|
| | 118 | CPUMR0DECL(int) CPUMR0LoadGuestFPU(PVM pVM, PCPUMCTX pCtx) |
|---|
| | 119 | { |
|---|
| | 120 | Assert(pVM->cpum.s.CPUFeatures.edx.u1FXSR); |
|---|
| | 121 | |
|---|
| | 122 | /* If the FPU state has already been loaded, then it's a guest trap. */ |
|---|
| | 123 | if (pVM->cpum.s.fUseFlags & CPUM_USED_FPU) |
|---|
| | 124 | { |
|---|
| | 125 | Assert( ((pCtx->cr0 & (X86_CR0_MP | X86_CR0_EM | X86_CR0_TS)) == (X86_CR0_MP | X86_CR0_EM | X86_CR0_TS)) |
|---|
| | 126 | || ((pCtx->cr0 & (X86_CR0_MP | X86_CR0_EM | X86_CR0_TS)) == (X86_CR0_MP | X86_CR0_TS))); |
|---|
| | 127 | return VINF_EM_RAW_GUEST_TRAP; |
|---|
| | 128 | } |
|---|
| | 129 | |
|---|
| | 130 | /* |
|---|
| | 131 | * There are two basic actions: |
|---|
| | 132 | * 1. Save host fpu and restore guest fpu. |
|---|
| | 133 | * 2. Generate guest trap. |
|---|
| | 134 | * |
|---|
| | 135 | * When entering the hypervisor we'll always enable MP (for proper wait |
|---|
| | 136 | * trapping) and TS (for intercepting all fpu/mmx/sse stuff). The EM flag |
|---|
| | 137 | * is taken from the guest OS in order to get proper SSE handling. |
|---|
| | 138 | * |
|---|
| | 139 | * |
|---|
| | 140 | * Actions taken depending on the guest CR0 flags: |
|---|
| | 141 | * |
|---|
| | 142 | * 3 2 1 |
|---|
| | 143 | * TS | EM | MP | FPUInstr | WAIT :: VMM Action |
|---|
| | 144 | * ------------------------------------------------------------------------ |
|---|
| | 145 | * 0 | 0 | 0 | Exec | Exec :: Clear TS & MP, Save HC, Load GC. |
|---|
| | 146 | * 0 | 0 | 1 | Exec | Exec :: Clear TS, Save HC, Load GC. |
|---|
| | 147 | * 0 | 1 | 0 | #NM | Exec :: Clear TS & MP, Save HC, Load GC. |
|---|
| | 148 | * 0 | 1 | 1 | #NM | Exec :: Clear TS, Save HC, Load GC. |
|---|
| | 149 | * 1 | 0 | 0 | #NM | Exec :: Clear MP, Save HC, Load GC. (EM is already cleared.) |
|---|
| | 150 | * 1 | 0 | 1 | #NM | #NM :: Go to guest taking trap there. |
|---|
| | 151 | * 1 | 1 | 0 | #NM | Exec :: Clear MP, Save HC, Load GC. (EM is already set.) |
|---|
| | 152 | * 1 | 1 | 1 | #NM | #NM :: Go to guest taking trap there. |
|---|
| | 153 | */ |
|---|
| | 154 | |
|---|
| | 155 | switch(pCtx->cr0 & (X86_CR0_MP | X86_CR0_EM | X86_CR0_TS)) |
|---|
| | 156 | { |
|---|
| | 157 | case X86_CR0_MP | X86_CR0_TS: |
|---|
| | 158 | case X86_CR0_MP | X86_CR0_EM | X86_CR0_TS: |
|---|
| | 159 | return VINF_EM_RAW_GUEST_TRAP; |
|---|
| | 160 | |
|---|
| | 161 | default: |
|---|
| | 162 | break; |
|---|
| | 163 | } |
|---|
| | 164 | CPUMLoadFPUAsm(pCtx); |
|---|
| | 165 | pVM->cpum.s.fUseFlags |= CPUM_USED_FPU; |
|---|
| | 166 | return VINF_SUCCESS; |
|---|
| | 167 | } |
|---|
| | 168 | |
|---|
| | 169 | |
|---|
| | 170 | /** |
|---|
| | 171 | * Save guest FPU/XMM state |
|---|
| | 172 | * |
|---|
| | 173 | * @returns VBox status code. |
|---|
| | 174 | * @param pVM VM handle. |
|---|
| | 175 | * @param pCtx CPU context |
|---|
| | 176 | */ |
|---|
| | 177 | CPUMR0DECL(int) CPUMR0SaveGuestFPU(PVM pVM, PCPUMCTX pCtx) |
|---|
| | 178 | { |
|---|
| | 179 | Assert(pVM->cpum.s.CPUFeatures.edx.u1FXSR); |
|---|
| | 180 | AssertReturn((pVM->cpum.s.fUseFlags & CPUM_USED_FPU), VINF_SUCCESS); |
|---|
| | 181 | |
|---|
| | 182 | CPUMSaveFPUAsm(pCtx); |
|---|
| | 183 | pVM->cpum.s.fUseFlags &= ~CPUM_USED_FPU; |
|---|
| | 184 | return VINF_SUCCESS; |
|---|
| | 185 | } |
|---|