VirtualBox

source: vbox/trunk/src/VBox/VMM/VMMAll/EMAll.cpp@ 99196

Last change on this file since 99196 was 99051, checked in by vboxsync, 21 months ago

VMM: More ARMv8 x86/amd64 separation work, VBoxVMMArm compiles and links now, bugref:10385

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 39.3 KB
Line 
1/* $Id: EMAll.cpp 99051 2023-03-19 16:40:06Z vboxsync $ */
2/** @file
3 * EM - Execution Monitor(/Manager) - All contexts
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_EM
33#include <VBox/vmm/em.h>
34#include <VBox/vmm/mm.h>
35#include <VBox/vmm/selm.h>
36#include <VBox/vmm/pgm.h>
37#include <VBox/vmm/iem.h>
38#include <VBox/vmm/iom.h>
39#include <VBox/vmm/hm.h>
40#include <VBox/vmm/pdmapi.h>
41#include <VBox/vmm/vmm.h>
42#include <VBox/vmm/stam.h>
43#include "EMInternal.h"
44#include <VBox/vmm/vmcc.h>
45#include <VBox/param.h>
46#include <VBox/err.h>
47#include <VBox/dis.h>
48#include <VBox/disopcode.h>
49#include <VBox/log.h>
50#include <iprt/assert.h>
51#include <iprt/string.h>
52
53
54
55
56/**
57 * Get the current execution manager status.
58 *
59 * @returns Current status.
60 * @param pVCpu The cross context virtual CPU structure.
61 */
62VMM_INT_DECL(EMSTATE) EMGetState(PVMCPU pVCpu)
63{
64 return pVCpu->em.s.enmState;
65}
66
67
68/**
69 * Sets the current execution manager status. (use only when you know what you're doing!)
70 *
71 * @param pVCpu The cross context virtual CPU structure.
72 * @param enmNewState The new state, EMSTATE_WAIT_SIPI or EMSTATE_HALTED.
73 */
74VMM_INT_DECL(void) EMSetState(PVMCPU pVCpu, EMSTATE enmNewState)
75{
76 /* Only allowed combination: */
77 Assert(pVCpu->em.s.enmState == EMSTATE_WAIT_SIPI && enmNewState == EMSTATE_HALTED);
78 pVCpu->em.s.enmState = enmNewState;
79}
80
81
82/**
83 * Enables / disable hypercall instructions.
84 *
85 * This interface is used by GIM to tell the execution monitors whether the
86 * hypercall instruction (VMMCALL & VMCALL) are allowed or should \#UD.
87 *
88 * @param pVCpu The cross context virtual CPU structure this applies to.
89 * @param fEnabled Whether hypercall instructions are enabled (true) or not.
90 */
91VMMDECL(void) EMSetHypercallInstructionsEnabled(PVMCPU pVCpu, bool fEnabled)
92{
93 pVCpu->em.s.fHypercallEnabled = fEnabled;
94}
95
96
97/**
98 * Checks if hypercall instructions (VMMCALL & VMCALL) are enabled or not.
99 *
100 * @returns true if enabled, false if not.
101 * @param pVCpu The cross context virtual CPU structure.
102 *
103 * @note If this call becomes a performance factor, we can make the data
104 * field available thru a read-only view in VMCPU. See VM::cpum.ro.
105 */
106VMMDECL(bool) EMAreHypercallInstructionsEnabled(PVMCPU pVCpu)
107{
108 return pVCpu->em.s.fHypercallEnabled;
109}
110
111
112#if !defined(VBOX_VMM_TARGET_ARMV8)
113/**
114 * Prepare an MWAIT - essentials of the MONITOR instruction.
115 *
116 * @returns VINF_SUCCESS
117 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
118 * @param rax The content of RAX.
119 * @param rcx The content of RCX.
120 * @param rdx The content of RDX.
121 * @param GCPhys The physical address corresponding to rax.
122 */
123VMM_INT_DECL(int) EMMonitorWaitPrepare(PVMCPU pVCpu, uint64_t rax, uint64_t rcx, uint64_t rdx, RTGCPHYS GCPhys)
124{
125 pVCpu->em.s.MWait.uMonitorRAX = rax;
126 pVCpu->em.s.MWait.uMonitorRCX = rcx;
127 pVCpu->em.s.MWait.uMonitorRDX = rdx;
128 pVCpu->em.s.MWait.fWait |= EMMWAIT_FLAG_MONITOR_ACTIVE;
129 /** @todo Make use of GCPhys. */
130 NOREF(GCPhys);
131 /** @todo Complete MONITOR implementation. */
132 return VINF_SUCCESS;
133}
134
135
136/**
137 * Checks if the monitor hardware is armed / active.
138 *
139 * @returns true if armed, false otherwise.
140 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
141 */
142VMM_INT_DECL(bool) EMMonitorIsArmed(PVMCPU pVCpu)
143{
144 return RT_BOOL(pVCpu->em.s.MWait.fWait & EMMWAIT_FLAG_MONITOR_ACTIVE);
145}
146
147
148/**
149 * Checks if we're in a MWAIT.
150 *
151 * @retval 1 if regular,
152 * @retval > 1 if MWAIT with EMMWAIT_FLAG_BREAKIRQIF0
153 * @retval 0 if not armed
154 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
155 */
156VMM_INT_DECL(unsigned) EMMonitorWaitIsActive(PVMCPU pVCpu)
157{
158 uint32_t fWait = pVCpu->em.s.MWait.fWait;
159 AssertCompile(EMMWAIT_FLAG_ACTIVE == 1);
160 AssertCompile(EMMWAIT_FLAG_BREAKIRQIF0 == 2);
161 AssertCompile((EMMWAIT_FLAG_ACTIVE << 1) == EMMWAIT_FLAG_BREAKIRQIF0);
162 return fWait & (EMMWAIT_FLAG_ACTIVE | ((fWait & EMMWAIT_FLAG_ACTIVE) << 1));
163}
164
165
166/**
167 * Performs an MWAIT.
168 *
169 * @returns VINF_SUCCESS
170 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
171 * @param rax The content of RAX.
172 * @param rcx The content of RCX.
173 */
174VMM_INT_DECL(int) EMMonitorWaitPerform(PVMCPU pVCpu, uint64_t rax, uint64_t rcx)
175{
176 pVCpu->em.s.MWait.uMWaitRAX = rax;
177 pVCpu->em.s.MWait.uMWaitRCX = rcx;
178 pVCpu->em.s.MWait.fWait |= EMMWAIT_FLAG_ACTIVE;
179 if (rcx)
180 pVCpu->em.s.MWait.fWait |= EMMWAIT_FLAG_BREAKIRQIF0;
181 else
182 pVCpu->em.s.MWait.fWait &= ~EMMWAIT_FLAG_BREAKIRQIF0;
183 /** @todo not completely correct?? */
184 return VINF_EM_HALT;
185}
186
187
188/**
189 * Clears any address-range monitoring that is active.
190 *
191 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
192 */
193VMM_INT_DECL(void) EMMonitorWaitClear(PVMCPU pVCpu)
194{
195 LogFlowFunc(("Clearing MWAIT\n"));
196 pVCpu->em.s.MWait.fWait &= ~(EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0);
197}
198
199
200/**
201 * Determine if we should continue execution in HM after encountering an mwait
202 * instruction.
203 *
204 * Clears MWAIT flags if returning @c true.
205 *
206 * @returns true if we should continue, false if we should halt.
207 * @param pVCpu The cross context virtual CPU structure.
208 * @param pCtx Current CPU context.
209 */
210VMM_INT_DECL(bool) EMMonitorWaitShouldContinue(PVMCPU pVCpu, PCPUMCTX pCtx)
211{
212 if (CPUMGetGuestGif(pCtx))
213 {
214 if ( CPUMIsGuestPhysIntrEnabled(pVCpu)
215 || ( CPUMIsGuestInNestedHwvirtMode(pCtx)
216 && CPUMIsGuestVirtIntrEnabled(pVCpu))
217 || ( (pVCpu->em.s.MWait.fWait & (EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0))
218 == (EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0)) )
219 {
220 if (VMCPU_FF_IS_ANY_SET(pVCpu, ( VMCPU_FF_UPDATE_APIC | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC
221 | VMCPU_FF_INTERRUPT_NESTED_GUEST)))
222 {
223 pVCpu->em.s.MWait.fWait &= ~(EMMWAIT_FLAG_ACTIVE | EMMWAIT_FLAG_BREAKIRQIF0);
224 return true;
225 }
226 }
227 }
228
229 return false;
230}
231
232
233/**
234 * Determine if we should continue execution in HM after encountering a hlt
235 * instruction.
236 *
237 * @returns true if we should continue, false if we should halt.
238 * @param pVCpu The cross context virtual CPU structure.
239 * @param pCtx Current CPU context.
240 */
241VMM_INT_DECL(bool) EMShouldContinueAfterHalt(PVMCPU pVCpu, PCPUMCTX pCtx)
242{
243 if (CPUMGetGuestGif(pCtx))
244 {
245 if (CPUMIsGuestPhysIntrEnabled(pVCpu))
246 return VMCPU_FF_IS_ANY_SET(pVCpu, (VMCPU_FF_UPDATE_APIC | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC));
247
248 if ( CPUMIsGuestInNestedHwvirtMode(pCtx)
249 && CPUMIsGuestVirtIntrEnabled(pVCpu))
250 return VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NESTED_GUEST);
251 }
252 return false;
253}
254#endif
255
256
257/**
258 * Unhalts and wakes up the given CPU.
259 *
260 * This is an API for assisting the KVM hypercall API in implementing KICK_CPU.
261 * It sets VMCPU_FF_UNHALT for @a pVCpuDst and makes sure it is woken up. If
262 * the CPU isn't currently in a halt, the next HLT instruction it executes will
263 * be affected.
264 *
265 * @returns GVMMR0SchedWakeUpEx result or VINF_SUCCESS depending on context.
266 * @param pVM The cross context VM structure.
267 * @param pVCpuDst The cross context virtual CPU structure of the
268 * CPU to unhalt and wake up. This is usually not the
269 * same as the caller.
270 * @thread EMT
271 */
272VMM_INT_DECL(int) EMUnhaltAndWakeUp(PVMCC pVM, PVMCPUCC pVCpuDst)
273{
274 /*
275 * Flag the current(/next) HLT to unhalt immediately.
276 */
277 VMCPU_FF_SET(pVCpuDst, VMCPU_FF_UNHALT);
278
279 /*
280 * Wake up the EMT (technically should be abstracted by VMM/VMEmt, but
281 * just do it here for now).
282 */
283#ifdef IN_RING0
284 /* We might be here with preemption disabled or enabled (i.e. depending on
285 thread-context hooks being used), so don't try obtaining the GVMMR0 used
286 lock here. See @bugref{7270#c148}. */
287 int rc = GVMMR0SchedWakeUpNoGVMNoLock(pVM, pVCpuDst->idCpu);
288 AssertRC(rc);
289
290#elif defined(IN_RING3)
291 VMR3NotifyCpuFFU(pVCpuDst->pUVCpu, 0 /*fFlags*/);
292 int rc = VINF_SUCCESS;
293 RT_NOREF(pVM);
294
295#else
296 /* Nothing to do for raw-mode, shouldn't really be used by raw-mode guests anyway. */
297 Assert(pVM->cCpus == 1); NOREF(pVM);
298 int rc = VINF_SUCCESS;
299#endif
300 return rc;
301}
302
303#ifndef IN_RING3
304
305/**
306 * Makes an I/O port write pending for ring-3 processing.
307 *
308 * @returns VINF_EM_PENDING_R3_IOPORT_READ
309 * @param pVCpu The cross context virtual CPU structure.
310 * @param uPort The I/O port.
311 * @param cbInstr The instruction length (for RIP updating).
312 * @param cbValue The write size.
313 * @param uValue The value being written.
314 * @sa emR3ExecutePendingIoPortWrite
315 *
316 * @note Must not be used when I/O port breakpoints are pending or when single stepping.
317 */
318VMMRZ_INT_DECL(VBOXSTRICTRC)
319EMRZSetPendingIoPortWrite(PVMCPU pVCpu, RTIOPORT uPort, uint8_t cbInstr, uint8_t cbValue, uint32_t uValue)
320{
321 Assert(pVCpu->em.s.PendingIoPortAccess.cbValue == 0);
322 pVCpu->em.s.PendingIoPortAccess.uPort = uPort;
323 pVCpu->em.s.PendingIoPortAccess.cbValue = cbValue;
324 pVCpu->em.s.PendingIoPortAccess.cbInstr = cbInstr;
325 pVCpu->em.s.PendingIoPortAccess.uValue = uValue;
326 return VINF_EM_PENDING_R3_IOPORT_WRITE;
327}
328
329
330/**
331 * Makes an I/O port read pending for ring-3 processing.
332 *
333 * @returns VINF_EM_PENDING_R3_IOPORT_READ
334 * @param pVCpu The cross context virtual CPU structure.
335 * @param uPort The I/O port.
336 * @param cbInstr The instruction length (for RIP updating).
337 * @param cbValue The read size.
338 * @sa emR3ExecutePendingIoPortRead
339 *
340 * @note Must not be used when I/O port breakpoints are pending or when single stepping.
341 */
342VMMRZ_INT_DECL(VBOXSTRICTRC)
343EMRZSetPendingIoPortRead(PVMCPU pVCpu, RTIOPORT uPort, uint8_t cbInstr, uint8_t cbValue)
344{
345 Assert(pVCpu->em.s.PendingIoPortAccess.cbValue == 0);
346 pVCpu->em.s.PendingIoPortAccess.uPort = uPort;
347 pVCpu->em.s.PendingIoPortAccess.cbValue = cbValue;
348 pVCpu->em.s.PendingIoPortAccess.cbInstr = cbInstr;
349 pVCpu->em.s.PendingIoPortAccess.uValue = UINT32_C(0x52454144); /* 'READ' */
350 return VINF_EM_PENDING_R3_IOPORT_READ;
351}
352
353#endif /* IN_RING3 */
354
355
356/**
357 * Worker for EMHistoryExec that checks for ring-3 returns and flags
358 * continuation of the EMHistoryExec run there.
359 */
360DECL_FORCE_INLINE(void) emHistoryExecSetContinueExitRecIdx(PVMCPU pVCpu, VBOXSTRICTRC rcStrict, PCEMEXITREC pExitRec)
361{
362 pVCpu->em.s.idxContinueExitRec = UINT16_MAX;
363#ifdef IN_RING3
364 RT_NOREF_PV(rcStrict); RT_NOREF_PV(pExitRec);
365#else
366 switch (VBOXSTRICTRC_VAL(rcStrict))
367 {
368 case VINF_SUCCESS:
369 default:
370 break;
371
372 /*
373 * Only status codes that EMHandleRCTmpl.h will resume EMHistoryExec with.
374 */
375 case VINF_IOM_R3_IOPORT_READ: /* -> emR3ExecuteIOInstruction */
376 case VINF_IOM_R3_IOPORT_WRITE: /* -> emR3ExecuteIOInstruction */
377 case VINF_IOM_R3_IOPORT_COMMIT_WRITE: /* -> VMCPU_FF_IOM -> VINF_EM_RESUME_R3_HISTORY_EXEC -> emR3ExecuteIOInstruction */
378 case VINF_IOM_R3_MMIO_READ: /* -> emR3ExecuteInstruction */
379 case VINF_IOM_R3_MMIO_WRITE: /* -> emR3ExecuteInstruction */
380 case VINF_IOM_R3_MMIO_READ_WRITE: /* -> emR3ExecuteInstruction */
381 case VINF_IOM_R3_MMIO_COMMIT_WRITE: /* -> VMCPU_FF_IOM -> VINF_EM_RESUME_R3_HISTORY_EXEC -> emR3ExecuteIOInstruction */
382 case VINF_CPUM_R3_MSR_READ: /* -> emR3ExecuteInstruction */
383 case VINF_CPUM_R3_MSR_WRITE: /* -> emR3ExecuteInstruction */
384 case VINF_GIM_R3_HYPERCALL: /* -> emR3ExecuteInstruction */
385 pVCpu->em.s.idxContinueExitRec = (uint16_t)(pExitRec - &pVCpu->em.s.aExitRecords[0]);
386 break;
387 }
388#endif /* !IN_RING3 */
389}
390
391
392/**
393 * Execute using history.
394 *
395 * This function will be called when EMHistoryAddExit() and friends returns a
396 * non-NULL result. This happens in response to probing or when probing has
397 * uncovered adjacent exits which can more effectively be reached by using IEM
398 * than restarting execution using the main execution engine and fielding an
399 * regular exit.
400 *
401 * @returns VBox strict status code, see IEMExecForExits.
402 * @param pVCpu The cross context virtual CPU structure.
403 * @param pExitRec The exit record return by a previous history add
404 * or update call.
405 * @param fWillExit Flags indicating to IEM what will cause exits, TBD.
406 */
407VMM_INT_DECL(VBOXSTRICTRC) EMHistoryExec(PVMCPUCC pVCpu, PCEMEXITREC pExitRec, uint32_t fWillExit)
408{
409 Assert(pExitRec);
410 VMCPU_ASSERT_EMT(pVCpu);
411 IEMEXECFOREXITSTATS ExecStats;
412 switch (pExitRec->enmAction)
413 {
414 /*
415 * Executes multiple instruction stopping only when we've gone a given
416 * number without perceived exits.
417 */
418 case EMEXITACTION_EXEC_WITH_MAX:
419 {
420 STAM_REL_PROFILE_START(&pVCpu->em.s.StatHistoryExec, a);
421 LogFlow(("EMHistoryExec/EXEC_WITH_MAX: %RX64, max %u\n", pExitRec->uFlatPC, pExitRec->cMaxInstructionsWithoutExit));
422 VBOXSTRICTRC rcStrict = IEMExecForExits(pVCpu, fWillExit,
423 pExitRec->cMaxInstructionsWithoutExit /* cMinInstructions*/,
424 pVCpu->em.s.cHistoryExecMaxInstructions,
425 pExitRec->cMaxInstructionsWithoutExit,
426 &ExecStats);
427 LogFlow(("EMHistoryExec/EXEC_WITH_MAX: %Rrc cExits=%u cMaxExitDistance=%u cInstructions=%u\n",
428 VBOXSTRICTRC_VAL(rcStrict), ExecStats.cExits, ExecStats.cMaxExitDistance, ExecStats.cInstructions));
429 emHistoryExecSetContinueExitRecIdx(pVCpu, rcStrict, pExitRec);
430
431 /* Ignore instructions IEM doesn't know about. */
432 if ( ( rcStrict != VERR_IEM_INSTR_NOT_IMPLEMENTED
433 && rcStrict != VERR_IEM_ASPECT_NOT_IMPLEMENTED)
434 || ExecStats.cInstructions == 0)
435 { /* likely */ }
436 else
437 rcStrict = VINF_SUCCESS;
438
439 if (ExecStats.cExits > 1)
440 STAM_REL_COUNTER_ADD(&pVCpu->em.s.StatHistoryExecSavedExits, ExecStats.cExits - 1);
441 STAM_REL_COUNTER_ADD(&pVCpu->em.s.StatHistoryExecInstructions, ExecStats.cInstructions);
442 STAM_REL_PROFILE_STOP(&pVCpu->em.s.StatHistoryExec, a);
443 return rcStrict;
444 }
445
446 /*
447 * Probe a exit for close by exits.
448 */
449 case EMEXITACTION_EXEC_PROBE:
450 {
451 STAM_REL_PROFILE_START(&pVCpu->em.s.StatHistoryProbe, b);
452 LogFlow(("EMHistoryExec/EXEC_PROBE: %RX64\n", pExitRec->uFlatPC));
453 PEMEXITREC pExitRecUnconst = (PEMEXITREC)pExitRec;
454 VBOXSTRICTRC rcStrict = IEMExecForExits(pVCpu, fWillExit,
455 pVCpu->em.s.cHistoryProbeMinInstructions,
456 pVCpu->em.s.cHistoryExecMaxInstructions,
457 pVCpu->em.s.cHistoryProbeMaxInstructionsWithoutExit,
458 &ExecStats);
459 LogFlow(("EMHistoryExec/EXEC_PROBE: %Rrc cExits=%u cMaxExitDistance=%u cInstructions=%u\n",
460 VBOXSTRICTRC_VAL(rcStrict), ExecStats.cExits, ExecStats.cMaxExitDistance, ExecStats.cInstructions));
461 emHistoryExecSetContinueExitRecIdx(pVCpu, rcStrict, pExitRecUnconst);
462 if ( ExecStats.cExits >= 2
463 && RT_SUCCESS(rcStrict))
464 {
465 Assert(ExecStats.cMaxExitDistance > 0 && ExecStats.cMaxExitDistance <= 32);
466 pExitRecUnconst->cMaxInstructionsWithoutExit = ExecStats.cMaxExitDistance;
467 pExitRecUnconst->enmAction = EMEXITACTION_EXEC_WITH_MAX;
468 LogFlow(("EMHistoryExec/EXEC_PROBE: -> EXEC_WITH_MAX %u\n", ExecStats.cMaxExitDistance));
469 STAM_REL_COUNTER_INC(&pVCpu->em.s.StatHistoryProbedExecWithMax);
470 }
471#ifndef IN_RING3
472 else if ( pVCpu->em.s.idxContinueExitRec != UINT16_MAX
473 && RT_SUCCESS(rcStrict))
474 {
475 STAM_REL_COUNTER_INC(&pVCpu->em.s.StatHistoryProbedToRing3);
476 LogFlow(("EMHistoryExec/EXEC_PROBE: -> ring-3\n"));
477 }
478#endif
479 else
480 {
481 pExitRecUnconst->enmAction = EMEXITACTION_NORMAL_PROBED;
482 pVCpu->em.s.idxContinueExitRec = UINT16_MAX;
483 LogFlow(("EMHistoryExec/EXEC_PROBE: -> PROBED\n"));
484 STAM_REL_COUNTER_INC(&pVCpu->em.s.StatHistoryProbedNormal);
485 if ( rcStrict == VERR_IEM_INSTR_NOT_IMPLEMENTED
486 || rcStrict == VERR_IEM_ASPECT_NOT_IMPLEMENTED)
487 rcStrict = VINF_SUCCESS;
488 }
489 STAM_REL_COUNTER_ADD(&pVCpu->em.s.StatHistoryProbeInstructions, ExecStats.cInstructions);
490 STAM_REL_PROFILE_STOP(&pVCpu->em.s.StatHistoryProbe, b);
491 return rcStrict;
492 }
493
494 /* We shouldn't ever see these here! */
495 case EMEXITACTION_FREE_RECORD:
496 case EMEXITACTION_NORMAL:
497 case EMEXITACTION_NORMAL_PROBED:
498 break;
499
500 /* No default case, want compiler warnings. */
501 }
502 AssertLogRelFailedReturn(VERR_EM_INTERNAL_ERROR);
503}
504
505
506/**
507 * Worker for emHistoryAddOrUpdateRecord.
508 */
509DECL_FORCE_INLINE(PCEMEXITREC) emHistoryRecordInit(PEMEXITREC pExitRec, uint64_t uFlatPC, uint32_t uFlagsAndType, uint64_t uExitNo)
510{
511 pExitRec->uFlatPC = uFlatPC;
512 pExitRec->uFlagsAndType = uFlagsAndType;
513 pExitRec->enmAction = EMEXITACTION_NORMAL;
514 pExitRec->bUnused = 0;
515 pExitRec->cMaxInstructionsWithoutExit = 64;
516 pExitRec->uLastExitNo = uExitNo;
517 pExitRec->cHits = 1;
518 return NULL;
519}
520
521
522/**
523 * Worker for emHistoryAddOrUpdateRecord.
524 */
525DECL_FORCE_INLINE(PCEMEXITREC) emHistoryRecordInitNew(PVMCPU pVCpu, PEMEXITENTRY pHistEntry, uintptr_t idxSlot,
526 PEMEXITREC pExitRec, uint64_t uFlatPC,
527 uint32_t uFlagsAndType, uint64_t uExitNo)
528{
529 pHistEntry->idxSlot = (uint32_t)idxSlot;
530 pVCpu->em.s.cExitRecordUsed++;
531 LogFlow(("emHistoryRecordInitNew: [%#x] = %#07x %016RX64; (%u of %u used)\n", idxSlot, uFlagsAndType, uFlatPC,
532 pVCpu->em.s.cExitRecordUsed, RT_ELEMENTS(pVCpu->em.s.aExitRecords) ));
533 return emHistoryRecordInit(pExitRec, uFlatPC, uFlagsAndType, uExitNo);
534}
535
536
537/**
538 * Worker for emHistoryAddOrUpdateRecord.
539 */
540DECL_FORCE_INLINE(PCEMEXITREC) emHistoryRecordInitReplacement(PEMEXITENTRY pHistEntry, uintptr_t idxSlot,
541 PEMEXITREC pExitRec, uint64_t uFlatPC,
542 uint32_t uFlagsAndType, uint64_t uExitNo)
543{
544 pHistEntry->idxSlot = (uint32_t)idxSlot;
545 LogFlow(("emHistoryRecordInitReplacement: [%#x] = %#07x %016RX64 replacing %#07x %016RX64 with %u hits, %u exits old\n",
546 idxSlot, uFlagsAndType, uFlatPC, pExitRec->uFlagsAndType, pExitRec->uFlatPC, pExitRec->cHits,
547 uExitNo - pExitRec->uLastExitNo));
548 return emHistoryRecordInit(pExitRec, uFlatPC, uFlagsAndType, uExitNo);
549}
550
551
552/**
553 * Adds or updates the EMEXITREC for this PC/type and decide on an action.
554 *
555 * @returns Pointer to an exit record if special action should be taken using
556 * EMHistoryExec(). Take normal exit action when NULL.
557 *
558 * @param pVCpu The cross context virtual CPU structure.
559 * @param uFlagsAndType Combined flags and type, EMEXIT_F_KIND_EM set and
560 * both EMEXIT_F_CS_EIP and EMEXIT_F_UNFLATTENED_PC are clear.
561 * @param uFlatPC The flattened program counter.
562 * @param pHistEntry The exit history entry.
563 * @param uExitNo The current exit number.
564 */
565static PCEMEXITREC emHistoryAddOrUpdateRecord(PVMCPU pVCpu, uint64_t uFlagsAndType, uint64_t uFlatPC,
566 PEMEXITENTRY pHistEntry, uint64_t uExitNo)
567{
568# ifdef IN_RING0
569 /* Disregard the hm flag. */
570 uFlagsAndType &= ~EMEXIT_F_HM;
571# endif
572
573 /*
574 * Work the hash table.
575 */
576 AssertCompile(RT_ELEMENTS(pVCpu->em.s.aExitRecords) == 1024);
577# define EM_EXIT_RECORDS_IDX_MASK 0x3ff
578 uintptr_t idxSlot = ((uintptr_t)uFlatPC >> 1) & EM_EXIT_RECORDS_IDX_MASK;
579 PEMEXITREC pExitRec = &pVCpu->em.s.aExitRecords[idxSlot];
580 if (pExitRec->uFlatPC == uFlatPC)
581 {
582 Assert(pExitRec->enmAction != EMEXITACTION_FREE_RECORD);
583 pHistEntry->idxSlot = (uint32_t)idxSlot;
584 if (pExitRec->uFlagsAndType == uFlagsAndType)
585 {
586 pExitRec->uLastExitNo = uExitNo;
587 STAM_REL_COUNTER_INC(&pVCpu->em.s.aStatHistoryRecHits[0]);
588 }
589 else
590 {
591 STAM_REL_COUNTER_INC(&pVCpu->em.s.aStatHistoryRecTypeChanged[0]);
592 return emHistoryRecordInit(pExitRec, uFlatPC, uFlagsAndType, uExitNo);
593 }
594 }
595 else if (pExitRec->enmAction == EMEXITACTION_FREE_RECORD)
596 {
597 STAM_REL_COUNTER_INC(&pVCpu->em.s.aStatHistoryRecNew[0]);
598 return emHistoryRecordInitNew(pVCpu, pHistEntry, idxSlot, pExitRec, uFlatPC, uFlagsAndType, uExitNo);
599 }
600 else
601 {
602 /*
603 * Collision. We calculate a new hash for stepping away from the first,
604 * doing up to 8 steps away before replacing the least recently used record.
605 */
606 uintptr_t idxOldest = idxSlot;
607 uint64_t uOldestExitNo = pExitRec->uLastExitNo;
608 unsigned iOldestStep = 0;
609 unsigned iStep = 1;
610 uintptr_t const idxAdd = (uintptr_t)(uFlatPC >> 11) & (EM_EXIT_RECORDS_IDX_MASK / 4);
611 for (;;)
612 {
613 Assert(iStep < RT_ELEMENTS(pVCpu->em.s.aStatHistoryRecHits));
614 AssertCompile(RT_ELEMENTS(pVCpu->em.s.aStatHistoryRecNew) == RT_ELEMENTS(pVCpu->em.s.aStatHistoryRecHits));
615 AssertCompile(RT_ELEMENTS(pVCpu->em.s.aStatHistoryRecReplaced) == RT_ELEMENTS(pVCpu->em.s.aStatHistoryRecHits));
616 AssertCompile(RT_ELEMENTS(pVCpu->em.s.aStatHistoryRecTypeChanged) == RT_ELEMENTS(pVCpu->em.s.aStatHistoryRecHits));
617
618 /* Step to the next slot. */
619 idxSlot += idxAdd;
620 idxSlot &= EM_EXIT_RECORDS_IDX_MASK;
621 pExitRec = &pVCpu->em.s.aExitRecords[idxSlot];
622
623 /* Does it match? */
624 if (pExitRec->uFlatPC == uFlatPC)
625 {
626 Assert(pExitRec->enmAction != EMEXITACTION_FREE_RECORD);
627 pHistEntry->idxSlot = (uint32_t)idxSlot;
628 if (pExitRec->uFlagsAndType == uFlagsAndType)
629 {
630 pExitRec->uLastExitNo = uExitNo;
631 STAM_REL_COUNTER_INC(&pVCpu->em.s.aStatHistoryRecHits[iStep]);
632 break;
633 }
634 STAM_REL_COUNTER_INC(&pVCpu->em.s.aStatHistoryRecTypeChanged[iStep]);
635 return emHistoryRecordInit(pExitRec, uFlatPC, uFlagsAndType, uExitNo);
636 }
637
638 /* Is it free? */
639 if (pExitRec->enmAction == EMEXITACTION_FREE_RECORD)
640 {
641 STAM_REL_COUNTER_INC(&pVCpu->em.s.aStatHistoryRecNew[iStep]);
642 return emHistoryRecordInitNew(pVCpu, pHistEntry, idxSlot, pExitRec, uFlatPC, uFlagsAndType, uExitNo);
643 }
644
645 /* Is it the least recently used one? */
646 if (pExitRec->uLastExitNo < uOldestExitNo)
647 {
648 uOldestExitNo = pExitRec->uLastExitNo;
649 idxOldest = idxSlot;
650 iOldestStep = iStep;
651 }
652
653 /* Next iteration? */
654 iStep++;
655 Assert(iStep < RT_ELEMENTS(pVCpu->em.s.aStatHistoryRecReplaced));
656 if (RT_LIKELY(iStep < 8 + 1))
657 { /* likely */ }
658 else
659 {
660 /* Replace the least recently used slot. */
661 STAM_REL_COUNTER_INC(&pVCpu->em.s.aStatHistoryRecReplaced[iOldestStep]);
662 pExitRec = &pVCpu->em.s.aExitRecords[idxOldest];
663 return emHistoryRecordInitReplacement(pHistEntry, idxOldest, pExitRec, uFlatPC, uFlagsAndType, uExitNo);
664 }
665 }
666 }
667
668 /*
669 * Found an existing record.
670 */
671 switch (pExitRec->enmAction)
672 {
673 case EMEXITACTION_NORMAL:
674 {
675 uint64_t const cHits = ++pExitRec->cHits;
676 if (cHits < 256)
677 return NULL;
678 LogFlow(("emHistoryAddOrUpdateRecord: [%#x] %#07x %16RX64: -> EXEC_PROBE\n", idxSlot, uFlagsAndType, uFlatPC));
679 pExitRec->enmAction = EMEXITACTION_EXEC_PROBE;
680 return pExitRec;
681 }
682
683 case EMEXITACTION_NORMAL_PROBED:
684 pExitRec->cHits += 1;
685 return NULL;
686
687 default:
688 pExitRec->cHits += 1;
689 return pExitRec;
690
691 /* This will happen if the caller ignores or cannot serve the probe
692 request (forced to ring-3, whatever). We retry this 256 times. */
693 case EMEXITACTION_EXEC_PROBE:
694 {
695 uint64_t const cHits = ++pExitRec->cHits;
696 if (cHits < 512)
697 return pExitRec;
698 pExitRec->enmAction = EMEXITACTION_NORMAL_PROBED;
699 LogFlow(("emHistoryAddOrUpdateRecord: [%#x] %#07x %16RX64: -> PROBED\n", idxSlot, uFlagsAndType, uFlatPC));
700 return NULL;
701 }
702 }
703}
704
705
706/**
707 * Adds an exit to the history for this CPU.
708 *
709 * @returns Pointer to an exit record if special action should be taken using
710 * EMHistoryExec(). Take normal exit action when NULL.
711 *
712 * @param pVCpu The cross context virtual CPU structure.
713 * @param uFlagsAndType Combined flags and type (see EMEXIT_MAKE_FT).
714 * @param uFlatPC The flattened program counter (RIP). UINT64_MAX if not available.
715 * @param uTimestamp The TSC value for the exit, 0 if not available.
716 * @thread EMT(pVCpu)
717 */
718VMM_INT_DECL(PCEMEXITREC) EMHistoryAddExit(PVMCPUCC pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC, uint64_t uTimestamp)
719{
720 VMCPU_ASSERT_EMT(pVCpu);
721
722 /*
723 * Add the exit history entry.
724 */
725 AssertCompile(RT_ELEMENTS(pVCpu->em.s.aExitHistory) == 256);
726 uint64_t uExitNo = pVCpu->em.s.iNextExit++;
727 PEMEXITENTRY pHistEntry = &pVCpu->em.s.aExitHistory[(uintptr_t)uExitNo & 0xff];
728 pHistEntry->uFlatPC = uFlatPC;
729 pHistEntry->uTimestamp = uTimestamp;
730 pHistEntry->uFlagsAndType = uFlagsAndType;
731 pHistEntry->idxSlot = UINT32_MAX;
732
733 /*
734 * If common exit type, we will insert/update the exit into the exit record hash table.
735 */
736 if ( (uFlagsAndType & (EMEXIT_F_KIND_MASK | EMEXIT_F_CS_EIP | EMEXIT_F_UNFLATTENED_PC)) == EMEXIT_F_KIND_EM
737#ifdef IN_RING0
738 && pVCpu->em.s.fExitOptimizationEnabledR0
739 && ( !(uFlagsAndType & EMEXIT_F_HM) || pVCpu->em.s.fExitOptimizationEnabledR0PreemptDisabled)
740#else
741 && pVCpu->em.s.fExitOptimizationEnabled
742#endif
743 && uFlatPC != UINT64_MAX
744 )
745 return emHistoryAddOrUpdateRecord(pVCpu, uFlagsAndType, uFlatPC, pHistEntry, uExitNo);
746 return NULL;
747}
748
749
750/**
751 * Interface that VT-x uses to supply the PC of an exit when CS:RIP is being read.
752 *
753 * @param pVCpu The cross context virtual CPU structure.
754 * @param uFlatPC The flattened program counter (RIP).
755 * @param fFlattened Set if RIP was subjected to CS.BASE, clear if not.
756 */
757VMM_INT_DECL(void) EMHistoryUpdatePC(PVMCPUCC pVCpu, uint64_t uFlatPC, bool fFlattened)
758{
759 VMCPU_ASSERT_EMT(pVCpu);
760
761 AssertCompile(RT_ELEMENTS(pVCpu->em.s.aExitHistory) == 256);
762 uint64_t uExitNo = pVCpu->em.s.iNextExit - 1;
763 PEMEXITENTRY pHistEntry = &pVCpu->em.s.aExitHistory[(uintptr_t)uExitNo & 0xff];
764 pHistEntry->uFlatPC = uFlatPC;
765 if (fFlattened)
766 pHistEntry->uFlagsAndType &= ~EMEXIT_F_UNFLATTENED_PC;
767 else
768 pHistEntry->uFlagsAndType |= EMEXIT_F_UNFLATTENED_PC;
769}
770
771
772/**
773 * Interface for convering a engine specific exit to a generic one and get guidance.
774 *
775 * @returns Pointer to an exit record if special action should be taken using
776 * EMHistoryExec(). Take normal exit action when NULL.
777 *
778 * @param pVCpu The cross context virtual CPU structure.
779 * @param uFlagsAndType Combined flags and type (see EMEXIT_MAKE_FLAGS_AND_TYPE).
780 * @thread EMT(pVCpu)
781 */
782VMM_INT_DECL(PCEMEXITREC) EMHistoryUpdateFlagsAndType(PVMCPUCC pVCpu, uint32_t uFlagsAndType)
783{
784 VMCPU_ASSERT_EMT(pVCpu);
785
786 /*
787 * Do the updating.
788 */
789 AssertCompile(RT_ELEMENTS(pVCpu->em.s.aExitHistory) == 256);
790 uint64_t uExitNo = pVCpu->em.s.iNextExit - 1;
791 PEMEXITENTRY pHistEntry = &pVCpu->em.s.aExitHistory[(uintptr_t)uExitNo & 0xff];
792 pHistEntry->uFlagsAndType = uFlagsAndType | (pHistEntry->uFlagsAndType & (EMEXIT_F_CS_EIP | EMEXIT_F_UNFLATTENED_PC));
793
794 /*
795 * If common exit type, we will insert/update the exit into the exit record hash table.
796 */
797 if ( (uFlagsAndType & (EMEXIT_F_KIND_MASK | EMEXIT_F_CS_EIP | EMEXIT_F_UNFLATTENED_PC)) == EMEXIT_F_KIND_EM
798#ifdef IN_RING0
799 && pVCpu->em.s.fExitOptimizationEnabledR0
800 && ( !(uFlagsAndType & EMEXIT_F_HM) || pVCpu->em.s.fExitOptimizationEnabledR0PreemptDisabled)
801#else
802 && pVCpu->em.s.fExitOptimizationEnabled
803#endif
804 && pHistEntry->uFlatPC != UINT64_MAX
805 )
806 return emHistoryAddOrUpdateRecord(pVCpu, uFlagsAndType, pHistEntry->uFlatPC, pHistEntry, uExitNo);
807 return NULL;
808}
809
810
811/**
812 * Interface for convering a engine specific exit to a generic one and get
813 * guidance, supplying flattened PC too.
814 *
815 * @returns Pointer to an exit record if special action should be taken using
816 * EMHistoryExec(). Take normal exit action when NULL.
817 *
818 * @param pVCpu The cross context virtual CPU structure.
819 * @param uFlagsAndType Combined flags and type (see EMEXIT_MAKE_FLAGS_AND_TYPE).
820 * @param uFlatPC The flattened program counter (RIP).
821 * @thread EMT(pVCpu)
822 */
823VMM_INT_DECL(PCEMEXITREC) EMHistoryUpdateFlagsAndTypeAndPC(PVMCPUCC pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC)
824{
825 VMCPU_ASSERT_EMT(pVCpu);
826 //Assert(uFlatPC != UINT64_MAX); - disable to make the pc wrapping tests in bs3-cpu-weird-1 work.
827
828 /*
829 * Do the updating.
830 */
831 AssertCompile(RT_ELEMENTS(pVCpu->em.s.aExitHistory) == 256);
832 uint64_t uExitNo = pVCpu->em.s.iNextExit - 1;
833 PEMEXITENTRY pHistEntry = &pVCpu->em.s.aExitHistory[(uintptr_t)uExitNo & 0xff];
834 pHistEntry->uFlagsAndType = uFlagsAndType;
835 pHistEntry->uFlatPC = uFlatPC;
836
837 /*
838 * If common exit type, we will insert/update the exit into the exit record hash table.
839 */
840 if ( (uFlagsAndType & (EMEXIT_F_KIND_MASK | EMEXIT_F_CS_EIP | EMEXIT_F_UNFLATTENED_PC)) == EMEXIT_F_KIND_EM
841#ifdef IN_RING0
842 && pVCpu->em.s.fExitOptimizationEnabledR0
843 && ( !(uFlagsAndType & EMEXIT_F_HM) || pVCpu->em.s.fExitOptimizationEnabledR0PreemptDisabled)
844#else
845 && pVCpu->em.s.fExitOptimizationEnabled
846#endif
847 )
848 return emHistoryAddOrUpdateRecord(pVCpu, uFlagsAndType, uFlatPC, pHistEntry, uExitNo);
849 return NULL;
850}
851
852
853/**
854 * @callback_method_impl{FNDISREADBYTES}
855 */
856static DECLCALLBACK(int) emReadBytes(PDISCPUSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
857{
858 PVMCPUCC pVCpu = (PVMCPUCC)pDis->pvUser;
859 RTUINTPTR uSrcAddr = pDis->uInstrAddr + offInstr;
860
861 /*
862 * Figure how much we can or must read.
863 */
864 size_t cbToRead = GUEST_PAGE_SIZE - (uSrcAddr & (GUEST_PAGE_SIZE - 1));
865 if (cbToRead > cbMaxRead)
866 cbToRead = cbMaxRead;
867 else if (cbToRead < cbMinRead)
868 cbToRead = cbMinRead;
869
870 int rc = PGMPhysSimpleReadGCPtr(pVCpu, &pDis->abInstr[offInstr], uSrcAddr, cbToRead);
871 if (RT_FAILURE(rc))
872 {
873 if (cbToRead > cbMinRead)
874 {
875 cbToRead = cbMinRead;
876 rc = PGMPhysSimpleReadGCPtr(pVCpu, &pDis->abInstr[offInstr], uSrcAddr, cbToRead);
877 }
878 if (RT_FAILURE(rc))
879 {
880#if defined(VBOX_VMM_TARGET_ARMV8)
881 AssertReleaseFailed();
882#else
883 /*
884 * If we fail to find the page via the guest's page tables
885 * we invalidate the page in the host TLB (pertaining to
886 * the guest in the NestedPaging case). See @bugref{6043}.
887 */
888 if (rc == VERR_PAGE_TABLE_NOT_PRESENT || rc == VERR_PAGE_NOT_PRESENT)
889 {
890 HMInvalidatePage(pVCpu, uSrcAddr);
891 if (((uSrcAddr + cbToRead - 1) >> GUEST_PAGE_SHIFT) != (uSrcAddr >> GUEST_PAGE_SHIFT))
892 HMInvalidatePage(pVCpu, uSrcAddr + cbToRead - 1);
893 }
894#endif
895 }
896 }
897
898 pDis->cbCachedInstr = offInstr + (uint8_t)cbToRead;
899 return rc;
900}
901
902
903/**
904 * Disassembles the current instruction.
905 *
906 * @returns VBox status code, see SELMToFlatEx and EMInterpretDisasOneEx for
907 * details.
908 *
909 * @param pVCpu The cross context virtual CPU structure.
910 * @param pDis Where to return the parsed instruction info.
911 * @param pcbInstr Where to return the instruction size. (optional)
912 */
913VMM_INT_DECL(int) EMInterpretDisasCurrent(PVMCPUCC pVCpu, PDISCPUSTATE pDis, unsigned *pcbInstr)
914{
915#if defined(VBOX_VMM_TARGET_ARMV8)
916 return EMInterpretDisasOneEx(pVCpu, (RTGCUINTPTR)CPUMGetGuestFlatPC(pVCpu), pDis, pcbInstr);
917#else
918 PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
919 RTGCPTR GCPtrInstr;
920
921# if 0
922 int rc = SELMToFlatEx(pVCpu, DISSELREG_CS, pCtx, pCtx->rip, 0, &GCPtrInstr);
923# else
924/** @todo Get the CPU mode as well while we're at it! */
925 int rc = SELMValidateAndConvertCSAddr(pVCpu, pCtx->eflags.u, pCtx->ss.Sel, pCtx->cs.Sel, &pCtx->cs, pCtx->rip, &GCPtrInstr);
926# endif
927 if (RT_SUCCESS(rc))
928 return EMInterpretDisasOneEx(pVCpu, (RTGCUINTPTR)GCPtrInstr, pDis, pcbInstr);
929
930 Log(("EMInterpretDisasOne: Failed to convert %RTsel:%RGv (cpl=%d) - rc=%Rrc !!\n",
931 pCtx->cs.Sel, (RTGCPTR)pCtx->rip, pCtx->ss.Sel & X86_SEL_RPL, rc));
932 return rc;
933#endif
934}
935
936
937/**
938 * Disassembles one instruction.
939 *
940 * This is used by internally by the interpreter and by trap/access handlers.
941 *
942 * @returns VBox status code.
943 *
944 * @param pVCpu The cross context virtual CPU structure.
945 * @param GCPtrInstr The flat address of the instruction.
946 * @param pDis Where to return the parsed instruction info.
947 * @param pcbInstr Where to return the instruction size. (optional)
948 */
949VMM_INT_DECL(int) EMInterpretDisasOneEx(PVMCPUCC pVCpu, RTGCUINTPTR GCPtrInstr, PDISCPUSTATE pDis, unsigned *pcbInstr)
950{
951 DISCPUMODE enmCpuMode = CPUMGetGuestDisMode(pVCpu);
952 /** @todo Deal with too long instruction (=> \#GP), opcode read errors (=>
953 * \#PF, \#GP, \#??), undefined opcodes (=> \#UD), and such. */
954 int rc = DISInstrWithReader(GCPtrInstr, enmCpuMode, emReadBytes, pVCpu, pDis, pcbInstr);
955 if (RT_SUCCESS(rc))
956 return VINF_SUCCESS;
957 AssertMsg(rc == VERR_PAGE_NOT_PRESENT || rc == VERR_PAGE_TABLE_NOT_PRESENT, ("DISCoreOne failed to GCPtrInstr=%RGv rc=%Rrc\n", GCPtrInstr, rc));
958 return rc;
959}
960
961
962/**
963 * Interprets the current instruction.
964 *
965 * @returns VBox status code.
966 * @retval VINF_* Scheduling instructions.
967 * @retval VERR_EM_INTERPRETER Something we can't cope with.
968 * @retval VERR_* Fatal errors.
969 *
970 * @param pVCpu The cross context virtual CPU structure.
971 *
972 * @remark Invalid opcode exceptions have a higher priority than \#GP (see
973 * Intel Architecture System Developers Manual, Vol 3, 5.5) so we don't
974 * need to worry about e.g. invalid modrm combinations (!)
975 */
976VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInstruction(PVMCPUCC pVCpu)
977{
978#if defined(VBOX_VMM_TARGET_ARMV8)
979 LogFlow(("EMInterpretInstruction %RGv\n", (RTGCPTR)CPUMGetGuestFlatPC(pVCpu)));
980#else
981 LogFlow(("EMInterpretInstruction %RGv\n", (RTGCPTR)CPUMGetGuestRIP(pVCpu)));
982#endif
983
984 VBOXSTRICTRC rc = IEMExecOneBypassEx(pVCpu, NULL /*pcbWritten*/);
985 if (RT_UNLIKELY( rc == VERR_IEM_ASPECT_NOT_IMPLEMENTED
986 || rc == VERR_IEM_INSTR_NOT_IMPLEMENTED))
987 rc = VERR_EM_INTERPRETER;
988 if (rc != VINF_SUCCESS)
989 Log(("EMInterpretInstruction: returns %Rrc\n", VBOXSTRICTRC_VAL(rc)));
990
991 return rc;
992}
993
994
995/**
996 * Interprets the current instruction using the supplied DISCPUSTATE structure.
997 *
998 * IP/EIP/RIP *IS* updated!
999 *
1000 * @returns VBox strict status code.
1001 * @retval VINF_* Scheduling instructions. When these are returned, it
1002 * starts to get a bit tricky to know whether code was
1003 * executed or not... We'll address this when it becomes a problem.
1004 * @retval VERR_EM_INTERPRETER Something we can't cope with.
1005 * @retval VERR_* Fatal errors.
1006 *
1007 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
1008 * @param pDis The disassembler cpu state for the instruction to be
1009 * interpreted.
1010 * @param rip The instruction pointer value.
1011 *
1012 * @remark Invalid opcode exceptions have a higher priority than GP (see Intel
1013 * Architecture System Developers Manual, Vol 3, 5.5) so we don't need
1014 * to worry about e.g. invalid modrm combinations (!)
1015 *
1016 * @todo At this time we do NOT check if the instruction overwrites vital information.
1017 * Make sure this can't happen!! (will add some assertions/checks later)
1018 */
1019VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInstructionDisasState(PVMCPUCC pVCpu, PDISCPUSTATE pDis, uint64_t rip)
1020{
1021 LogFlow(("EMInterpretInstructionDisasState %RGv\n", (RTGCPTR)rip));
1022
1023 VBOXSTRICTRC rc = IEMExecOneBypassWithPrefetchedByPC(pVCpu, rip, pDis->abInstr, pDis->cbCachedInstr);
1024 if (RT_UNLIKELY( rc == VERR_IEM_ASPECT_NOT_IMPLEMENTED
1025 || rc == VERR_IEM_INSTR_NOT_IMPLEMENTED))
1026 rc = VERR_EM_INTERPRETER;
1027
1028 if (rc != VINF_SUCCESS)
1029 Log(("EMInterpretInstructionDisasState: returns %Rrc\n", VBOXSTRICTRC_VAL(rc)));
1030
1031 return rc;
1032}
1033
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