VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/HMSVMAll.cpp@ 71859

Last change on this file since 71859 was 71859, checked in by vboxsync, 7 years ago

VMM: SVM NestedPagingCtrl naming consistency with rest of the VMCB fields.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.6 KB
Line 
1/* $Id: HMSVMAll.cpp 71859 2018-04-13 10:56:05Z vboxsync $ */
2/** @file
3 * HM SVM (AMD-V) - All contexts.
4 */
5
6/*
7 * Copyright (C) 2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_HM
23#define VMCPU_INCL_CPUM_GST_CTX
24#include "HMInternal.h"
25#include <VBox/vmm/apic.h>
26#include <VBox/vmm/gim.h>
27#include <VBox/vmm/hm.h>
28#include <VBox/vmm/iem.h>
29#include <VBox/vmm/vm.h>
30#include <VBox/vmm/hm_svm.h>
31
32
33#ifndef IN_RC
34/**
35 * Emulates a simple MOV TPR (CR8) instruction.
36 *
37 * Used for TPR patching on 32-bit guests. This simply looks up the patch record
38 * at EIP and does the required.
39 *
40 * This VMMCALL is used a fallback mechanism when mov to/from cr8 isn't exactly
41 * like how we want it to be (e.g. not followed by shr 4 as is usually done for
42 * TPR). See hmR3ReplaceTprInstr() for the details.
43 *
44 * @returns VBox status code.
45 * @retval VINF_SUCCESS if the access was handled successfully.
46 * @retval VERR_NOT_FOUND if no patch record for this RIP could be found.
47 * @retval VERR_SVM_UNEXPECTED_PATCH_TYPE if the found patch type is invalid.
48 *
49 * @param pVCpu The cross context virtual CPU structure.
50 * @param pCtx Pointer to the guest-CPU context.
51 * @param pfUpdateRipAndRF Whether the guest RIP/EIP has been updated as
52 * part of the TPR patch operation.
53 */
54static int hmSvmEmulateMovTpr(PVMCPU pVCpu, PCPUMCTX pCtx, bool *pfUpdateRipAndRF)
55{
56 Log4(("Emulated VMMCall TPR access replacement at RIP=%RGv\n", pCtx->rip));
57
58 /*
59 * We do this in a loop as we increment the RIP after a successful emulation
60 * and the new RIP may be a patched instruction which needs emulation as well.
61 */
62 bool fUpdateRipAndRF = false;
63 bool fPatchFound = false;
64 PVM pVM = pVCpu->CTX_SUFF(pVM);
65 for (;;)
66 {
67 bool fPending;
68 uint8_t u8Tpr;
69
70 PHMTPRPATCH pPatch = (PHMTPRPATCH)RTAvloU32Get(&pVM->hm.s.PatchTree, (AVLOU32KEY)pCtx->eip);
71 if (!pPatch)
72 break;
73
74 fPatchFound = true;
75 switch (pPatch->enmType)
76 {
77 case HMTPRINSTR_READ:
78 {
79 int rc = APICGetTpr(pVCpu, &u8Tpr, &fPending, NULL /* pu8PendingIrq */);
80 AssertRC(rc);
81
82 rc = DISWriteReg32(CPUMCTX2CORE(pCtx), pPatch->uDstOperand, u8Tpr);
83 AssertRC(rc);
84 pCtx->rip += pPatch->cbOp;
85 pCtx->eflags.Bits.u1RF = 0;
86 fUpdateRipAndRF = true;
87 break;
88 }
89
90 case HMTPRINSTR_WRITE_REG:
91 case HMTPRINSTR_WRITE_IMM:
92 {
93 if (pPatch->enmType == HMTPRINSTR_WRITE_REG)
94 {
95 uint32_t u32Val;
96 int rc = DISFetchReg32(CPUMCTX2CORE(pCtx), pPatch->uSrcOperand, &u32Val);
97 AssertRC(rc);
98 u8Tpr = u32Val;
99 }
100 else
101 u8Tpr = (uint8_t)pPatch->uSrcOperand;
102
103 int rc2 = APICSetTpr(pVCpu, u8Tpr);
104 AssertRC(rc2);
105 HMCPU_CF_SET(pVCpu, HM_CHANGED_SVM_GUEST_APIC_STATE);
106
107 pCtx->rip += pPatch->cbOp;
108 pCtx->eflags.Bits.u1RF = 0;
109 fUpdateRipAndRF = true;
110 break;
111 }
112
113 default:
114 {
115 AssertMsgFailed(("Unexpected patch type %d\n", pPatch->enmType));
116 pVCpu->hm.s.u32HMError = pPatch->enmType;
117 *pfUpdateRipAndRF = fUpdateRipAndRF;
118 return VERR_SVM_UNEXPECTED_PATCH_TYPE;
119 }
120 }
121 }
122
123 *pfUpdateRipAndRF = fUpdateRipAndRF;
124 if (fPatchFound)
125 return VINF_SUCCESS;
126 return VERR_NOT_FOUND;
127}
128
129
130/**
131 * Notification callback for when a \#VMEXIT happens outside SVM R0 code (e.g.
132 * in IEM).
133 *
134 * @param pVCpu The cross context virtual CPU structure.
135 * @param pCtx Pointer to the guest-CPU context.
136 *
137 * @sa hmR0SvmVmRunCacheVmcb.
138 */
139VMM_INT_DECL(void) HMSvmNstGstVmExitNotify(PVMCPU pVCpu, PCPUMCTX pCtx)
140{
141 /*
142 * Restore the nested-guest VMCB fields which have been modified for executing
143 * the nested-guest under SVM R0.
144 */
145 if (pCtx->hwvirt.svm.fHMCachedVmcb)
146 {
147 PSVMVMCB pVmcbNstGst = pCtx->hwvirt.svm.CTX_SUFF(pVmcb);
148 PSVMVMCBCTRL pVmcbNstGstCtrl = &pVmcbNstGst->ctrl;
149 PSVMVMCBSTATESAVE pVmcbNstGstState = &pVmcbNstGst->guest;
150 PSVMNESTEDVMCBCACHE pNstGstVmcbCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
151
152 /*
153 * The fields that are guaranteed to be read-only during SVM guest execution
154 * can safely be restored from our VMCB cache. Other fields like control registers
155 * are already updated by hardware-assisted SVM or by IEM. We only restore those
156 * fields that are potentially modified by hardware-assisted SVM.
157 */
158 pVmcbNstGstCtrl->u16InterceptRdCRx = pNstGstVmcbCache->u16InterceptRdCRx;
159 pVmcbNstGstCtrl->u16InterceptWrCRx = pNstGstVmcbCache->u16InterceptWrCRx;
160 pVmcbNstGstCtrl->u16InterceptRdDRx = pNstGstVmcbCache->u16InterceptRdDRx;
161 pVmcbNstGstCtrl->u16InterceptWrDRx = pNstGstVmcbCache->u16InterceptWrDRx;
162 pVmcbNstGstCtrl->u16PauseFilterCount = pNstGstVmcbCache->u16PauseFilterCount;
163 pVmcbNstGstCtrl->u16PauseFilterThreshold = pNstGstVmcbCache->u16PauseFilterThreshold;
164 pVmcbNstGstCtrl->u32InterceptXcpt = pNstGstVmcbCache->u32InterceptXcpt;
165 pVmcbNstGstCtrl->u64InterceptCtrl = pNstGstVmcbCache->u64InterceptCtrl;
166 pVmcbNstGstState->u64DBGCTL = pNstGstVmcbCache->u64DBGCTL;
167 pVmcbNstGstCtrl->u32VmcbCleanBits = pNstGstVmcbCache->u32VmcbCleanBits;
168 pVmcbNstGstCtrl->u64IOPMPhysAddr = pNstGstVmcbCache->u64IOPMPhysAddr;
169 pVmcbNstGstCtrl->u64MSRPMPhysAddr = pNstGstVmcbCache->u64MSRPMPhysAddr;
170 pVmcbNstGstCtrl->u64TSCOffset = pNstGstVmcbCache->u64TSCOffset;
171 pVmcbNstGstCtrl->IntCtrl.n.u1VIntrMasking = pNstGstVmcbCache->fVIntrMasking;
172 pVmcbNstGstCtrl->TLBCtrl = pNstGstVmcbCache->TLBCtrl;
173
174 /*
175 * If the nested-hypervisor isn't using nested-paging (and thus shadow paging
176 * is used by HM), we restore the original PAT MSR from the nested-guest VMCB.
177 * Otherwise, the nested-guest-CPU PAT MSR would've already been saved here by
178 * hardware-assisted SVM or by IEM.
179 */
180 if (!pNstGstVmcbCache->u1NestedPaging)
181 pVmcbNstGstState->u64PAT = pNstGstVmcbCache->u64PAT;
182
183 pVmcbNstGstCtrl->NestedPagingCtrl.n.u1NestedPaging = pNstGstVmcbCache->u1NestedPaging;
184 pVmcbNstGstCtrl->LbrVirt.n.u1LbrVirt = pNstGstVmcbCache->u1LbrVirt;
185 pCtx->hwvirt.svm.fHMCachedVmcb = false;
186 }
187
188 /*
189 * Currently, VMRUN, #VMEXIT transitions involves trips to ring-3 that would flag a full
190 * CPU state change. However, if we exit to ring-3 in response to receiving a physical
191 * interrupt, we skip signaling any CPU state change as normally no change is done to the
192 * execution state (see VINF_EM_RAW_INTERRUPT handling in hmR0SvmExitToRing3).
193 *
194 * With nested-guests, the state can change on trip to ring-3 for e.g., we might perform a
195 * SVM_EXIT_INTR #VMEXIT for the nested-guest in ring-3. Hence we signal a full CPU state
196 * change here.
197 */
198 HMCPU_CF_SET(pVCpu, HM_CHANGED_ALL_GUEST);
199}
200
201
202/**
203 * Checks if the Virtual GIF (Global Interrupt Flag) feature is supported and
204 * enabled for the VM.
205 *
206 * @returns @c true if VGIF is enabled, @c false otherwise.
207 * @param pVM The cross context VM structure.
208 *
209 * @remarks This value returned by this functions is expected by the callers not
210 * to change throughout the lifetime of the VM.
211 */
212VMM_INT_DECL(bool) HMSvmIsVGifActive(PVM pVM)
213{
214 bool const fVGif = RT_BOOL(pVM->hm.s.svm.u32Features & X86_CPUID_SVM_FEATURE_EDX_VGIF);
215 bool const fUseVGif = fVGif && pVM->hm.s.svm.fVGif;
216
217 return HMIsEnabled(pVM) && fVGif && fUseVGif;
218}
219
220
221/**
222 * Applies the TSC offset of an SVM nested-guest if any and returns the new TSC
223 * value for the nested-guest.
224 *
225 * @returns The TSC offset after applying any nested-guest TSC offset.
226 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
227 * @param uTicks The guest TSC.
228 *
229 * @remarks This function looks at the VMCB cache rather than directly at the
230 * nested-guest VMCB. The latter may have been modified for executing
231 * using hardware-assisted SVM.
232 *
233 * @sa CPUMApplyNestedGuestTscOffset.
234 */
235VMM_INT_DECL(uint64_t) HMSvmNstGstApplyTscOffset(PVMCPU pVCpu, uint64_t uTicks)
236{
237 PCCPUMCTX pCtx = &pVCpu->cpum.GstCtx;
238 Assert(CPUMIsGuestInSvmNestedHwVirtMode(pCtx));
239 Assert(pCtx->hwvirt.svm.fHMCachedVmcb);
240 NOREF(pCtx);
241 PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
242 return uTicks + pVmcbNstGstCache->u64TSCOffset;
243}
244#endif /* !IN_RC */
245
246
247/**
248 * Performs the operations necessary that are part of the vmmcall instruction
249 * execution in the guest.
250 *
251 * @returns Strict VBox status code (i.e. informational status codes too).
252 * @retval VINF_SUCCESS on successful handling, no \#UD needs to be thrown,
253 * update RIP and eflags.RF depending on @a pfUpdatedRipAndRF and
254 * continue guest execution.
255 * @retval VINF_GIM_HYPERCALL_CONTINUING continue hypercall without updating
256 * RIP.
257 * @retval VINF_GIM_R3_HYPERCALL re-start the hypercall from ring-3.
258 *
259 * @param pVCpu The cross context virtual CPU structure.
260 * @param pCtx Pointer to the guest-CPU context.
261 * @param pfUpdatedRipAndRF Whether the guest RIP/EIP has been updated as
262 * part of handling the VMMCALL operation.
263 */
264VMM_INT_DECL(VBOXSTRICTRC) HMSvmVmmcall(PVMCPU pVCpu, PCPUMCTX pCtx, bool *pfUpdatedRipAndRF)
265{
266#ifndef IN_RC
267 /*
268 * TPR patched instruction emulation for 32-bit guests.
269 */
270 PVM pVM = pVCpu->CTX_SUFF(pVM);
271 if (pVM->hm.s.fTprPatchingAllowed)
272 {
273 int rc = hmSvmEmulateMovTpr(pVCpu, pCtx, pfUpdatedRipAndRF);
274 if (RT_SUCCESS(rc))
275 return VINF_SUCCESS;
276
277 if (rc != VERR_NOT_FOUND)
278 {
279 Log(("hmSvmExitVmmCall: hmSvmEmulateMovTpr returns %Rrc\n", rc));
280 return rc;
281 }
282 }
283#endif
284
285 /*
286 * Paravirtualized hypercalls.
287 */
288 *pfUpdatedRipAndRF = false;
289 if (pVCpu->hm.s.fHypercallsEnabled)
290 return GIMHypercall(pVCpu, pCtx);
291
292 return VERR_NOT_AVAILABLE;
293}
294
295
296/**
297 * Converts an SVM event type to a TRPM event type.
298 *
299 * @returns The TRPM event type.
300 * @retval TRPM_32BIT_HACK if the specified type of event isn't among the set
301 * of recognized trap types.
302 *
303 * @param pEvent Pointer to the SVM event.
304 */
305VMM_INT_DECL(TRPMEVENT) HMSvmEventToTrpmEventType(PCSVMEVENT pEvent)
306{
307 uint8_t const uType = pEvent->n.u3Type;
308 switch (uType)
309 {
310 case SVM_EVENT_EXTERNAL_IRQ: return TRPM_HARDWARE_INT;
311 case SVM_EVENT_SOFTWARE_INT: return TRPM_SOFTWARE_INT;
312 case SVM_EVENT_EXCEPTION:
313 case SVM_EVENT_NMI: return TRPM_TRAP;
314 default:
315 break;
316 }
317 AssertMsgFailed(("HMSvmEventToTrpmEvent: Invalid pending-event type %#x\n", uType));
318 return TRPM_32BIT_HACK;
319}
320
321
322/**
323 * Gets the MSR permission bitmap byte and bit offset for the specified MSR.
324 *
325 * @returns VBox status code.
326 * @param idMsr The MSR being requested.
327 * @param pbOffMsrpm Where to store the byte offset in the MSR permission
328 * bitmap for @a idMsr.
329 * @param puMsrpmBit Where to store the bit offset starting at the byte
330 * returned in @a pbOffMsrpm.
331 */
332VMM_INT_DECL(int) HMSvmGetMsrpmOffsetAndBit(uint32_t idMsr, uint16_t *pbOffMsrpm, uint8_t *puMsrpmBit)
333{
334 Assert(pbOffMsrpm);
335 Assert(puMsrpmBit);
336
337 /*
338 * MSRPM Layout:
339 * Byte offset MSR range
340 * 0x000 - 0x7ff 0x00000000 - 0x00001fff
341 * 0x800 - 0xfff 0xc0000000 - 0xc0001fff
342 * 0x1000 - 0x17ff 0xc0010000 - 0xc0011fff
343 * 0x1800 - 0x1fff Reserved
344 *
345 * Each MSR is represented by 2 permission bits (read and write).
346 */
347 if (idMsr <= 0x00001fff)
348 {
349 /* Pentium-compatible MSRs. */
350 uint32_t const bitoffMsr = idMsr << 1;
351 *pbOffMsrpm = bitoffMsr >> 3;
352 *puMsrpmBit = bitoffMsr & 7;
353 return VINF_SUCCESS;
354 }
355
356 if ( idMsr >= 0xc0000000
357 && idMsr <= 0xc0001fff)
358 {
359 /* AMD Sixth Generation x86 Processor MSRs. */
360 uint32_t const bitoffMsr = (idMsr - 0xc0000000) << 1;
361 *pbOffMsrpm = 0x800 + (bitoffMsr >> 3);
362 *puMsrpmBit = bitoffMsr & 7;
363 return VINF_SUCCESS;
364 }
365
366 if ( idMsr >= 0xc0010000
367 && idMsr <= 0xc0011fff)
368 {
369 /* AMD Seventh and Eighth Generation Processor MSRs. */
370 uint32_t const bitoffMsr = (idMsr - 0xc0010000) << 1;
371 *pbOffMsrpm = 0x1000 + (bitoffMsr >> 3);
372 *puMsrpmBit = bitoffMsr & 7;
373 return VINF_SUCCESS;
374 }
375
376 *pbOffMsrpm = 0;
377 *puMsrpmBit = 0;
378 return VERR_OUT_OF_RANGE;
379}
380
381
382/**
383 * Determines whether an IOIO intercept is active for the nested-guest or not.
384 *
385 * @param pvIoBitmap Pointer to the nested-guest IO bitmap.
386 * @param u16Port The IO port being accessed.
387 * @param enmIoType The type of IO access.
388 * @param cbReg The IO operand size in bytes.
389 * @param cAddrSizeBits The address size bits (for 16, 32 or 64).
390 * @param iEffSeg The effective segment number.
391 * @param fRep Whether this is a repeating IO instruction (REP prefix).
392 * @param fStrIo Whether this is a string IO instruction.
393 * @param pIoExitInfo Pointer to the SVMIOIOEXITINFO struct to be filled.
394 * Optional, can be NULL.
395 */
396VMM_INT_DECL(bool) HMSvmIsIOInterceptActive(void *pvIoBitmap, uint16_t u16Port, SVMIOIOTYPE enmIoType, uint8_t cbReg,
397 uint8_t cAddrSizeBits, uint8_t iEffSeg, bool fRep, bool fStrIo,
398 PSVMIOIOEXITINFO pIoExitInfo)
399{
400 Assert(cAddrSizeBits == 16 || cAddrSizeBits == 32 || cAddrSizeBits == 64);
401 Assert(cbReg == 1 || cbReg == 2 || cbReg == 4 || cbReg == 8);
402
403 /*
404 * The IOPM layout:
405 * Each bit represents one 8-bit port. That makes a total of 0..65535 bits or
406 * two 4K pages.
407 *
408 * For IO instructions that access more than a single byte, the permission bits
409 * for all bytes are checked; if any bit is set to 1, the IO access is intercepted.
410 *
411 * Since it's possible to do a 32-bit IO access at port 65534 (accessing 4 bytes),
412 * we need 3 extra bits beyond the second 4K page.
413 */
414 static const uint16_t s_auSizeMasks[] = { 0, 1, 3, 0, 0xf, 0, 0, 0 };
415
416 uint16_t const offIopm = u16Port >> 3;
417 uint16_t const fSizeMask = s_auSizeMasks[(cAddrSizeBits >> SVM_IOIO_OP_SIZE_SHIFT) & 7];
418 uint8_t const cShift = u16Port - (offIopm << 3);
419 uint16_t const fIopmMask = (1 << cShift) | (fSizeMask << cShift);
420
421 uint8_t const *pbIopm = (uint8_t *)pvIoBitmap;
422 Assert(pbIopm);
423 pbIopm += offIopm;
424 uint16_t const u16Iopm = *(uint16_t *)pbIopm;
425 if (u16Iopm & fIopmMask)
426 {
427 if (pIoExitInfo)
428 {
429 static const uint32_t s_auIoOpSize[] =
430 { SVM_IOIO_32_BIT_OP, SVM_IOIO_8_BIT_OP, SVM_IOIO_16_BIT_OP, 0, SVM_IOIO_32_BIT_OP, 0, 0, 0 };
431
432 static const uint32_t s_auIoAddrSize[] =
433 { 0, SVM_IOIO_16_BIT_ADDR, SVM_IOIO_32_BIT_ADDR, 0, SVM_IOIO_64_BIT_ADDR, 0, 0, 0 };
434
435 pIoExitInfo->u = s_auIoOpSize[cbReg & 7];
436 pIoExitInfo->u |= s_auIoAddrSize[(cAddrSizeBits >> 4) & 7];
437 pIoExitInfo->n.u1STR = fStrIo;
438 pIoExitInfo->n.u1REP = fRep;
439 pIoExitInfo->n.u3SEG = iEffSeg & 7;
440 pIoExitInfo->n.u1Type = enmIoType;
441 pIoExitInfo->n.u16Port = u16Port;
442 }
443 return true;
444 }
445
446 /** @todo remove later (for debugging as VirtualBox always traps all IO
447 * intercepts). */
448 AssertMsgFailed(("iemSvmHandleIOIntercept: We expect an IO intercept here!\n"));
449 return false;
450}
451
452
453/**
454 * Checks if the nested-guest VMCB has the specified ctrl/instruction intercept
455 * active.
456 *
457 * @returns @c true if in intercept is set, @c false otherwise.
458 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
459 * @param pCtx Pointer to the context.
460 * @param fIntercept The SVM control/instruction intercept, see
461 * SVM_CTRL_INTERCEPT_*.
462 */
463VMM_INT_DECL(bool) HMIsGuestSvmCtrlInterceptSet(PVMCPU pVCpu, PCPUMCTX pCtx, uint64_t fIntercept)
464{
465 Assert(pCtx->hwvirt.svm.fHMCachedVmcb); NOREF(pCtx);
466 PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
467 return RT_BOOL(pVmcbNstGstCache->u64InterceptCtrl & fIntercept);
468}
469
470
471/**
472 * Checks if the nested-guest VMCB has the specified CR read intercept active.
473 *
474 * @returns @c true if in intercept is set, @c false otherwise.
475 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
476 * @param pCtx Pointer to the context.
477 * @param uCr The CR register number (0 to 15).
478 */
479VMM_INT_DECL(bool) HMIsGuestSvmReadCRxInterceptSet(PVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uCr)
480{
481 Assert(uCr < 16);
482 Assert(pCtx->hwvirt.svm.fHMCachedVmcb); NOREF(pCtx);
483 PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
484 return RT_BOOL(pVmcbNstGstCache->u16InterceptRdCRx & (1 << uCr));
485}
486
487
488/**
489 * Checks if the nested-guest VMCB has the specified CR write intercept active.
490 *
491 * @returns @c true if in intercept is set, @c false otherwise.
492 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
493 * @param pCtx Pointer to the context.
494 * @param uCr The CR register number (0 to 15).
495 */
496VMM_INT_DECL(bool) HMIsGuestSvmWriteCRxInterceptSet(PVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uCr)
497{
498 Assert(uCr < 16);
499 Assert(pCtx->hwvirt.svm.fHMCachedVmcb); NOREF(pCtx);
500 PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
501 return RT_BOOL(pVmcbNstGstCache->u16InterceptWrCRx & (1 << uCr));
502}
503
504
505/**
506 * Checks if the nested-guest VMCB has the specified DR read intercept active.
507 *
508 * @returns @c true if in intercept is set, @c false otherwise.
509 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
510 * @param pCtx Pointer to the context.
511 * @param uDr The DR register number (0 to 15).
512 */
513VMM_INT_DECL(bool) HMIsGuestSvmReadDRxInterceptSet(PVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uDr)
514{
515 Assert(uDr < 16);
516 Assert(pCtx->hwvirt.svm.fHMCachedVmcb); NOREF(pCtx);
517 PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
518 return RT_BOOL(pVmcbNstGstCache->u16InterceptRdDRx & (1 << uDr));
519}
520
521
522/**
523 * Checks if the nested-guest VMCB has the specified DR write intercept active.
524 *
525 * @returns @c true if in intercept is set, @c false otherwise.
526 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
527 * @param pCtx Pointer to the context.
528 * @param uDr The DR register number (0 to 15).
529 */
530VMM_INT_DECL(bool) HMIsGuestSvmWriteDRxInterceptSet(PVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uDr)
531{
532 Assert(uDr < 16);
533 Assert(pCtx->hwvirt.svm.fHMCachedVmcb); NOREF(pCtx);
534 PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
535 return RT_BOOL(pVmcbNstGstCache->u16InterceptWrDRx & (1 << uDr));
536}
537
538
539/**
540 * Checks if the nested-guest VMCB has the specified exception intercept active.
541 *
542 * @returns true if in intercept is active, false otherwise.
543 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
544 * @param pCtx Pointer to the context.
545 * @param uVector The exception / interrupt vector.
546 */
547VMM_INT_DECL(bool) HMIsGuestSvmXcptInterceptSet(PVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uVector)
548{
549 Assert(uVector < 32);
550 Assert(pCtx->hwvirt.svm.fHMCachedVmcb); NOREF(pCtx);
551 PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
552 return RT_BOOL(pVmcbNstGstCache->u32InterceptXcpt & (1 << uVector));
553}
554
555
556/**
557 * Checks if the nested-guest VMCB has virtual-interrupts masking enabled.
558 *
559 * @returns true if virtual-interrupts are masked, @c false otherwise.
560 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
561 * @param pCtx Pointer to the context.
562 */
563VMM_INT_DECL(bool) HMIsGuestSvmVirtIntrMasking(PVMCPU pVCpu, PCCPUMCTX pCtx)
564{
565 Assert(pCtx->hwvirt.svm.fHMCachedVmcb); NOREF(pCtx);
566 PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
567 return pVmcbNstGstCache->fVIntrMasking;
568}
569
570
571/**
572 * Checks if the nested-guest VMCB has nested-paging enabled.
573 *
574 * @returns true if nested-paging is enabled, @c false otherwise.
575 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
576 * @param pCtx Pointer to the context.
577 */
578VMM_INT_DECL(bool) HMIsGuestSvmNestedPagingEnabled(PVMCPU pVCpu, PCCPUMCTX pCtx)
579{
580 Assert(pCtx->hwvirt.svm.fHMCachedVmcb); NOREF(pCtx);
581 PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
582 return RT_BOOL(pVmcbNstGstCache->u1NestedPaging);
583}
584
585
586/**
587 * Returns the nested-guest VMCB pause-filter count.
588 *
589 * @returns The pause-filter count.
590 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
591 * @param pCtx Pointer to the context.
592 */
593VMM_INT_DECL(uint16_t) HMGetGuestSvmPauseFilterCount(PVMCPU pVCpu, PCCPUMCTX pCtx)
594{
595 Assert(pCtx->hwvirt.svm.fHMCachedVmcb); NOREF(pCtx);
596 PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
597 return pVmcbNstGstCache->u16PauseFilterCount;
598}
599
600
601/**
602 * Checks whether the SVM nested-guest is in a state to receive physical (APIC)
603 * interrupts.
604 *
605 * @returns true if it's ready, false otherwise.
606 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
607 * @param pCtx The guest-CPU context.
608 *
609 * @remarks This function looks at the VMCB cache rather than directly at the
610 * nested-guest VMCB. The latter may have been modified for executing
611 * using hardware-assisted SVM.
612 *
613 * @sa CPUMCanSvmNstGstTakePhysIntr.
614 */
615VMM_INT_DECL(bool) HMCanSvmNstGstTakePhysIntr(PVMCPU pVCpu, PCCPUMCTX pCtx)
616{
617 Assert(pCtx->hwvirt.svm.fHMCachedVmcb);
618 Assert(pCtx->hwvirt.fGif);
619 PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
620 X86EFLAGS fEFlags;
621 if (pVmcbNstGstCache->fVIntrMasking)
622 fEFlags.u = pCtx->hwvirt.svm.HostState.rflags.u;
623 else
624 fEFlags.u = pCtx->eflags.u;
625 return fEFlags.Bits.u1IF;
626}
627
628
629/**
630 * Checks whether the SVM nested-guest is in a state to receive virtual (setup
631 * for injection by VMRUN instruction) interrupts.
632 *
633 * @returns true if it's ready, false otherwise.
634 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
635 * @param pCtx The guest-CPU context.
636 *
637 * @remarks This function looks at the VMCB cache rather than directly at the
638 * nested-guest VMCB. The latter may have been modified for executing
639 * using hardware-assisted SVM.
640 *
641 * @sa CPUMCanSvmNstGstTakeVirtIntr.
642 */
643VMM_INT_DECL(bool) HMCanSvmNstGstTakeVirtIntr(PVMCPU pVCpu, PCCPUMCTX pCtx)
644{
645#ifdef IN_RC
646 RT_NOREF2(pVCpu, pCtx);
647 AssertReleaseFailedReturn(false);
648#else
649 Assert(pCtx->hwvirt.svm.fHMCachedVmcb);
650 Assert(pCtx->hwvirt.fGif);
651 PCSVMNESTEDVMCBCACHE pVmcbNstGstCache = &pVCpu->hm.s.svm.NstGstVmcbCache;
652
653 PCSVMVMCBCTRL pVmcbCtrl = &pCtx->hwvirt.svm.CTX_SUFF(pVmcb)->ctrl;
654 if ( !pVmcbCtrl->IntCtrl.n.u1IgnoreTPR
655 && pVmcbCtrl->IntCtrl.n.u4VIntrPrio <= pVmcbCtrl->IntCtrl.n.u8VTPR)
656 return false;
657
658 X86EFLAGS fEFlags;
659 if (pVmcbNstGstCache->fVIntrMasking)
660 fEFlags.u = pCtx->eflags.u;
661 else
662 fEFlags.u = pCtx->hwvirt.svm.HostState.rflags.u;
663 return fEFlags.Bits.u1IF;
664#endif
665}
666
Note: See TracBrowser for help on using the repository browser.

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