VirtualBox

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

Last change on this file since 99208 was 99208, checked in by vboxsync, 14 months ago

Disassembler,VMM,Runtime: Get rid of deprecated DISCPUSTATE types (preparation for architecture specific separation in order to support ARMv8), bugref:10394

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 39.2 KB
RevLine 
[23]1/* $Id: EMAll.cpp 99208 2023-03-29 14:13:56Z vboxsync $ */
[1]2/** @file
3 * EM - Execution Monitor(/Manager) - All contexts
4 */
5
6/*
[98103]7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[1]8 *
[96407]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
[1]26 */
27
[57358]28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
[1]32#define LOG_GROUP LOG_GROUP_EM
[35346]33#include <VBox/vmm/em.h>
34#include <VBox/vmm/mm.h>
35#include <VBox/vmm/selm.h>
36#include <VBox/vmm/pgm.h>
[72885]37#include <VBox/vmm/iem.h>
[35346]38#include <VBox/vmm/iom.h>
[72885]39#include <VBox/vmm/hm.h>
40#include <VBox/vmm/pdmapi.h>
41#include <VBox/vmm/vmm.h>
[35346]42#include <VBox/vmm/stam.h>
[1]43#include "EMInternal.h"
[80253]44#include <VBox/vmm/vmcc.h>
[1]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
[2505]53
[45276]54
[45485]55
[1]56/**
57 * Get the current execution manager status.
58 *
59 * @returns Current status.
[58123]60 * @param pVCpu The cross context virtual CPU structure.
[1]61 */
[44375]62VMM_INT_DECL(EMSTATE) EMGetState(PVMCPU pVCpu)
[1]63{
[18927]64 return pVCpu->em.s.enmState;
[1]65}
66
[58126]67
[19611]68/**
69 * Sets the current execution manager status. (use only when you know what you're doing!)
70 *
[58126]71 * @param pVCpu The cross context virtual CPU structure.
72 * @param enmNewState The new state, EMSTATE_WAIT_SIPI or EMSTATE_HALTED.
[19611]73 */
[44375]74VMM_INT_DECL(void) EMSetState(PVMCPU pVCpu, EMSTATE enmNewState)
[19611]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
[1]82/**
[72462]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
[99051]112#if !defined(VBOX_VMM_TARGET_ARMV8)
[72462]113/**
[40357]114 * Prepare an MWAIT - essentials of the MONITOR instruction.
115 *
116 * @returns VINF_SUCCESS
[58123]117 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
[40357]118 * @param rax The content of RAX.
119 * @param rcx The content of RCX.
120 * @param rdx The content of RDX.
[47326]121 * @param GCPhys The physical address corresponding to rax.
[40357]122 */
[47326]123VMM_INT_DECL(int) EMMonitorWaitPrepare(PVMCPU pVCpu, uint64_t rax, uint64_t rcx, uint64_t rdx, RTGCPHYS GCPhys)
[40357]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;
[47326]129 /** @todo Make use of GCPhys. */
[49481]130 NOREF(GCPhys);
[40357]131 /** @todo Complete MONITOR implementation. */
132 return VINF_SUCCESS;
133}
134
135
136/**
[66581]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/**
[75646]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/**
[40357]167 * Performs an MWAIT.
168 *
169 * @returns VINF_SUCCESS
[58123]170 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
[40357]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
[74204]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}
[40357]198
[74204]199
[40357]200/**
[60804]201 * Determine if we should continue execution in HM after encountering an mwait
202 * instruction.
[40357]203 *
204 * Clears MWAIT flags if returning @c true.
205 *
[48370]206 * @returns true if we should continue, false if we should halt.
[58123]207 * @param pVCpu The cross context virtual CPU structure.
[40357]208 * @param pCtx Current CPU context.
209 */
[48370]210VMM_INT_DECL(bool) EMMonitorWaitShouldContinue(PVMCPU pVCpu, PCPUMCTX pCtx)
[40357]211{
[75998]212 if (CPUMGetGuestGif(pCtx))
[40357]213 {
[75998]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)) )
[48370]219 {
[75998]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 }
[48370]226 }
[40357]227 }
228
229 return false;
230}
231
232
233/**
[60804]234 * Determine if we should continue execution in HM after encountering a hlt
235 * instruction.
[48370]236 *
237 * @returns true if we should continue, false if we should halt.
[58123]238 * @param pVCpu The cross context virtual CPU structure.
[48370]239 * @param pCtx Current CPU context.
240 */
241VMM_INT_DECL(bool) EMShouldContinueAfterHalt(PVMCPU pVCpu, PCPUMCTX pCtx)
242{
[75998]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 }
[48370]252 return false;
253}
[99051]254#endif
[48370]255
256
257/**
[65792]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 */
[80281]272VMM_INT_DECL(int) EMUnhaltAndWakeUp(PVMCC pVM, PVMCPUCC pVCpuDst)
[65792]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}. */
[67989]287 int rc = GVMMR0SchedWakeUpNoGVMNoLock(pVM, pVCpuDst->idCpu);
[65792]288 AssertRC(rc);
289
290#elif defined(IN_RING3)
[92723]291 VMR3NotifyCpuFFU(pVCpuDst->pUVCpu, 0 /*fFlags*/);
292 int rc = VINF_SUCCESS;
293 RT_NOREF(pVM);
[65792]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
[72490]303#ifndef IN_RING3
[65792]304
305/**
[72490]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
[72555]355
[72490]356/**
[72580]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
[72582]372 /*
373 * Only status codes that EMHandleRCTmpl.h will resume EMHistoryExec with.
374 */
[72580]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/**
[72569]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 */
[80253]407VMM_INT_DECL(VBOXSTRICTRC) EMHistoryExec(PVMCPUCC pVCpu, PCEMEXITREC pExitRec, uint32_t fWillExit)
[72569]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 {
[72582]420 STAM_REL_PROFILE_START(&pVCpu->em.s.StatHistoryExec, a);
[72569]421 LogFlow(("EMHistoryExec/EXEC_WITH_MAX: %RX64, max %u\n", pExitRec->uFlatPC, pExitRec->cMaxInstructionsWithoutExit));
422 VBOXSTRICTRC rcStrict = IEMExecForExits(pVCpu, fWillExit,
423 pExitRec->cMaxInstructionsWithoutExit /* cMinInstructions*/,
[72657]424 pVCpu->em.s.cHistoryExecMaxInstructions,
[72569]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));
[72580]429 emHistoryExecSetContinueExitRecIdx(pVCpu, rcStrict, pExitRec);
[72674]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
[72582]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);
[72569]443 return rcStrict;
444 }
445
446 /*
447 * Probe a exit for close by exits.
448 */
449 case EMEXITACTION_EXEC_PROBE:
450 {
[72582]451 STAM_REL_PROFILE_START(&pVCpu->em.s.StatHistoryProbe, b);
[72570]452 LogFlow(("EMHistoryExec/EXEC_PROBE: %RX64\n", pExitRec->uFlatPC));
[72569]453 PEMEXITREC pExitRecUnconst = (PEMEXITREC)pExitRec;
454 VBOXSTRICTRC rcStrict = IEMExecForExits(pVCpu, fWillExit,
[72657]455 pVCpu->em.s.cHistoryProbeMinInstructions,
456 pVCpu->em.s.cHistoryExecMaxInstructions,
457 pVCpu->em.s.cHistoryProbeMaxInstructionsWithoutExit,
[72569]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));
[72580]461 emHistoryExecSetContinueExitRecIdx(pVCpu, rcStrict, pExitRecUnconst);
[72674]462 if ( ExecStats.cExits >= 2
463 && RT_SUCCESS(rcStrict))
[72569]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));
[72582]469 STAM_REL_COUNTER_INC(&pVCpu->em.s.StatHistoryProbedExecWithMax);
[72569]470 }
[72580]471#ifndef IN_RING3
[72674]472 else if ( pVCpu->em.s.idxContinueExitRec != UINT16_MAX
473 && RT_SUCCESS(rcStrict))
[72582]474 {
475 STAM_REL_COUNTER_INC(&pVCpu->em.s.StatHistoryProbedToRing3);
[72580]476 LogFlow(("EMHistoryExec/EXEC_PROBE: -> ring-3\n"));
[72582]477 }
[72580]478#endif
[72569]479 else
480 {
481 pExitRecUnconst->enmAction = EMEXITACTION_NORMAL_PROBED;
[72580]482 pVCpu->em.s.idxContinueExitRec = UINT16_MAX;
[72569]483 LogFlow(("EMHistoryExec/EXEC_PROBE: -> PROBED\n"));
[72582]484 STAM_REL_COUNTER_INC(&pVCpu->em.s.StatHistoryProbedNormal);
[72674]485 if ( rcStrict == VERR_IEM_INSTR_NOT_IMPLEMENTED
486 || rcStrict == VERR_IEM_ASPECT_NOT_IMPLEMENTED)
487 rcStrict = VINF_SUCCESS;
[72569]488 }
[72582]489 STAM_REL_COUNTER_ADD(&pVCpu->em.s.StatHistoryProbeInstructions, ExecStats.cInstructions);
490 STAM_REL_PROFILE_STOP(&pVCpu->em.s.StatHistoryProbe, b);
[72569]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
[72580]506/**
507 * Worker for emHistoryAddOrUpdateRecord.
508 */
[72569]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
[72580]522/**
523 * Worker for emHistoryAddOrUpdateRecord.
524 */
[72569]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/**
[72580]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/**
[72569]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{
[72642]568# ifdef IN_RING0
[72655]569 /* Disregard the hm flag. */
570 uFlagsAndType &= ~EMEXIT_F_HM;
[72642]571# endif
572
[72569]573 /*
574 * Work the hash table.
575 */
576 AssertCompile(RT_ELEMENTS(pVCpu->em.s.aExitRecords) == 1024);
[72642]577# define EM_EXIT_RECORDS_IDX_MASK 0x3ff
[72569]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)
[72579]585 {
[72569]586 pExitRec->uLastExitNo = uExitNo;
[72579]587 STAM_REL_COUNTER_INC(&pVCpu->em.s.aStatHistoryRecHits[0]);
588 }
[72569]589 else
[72579]590 {
591 STAM_REL_COUNTER_INC(&pVCpu->em.s.aStatHistoryRecTypeChanged[0]);
[72569]592 return emHistoryRecordInit(pExitRec, uFlatPC, uFlagsAndType, uExitNo);
[72579]593 }
[72569]594 }
595 else if (pExitRec->enmAction == EMEXITACTION_FREE_RECORD)
[72579]596 {
597 STAM_REL_COUNTER_INC(&pVCpu->em.s.aStatHistoryRecNew[0]);
[72569]598 return emHistoryRecordInitNew(pVCpu, pHistEntry, idxSlot, pExitRec, uFlatPC, uFlagsAndType, uExitNo);
[72579]599 }
[72569]600 else
601 {
602 /*
[72579]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.
[72569]605 */
[72579]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];
[72580]663 return emHistoryRecordInitReplacement(pHistEntry, idxOldest, pExitRec, uFlatPC, uFlagsAndType, uExitNo);
[72579]664 }
665 }
[72569]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/**
[72555]707 * Adds an exit to the history for this CPU.
708 *
[72569]709 * @returns Pointer to an exit record if special action should be taken using
710 * EMHistoryExec(). Take normal exit action when NULL.
711 *
[72560]712 * @param pVCpu The cross context virtual CPU structure.
[95560]713 * @param uFlagsAndType Combined flags and type (see EMEXIT_MAKE_FT).
[72560]714 * @param uFlatPC The flattened program counter (RIP). UINT64_MAX if not available.
[72555]715 * @param uTimestamp The TSC value for the exit, 0 if not available.
716 * @thread EMT(pVCpu)
717 */
[80253]718VMM_INT_DECL(PCEMEXITREC) EMHistoryAddExit(PVMCPUCC pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC, uint64_t uTimestamp)
[72555]719{
720 VMCPU_ASSERT_EMT(pVCpu);
721
722 /*
723 * Add the exit history entry.
724 */
725 AssertCompile(RT_ELEMENTS(pVCpu->em.s.aExitHistory) == 256);
[72569]726 uint64_t uExitNo = pVCpu->em.s.iNextExit++;
727 PEMEXITENTRY pHistEntry = &pVCpu->em.s.aExitHistory[(uintptr_t)uExitNo & 0xff];
[72555]728 pHistEntry->uFlatPC = uFlatPC;
729 pHistEntry->uTimestamp = uTimestamp;
730 pHistEntry->uFlagsAndType = uFlagsAndType;
731 pHistEntry->idxSlot = UINT32_MAX;
732
733 /*
[72569]734 * If common exit type, we will insert/update the exit into the exit record hash table.
[72555]735 */
[72569]736 if ( (uFlagsAndType & (EMEXIT_F_KIND_MASK | EMEXIT_F_CS_EIP | EMEXIT_F_UNFLATTENED_PC)) == EMEXIT_F_KIND_EM
[80161]737#ifdef IN_RING0
[72642]738 && pVCpu->em.s.fExitOptimizationEnabledR0
[72655]739 && ( !(uFlagsAndType & EMEXIT_F_HM) || pVCpu->em.s.fExitOptimizationEnabledR0PreemptDisabled)
[80161]740#else
[72580]741 && pVCpu->em.s.fExitOptimizationEnabled
[80161]742#endif
[72642]743 && uFlatPC != UINT64_MAX
744 )
[72569]745 return emHistoryAddOrUpdateRecord(pVCpu, uFlagsAndType, uFlatPC, pHistEntry, uExitNo);
746 return NULL;
[72555]747}
748
749
[72559]750/**
[72560]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.
[72564]754 * @param uFlatPC The flattened program counter (RIP).
[72560]755 * @param fFlattened Set if RIP was subjected to CS.BASE, clear if not.
756 */
[92216]757VMM_INT_DECL(void) EMHistoryUpdatePC(PVMCPUCC pVCpu, uint64_t uFlatPC, bool fFlattened)
[72560]758{
[92216]759 VMCPU_ASSERT_EMT(pVCpu);
760
[72560]761 AssertCompile(RT_ELEMENTS(pVCpu->em.s.aExitHistory) == 256);
[72569]762 uint64_t uExitNo = pVCpu->em.s.iNextExit - 1;
763 PEMEXITENTRY pHistEntry = &pVCpu->em.s.aExitHistory[(uintptr_t)uExitNo & 0xff];
[72560]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/**
[72564]773 * Interface for convering a engine specific exit to a generic one and get guidance.
774 *
[72569]775 * @returns Pointer to an exit record if special action should be taken using
776 * EMHistoryExec(). Take normal exit action when NULL.
777 *
[72564]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 */
[80253]782VMM_INT_DECL(PCEMEXITREC) EMHistoryUpdateFlagsAndType(PVMCPUCC pVCpu, uint32_t uFlagsAndType)
[72564]783{
784 VMCPU_ASSERT_EMT(pVCpu);
785
786 /*
787 * Do the updating.
788 */
789 AssertCompile(RT_ELEMENTS(pVCpu->em.s.aExitHistory) == 256);
[72569]790 uint64_t uExitNo = pVCpu->em.s.iNextExit - 1;
791 PEMEXITENTRY pHistEntry = &pVCpu->em.s.aExitHistory[(uintptr_t)uExitNo & 0xff];
[72564]792 pHistEntry->uFlagsAndType = uFlagsAndType | (pHistEntry->uFlagsAndType & (EMEXIT_F_CS_EIP | EMEXIT_F_UNFLATTENED_PC));
793
794 /*
[72569]795 * If common exit type, we will insert/update the exit into the exit record hash table.
[72564]796 */
[72569]797 if ( (uFlagsAndType & (EMEXIT_F_KIND_MASK | EMEXIT_F_CS_EIP | EMEXIT_F_UNFLATTENED_PC)) == EMEXIT_F_KIND_EM
[80161]798#ifdef IN_RING0
[72642]799 && pVCpu->em.s.fExitOptimizationEnabledR0
[72655]800 && ( !(uFlagsAndType & EMEXIT_F_HM) || pVCpu->em.s.fExitOptimizationEnabledR0PreemptDisabled)
[80161]801#else
[72580]802 && pVCpu->em.s.fExitOptimizationEnabled
[80161]803#endif
[72642]804 && pHistEntry->uFlatPC != UINT64_MAX
805 )
[72569]806 return emHistoryAddOrUpdateRecord(pVCpu, uFlagsAndType, pHistEntry->uFlatPC, pHistEntry, uExitNo);
807 return NULL;
[72564]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 *
[72569]815 * @returns Pointer to an exit record if special action should be taken using
816 * EMHistoryExec(). Take normal exit action when NULL.
817 *
[72564]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 */
[80253]823VMM_INT_DECL(PCEMEXITREC) EMHistoryUpdateFlagsAndTypeAndPC(PVMCPUCC pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC)
[72564]824{
825 VMCPU_ASSERT_EMT(pVCpu);
[97331]826 //Assert(uFlatPC != UINT64_MAX); - disable to make the pc wrapping tests in bs3-cpu-weird-1 work.
[72564]827
828 /*
829 * Do the updating.
830 */
831 AssertCompile(RT_ELEMENTS(pVCpu->em.s.aExitHistory) == 256);
[72569]832 uint64_t uExitNo = pVCpu->em.s.iNextExit - 1;
833 PEMEXITENTRY pHistEntry = &pVCpu->em.s.aExitHistory[(uintptr_t)uExitNo & 0xff];
[72564]834 pHistEntry->uFlagsAndType = uFlagsAndType;
835 pHistEntry->uFlatPC = uFlatPC;
836
837 /*
[72569]838 * If common exit type, we will insert/update the exit into the exit record hash table.
[72564]839 */
[72580]840 if ( (uFlagsAndType & (EMEXIT_F_KIND_MASK | EMEXIT_F_CS_EIP | EMEXIT_F_UNFLATTENED_PC)) == EMEXIT_F_KIND_EM
[80161]841#ifdef IN_RING0
[72642]842 && pVCpu->em.s.fExitOptimizationEnabledR0
[72655]843 && ( !(uFlagsAndType & EMEXIT_F_HM) || pVCpu->em.s.fExitOptimizationEnabledR0PreemptDisabled)
[80161]844#else
[72642]845 && pVCpu->em.s.fExitOptimizationEnabled
[80161]846#endif
[72642]847 )
[72569]848 return emHistoryAddOrUpdateRecord(pVCpu, uFlagsAndType, uFlatPC, pHistEntry, uExitNo);
849 return NULL;
[72564]850}
851
852
853/**
[41658]854 * @callback_method_impl{FNDISREADBYTES}
[1]855 */
[99208]856static DECLCALLBACK(int) emReadBytes(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
[1]857{
[80281]858 PVMCPUCC pVCpu = (PVMCPUCC)pDis->pvUser;
[41766]859 RTUINTPTR uSrcAddr = pDis->uInstrAddr + offInstr;
[18927]860
[41766]861 /*
862 * Figure how much we can or must read.
863 */
[93554]864 size_t cbToRead = GUEST_PAGE_SIZE - (uSrcAddr & (GUEST_PAGE_SIZE - 1));
[41766]865 if (cbToRead > cbMaxRead)
866 cbToRead = cbMaxRead;
867 else if (cbToRead < cbMinRead)
868 cbToRead = cbMinRead;
[21174]869
[80016]870 int rc = PGMPhysSimpleReadGCPtr(pVCpu, &pDis->abInstr[offInstr], uSrcAddr, cbToRead);
871 if (RT_FAILURE(rc))
[21174]872 {
[80016]873 if (cbToRead > cbMinRead)
[41766]874 {
875 cbToRead = cbMinRead;
[80016]876 rc = PGMPhysSimpleReadGCPtr(pVCpu, &pDis->abInstr[offInstr], uSrcAddr, cbToRead);
[41766]877 }
[80016]878 if (RT_FAILURE(rc))
[1]879 {
[99051]880#if defined(VBOX_VMM_TARGET_ARMV8)
881 AssertReleaseFailed();
882#else
[80016]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)
[41766]889 {
[80016]890 HMInvalidatePage(pVCpu, uSrcAddr);
[93554]891 if (((uSrcAddr + cbToRead - 1) >> GUEST_PAGE_SHIFT) != (uSrcAddr >> GUEST_PAGE_SHIFT))
[80016]892 HMInvalidatePage(pVCpu, uSrcAddr + cbToRead - 1);
893 }
[99051]894#endif
[1]895 }
896 }
[25550]897
[41771]898 pDis->cbCachedInstr = offInstr + (uint8_t)cbToRead;
[41766]899 return rc;
[1]900}
901
[25550]902
[1]903/**
[42186]904 * Disassembles the current instruction.
[1]905 *
[18338]906 * @returns VBox status code, see SELMToFlatEx and EMInterpretDisasOneEx for
907 * details.
908 *
[58123]909 * @param pVCpu The cross context virtual CPU structure.
[20530]910 * @param pDis Where to return the parsed instruction info.
[1]911 * @param pcbInstr Where to return the instruction size. (optional)
912 */
[99208]913VMM_INT_DECL(int) EMInterpretDisasCurrent(PVMCPUCC pVCpu, PDISSTATE pDis, unsigned *pcbInstr)
[1]914{
[99051]915#if defined(VBOX_VMM_TARGET_ARMV8)
916 return EMInterpretDisasOneEx(pVCpu, (RTGCUINTPTR)CPUMGetGuestFlatPC(pVCpu), pDis, pcbInstr);
917#else
[97193]918 PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
919 RTGCPTR GCPtrInstr;
[99051]920
921# if 0
[97193]922 int rc = SELMToFlatEx(pVCpu, DISSELREG_CS, pCtx, pCtx->rip, 0, &GCPtrInstr);
[99051]923# else
[41823]924/** @todo Get the CPU mode as well while we're at it! */
[97218]925 int rc = SELMValidateAndConvertCSAddr(pVCpu, pCtx->eflags.u, pCtx->ss.Sel, pCtx->cs.Sel, &pCtx->cs, pCtx->rip, &GCPtrInstr);
[99051]926# endif
[97193]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;
[99051]933#endif
[1]934}
935
936
937/**
938 * Disassembles one instruction.
939 *
940 * This is used by internally by the interpreter and by trap/access handlers.
941 *
[18338]942 * @returns VBox status code.
943 *
[58123]944 * @param pVCpu The cross context virtual CPU structure.
[1]945 * @param GCPtrInstr The flat address of the instruction.
[20530]946 * @param pDis Where to return the parsed instruction info.
[1]947 * @param pcbInstr Where to return the instruction size. (optional)
948 */
[99208]949VMM_INT_DECL(int) EMInterpretDisasOneEx(PVMCPUCC pVCpu, RTGCUINTPTR GCPtrInstr, PDISSTATE pDis, unsigned *pcbInstr)
[1]950{
[42186]951 DISCPUMODE enmCpuMode = CPUMGetGuestDisMode(pVCpu);
[41823]952 /** @todo Deal with too long instruction (=> \#GP), opcode read errors (=>
953 * \#PF, \#GP, \#??), undefined opcodes (=> \#UD), and such. */
[41766]954 int rc = DISInstrWithReader(GCPtrInstr, enmCpuMode, emReadBytes, pVCpu, pDis, pcbInstr);
[13816]955 if (RT_SUCCESS(rc))
[1]956 return VINF_SUCCESS;
[45428]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;
[1]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 *
[58123]970 * @param pVCpu The cross context virtual CPU structure.
[1]971 *
[97197]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 (!)
[1]975 */
[97197]976VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInstruction(PVMCPUCC pVCpu)
[1]977{
[99051]978#if defined(VBOX_VMM_TARGET_ARMV8)
979 LogFlow(("EMInterpretInstruction %RGv\n", (RTGCPTR)CPUMGetGuestFlatPC(pVCpu)));
980#else
[97197]981 LogFlow(("EMInterpretInstruction %RGv\n", (RTGCPTR)CPUMGetGuestRIP(pVCpu)));
[99051]982#endif
[42707]983
[97197]984 VBOXSTRICTRC rc = IEMExecOneBypassEx(pVCpu, NULL /*pcbWritten*/);
[40453]985 if (RT_UNLIKELY( rc == VERR_IEM_ASPECT_NOT_IMPLEMENTED
986 || rc == VERR_IEM_INSTR_NOT_IMPLEMENTED))
[42707]987 rc = VERR_EM_INTERPRETER;
988 if (rc != VINF_SUCCESS)
989 Log(("EMInterpretInstruction: returns %Rrc\n", VBOXSTRICTRC_VAL(rc)));
990
[40442]991 return rc;
[1]992}
993
[12688]994
[1]995/**
[99208]996 * Interprets the current instruction using the supplied DISSTATE structure.
[1]997 *
[40442]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 *
[58126]1007 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
[40442]1008 * @param pDis The disassembler cpu state for the instruction to be
1009 * interpreted.
[97200]1010 * @param rip The instruction pointer value.
[40442]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)
[1]1018 */
[99208]1019VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInstructionDisasState(PVMCPUCC pVCpu, PDISSTATE pDis, uint64_t rip)
[1]1020{
[97200]1021 LogFlow(("EMInterpretInstructionDisasState %RGv\n", (RTGCPTR)rip));
[42707]1022
[97200]1023 VBOXSTRICTRC rc = IEMExecOneBypassWithPrefetchedByPC(pVCpu, rip, pDis->abInstr, pDis->cbCachedInstr);
[40453]1024 if (RT_UNLIKELY( rc == VERR_IEM_ASPECT_NOT_IMPLEMENTED
1025 || rc == VERR_IEM_INSTR_NOT_IMPLEMENTED))
[42707]1026 rc = VERR_EM_INTERPRETER;
1027
1028 if (rc != VINF_SUCCESS)
1029 Log(("EMInterpretInstructionDisasState: returns %Rrc\n", VBOXSTRICTRC_VAL(rc)));
1030
[40453]1031 return rc;
[1]1032}
1033
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use