VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

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