VirtualBox

source: vbox/trunk/src/VBox/VMM/include/IEMInline.h@ 105673

Last change on this file since 105673 was 105465, checked in by vboxsync, 4 months ago

VMM/IEM: Some more TLB tracing related changes. bugref:10727

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 168.3 KB
Line 
1/* $Id: IEMInline.h 105465 2024-07-24 09:05:40Z vboxsync $ */
2/** @file
3 * IEM - Interpreted Execution Manager - Inlined Functions.
4 */
5
6/*
7 * Copyright (C) 2011-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#ifndef VMM_INCLUDED_SRC_include_IEMInline_h
29#define VMM_INCLUDED_SRC_include_IEMInline_h
30#ifndef RT_WITHOUT_PRAGMA_ONCE
31# pragma once
32#endif
33
34
35
36/**
37 * Makes status code addjustments (pass up from I/O and access handler)
38 * as well as maintaining statistics.
39 *
40 * @returns Strict VBox status code to pass up.
41 * @param pVCpu The cross context virtual CPU structure of the calling thread.
42 * @param rcStrict The status from executing an instruction.
43 */
44DECL_FORCE_INLINE(VBOXSTRICTRC) iemExecStatusCodeFiddling(PVMCPUCC pVCpu, VBOXSTRICTRC rcStrict) RT_NOEXCEPT
45{
46 if (rcStrict != VINF_SUCCESS)
47 {
48 /* Deal with the cases that should be treated as VINF_SUCCESS first. */
49 if ( rcStrict == VINF_IEM_YIELD_PENDING_FF
50#ifdef VBOX_WITH_NESTED_HWVIRT_VMX /** @todo r=bird: Why do we need TWO status codes here? */
51 || rcStrict == VINF_VMX_VMEXIT
52#endif
53#ifdef VBOX_WITH_NESTED_HWVIRT_SVM
54 || rcStrict == VINF_SVM_VMEXIT
55#endif
56 )
57 {
58 rcStrict = pVCpu->iem.s.rcPassUp;
59 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
60 { /* likely */ }
61 else
62 pVCpu->iem.s.cRetPassUpStatus++;
63 }
64 else if (RT_SUCCESS(rcStrict))
65 {
66 AssertMsg( (rcStrict >= VINF_EM_FIRST && rcStrict <= VINF_EM_LAST)
67 || rcStrict == VINF_IOM_R3_IOPORT_READ
68 || rcStrict == VINF_IOM_R3_IOPORT_WRITE
69 || rcStrict == VINF_IOM_R3_IOPORT_COMMIT_WRITE
70 || rcStrict == VINF_IOM_R3_MMIO_READ
71 || rcStrict == VINF_IOM_R3_MMIO_READ_WRITE
72 || rcStrict == VINF_IOM_R3_MMIO_WRITE
73 || rcStrict == VINF_IOM_R3_MMIO_COMMIT_WRITE
74 || rcStrict == VINF_CPUM_R3_MSR_READ
75 || rcStrict == VINF_CPUM_R3_MSR_WRITE
76 || rcStrict == VINF_EM_RAW_EMULATE_INSTR
77 || rcStrict == VINF_EM_RAW_TO_R3
78 || rcStrict == VINF_EM_TRIPLE_FAULT
79 || rcStrict == VINF_EM_EMULATE_SPLIT_LOCK
80 || rcStrict == VINF_GIM_R3_HYPERCALL
81 /* raw-mode / virt handlers only: */
82 || rcStrict == VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT
83 || rcStrict == VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT
84 || rcStrict == VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT
85 || rcStrict == VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT
86 || rcStrict == VINF_SELM_SYNC_GDT
87 || rcStrict == VINF_CSAM_PENDING_ACTION
88 || rcStrict == VINF_PATM_CHECK_PATCH_PAGE
89 /* nested hw.virt codes: */
90 || rcStrict == VINF_VMX_INTERCEPT_NOT_ACTIVE
91 || rcStrict == VINF_VMX_MODIFIES_BEHAVIOR
92 , ("rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
93/** @todo adjust for VINF_EM_RAW_EMULATE_INSTR. */
94 int32_t const rcPassUp = pVCpu->iem.s.rcPassUp;
95 if (rcPassUp == VINF_SUCCESS)
96 pVCpu->iem.s.cRetInfStatuses++;
97 else if ( rcPassUp < VINF_EM_FIRST
98 || rcPassUp > VINF_EM_LAST
99 || rcPassUp < VBOXSTRICTRC_VAL(rcStrict))
100 {
101 LogEx(LOG_GROUP_IEM,("IEM: rcPassUp=%Rrc! rcStrict=%Rrc\n", rcPassUp, VBOXSTRICTRC_VAL(rcStrict)));
102 pVCpu->iem.s.cRetPassUpStatus++;
103 rcStrict = rcPassUp;
104 }
105 else
106 {
107 LogEx(LOG_GROUP_IEM,("IEM: rcPassUp=%Rrc rcStrict=%Rrc!\n", rcPassUp, VBOXSTRICTRC_VAL(rcStrict)));
108 pVCpu->iem.s.cRetInfStatuses++;
109 }
110 }
111 else if (rcStrict == VERR_IEM_ASPECT_NOT_IMPLEMENTED)
112 pVCpu->iem.s.cRetAspectNotImplemented++;
113 else if (rcStrict == VERR_IEM_INSTR_NOT_IMPLEMENTED)
114 pVCpu->iem.s.cRetInstrNotImplemented++;
115 else
116 pVCpu->iem.s.cRetErrStatuses++;
117 }
118 else
119 {
120 rcStrict = pVCpu->iem.s.rcPassUp;
121 if (rcStrict != VINF_SUCCESS)
122 pVCpu->iem.s.cRetPassUpStatus++;
123 }
124
125 /* Just clear it here as well. */
126 pVCpu->iem.s.rcPassUp = VINF_SUCCESS;
127
128 return rcStrict;
129}
130
131
132/**
133 * Sets the pass up status.
134 *
135 * @returns VINF_SUCCESS.
136 * @param pVCpu The cross context virtual CPU structure of the
137 * calling thread.
138 * @param rcPassUp The pass up status. Must be informational.
139 * VINF_SUCCESS is not allowed.
140 */
141DECLINLINE(int) iemSetPassUpStatus(PVMCPUCC pVCpu, VBOXSTRICTRC rcPassUp) RT_NOEXCEPT
142{
143 AssertRC(VBOXSTRICTRC_VAL(rcPassUp)); Assert(rcPassUp != VINF_SUCCESS);
144
145 int32_t const rcOldPassUp = pVCpu->iem.s.rcPassUp;
146 if (rcOldPassUp == VINF_SUCCESS)
147 pVCpu->iem.s.rcPassUp = VBOXSTRICTRC_VAL(rcPassUp);
148 /* If both are EM scheduling codes, use EM priority rules. */
149 else if ( rcOldPassUp >= VINF_EM_FIRST && rcOldPassUp <= VINF_EM_LAST
150 && rcPassUp >= VINF_EM_FIRST && rcPassUp <= VINF_EM_LAST)
151 {
152 if (rcPassUp < rcOldPassUp)
153 {
154 LogEx(LOG_GROUP_IEM,("IEM: rcPassUp=%Rrc! rcOldPassUp=%Rrc\n", VBOXSTRICTRC_VAL(rcPassUp), rcOldPassUp));
155 pVCpu->iem.s.rcPassUp = VBOXSTRICTRC_VAL(rcPassUp);
156 }
157 else
158 LogEx(LOG_GROUP_IEM,("IEM: rcPassUp=%Rrc rcOldPassUp=%Rrc!\n", VBOXSTRICTRC_VAL(rcPassUp), rcOldPassUp));
159 }
160 /* Override EM scheduling with specific status code. */
161 else if (rcOldPassUp >= VINF_EM_FIRST && rcOldPassUp <= VINF_EM_LAST)
162 {
163 LogEx(LOG_GROUP_IEM,("IEM: rcPassUp=%Rrc! rcOldPassUp=%Rrc\n", VBOXSTRICTRC_VAL(rcPassUp), rcOldPassUp));
164 pVCpu->iem.s.rcPassUp = VBOXSTRICTRC_VAL(rcPassUp);
165 }
166 /* Don't override specific status code, first come first served. */
167 else
168 LogEx(LOG_GROUP_IEM,("IEM: rcPassUp=%Rrc rcOldPassUp=%Rrc!\n", VBOXSTRICTRC_VAL(rcPassUp), rcOldPassUp));
169 return VINF_SUCCESS;
170}
171
172
173/**
174 * Calculates the IEM_F_X86_AC flags.
175 *
176 * @returns IEM_F_X86_AC or zero
177 * @param pVCpu The cross context virtual CPU structure of the
178 * calling thread.
179 */
180DECL_FORCE_INLINE(uint32_t) iemCalcExecAcFlag(PVMCPUCC pVCpu) RT_NOEXCEPT
181{
182 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_RFLAGS);
183 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));
184
185 if ( !pVCpu->cpum.GstCtx.eflags.Bits.u1AC
186 || (pVCpu->cpum.GstCtx.cr0 & (X86_CR0_AM | X86_CR0_PE)) != (X86_CR0_AM | X86_CR0_PE)
187 || ( !pVCpu->cpum.GstCtx.eflags.Bits.u1VM
188 && pVCpu->cpum.GstCtx.ss.Attr.n.u2Dpl != 3))
189 return 0;
190 return IEM_F_X86_AC;
191}
192
193
194/**
195 * Calculates the IEM_F_MODE_X86_32BIT_FLAT flag.
196 *
197 * Checks if CS, SS, DS and SS are all wide open flat 32-bit segments. This will
198 * reject expand down data segments and conforming code segments.
199 *
200 * ASSUMES that the CPU is in 32-bit mode.
201 *
202 * @note Will return zero when if any of the segment register state is marked
203 * external, this must be factored into assertions checking fExec
204 * consistency.
205 *
206 * @returns IEM_F_MODE_X86_32BIT_FLAT or zero.
207 * @param pVCpu The cross context virtual CPU structure of the
208 * calling thread.
209 * @sa iemCalc32BitFlatIndicatorEsDs
210 */
211DECL_FORCE_INLINE(uint32_t) iemCalc32BitFlatIndicator(PVMCPUCC pVCpu) RT_NOEXCEPT
212{
213 AssertCompile(X86_SEL_TYPE_DOWN == X86_SEL_TYPE_CONF);
214 return ( ( pVCpu->cpum.GstCtx.es.Attr.u
215 | pVCpu->cpum.GstCtx.cs.Attr.u
216 | pVCpu->cpum.GstCtx.ss.Attr.u
217 | pVCpu->cpum.GstCtx.ds.Attr.u)
218 & (X86_SEL_TYPE_ACCESSED | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_P | X86_SEL_TYPE_DOWN | X86DESCATTR_UNUSABLE))
219 == (X86_SEL_TYPE_ACCESSED | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_P)
220 && ( (pVCpu->cpum.GstCtx.es.u32Limit + 1)
221 | (pVCpu->cpum.GstCtx.cs.u32Limit + 1)
222 | (pVCpu->cpum.GstCtx.ss.u32Limit + 1)
223 | (pVCpu->cpum.GstCtx.ds.u32Limit + 1))
224 == 0
225 && ( pVCpu->cpum.GstCtx.es.u64Base
226 | pVCpu->cpum.GstCtx.cs.u64Base
227 | pVCpu->cpum.GstCtx.ss.u64Base
228 | pVCpu->cpum.GstCtx.ds.u64Base)
229 == 0
230 && !(pVCpu->cpum.GstCtx.fExtrn & (CPUMCTX_EXTRN_ES | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_ES))
231 ? IEM_F_MODE_X86_32BIT_FLAT : 0;
232}
233
234
235/**
236 * Calculates the IEM_F_MODE_X86_32BIT_FLAT flag, ASSUMING the CS and SS are
237 * flat already.
238 *
239 * This is used by sysenter.
240 *
241 * @note Will return zero when if any of the segment register state is marked
242 * external, this must be factored into assertions checking fExec
243 * consistency.
244 *
245 * @returns IEM_F_MODE_X86_32BIT_FLAT or zero.
246 * @param pVCpu The cross context virtual CPU structure of the
247 * calling thread.
248 * @sa iemCalc32BitFlatIndicator
249 */
250DECL_FORCE_INLINE(uint32_t) iemCalc32BitFlatIndicatorEsDs(PVMCPUCC pVCpu) RT_NOEXCEPT
251{
252 AssertCompile(X86_SEL_TYPE_DOWN == X86_SEL_TYPE_CONF);
253 return ( ( pVCpu->cpum.GstCtx.es.Attr.u
254 | pVCpu->cpum.GstCtx.ds.Attr.u)
255 & (X86_SEL_TYPE_ACCESSED | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_P | X86_SEL_TYPE_DOWN | X86DESCATTR_UNUSABLE))
256 == (X86_SEL_TYPE_ACCESSED | X86DESCATTR_G | X86DESCATTR_D | X86DESCATTR_P)
257 && ( (pVCpu->cpum.GstCtx.es.u32Limit + 1)
258 | (pVCpu->cpum.GstCtx.ds.u32Limit + 1))
259 == 0
260 && ( pVCpu->cpum.GstCtx.es.u64Base
261 | pVCpu->cpum.GstCtx.ds.u64Base)
262 == 0
263 && !(pVCpu->cpum.GstCtx.fExtrn & (CPUMCTX_EXTRN_ES | CPUMCTX_EXTRN_CS | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_ES))
264 ? IEM_F_MODE_X86_32BIT_FLAT : 0;
265}
266
267
268/**
269 * Calculates the IEM_F_MODE_XXX, CPL and AC flags.
270 *
271 * @returns IEM_F_MODE_XXX, IEM_F_X86_CPL_MASK and IEM_F_X86_AC.
272 * @param pVCpu The cross context virtual CPU structure of the
273 * calling thread.
274 */
275DECL_FORCE_INLINE(uint32_t) iemCalcExecModeAndCplFlags(PVMCPUCC pVCpu) RT_NOEXCEPT
276{
277 /*
278 * We're duplicates code from CPUMGetGuestCPL and CPUMIsGuestIn64BitCodeEx
279 * here to try get this done as efficiently as possible.
280 */
281 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_EFER | CPUMCTX_EXTRN_RFLAGS | CPUMCTX_EXTRN_SS | CPUMCTX_EXTRN_CS);
282
283 if (pVCpu->cpum.GstCtx.cr0 & X86_CR0_PE)
284 {
285 if (!pVCpu->cpum.GstCtx.eflags.Bits.u1VM)
286 {
287 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));
288 uint32_t fExec = ((uint32_t)pVCpu->cpum.GstCtx.ss.Attr.n.u2Dpl << IEM_F_X86_CPL_SHIFT);
289 if ( !pVCpu->cpum.GstCtx.eflags.Bits.u1AC
290 || !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_AM)
291 || fExec != (3U << IEM_F_X86_CPL_SHIFT))
292 { /* likely */ }
293 else
294 fExec |= IEM_F_X86_AC;
295
296 if (pVCpu->cpum.GstCtx.cs.Attr.n.u1DefBig)
297 {
298 Assert(!pVCpu->cpum.GstCtx.cs.Attr.n.u1Long || !(pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_LMA));
299 fExec |= IEM_F_MODE_X86_32BIT_PROT | iemCalc32BitFlatIndicator(pVCpu);
300 }
301 else if ( pVCpu->cpum.GstCtx.cs.Attr.n.u1Long
302 && (pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_LMA))
303 fExec |= IEM_F_MODE_X86_64BIT;
304 else if (IEM_GET_TARGET_CPU(pVCpu) >= IEMTARGETCPU_386)
305 fExec |= IEM_F_MODE_X86_16BIT_PROT;
306 else
307 fExec |= IEM_F_MODE_X86_16BIT_PROT_PRE_386;
308 return fExec;
309 }
310 if ( !pVCpu->cpum.GstCtx.eflags.Bits.u1AC
311 || !(pVCpu->cpum.GstCtx.cr0 & X86_CR0_AM))
312 return IEM_F_MODE_X86_16BIT_PROT_V86 | (UINT32_C(3) << IEM_F_X86_CPL_SHIFT);
313 return IEM_F_MODE_X86_16BIT_PROT_V86 | (UINT32_C(3) << IEM_F_X86_CPL_SHIFT) | IEM_F_X86_AC;
314 }
315
316 /* Real mode is zero; CPL set to 3 for VT-x real-mode emulation. */
317 if (RT_LIKELY(!pVCpu->cpum.GstCtx.cs.Attr.n.u1DefBig))
318 {
319 if (IEM_GET_TARGET_CPU(pVCpu) >= IEMTARGETCPU_386)
320 return IEM_F_MODE_X86_16BIT;
321 return IEM_F_MODE_X86_16BIT_PRE_386;
322 }
323
324 /* 32-bit unreal mode. */
325 return IEM_F_MODE_X86_32BIT | iemCalc32BitFlatIndicator(pVCpu);
326}
327
328
329/**
330 * Calculates the AMD-V and VT-x related context flags.
331 *
332 * @returns 0 or a combination of IEM_F_X86_CTX_IN_GUEST, IEM_F_X86_CTX_SVM and
333 * IEM_F_X86_CTX_VMX.
334 * @param pVCpu The cross context virtual CPU structure of the
335 * calling thread.
336 */
337DECL_FORCE_INLINE(uint32_t) iemCalcExecHwVirtFlags(PVMCPUCC pVCpu) RT_NOEXCEPT
338{
339 /*
340 * This duplicates code from CPUMIsGuestVmxEnabled, CPUMIsGuestSvmEnabled
341 * and CPUMIsGuestInNestedHwvirtMode to some extent.
342 */
343 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_CR4 | CPUMCTX_EXTRN_EFER);
344
345 AssertCompile(X86_CR4_VMXE != MSR_K6_EFER_SVME);
346 uint64_t const fTmp = (pVCpu->cpum.GstCtx.cr4 & X86_CR4_VMXE)
347 | (pVCpu->cpum.GstCtx.msrEFER & MSR_K6_EFER_SVME);
348 if (RT_LIKELY(!fTmp))
349 return 0; /* likely */
350
351 if (fTmp & X86_CR4_VMXE)
352 {
353 Assert(pVCpu->cpum.GstCtx.hwvirt.enmHwvirt == CPUMHWVIRT_VMX);
354 if (pVCpu->cpum.GstCtx.hwvirt.vmx.fInVmxNonRootMode)
355 return IEM_F_X86_CTX_VMX | IEM_F_X86_CTX_IN_GUEST;
356 return IEM_F_X86_CTX_VMX;
357 }
358
359 Assert(pVCpu->cpum.GstCtx.hwvirt.enmHwvirt == CPUMHWVIRT_SVM);
360 if (pVCpu->cpum.GstCtx.hwvirt.svm.Vmcb.ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_VMRUN)
361 return IEM_F_X86_CTX_SVM | IEM_F_X86_CTX_IN_GUEST;
362 return IEM_F_X86_CTX_SVM;
363}
364
365#ifdef VBOX_INCLUDED_vmm_dbgf_h /* VM::dbgf.ro.cEnabledHwBreakpoints is only accessible if VBox/vmm/dbgf.h is included. */
366
367/**
368 * Calculates IEM_F_BRK_PENDING_XXX (IEM_F_PENDING_BRK_MASK) flags.
369 *
370 * @returns IEM_F_BRK_PENDING_XXX or zero.
371 * @param pVCpu The cross context virtual CPU structure of the
372 * calling thread.
373 */
374DECL_FORCE_INLINE(uint32_t) iemCalcExecDbgFlags(PVMCPUCC pVCpu) RT_NOEXCEPT
375{
376 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_DR7);
377
378 if (RT_LIKELY( !(pVCpu->cpum.GstCtx.dr[7] & X86_DR7_ENABLED_MASK)
379 && pVCpu->CTX_SUFF(pVM)->dbgf.ro.cEnabledHwBreakpoints == 0))
380 return 0;
381 return iemCalcExecDbgFlagsSlow(pVCpu);
382}
383
384/**
385 * Calculates the the IEM_F_XXX flags.
386 *
387 * @returns IEM_F_XXX combination match the current CPU state.
388 * @param pVCpu The cross context virtual CPU structure of the
389 * calling thread.
390 */
391DECL_FORCE_INLINE(uint32_t) iemCalcExecFlags(PVMCPUCC pVCpu) RT_NOEXCEPT
392{
393 return iemCalcExecModeAndCplFlags(pVCpu)
394 | iemCalcExecHwVirtFlags(pVCpu)
395 /* SMM is not yet implemented */
396 | iemCalcExecDbgFlags(pVCpu)
397 ;
398}
399
400
401/**
402 * Re-calculates the MODE and CPL parts of IEMCPU::fExec.
403 *
404 * @param pVCpu The cross context virtual CPU structure of the
405 * calling thread.
406 */
407DECL_FORCE_INLINE(void) iemRecalcExecModeAndCplAndAcFlags(PVMCPUCC pVCpu)
408{
409 pVCpu->iem.s.fExec = (pVCpu->iem.s.fExec & ~(IEM_F_MODE_MASK | IEM_F_X86_CPL_MASK | IEM_F_X86_AC))
410 | iemCalcExecModeAndCplFlags(pVCpu);
411}
412
413
414/**
415 * Re-calculates the IEM_F_PENDING_BRK_MASK part of IEMCPU::fExec.
416 *
417 * @param pVCpu The cross context virtual CPU structure of the
418 * calling thread.
419 */
420DECL_FORCE_INLINE(void) iemRecalcExecDbgFlags(PVMCPUCC pVCpu)
421{
422 pVCpu->iem.s.fExec = (pVCpu->iem.s.fExec & ~IEM_F_PENDING_BRK_MASK)
423 | iemCalcExecDbgFlags(pVCpu);
424}
425
426#endif /* VBOX_INCLUDED_vmm_dbgf_h */
427
428
429#ifndef IEM_WITH_OPAQUE_DECODER_STATE
430
431# if defined(VBOX_INCLUDED_vmm_dbgf_h) || defined(DOXYGEN_RUNNING) /* dbgf.ro.cEnabledHwBreakpoints */
432
433/**
434 * Initializes the execution state.
435 *
436 * @param pVCpu The cross context virtual CPU structure of the
437 * calling thread.
438 * @param fExecOpts Optional execution flags:
439 * - IEM_F_BYPASS_HANDLERS
440 * - IEM_F_X86_DISREGARD_LOCK
441 *
442 * @remarks Callers of this must call iemUninitExec() to undo potentially fatal
443 * side-effects in strict builds.
444 */
445DECLINLINE(void) iemInitExec(PVMCPUCC pVCpu, uint32_t fExecOpts) RT_NOEXCEPT
446{
447 IEM_CTX_ASSERT(pVCpu, IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK);
448 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_IEM));
449 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.cs));
450 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ss));
451 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.es));
452 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ds));
453 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.fs));
454 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.gs));
455 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.ldtr));
456 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, &pVCpu->cpum.GstCtx.tr));
457
458 pVCpu->iem.s.rcPassUp = VINF_SUCCESS;
459 pVCpu->iem.s.fExec = iemCalcExecFlags(pVCpu) | fExecOpts;
460 pVCpu->iem.s.cActiveMappings = 0;
461 pVCpu->iem.s.iNextMapping = 0;
462
463# ifdef VBOX_STRICT
464 pVCpu->iem.s.enmDefAddrMode = (IEMMODE)0xfe;
465 pVCpu->iem.s.enmEffAddrMode = (IEMMODE)0xfe;
466 pVCpu->iem.s.enmDefOpSize = (IEMMODE)0xfe;
467 pVCpu->iem.s.enmEffOpSize = (IEMMODE)0xfe;
468 pVCpu->iem.s.fPrefixes = 0xfeedbeef;
469 pVCpu->iem.s.uRexReg = 127;
470 pVCpu->iem.s.uRexB = 127;
471 pVCpu->iem.s.offModRm = 127;
472 pVCpu->iem.s.uRexIndex = 127;
473 pVCpu->iem.s.iEffSeg = 127;
474 pVCpu->iem.s.idxPrefix = 127;
475 pVCpu->iem.s.uVex3rdReg = 127;
476 pVCpu->iem.s.uVexLength = 127;
477 pVCpu->iem.s.fEvexStuff = 127;
478 pVCpu->iem.s.uFpuOpcode = UINT16_MAX;
479# ifdef IEM_WITH_CODE_TLB
480 pVCpu->iem.s.offInstrNextByte = UINT16_MAX;
481 pVCpu->iem.s.pbInstrBuf = NULL;
482 pVCpu->iem.s.cbInstrBuf = UINT16_MAX;
483 pVCpu->iem.s.cbInstrBufTotal = UINT16_MAX;
484 pVCpu->iem.s.offCurInstrStart = INT16_MAX;
485 pVCpu->iem.s.uInstrBufPc = UINT64_C(0xc0ffc0ffcff0c0ff);
486# ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
487 pVCpu->iem.s.offOpcode = 127;
488# endif
489# else
490 pVCpu->iem.s.offOpcode = 127;
491 pVCpu->iem.s.cbOpcode = 127;
492# endif
493# endif /* VBOX_STRICT */
494}
495
496
497# if defined(VBOX_WITH_NESTED_HWVIRT_SVM) || defined(VBOX_WITH_NESTED_HWVIRT_VMX)
498/**
499 * Performs a minimal reinitialization of the execution state.
500 *
501 * This is intended to be used by VM-exits, SMM, LOADALL and other similar
502 * 'world-switch' types operations on the CPU. Currently only nested
503 * hardware-virtualization uses it.
504 *
505 * @param pVCpu The cross context virtual CPU structure of the calling EMT.
506 * @param cbInstr The instruction length (for flushing).
507 */
508DECLINLINE(void) iemReInitExec(PVMCPUCC pVCpu, uint8_t cbInstr) RT_NOEXCEPT
509{
510 pVCpu->iem.s.fExec = iemCalcExecFlags(pVCpu) | (pVCpu->iem.s.fExec & IEM_F_USER_OPTS);
511 iemOpcodeFlushHeavy(pVCpu, cbInstr);
512}
513# endif
514
515# endif /* VBOX_INCLUDED_vmm_dbgf_h || DOXYGEN_RUNNING */
516
517/**
518 * Counterpart to #iemInitExec that undoes evil strict-build stuff.
519 *
520 * @param pVCpu The cross context virtual CPU structure of the
521 * calling thread.
522 */
523DECLINLINE(void) iemUninitExec(PVMCPUCC pVCpu) RT_NOEXCEPT
524{
525 /* Note! do not touch fInPatchCode here! (see iemUninitExecAndFiddleStatusAndMaybeReenter) */
526# ifdef VBOX_STRICT
527# ifdef IEM_WITH_CODE_TLB
528 NOREF(pVCpu);
529# else
530 pVCpu->iem.s.cbOpcode = 0;
531# endif
532# else
533 NOREF(pVCpu);
534# endif
535}
536
537
538/**
539 * Calls iemUninitExec, iemExecStatusCodeFiddling and iemRCRawMaybeReenter.
540 *
541 * Only calling iemRCRawMaybeReenter in raw-mode, obviously.
542 *
543 * @returns Fiddled strict vbox status code, ready to return to non-IEM caller.
544 * @param pVCpu The cross context virtual CPU structure of the calling thread.
545 * @param rcStrict The status code to fiddle.
546 */
547DECLINLINE(VBOXSTRICTRC) iemUninitExecAndFiddleStatusAndMaybeReenter(PVMCPUCC pVCpu, VBOXSTRICTRC rcStrict) RT_NOEXCEPT
548{
549 iemUninitExec(pVCpu);
550 return iemExecStatusCodeFiddling(pVCpu, rcStrict);
551}
552
553
554/**
555 * Macro used by the IEMExec* method to check the given instruction length.
556 *
557 * Will return on failure!
558 *
559 * @param a_cbInstr The given instruction length.
560 * @param a_cbMin The minimum length.
561 */
562# define IEMEXEC_ASSERT_INSTR_LEN_RETURN(a_cbInstr, a_cbMin) \
563 AssertMsgReturn((unsigned)(a_cbInstr) - (unsigned)(a_cbMin) <= (unsigned)15 - (unsigned)(a_cbMin), \
564 ("cbInstr=%u cbMin=%u\n", (a_cbInstr), (a_cbMin)), VERR_IEM_INVALID_INSTR_LENGTH)
565
566
567# ifndef IEM_WITH_SETJMP
568
569/**
570 * Fetches the first opcode byte.
571 *
572 * @returns Strict VBox status code.
573 * @param pVCpu The cross context virtual CPU structure of the
574 * calling thread.
575 * @param pu8 Where to return the opcode byte.
576 */
577DECLINLINE(VBOXSTRICTRC) iemOpcodeGetFirstU8(PVMCPUCC pVCpu, uint8_t *pu8) RT_NOEXCEPT
578{
579 /*
580 * Check for hardware instruction breakpoints.
581 * Note! Guest breakpoints are only checked after POP SS or MOV SS on AMD CPUs.
582 */
583 if (RT_LIKELY(!(pVCpu->iem.s.fExec & IEM_F_PENDING_BRK_INSTR)))
584 { /* likely */ }
585 else
586 {
587 VBOXSTRICTRC rcStrict = DBGFBpCheckInstruction(pVCpu->CTX_SUFF(pVM), pVCpu,
588 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base,
589 !(pVCpu->cpum.GstCtx.rflags.uBoth & CPUMCTX_INHIBIT_SHADOW_SS)
590 || IEM_IS_GUEST_CPU_AMD(pVCpu));
591 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
592 { /* likely */ }
593 else
594 {
595 *pu8 = 0xff; /* shut up gcc. sigh */
596 if (rcStrict == VINF_EM_RAW_GUEST_TRAP)
597 return iemRaiseDebugException(pVCpu);
598 return rcStrict;
599 }
600 }
601
602 /*
603 * Fetch the first opcode byte.
604 */
605 uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
606 if (RT_LIKELY((uint8_t)offOpcode < pVCpu->iem.s.cbOpcode))
607 {
608 pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + 1;
609 *pu8 = pVCpu->iem.s.abOpcode[offOpcode];
610 return VINF_SUCCESS;
611 }
612 return iemOpcodeGetNextU8Slow(pVCpu, pu8);
613}
614
615# else /* IEM_WITH_SETJMP */
616
617/**
618 * Fetches the first opcode byte, longjmp on error.
619 *
620 * @returns The opcode byte.
621 * @param pVCpu The cross context virtual CPU structure of the calling thread.
622 */
623DECL_INLINE_THROW(uint8_t) iemOpcodeGetFirstU8Jmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP
624{
625 /*
626 * Check for hardware instruction breakpoints.
627 * Note! Guest breakpoints are only checked after POP SS or MOV SS on AMD CPUs.
628 */
629 if (RT_LIKELY(!(pVCpu->iem.s.fExec & IEM_F_PENDING_BRK_INSTR)))
630 { /* likely */ }
631 else
632 {
633 VBOXSTRICTRC rcStrict = DBGFBpCheckInstruction(pVCpu->CTX_SUFF(pVM), pVCpu,
634 pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base,
635 !(pVCpu->cpum.GstCtx.rflags.uBoth & CPUMCTX_INHIBIT_SHADOW_SS)
636 || IEM_IS_GUEST_CPU_AMD(pVCpu));
637 if (RT_LIKELY(rcStrict == VINF_SUCCESS))
638 { /* likely */ }
639 else
640 {
641 if (rcStrict == VINF_EM_RAW_GUEST_TRAP)
642 rcStrict = iemRaiseDebugException(pVCpu);
643 IEM_DO_LONGJMP(pVCpu, VBOXSTRICTRC_VAL(rcStrict));
644 }
645 }
646
647 /*
648 * Fetch the first opcode byte.
649 */
650# ifdef IEM_WITH_CODE_TLB
651 uint8_t bRet;
652 uintptr_t offBuf = pVCpu->iem.s.offInstrNextByte;
653 uint8_t const *pbBuf = pVCpu->iem.s.pbInstrBuf;
654 if (RT_LIKELY( pbBuf != NULL
655 && offBuf < pVCpu->iem.s.cbInstrBuf))
656 {
657 pVCpu->iem.s.offInstrNextByte = (uint32_t)offBuf + 1;
658 bRet = pbBuf[offBuf];
659 }
660 else
661 bRet = iemOpcodeGetNextU8SlowJmp(pVCpu);
662# ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
663 Assert(pVCpu->iem.s.offOpcode == 0);
664 pVCpu->iem.s.abOpcode[pVCpu->iem.s.offOpcode++] = bRet;
665# endif
666 return bRet;
667
668# else /* !IEM_WITH_CODE_TLB */
669 uintptr_t offOpcode = pVCpu->iem.s.offOpcode;
670 if (RT_LIKELY((uint8_t)offOpcode < pVCpu->iem.s.cbOpcode))
671 {
672 pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + 1;
673 return pVCpu->iem.s.abOpcode[offOpcode];
674 }
675 return iemOpcodeGetNextU8SlowJmp(pVCpu);
676# endif
677}
678
679# endif /* IEM_WITH_SETJMP */
680
681/**
682 * Fetches the first opcode byte, returns/throws automatically on failure.
683 *
684 * @param a_pu8 Where to return the opcode byte.
685 * @remark Implicitly references pVCpu.
686 */
687# ifndef IEM_WITH_SETJMP
688# define IEM_OPCODE_GET_FIRST_U8(a_pu8) \
689 do \
690 { \
691 VBOXSTRICTRC rcStrict2 = iemOpcodeGetFirstU8(pVCpu, (a_pu8)); \
692 if (rcStrict2 == VINF_SUCCESS) \
693 { /* likely */ } \
694 else \
695 return rcStrict2; \
696 } while (0)
697# else
698# define IEM_OPCODE_GET_FIRST_U8(a_pu8) (*(a_pu8) = iemOpcodeGetFirstU8Jmp(pVCpu))
699# endif /* IEM_WITH_SETJMP */
700
701
702# ifndef IEM_WITH_SETJMP
703
704/**
705 * Fetches the next opcode byte.
706 *
707 * @returns Strict VBox status code.
708 * @param pVCpu The cross context virtual CPU structure of the
709 * calling thread.
710 * @param pu8 Where to return the opcode byte.
711 */
712DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextU8(PVMCPUCC pVCpu, uint8_t *pu8) RT_NOEXCEPT
713{
714 uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
715 if (RT_LIKELY((uint8_t)offOpcode < pVCpu->iem.s.cbOpcode))
716 {
717 pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + 1;
718 *pu8 = pVCpu->iem.s.abOpcode[offOpcode];
719 return VINF_SUCCESS;
720 }
721 return iemOpcodeGetNextU8Slow(pVCpu, pu8);
722}
723
724# else /* IEM_WITH_SETJMP */
725
726/**
727 * Fetches the next opcode byte, longjmp on error.
728 *
729 * @returns The opcode byte.
730 * @param pVCpu The cross context virtual CPU structure of the calling thread.
731 */
732DECL_INLINE_THROW(uint8_t) iemOpcodeGetNextU8Jmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP
733{
734# ifdef IEM_WITH_CODE_TLB
735 uint8_t bRet;
736 uintptr_t offBuf = pVCpu->iem.s.offInstrNextByte;
737 uint8_t const *pbBuf = pVCpu->iem.s.pbInstrBuf;
738 if (RT_LIKELY( pbBuf != NULL
739 && offBuf < pVCpu->iem.s.cbInstrBuf))
740 {
741 pVCpu->iem.s.offInstrNextByte = (uint32_t)offBuf + 1;
742 bRet = pbBuf[offBuf];
743 }
744 else
745 bRet = iemOpcodeGetNextU8SlowJmp(pVCpu);
746# ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
747 Assert(pVCpu->iem.s.offOpcode < sizeof(pVCpu->iem.s.abOpcode));
748 pVCpu->iem.s.abOpcode[pVCpu->iem.s.offOpcode++] = bRet;
749# endif
750 return bRet;
751
752# else /* !IEM_WITH_CODE_TLB */
753 uintptr_t offOpcode = pVCpu->iem.s.offOpcode;
754 if (RT_LIKELY((uint8_t)offOpcode < pVCpu->iem.s.cbOpcode))
755 {
756 pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + 1;
757 return pVCpu->iem.s.abOpcode[offOpcode];
758 }
759 return iemOpcodeGetNextU8SlowJmp(pVCpu);
760# endif
761}
762
763# endif /* IEM_WITH_SETJMP */
764
765/**
766 * Fetches the next opcode byte, returns automatically on failure.
767 *
768 * @param a_pu8 Where to return the opcode byte.
769 * @remark Implicitly references pVCpu.
770 */
771# ifndef IEM_WITH_SETJMP
772# define IEM_OPCODE_GET_NEXT_U8(a_pu8) \
773 do \
774 { \
775 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextU8(pVCpu, (a_pu8)); \
776 if (rcStrict2 == VINF_SUCCESS) \
777 { /* likely */ } \
778 else \
779 return rcStrict2; \
780 } while (0)
781# else
782# define IEM_OPCODE_GET_NEXT_U8(a_pu8) (*(a_pu8) = iemOpcodeGetNextU8Jmp(pVCpu))
783# endif /* IEM_WITH_SETJMP */
784
785
786# ifndef IEM_WITH_SETJMP
787/**
788 * Fetches the next signed byte from the opcode stream.
789 *
790 * @returns Strict VBox status code.
791 * @param pVCpu The cross context virtual CPU structure of the calling thread.
792 * @param pi8 Where to return the signed byte.
793 */
794DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextS8(PVMCPUCC pVCpu, int8_t *pi8) RT_NOEXCEPT
795{
796 return iemOpcodeGetNextU8(pVCpu, (uint8_t *)pi8);
797}
798# endif /* !IEM_WITH_SETJMP */
799
800
801/**
802 * Fetches the next signed byte from the opcode stream, returning automatically
803 * on failure.
804 *
805 * @param a_pi8 Where to return the signed byte.
806 * @remark Implicitly references pVCpu.
807 */
808# ifndef IEM_WITH_SETJMP
809# define IEM_OPCODE_GET_NEXT_S8(a_pi8) \
810 do \
811 { \
812 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextS8(pVCpu, (a_pi8)); \
813 if (rcStrict2 != VINF_SUCCESS) \
814 return rcStrict2; \
815 } while (0)
816# else /* IEM_WITH_SETJMP */
817# define IEM_OPCODE_GET_NEXT_S8(a_pi8) (*(a_pi8) = (int8_t)iemOpcodeGetNextU8Jmp(pVCpu))
818
819# endif /* IEM_WITH_SETJMP */
820
821
822# ifndef IEM_WITH_SETJMP
823/**
824 * Fetches the next signed byte from the opcode stream, extending it to
825 * unsigned 16-bit.
826 *
827 * @returns Strict VBox status code.
828 * @param pVCpu The cross context virtual CPU structure of the calling thread.
829 * @param pu16 Where to return the unsigned word.
830 */
831DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextS8SxU16(PVMCPUCC pVCpu, uint16_t *pu16) RT_NOEXCEPT
832{
833 uint8_t const offOpcode = pVCpu->iem.s.offOpcode;
834 if (RT_UNLIKELY(offOpcode >= pVCpu->iem.s.cbOpcode))
835 return iemOpcodeGetNextS8SxU16Slow(pVCpu, pu16);
836
837 *pu16 = (uint16_t)(int16_t)(int8_t)pVCpu->iem.s.abOpcode[offOpcode];
838 pVCpu->iem.s.offOpcode = offOpcode + 1;
839 return VINF_SUCCESS;
840}
841# endif /* !IEM_WITH_SETJMP */
842
843/**
844 * Fetches the next signed byte from the opcode stream and sign-extending it to
845 * a word, returning automatically on failure.
846 *
847 * @param a_pu16 Where to return the word.
848 * @remark Implicitly references pVCpu.
849 */
850# ifndef IEM_WITH_SETJMP
851# define IEM_OPCODE_GET_NEXT_S8_SX_U16(a_pu16) \
852 do \
853 { \
854 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextS8SxU16(pVCpu, (a_pu16)); \
855 if (rcStrict2 != VINF_SUCCESS) \
856 return rcStrict2; \
857 } while (0)
858# else
859# define IEM_OPCODE_GET_NEXT_S8_SX_U16(a_pu16) (*(a_pu16) = (uint16_t)(int16_t)(int8_t)iemOpcodeGetNextU8Jmp(pVCpu))
860# endif
861
862# ifndef IEM_WITH_SETJMP
863/**
864 * Fetches the next signed byte from the opcode stream, extending it to
865 * unsigned 32-bit.
866 *
867 * @returns Strict VBox status code.
868 * @param pVCpu The cross context virtual CPU structure of the calling thread.
869 * @param pu32 Where to return the unsigned dword.
870 */
871DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextS8SxU32(PVMCPUCC pVCpu, uint32_t *pu32) RT_NOEXCEPT
872{
873 uint8_t const offOpcode = pVCpu->iem.s.offOpcode;
874 if (RT_UNLIKELY(offOpcode >= pVCpu->iem.s.cbOpcode))
875 return iemOpcodeGetNextS8SxU32Slow(pVCpu, pu32);
876
877 *pu32 = (uint32_t)(int32_t)(int8_t)pVCpu->iem.s.abOpcode[offOpcode];
878 pVCpu->iem.s.offOpcode = offOpcode + 1;
879 return VINF_SUCCESS;
880}
881# endif /* !IEM_WITH_SETJMP */
882
883/**
884 * Fetches the next signed byte from the opcode stream and sign-extending it to
885 * a word, returning automatically on failure.
886 *
887 * @param a_pu32 Where to return the word.
888 * @remark Implicitly references pVCpu.
889 */
890# ifndef IEM_WITH_SETJMP
891# define IEM_OPCODE_GET_NEXT_S8_SX_U32(a_pu32) \
892 do \
893 { \
894 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextS8SxU32(pVCpu, (a_pu32)); \
895 if (rcStrict2 != VINF_SUCCESS) \
896 return rcStrict2; \
897 } while (0)
898# else
899# define IEM_OPCODE_GET_NEXT_S8_SX_U32(a_pu32) (*(a_pu32) = (uint32_t)(int32_t)(int8_t)iemOpcodeGetNextU8Jmp(pVCpu))
900# endif
901
902
903# ifndef IEM_WITH_SETJMP
904/**
905 * Fetches the next signed byte from the opcode stream, extending it to
906 * unsigned 64-bit.
907 *
908 * @returns Strict VBox status code.
909 * @param pVCpu The cross context virtual CPU structure of the calling thread.
910 * @param pu64 Where to return the unsigned qword.
911 */
912DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextS8SxU64(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT
913{
914 uint8_t const offOpcode = pVCpu->iem.s.offOpcode;
915 if (RT_UNLIKELY(offOpcode >= pVCpu->iem.s.cbOpcode))
916 return iemOpcodeGetNextS8SxU64Slow(pVCpu, pu64);
917
918 *pu64 = (uint64_t)(int64_t)(int8_t)pVCpu->iem.s.abOpcode[offOpcode];
919 pVCpu->iem.s.offOpcode = offOpcode + 1;
920 return VINF_SUCCESS;
921}
922# endif /* !IEM_WITH_SETJMP */
923
924/**
925 * Fetches the next signed byte from the opcode stream and sign-extending it to
926 * a word, returning automatically on failure.
927 *
928 * @param a_pu64 Where to return the word.
929 * @remark Implicitly references pVCpu.
930 */
931# ifndef IEM_WITH_SETJMP
932# define IEM_OPCODE_GET_NEXT_S8_SX_U64(a_pu64) \
933 do \
934 { \
935 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextS8SxU64(pVCpu, (a_pu64)); \
936 if (rcStrict2 != VINF_SUCCESS) \
937 return rcStrict2; \
938 } while (0)
939# else
940# define IEM_OPCODE_GET_NEXT_S8_SX_U64(a_pu64) (*(a_pu64) = (uint64_t)(int64_t)(int8_t)iemOpcodeGetNextU8Jmp(pVCpu))
941# endif
942
943
944# ifndef IEM_WITH_SETJMP
945
946/**
947 * Fetches the next opcode word.
948 *
949 * @returns Strict VBox status code.
950 * @param pVCpu The cross context virtual CPU structure of the calling thread.
951 * @param pu16 Where to return the opcode word.
952 */
953DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextU16(PVMCPUCC pVCpu, uint16_t *pu16) RT_NOEXCEPT
954{
955 uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
956 if (RT_LIKELY((uint8_t)offOpcode + 2 <= pVCpu->iem.s.cbOpcode))
957 {
958 pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + 2;
959# ifdef IEM_USE_UNALIGNED_DATA_ACCESS
960 *pu16 = *(uint16_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
961# else
962 *pu16 = RT_MAKE_U16(pVCpu->iem.s.abOpcode[offOpcode], pVCpu->iem.s.abOpcode[offOpcode + 1]);
963# endif
964 return VINF_SUCCESS;
965 }
966 return iemOpcodeGetNextU16Slow(pVCpu, pu16);
967}
968
969# else /* IEM_WITH_SETJMP */
970
971/**
972 * Fetches the next opcode word, longjmp on error.
973 *
974 * @returns The opcode word.
975 * @param pVCpu The cross context virtual CPU structure of the calling thread.
976 */
977DECL_INLINE_THROW(uint16_t) iemOpcodeGetNextU16Jmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP
978{
979# ifdef IEM_WITH_CODE_TLB
980 uint16_t u16Ret;
981 uintptr_t offBuf = pVCpu->iem.s.offInstrNextByte;
982 uint8_t const *pbBuf = pVCpu->iem.s.pbInstrBuf;
983 if (RT_LIKELY( pbBuf != NULL
984 && offBuf + 2 <= pVCpu->iem.s.cbInstrBuf))
985 {
986 pVCpu->iem.s.offInstrNextByte = (uint32_t)offBuf + 2;
987# ifdef IEM_USE_UNALIGNED_DATA_ACCESS
988 u16Ret = *(uint16_t const *)&pbBuf[offBuf];
989# else
990 u16Ret = RT_MAKE_U16(pbBuf[offBuf], pbBuf[offBuf + 1]);
991# endif
992 }
993 else
994 u16Ret = iemOpcodeGetNextU16SlowJmp(pVCpu);
995
996# ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
997 uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
998 Assert(offOpcode + 1 < sizeof(pVCpu->iem.s.abOpcode));
999# ifdef IEM_USE_UNALIGNED_DATA_ACCESS
1000 *(uint16_t *)&pVCpu->iem.s.abOpcode[offOpcode] = u16Ret;
1001# else
1002 pVCpu->iem.s.abOpcode[offOpcode] = RT_LO_U8(u16Ret);
1003 pVCpu->iem.s.abOpcode[offOpcode + 1] = RT_HI_U8(u16Ret);
1004# endif
1005 pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + (uint8_t)2;
1006# endif
1007
1008 return u16Ret;
1009
1010# else /* !IEM_WITH_CODE_TLB */
1011 uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
1012 if (RT_LIKELY((uint8_t)offOpcode + 2 <= pVCpu->iem.s.cbOpcode))
1013 {
1014 pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + 2;
1015# ifdef IEM_USE_UNALIGNED_DATA_ACCESS
1016 return *(uint16_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
1017# else
1018 return RT_MAKE_U16(pVCpu->iem.s.abOpcode[offOpcode], pVCpu->iem.s.abOpcode[offOpcode + 1]);
1019# endif
1020 }
1021 return iemOpcodeGetNextU16SlowJmp(pVCpu);
1022# endif /* !IEM_WITH_CODE_TLB */
1023}
1024
1025# endif /* IEM_WITH_SETJMP */
1026
1027/**
1028 * Fetches the next opcode word, returns automatically on failure.
1029 *
1030 * @param a_pu16 Where to return the opcode word.
1031 * @remark Implicitly references pVCpu.
1032 */
1033# ifndef IEM_WITH_SETJMP
1034# define IEM_OPCODE_GET_NEXT_U16(a_pu16) \
1035 do \
1036 { \
1037 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextU16(pVCpu, (a_pu16)); \
1038 if (rcStrict2 != VINF_SUCCESS) \
1039 return rcStrict2; \
1040 } while (0)
1041# else
1042# define IEM_OPCODE_GET_NEXT_U16(a_pu16) (*(a_pu16) = iemOpcodeGetNextU16Jmp(pVCpu))
1043# endif
1044
1045# ifndef IEM_WITH_SETJMP
1046/**
1047 * Fetches the next opcode word, zero extending it to a double word.
1048 *
1049 * @returns Strict VBox status code.
1050 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1051 * @param pu32 Where to return the opcode double word.
1052 */
1053DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextU16ZxU32(PVMCPUCC pVCpu, uint32_t *pu32) RT_NOEXCEPT
1054{
1055 uint8_t const offOpcode = pVCpu->iem.s.offOpcode;
1056 if (RT_UNLIKELY(offOpcode + 2 > pVCpu->iem.s.cbOpcode))
1057 return iemOpcodeGetNextU16ZxU32Slow(pVCpu, pu32);
1058
1059 *pu32 = RT_MAKE_U16(pVCpu->iem.s.abOpcode[offOpcode], pVCpu->iem.s.abOpcode[offOpcode + 1]);
1060 pVCpu->iem.s.offOpcode = offOpcode + 2;
1061 return VINF_SUCCESS;
1062}
1063# endif /* !IEM_WITH_SETJMP */
1064
1065/**
1066 * Fetches the next opcode word and zero extends it to a double word, returns
1067 * automatically on failure.
1068 *
1069 * @param a_pu32 Where to return the opcode double word.
1070 * @remark Implicitly references pVCpu.
1071 */
1072# ifndef IEM_WITH_SETJMP
1073# define IEM_OPCODE_GET_NEXT_U16_ZX_U32(a_pu32) \
1074 do \
1075 { \
1076 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextU16ZxU32(pVCpu, (a_pu32)); \
1077 if (rcStrict2 != VINF_SUCCESS) \
1078 return rcStrict2; \
1079 } while (0)
1080# else
1081# define IEM_OPCODE_GET_NEXT_U16_ZX_U32(a_pu32) (*(a_pu32) = iemOpcodeGetNextU16Jmp(pVCpu))
1082# endif
1083
1084# ifndef IEM_WITH_SETJMP
1085/**
1086 * Fetches the next opcode word, zero extending it to a quad word.
1087 *
1088 * @returns Strict VBox status code.
1089 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1090 * @param pu64 Where to return the opcode quad word.
1091 */
1092DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextU16ZxU64(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT
1093{
1094 uint8_t const offOpcode = pVCpu->iem.s.offOpcode;
1095 if (RT_UNLIKELY(offOpcode + 2 > pVCpu->iem.s.cbOpcode))
1096 return iemOpcodeGetNextU16ZxU64Slow(pVCpu, pu64);
1097
1098 *pu64 = RT_MAKE_U16(pVCpu->iem.s.abOpcode[offOpcode], pVCpu->iem.s.abOpcode[offOpcode + 1]);
1099 pVCpu->iem.s.offOpcode = offOpcode + 2;
1100 return VINF_SUCCESS;
1101}
1102# endif /* !IEM_WITH_SETJMP */
1103
1104/**
1105 * Fetches the next opcode word and zero extends it to a quad word, returns
1106 * automatically on failure.
1107 *
1108 * @param a_pu64 Where to return the opcode quad word.
1109 * @remark Implicitly references pVCpu.
1110 */
1111# ifndef IEM_WITH_SETJMP
1112# define IEM_OPCODE_GET_NEXT_U16_ZX_U64(a_pu64) \
1113 do \
1114 { \
1115 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextU16ZxU64(pVCpu, (a_pu64)); \
1116 if (rcStrict2 != VINF_SUCCESS) \
1117 return rcStrict2; \
1118 } while (0)
1119# else
1120# define IEM_OPCODE_GET_NEXT_U16_ZX_U64(a_pu64) (*(a_pu64) = iemOpcodeGetNextU16Jmp(pVCpu))
1121# endif
1122
1123
1124# ifndef IEM_WITH_SETJMP
1125/**
1126 * Fetches the next signed word from the opcode stream.
1127 *
1128 * @returns Strict VBox status code.
1129 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1130 * @param pi16 Where to return the signed word.
1131 */
1132DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextS16(PVMCPUCC pVCpu, int16_t *pi16) RT_NOEXCEPT
1133{
1134 return iemOpcodeGetNextU16(pVCpu, (uint16_t *)pi16);
1135}
1136# endif /* !IEM_WITH_SETJMP */
1137
1138
1139/**
1140 * Fetches the next signed word from the opcode stream, returning automatically
1141 * on failure.
1142 *
1143 * @param a_pi16 Where to return the signed word.
1144 * @remark Implicitly references pVCpu.
1145 */
1146# ifndef IEM_WITH_SETJMP
1147# define IEM_OPCODE_GET_NEXT_S16(a_pi16) \
1148 do \
1149 { \
1150 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextS16(pVCpu, (a_pi16)); \
1151 if (rcStrict2 != VINF_SUCCESS) \
1152 return rcStrict2; \
1153 } while (0)
1154# else
1155# define IEM_OPCODE_GET_NEXT_S16(a_pi16) (*(a_pi16) = (int16_t)iemOpcodeGetNextU16Jmp(pVCpu))
1156# endif
1157
1158# ifndef IEM_WITH_SETJMP
1159
1160/**
1161 * Fetches the next opcode dword.
1162 *
1163 * @returns Strict VBox status code.
1164 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1165 * @param pu32 Where to return the opcode double word.
1166 */
1167DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextU32(PVMCPUCC pVCpu, uint32_t *pu32) RT_NOEXCEPT
1168{
1169 uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
1170 if (RT_LIKELY((uint8_t)offOpcode + 4 <= pVCpu->iem.s.cbOpcode))
1171 {
1172 pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + 4;
1173# ifdef IEM_USE_UNALIGNED_DATA_ACCESS
1174 *pu32 = *(uint32_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
1175# else
1176 *pu32 = RT_MAKE_U32_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
1177 pVCpu->iem.s.abOpcode[offOpcode + 1],
1178 pVCpu->iem.s.abOpcode[offOpcode + 2],
1179 pVCpu->iem.s.abOpcode[offOpcode + 3]);
1180# endif
1181 return VINF_SUCCESS;
1182 }
1183 return iemOpcodeGetNextU32Slow(pVCpu, pu32);
1184}
1185
1186# else /* IEM_WITH_SETJMP */
1187
1188/**
1189 * Fetches the next opcode dword, longjmp on error.
1190 *
1191 * @returns The opcode dword.
1192 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1193 */
1194DECL_INLINE_THROW(uint32_t) iemOpcodeGetNextU32Jmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP
1195{
1196# ifdef IEM_WITH_CODE_TLB
1197 uint32_t u32Ret;
1198 uintptr_t offBuf = pVCpu->iem.s.offInstrNextByte;
1199 uint8_t const *pbBuf = pVCpu->iem.s.pbInstrBuf;
1200 if (RT_LIKELY( pbBuf != NULL
1201 && offBuf + 4 <= pVCpu->iem.s.cbInstrBuf))
1202 {
1203 pVCpu->iem.s.offInstrNextByte = (uint32_t)offBuf + 4;
1204# ifdef IEM_USE_UNALIGNED_DATA_ACCESS
1205 u32Ret = *(uint32_t const *)&pbBuf[offBuf];
1206# else
1207 u32Ret = RT_MAKE_U32_FROM_U8(pbBuf[offBuf],
1208 pbBuf[offBuf + 1],
1209 pbBuf[offBuf + 2],
1210 pbBuf[offBuf + 3]);
1211# endif
1212 }
1213 else
1214 u32Ret = iemOpcodeGetNextU32SlowJmp(pVCpu);
1215
1216# ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
1217 uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
1218 Assert(offOpcode + 3 < sizeof(pVCpu->iem.s.abOpcode));
1219# ifdef IEM_USE_UNALIGNED_DATA_ACCESS
1220 *(uint32_t *)&pVCpu->iem.s.abOpcode[offOpcode] = u32Ret;
1221# else
1222 pVCpu->iem.s.abOpcode[offOpcode] = RT_BYTE1(u32Ret);
1223 pVCpu->iem.s.abOpcode[offOpcode + 1] = RT_BYTE2(u32Ret);
1224 pVCpu->iem.s.abOpcode[offOpcode + 2] = RT_BYTE3(u32Ret);
1225 pVCpu->iem.s.abOpcode[offOpcode + 3] = RT_BYTE4(u32Ret);
1226# endif
1227 pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + (uint8_t)4;
1228# endif /* IEM_WITH_CODE_TLB_AND_OPCODE_BUF */
1229
1230 return u32Ret;
1231
1232# else /* !IEM_WITH_CODE_TLB */
1233 uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
1234 if (RT_LIKELY((uint8_t)offOpcode + 4 <= pVCpu->iem.s.cbOpcode))
1235 {
1236 pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + 4;
1237# ifdef IEM_USE_UNALIGNED_DATA_ACCESS
1238 return *(uint32_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
1239# else
1240 return RT_MAKE_U32_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
1241 pVCpu->iem.s.abOpcode[offOpcode + 1],
1242 pVCpu->iem.s.abOpcode[offOpcode + 2],
1243 pVCpu->iem.s.abOpcode[offOpcode + 3]);
1244# endif
1245 }
1246 return iemOpcodeGetNextU32SlowJmp(pVCpu);
1247# endif
1248}
1249
1250# endif /* IEM_WITH_SETJMP */
1251
1252/**
1253 * Fetches the next opcode dword, returns automatically on failure.
1254 *
1255 * @param a_pu32 Where to return the opcode dword.
1256 * @remark Implicitly references pVCpu.
1257 */
1258# ifndef IEM_WITH_SETJMP
1259# define IEM_OPCODE_GET_NEXT_U32(a_pu32) \
1260 do \
1261 { \
1262 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextU32(pVCpu, (a_pu32)); \
1263 if (rcStrict2 != VINF_SUCCESS) \
1264 return rcStrict2; \
1265 } while (0)
1266# else
1267# define IEM_OPCODE_GET_NEXT_U32(a_pu32) (*(a_pu32) = iemOpcodeGetNextU32Jmp(pVCpu))
1268# endif
1269
1270# ifndef IEM_WITH_SETJMP
1271/**
1272 * Fetches the next opcode dword, zero extending it to a quad word.
1273 *
1274 * @returns Strict VBox status code.
1275 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1276 * @param pu64 Where to return the opcode quad word.
1277 */
1278DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextU32ZxU64(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT
1279{
1280 uint8_t const offOpcode = pVCpu->iem.s.offOpcode;
1281 if (RT_UNLIKELY(offOpcode + 4 > pVCpu->iem.s.cbOpcode))
1282 return iemOpcodeGetNextU32ZxU64Slow(pVCpu, pu64);
1283
1284 *pu64 = RT_MAKE_U32_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
1285 pVCpu->iem.s.abOpcode[offOpcode + 1],
1286 pVCpu->iem.s.abOpcode[offOpcode + 2],
1287 pVCpu->iem.s.abOpcode[offOpcode + 3]);
1288 pVCpu->iem.s.offOpcode = offOpcode + 4;
1289 return VINF_SUCCESS;
1290}
1291# endif /* !IEM_WITH_SETJMP */
1292
1293/**
1294 * Fetches the next opcode dword and zero extends it to a quad word, returns
1295 * automatically on failure.
1296 *
1297 * @param a_pu64 Where to return the opcode quad word.
1298 * @remark Implicitly references pVCpu.
1299 */
1300# ifndef IEM_WITH_SETJMP
1301# define IEM_OPCODE_GET_NEXT_U32_ZX_U64(a_pu64) \
1302 do \
1303 { \
1304 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextU32ZxU64(pVCpu, (a_pu64)); \
1305 if (rcStrict2 != VINF_SUCCESS) \
1306 return rcStrict2; \
1307 } while (0)
1308# else
1309# define IEM_OPCODE_GET_NEXT_U32_ZX_U64(a_pu64) (*(a_pu64) = iemOpcodeGetNextU32Jmp(pVCpu))
1310# endif
1311
1312
1313# ifndef IEM_WITH_SETJMP
1314/**
1315 * Fetches the next signed double word from the opcode stream.
1316 *
1317 * @returns Strict VBox status code.
1318 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1319 * @param pi32 Where to return the signed double word.
1320 */
1321DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextS32(PVMCPUCC pVCpu, int32_t *pi32) RT_NOEXCEPT
1322{
1323 return iemOpcodeGetNextU32(pVCpu, (uint32_t *)pi32);
1324}
1325# endif
1326
1327/**
1328 * Fetches the next signed double word from the opcode stream, returning
1329 * automatically on failure.
1330 *
1331 * @param a_pi32 Where to return the signed double word.
1332 * @remark Implicitly references pVCpu.
1333 */
1334# ifndef IEM_WITH_SETJMP
1335# define IEM_OPCODE_GET_NEXT_S32(a_pi32) \
1336 do \
1337 { \
1338 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextS32(pVCpu, (a_pi32)); \
1339 if (rcStrict2 != VINF_SUCCESS) \
1340 return rcStrict2; \
1341 } while (0)
1342# else
1343# define IEM_OPCODE_GET_NEXT_S32(a_pi32) (*(a_pi32) = (int32_t)iemOpcodeGetNextU32Jmp(pVCpu))
1344# endif
1345
1346# ifndef IEM_WITH_SETJMP
1347/**
1348 * Fetches the next opcode dword, sign extending it into a quad word.
1349 *
1350 * @returns Strict VBox status code.
1351 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1352 * @param pu64 Where to return the opcode quad word.
1353 */
1354DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextS32SxU64(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT
1355{
1356 uint8_t const offOpcode = pVCpu->iem.s.offOpcode;
1357 if (RT_UNLIKELY(offOpcode + 4 > pVCpu->iem.s.cbOpcode))
1358 return iemOpcodeGetNextS32SxU64Slow(pVCpu, pu64);
1359
1360 int32_t i32 = RT_MAKE_U32_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
1361 pVCpu->iem.s.abOpcode[offOpcode + 1],
1362 pVCpu->iem.s.abOpcode[offOpcode + 2],
1363 pVCpu->iem.s.abOpcode[offOpcode + 3]);
1364 *pu64 = (uint64_t)(int64_t)i32;
1365 pVCpu->iem.s.offOpcode = offOpcode + 4;
1366 return VINF_SUCCESS;
1367}
1368# endif /* !IEM_WITH_SETJMP */
1369
1370/**
1371 * Fetches the next opcode double word and sign extends it to a quad word,
1372 * returns automatically on failure.
1373 *
1374 * @param a_pu64 Where to return the opcode quad word.
1375 * @remark Implicitly references pVCpu.
1376 */
1377# ifndef IEM_WITH_SETJMP
1378# define IEM_OPCODE_GET_NEXT_S32_SX_U64(a_pu64) \
1379 do \
1380 { \
1381 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextS32SxU64(pVCpu, (a_pu64)); \
1382 if (rcStrict2 != VINF_SUCCESS) \
1383 return rcStrict2; \
1384 } while (0)
1385# else
1386# define IEM_OPCODE_GET_NEXT_S32_SX_U64(a_pu64) (*(a_pu64) = (uint64_t)(int64_t)(int32_t)iemOpcodeGetNextU32Jmp(pVCpu))
1387# endif
1388
1389# ifndef IEM_WITH_SETJMP
1390
1391/**
1392 * Fetches the next opcode qword.
1393 *
1394 * @returns Strict VBox status code.
1395 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1396 * @param pu64 Where to return the opcode qword.
1397 */
1398DECLINLINE(VBOXSTRICTRC) iemOpcodeGetNextU64(PVMCPUCC pVCpu, uint64_t *pu64) RT_NOEXCEPT
1399{
1400 uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
1401 if (RT_LIKELY((uint8_t)offOpcode + 8 <= pVCpu->iem.s.cbOpcode))
1402 {
1403# ifdef IEM_USE_UNALIGNED_DATA_ACCESS
1404 *pu64 = *(uint64_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
1405# else
1406 *pu64 = RT_MAKE_U64_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
1407 pVCpu->iem.s.abOpcode[offOpcode + 1],
1408 pVCpu->iem.s.abOpcode[offOpcode + 2],
1409 pVCpu->iem.s.abOpcode[offOpcode + 3],
1410 pVCpu->iem.s.abOpcode[offOpcode + 4],
1411 pVCpu->iem.s.abOpcode[offOpcode + 5],
1412 pVCpu->iem.s.abOpcode[offOpcode + 6],
1413 pVCpu->iem.s.abOpcode[offOpcode + 7]);
1414# endif
1415 pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + 8;
1416 return VINF_SUCCESS;
1417 }
1418 return iemOpcodeGetNextU64Slow(pVCpu, pu64);
1419}
1420
1421# else /* IEM_WITH_SETJMP */
1422
1423/**
1424 * Fetches the next opcode qword, longjmp on error.
1425 *
1426 * @returns The opcode qword.
1427 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1428 */
1429DECL_INLINE_THROW(uint64_t) iemOpcodeGetNextU64Jmp(PVMCPUCC pVCpu) IEM_NOEXCEPT_MAY_LONGJMP
1430{
1431# ifdef IEM_WITH_CODE_TLB
1432 uint64_t u64Ret;
1433 uintptr_t offBuf = pVCpu->iem.s.offInstrNextByte;
1434 uint8_t const *pbBuf = pVCpu->iem.s.pbInstrBuf;
1435 if (RT_LIKELY( pbBuf != NULL
1436 && offBuf + 8 <= pVCpu->iem.s.cbInstrBuf))
1437 {
1438 pVCpu->iem.s.offInstrNextByte = (uint32_t)offBuf + 8;
1439# ifdef IEM_USE_UNALIGNED_DATA_ACCESS
1440 u64Ret = *(uint64_t const *)&pbBuf[offBuf];
1441# else
1442 u64Ret = RT_MAKE_U64_FROM_U8(pbBuf[offBuf],
1443 pbBuf[offBuf + 1],
1444 pbBuf[offBuf + 2],
1445 pbBuf[offBuf + 3],
1446 pbBuf[offBuf + 4],
1447 pbBuf[offBuf + 5],
1448 pbBuf[offBuf + 6],
1449 pbBuf[offBuf + 7]);
1450# endif
1451 }
1452 else
1453 u64Ret = iemOpcodeGetNextU64SlowJmp(pVCpu);
1454
1455# ifdef IEM_WITH_CODE_TLB_AND_OPCODE_BUF
1456 uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
1457 Assert(offOpcode + 7 < sizeof(pVCpu->iem.s.abOpcode));
1458# ifdef IEM_USE_UNALIGNED_DATA_ACCESS
1459 *(uint64_t *)&pVCpu->iem.s.abOpcode[offOpcode] = u64Ret;
1460# else
1461 pVCpu->iem.s.abOpcode[offOpcode] = RT_BYTE1(u64Ret);
1462 pVCpu->iem.s.abOpcode[offOpcode + 1] = RT_BYTE2(u64Ret);
1463 pVCpu->iem.s.abOpcode[offOpcode + 2] = RT_BYTE3(u64Ret);
1464 pVCpu->iem.s.abOpcode[offOpcode + 3] = RT_BYTE4(u64Ret);
1465 pVCpu->iem.s.abOpcode[offOpcode + 4] = RT_BYTE5(u64Ret);
1466 pVCpu->iem.s.abOpcode[offOpcode + 5] = RT_BYTE6(u64Ret);
1467 pVCpu->iem.s.abOpcode[offOpcode + 6] = RT_BYTE7(u64Ret);
1468 pVCpu->iem.s.abOpcode[offOpcode + 7] = RT_BYTE8(u64Ret);
1469# endif
1470 pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + (uint8_t)8;
1471# endif /* IEM_WITH_CODE_TLB_AND_OPCODE_BUF */
1472
1473 return u64Ret;
1474
1475# else /* !IEM_WITH_CODE_TLB */
1476 uintptr_t const offOpcode = pVCpu->iem.s.offOpcode;
1477 if (RT_LIKELY((uint8_t)offOpcode + 8 <= pVCpu->iem.s.cbOpcode))
1478 {
1479 pVCpu->iem.s.offOpcode = (uint8_t)offOpcode + 8;
1480# ifdef IEM_USE_UNALIGNED_DATA_ACCESS
1481 return *(uint64_t const *)&pVCpu->iem.s.abOpcode[offOpcode];
1482# else
1483 return RT_MAKE_U64_FROM_U8(pVCpu->iem.s.abOpcode[offOpcode],
1484 pVCpu->iem.s.abOpcode[offOpcode + 1],
1485 pVCpu->iem.s.abOpcode[offOpcode + 2],
1486 pVCpu->iem.s.abOpcode[offOpcode + 3],
1487 pVCpu->iem.s.abOpcode[offOpcode + 4],
1488 pVCpu->iem.s.abOpcode[offOpcode + 5],
1489 pVCpu->iem.s.abOpcode[offOpcode + 6],
1490 pVCpu->iem.s.abOpcode[offOpcode + 7]);
1491# endif
1492 }
1493 return iemOpcodeGetNextU64SlowJmp(pVCpu);
1494# endif /* !IEM_WITH_CODE_TLB */
1495}
1496
1497# endif /* IEM_WITH_SETJMP */
1498
1499/**
1500 * Fetches the next opcode quad word, returns automatically on failure.
1501 *
1502 * @param a_pu64 Where to return the opcode quad word.
1503 * @remark Implicitly references pVCpu.
1504 */
1505# ifndef IEM_WITH_SETJMP
1506# define IEM_OPCODE_GET_NEXT_U64(a_pu64) \
1507 do \
1508 { \
1509 VBOXSTRICTRC rcStrict2 = iemOpcodeGetNextU64(pVCpu, (a_pu64)); \
1510 if (rcStrict2 != VINF_SUCCESS) \
1511 return rcStrict2; \
1512 } while (0)
1513# else
1514# define IEM_OPCODE_GET_NEXT_U64(a_pu64) ( *(a_pu64) = iemOpcodeGetNextU64Jmp(pVCpu) )
1515# endif
1516
1517/**
1518 * For fetching the opcode bytes for an ModR/M effective address, but throw
1519 * away the result.
1520 *
1521 * This is used when decoding undefined opcodes and such where we want to avoid
1522 * unnecessary MC blocks.
1523 *
1524 * @note The recompiler code overrides this one so iemOpHlpCalcRmEffAddrJmpEx is
1525 * used instead. At least for now...
1526 */
1527# ifndef IEM_WITH_SETJMP
1528# define IEM_OPCODE_SKIP_RM_EFF_ADDR_BYTES(a_bRm) do { \
1529 RTGCPTR GCPtrEff; \
1530 VBOXSTRICTRC rcStrict = iemOpHlpCalcRmEffAddr(pVCpu, bRm, 0, &GCPtrEff); \
1531 if (rcStrict != VINF_SUCCESS) \
1532 return rcStrict; \
1533 } while (0)
1534# else
1535# define IEM_OPCODE_SKIP_RM_EFF_ADDR_BYTES(a_bRm) do { \
1536 (void)iemOpHlpCalcRmEffAddrJmp(pVCpu, bRm, 0); \
1537 } while (0)
1538# endif
1539
1540#endif /* !IEM_WITH_OPAQUE_DECODER_STATE */
1541
1542
1543/** @name Misc Worker Functions.
1544 * @{
1545 */
1546
1547/**
1548 * Gets the correct EFLAGS regardless of whether PATM stores parts of them or
1549 * not (kind of obsolete now).
1550 *
1551 * @param a_pVCpu The cross context virtual CPU structure of the calling thread.
1552 */
1553#define IEMMISC_GET_EFL(a_pVCpu) ( (a_pVCpu)->cpum.GstCtx.eflags.u )
1554
1555/**
1556 * Updates the EFLAGS in the correct manner wrt. PATM (kind of obsolete).
1557 *
1558 * @param a_pVCpu The cross context virtual CPU structure of the calling thread.
1559 * @param a_fEfl The new EFLAGS.
1560 */
1561#define IEMMISC_SET_EFL(a_pVCpu, a_fEfl) do { (a_pVCpu)->cpum.GstCtx.eflags.u = (a_fEfl); } while (0)
1562
1563
1564/**
1565 * Loads a NULL data selector into a selector register, both the hidden and
1566 * visible parts, in protected mode.
1567 *
1568 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1569 * @param pSReg Pointer to the segment register.
1570 * @param uRpl The RPL.
1571 */
1572DECLINLINE(void) iemHlpLoadNullDataSelectorProt(PVMCPUCC pVCpu, PCPUMSELREG pSReg, RTSEL uRpl) RT_NOEXCEPT
1573{
1574 /** @todo Testcase: write a testcase checking what happends when loading a NULL
1575 * data selector in protected mode. */
1576 pSReg->Sel = uRpl;
1577 pSReg->ValidSel = uRpl;
1578 pSReg->fFlags = CPUMSELREG_FLAGS_VALID;
1579 if (IEM_IS_GUEST_CPU_INTEL(pVCpu))
1580 {
1581 /* VT-x (Intel 3960x) observed doing something like this. */
1582 pSReg->Attr.u = X86DESCATTR_UNUSABLE | X86DESCATTR_G | X86DESCATTR_D | (IEM_GET_CPL(pVCpu) << X86DESCATTR_DPL_SHIFT);
1583 pSReg->u32Limit = UINT32_MAX;
1584 pSReg->u64Base = 0;
1585 }
1586 else
1587 {
1588 pSReg->Attr.u = X86DESCATTR_UNUSABLE;
1589 pSReg->u32Limit = 0;
1590 pSReg->u64Base = 0;
1591 }
1592}
1593
1594/** @} */
1595
1596
1597/*
1598 *
1599 * Helpers routines.
1600 * Helpers routines.
1601 * Helpers routines.
1602 *
1603 */
1604
1605#ifndef IEM_WITH_OPAQUE_DECODER_STATE
1606
1607/**
1608 * Recalculates the effective operand size.
1609 *
1610 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1611 */
1612DECLINLINE(void) iemRecalEffOpSize(PVMCPUCC pVCpu) RT_NOEXCEPT
1613{
1614 switch (IEM_GET_CPU_MODE(pVCpu))
1615 {
1616 case IEMMODE_16BIT:
1617 pVCpu->iem.s.enmEffOpSize = pVCpu->iem.s.fPrefixes & IEM_OP_PRF_SIZE_OP ? IEMMODE_32BIT : IEMMODE_16BIT;
1618 break;
1619 case IEMMODE_32BIT:
1620 pVCpu->iem.s.enmEffOpSize = pVCpu->iem.s.fPrefixes & IEM_OP_PRF_SIZE_OP ? IEMMODE_16BIT : IEMMODE_32BIT;
1621 break;
1622 case IEMMODE_64BIT:
1623 switch (pVCpu->iem.s.fPrefixes & (IEM_OP_PRF_SIZE_REX_W | IEM_OP_PRF_SIZE_OP))
1624 {
1625 case 0:
1626 pVCpu->iem.s.enmEffOpSize = pVCpu->iem.s.enmDefOpSize;
1627 break;
1628 case IEM_OP_PRF_SIZE_OP:
1629 pVCpu->iem.s.enmEffOpSize = IEMMODE_16BIT;
1630 break;
1631 case IEM_OP_PRF_SIZE_REX_W:
1632 case IEM_OP_PRF_SIZE_REX_W | IEM_OP_PRF_SIZE_OP:
1633 pVCpu->iem.s.enmEffOpSize = IEMMODE_64BIT;
1634 break;
1635 }
1636 break;
1637 default:
1638 AssertFailed();
1639 }
1640}
1641
1642
1643/**
1644 * Sets the default operand size to 64-bit and recalculates the effective
1645 * operand size.
1646 *
1647 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1648 */
1649DECLINLINE(void) iemRecalEffOpSize64Default(PVMCPUCC pVCpu) RT_NOEXCEPT
1650{
1651 Assert(IEM_IS_64BIT_CODE(pVCpu));
1652 pVCpu->iem.s.enmDefOpSize = IEMMODE_64BIT;
1653 if ((pVCpu->iem.s.fPrefixes & (IEM_OP_PRF_SIZE_REX_W | IEM_OP_PRF_SIZE_OP)) != IEM_OP_PRF_SIZE_OP)
1654 pVCpu->iem.s.enmEffOpSize = IEMMODE_64BIT;
1655 else
1656 pVCpu->iem.s.enmEffOpSize = IEMMODE_16BIT;
1657}
1658
1659
1660/**
1661 * Sets the default operand size to 64-bit and recalculates the effective
1662 * operand size, with intel ignoring any operand size prefix (AMD respects it).
1663 *
1664 * This is for the relative jumps.
1665 *
1666 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1667 */
1668DECLINLINE(void) iemRecalEffOpSize64DefaultAndIntelIgnoresOpSizePrefix(PVMCPUCC pVCpu) RT_NOEXCEPT
1669{
1670 Assert(IEM_IS_64BIT_CODE(pVCpu));
1671 pVCpu->iem.s.enmDefOpSize = IEMMODE_64BIT;
1672 if ( (pVCpu->iem.s.fPrefixes & (IEM_OP_PRF_SIZE_REX_W | IEM_OP_PRF_SIZE_OP)) != IEM_OP_PRF_SIZE_OP
1673 || pVCpu->iem.s.enmCpuVendor == CPUMCPUVENDOR_INTEL)
1674 pVCpu->iem.s.enmEffOpSize = IEMMODE_64BIT;
1675 else
1676 pVCpu->iem.s.enmEffOpSize = IEMMODE_16BIT;
1677}
1678
1679#endif /* !IEM_WITH_OPAQUE_DECODER_STATE */
1680
1681
1682
1683/** @name Register Access.
1684 * @{
1685 */
1686
1687/**
1688 * Gets a reference (pointer) to the specified hidden segment register.
1689 *
1690 * @returns Hidden register reference.
1691 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1692 * @param iSegReg The segment register.
1693 */
1694DECL_FORCE_INLINE(PCPUMSELREG) iemSRegGetHid(PVMCPUCC pVCpu, uint8_t iSegReg) RT_NOEXCEPT
1695{
1696 Assert(iSegReg < X86_SREG_COUNT);
1697 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SREG_FROM_IDX(iSegReg));
1698 PCPUMSELREG pSReg = &pVCpu->cpum.GstCtx.aSRegs[iSegReg];
1699
1700 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg));
1701 return pSReg;
1702}
1703
1704
1705/**
1706 * Ensures that the given hidden segment register is up to date.
1707 *
1708 * @returns Hidden register reference.
1709 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1710 * @param pSReg The segment register.
1711 */
1712DECL_FORCE_INLINE(PCPUMSELREG) iemSRegUpdateHid(PVMCPUCC pVCpu, PCPUMSELREG pSReg) RT_NOEXCEPT
1713{
1714 Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pSReg));
1715 NOREF(pVCpu);
1716 return pSReg;
1717}
1718
1719
1720/**
1721 * Gets a reference (pointer) to the specified segment register (the selector
1722 * value).
1723 *
1724 * @returns Pointer to the selector variable.
1725 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1726 * @param iSegReg The segment register.
1727 */
1728DECL_FORCE_INLINE(uint16_t *) iemSRegRef(PVMCPUCC pVCpu, uint8_t iSegReg) RT_NOEXCEPT
1729{
1730 Assert(iSegReg < X86_SREG_COUNT);
1731 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SREG_FROM_IDX(iSegReg));
1732 return &pVCpu->cpum.GstCtx.aSRegs[iSegReg].Sel;
1733}
1734
1735
1736/**
1737 * Fetches the selector value of a segment register.
1738 *
1739 * @returns The selector value.
1740 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1741 * @param iSegReg The segment register.
1742 */
1743DECL_FORCE_INLINE(uint16_t) iemSRegFetchU16(PVMCPUCC pVCpu, uint8_t iSegReg) RT_NOEXCEPT
1744{
1745 Assert(iSegReg < X86_SREG_COUNT);
1746 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SREG_FROM_IDX(iSegReg));
1747 return pVCpu->cpum.GstCtx.aSRegs[iSegReg].Sel;
1748}
1749
1750
1751/**
1752 * Fetches the base address value of a segment register.
1753 *
1754 * @returns The selector value.
1755 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1756 * @param iSegReg The segment register.
1757 */
1758DECL_FORCE_INLINE(uint64_t) iemSRegBaseFetchU64(PVMCPUCC pVCpu, uint8_t iSegReg) RT_NOEXCEPT
1759{
1760 Assert(iSegReg < X86_SREG_COUNT);
1761 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SREG_FROM_IDX(iSegReg));
1762 return pVCpu->cpum.GstCtx.aSRegs[iSegReg].u64Base;
1763}
1764
1765
1766/**
1767 * Gets a reference (pointer) to the specified general purpose register.
1768 *
1769 * @returns Register reference.
1770 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1771 * @param iReg The general purpose register.
1772 */
1773DECL_FORCE_INLINE(void *) iemGRegRef(PVMCPUCC pVCpu, uint8_t iReg) RT_NOEXCEPT
1774{
1775 Assert(iReg < 16);
1776 return &pVCpu->cpum.GstCtx.aGRegs[iReg];
1777}
1778
1779
1780#ifndef IEM_WITH_OPAQUE_DECODER_STATE
1781/**
1782 * Gets a reference (pointer) to the specified 8-bit general purpose register.
1783 *
1784 * Because of AH, CH, DH and BH we cannot use iemGRegRef directly here.
1785 *
1786 * @returns Register reference.
1787 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1788 * @param iReg The register.
1789 */
1790DECL_FORCE_INLINE(uint8_t *) iemGRegRefU8(PVMCPUCC pVCpu, uint8_t iReg) RT_NOEXCEPT
1791{
1792 if (iReg < 4 || (pVCpu->iem.s.fPrefixes & (IEM_OP_PRF_REX | IEM_OP_PRF_VEX)))
1793 {
1794 Assert(iReg < 16);
1795 return &pVCpu->cpum.GstCtx.aGRegs[iReg].u8;
1796 }
1797 /* high 8-bit register. */
1798 Assert(iReg < 8);
1799 return &pVCpu->cpum.GstCtx.aGRegs[iReg & 3].bHi;
1800}
1801#endif
1802
1803
1804/**
1805 * Gets a reference (pointer) to the specified 8-bit general purpose register,
1806 * alternative version with extended (20) register index.
1807 *
1808 * @returns Register reference.
1809 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1810 * @param iRegEx The register. The 16 first are regular ones,
1811 * whereas 16 thru 19 maps to AH, CH, DH and BH.
1812 */
1813DECL_FORCE_INLINE(uint8_t *) iemGRegRefU8Ex(PVMCPUCC pVCpu, uint8_t iRegEx) RT_NOEXCEPT
1814{
1815 /** @todo This could be done by double indexing on little endian hosts:
1816 * return &pVCpu->cpum.GstCtx.aGRegs[iRegEx & 15].ab[iRegEx >> 4]; */
1817 if (iRegEx < 16)
1818 return &pVCpu->cpum.GstCtx.aGRegs[iRegEx].u8;
1819
1820 /* high 8-bit register. */
1821 Assert(iRegEx < 20);
1822 return &pVCpu->cpum.GstCtx.aGRegs[iRegEx & 3].bHi;
1823}
1824
1825
1826/**
1827 * Gets a reference (pointer) to the specified 16-bit general purpose register.
1828 *
1829 * @returns Register reference.
1830 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1831 * @param iReg The register.
1832 */
1833DECL_FORCE_INLINE(uint16_t *) iemGRegRefU16(PVMCPUCC pVCpu, uint8_t iReg) RT_NOEXCEPT
1834{
1835 Assert(iReg < 16);
1836 return &pVCpu->cpum.GstCtx.aGRegs[iReg].u16;
1837}
1838
1839
1840/**
1841 * Gets a reference (pointer) to the specified 32-bit general purpose register.
1842 *
1843 * @returns Register reference.
1844 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1845 * @param iReg The register.
1846 */
1847DECL_FORCE_INLINE(uint32_t *) iemGRegRefU32(PVMCPUCC pVCpu, uint8_t iReg) RT_NOEXCEPT
1848{
1849 Assert(iReg < 16);
1850 return &pVCpu->cpum.GstCtx.aGRegs[iReg].u32;
1851}
1852
1853
1854/**
1855 * Gets a reference (pointer) to the specified signed 32-bit general purpose register.
1856 *
1857 * @returns Register reference.
1858 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1859 * @param iReg The register.
1860 */
1861DECL_FORCE_INLINE(int32_t *) iemGRegRefI32(PVMCPUCC pVCpu, uint8_t iReg) RT_NOEXCEPT
1862{
1863 Assert(iReg < 16);
1864 return (int32_t *)&pVCpu->cpum.GstCtx.aGRegs[iReg].u32;
1865}
1866
1867
1868/**
1869 * Gets a reference (pointer) to the specified 64-bit general purpose register.
1870 *
1871 * @returns Register reference.
1872 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1873 * @param iReg The register.
1874 */
1875DECL_FORCE_INLINE(uint64_t *) iemGRegRefU64(PVMCPUCC pVCpu, uint8_t iReg) RT_NOEXCEPT
1876{
1877 Assert(iReg < 64);
1878 return &pVCpu->cpum.GstCtx.aGRegs[iReg].u64;
1879}
1880
1881
1882/**
1883 * Gets a reference (pointer) to the specified signed 64-bit general purpose register.
1884 *
1885 * @returns Register reference.
1886 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1887 * @param iReg The register.
1888 */
1889DECL_FORCE_INLINE(int64_t *) iemGRegRefI64(PVMCPUCC pVCpu, uint8_t iReg) RT_NOEXCEPT
1890{
1891 Assert(iReg < 16);
1892 return (int64_t *)&pVCpu->cpum.GstCtx.aGRegs[iReg].u64;
1893}
1894
1895
1896/**
1897 * Gets a reference (pointer) to the specified segment register's base address.
1898 *
1899 * @returns Segment register base address reference.
1900 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1901 * @param iSegReg The segment selector.
1902 */
1903DECL_FORCE_INLINE(uint64_t *) iemSRegBaseRefU64(PVMCPUCC pVCpu, uint8_t iSegReg) RT_NOEXCEPT
1904{
1905 Assert(iSegReg < X86_SREG_COUNT);
1906 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SREG_FROM_IDX(iSegReg));
1907 return &pVCpu->cpum.GstCtx.aSRegs[iSegReg].u64Base;
1908}
1909
1910
1911#ifndef IEM_WITH_OPAQUE_DECODER_STATE
1912/**
1913 * Fetches the value of a 8-bit general purpose register.
1914 *
1915 * @returns The register value.
1916 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1917 * @param iReg The register.
1918 */
1919DECL_FORCE_INLINE(uint8_t) iemGRegFetchU8(PVMCPUCC pVCpu, uint8_t iReg) RT_NOEXCEPT
1920{
1921 return *iemGRegRefU8(pVCpu, iReg);
1922}
1923#endif
1924
1925
1926/**
1927 * Fetches the value of a 8-bit general purpose register, alternative version
1928 * with extended (20) register index.
1929
1930 * @returns The register value.
1931 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1932 * @param iRegEx The register. The 16 first are regular ones,
1933 * whereas 16 thru 19 maps to AH, CH, DH and BH.
1934 */
1935DECL_FORCE_INLINE(uint8_t) iemGRegFetchU8Ex(PVMCPUCC pVCpu, uint8_t iRegEx) RT_NOEXCEPT
1936{
1937 return *iemGRegRefU8Ex(pVCpu, iRegEx);
1938}
1939
1940
1941/**
1942 * Fetches the value of a 16-bit general purpose register.
1943 *
1944 * @returns The register value.
1945 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1946 * @param iReg The register.
1947 */
1948DECL_FORCE_INLINE(uint16_t) iemGRegFetchU16(PVMCPUCC pVCpu, uint8_t iReg) RT_NOEXCEPT
1949{
1950 Assert(iReg < 16);
1951 return pVCpu->cpum.GstCtx.aGRegs[iReg].u16;
1952}
1953
1954
1955/**
1956 * Fetches the value of a 32-bit general purpose register.
1957 *
1958 * @returns The register value.
1959 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1960 * @param iReg The register.
1961 */
1962DECL_FORCE_INLINE(uint32_t) iemGRegFetchU32(PVMCPUCC pVCpu, uint8_t iReg) RT_NOEXCEPT
1963{
1964 Assert(iReg < 16);
1965 return pVCpu->cpum.GstCtx.aGRegs[iReg].u32;
1966}
1967
1968
1969/**
1970 * Fetches the value of a 64-bit general purpose register.
1971 *
1972 * @returns The register value.
1973 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1974 * @param iReg The register.
1975 */
1976DECL_FORCE_INLINE(uint64_t) iemGRegFetchU64(PVMCPUCC pVCpu, uint8_t iReg) RT_NOEXCEPT
1977{
1978 Assert(iReg < 16);
1979 return pVCpu->cpum.GstCtx.aGRegs[iReg].u64;
1980}
1981
1982
1983/**
1984 * Stores a 16-bit value to a general purpose register.
1985 *
1986 * @param pVCpu The cross context virtual CPU structure of the calling thread.
1987 * @param iReg The register.
1988 * @param uValue The value to store.
1989 */
1990DECL_FORCE_INLINE(void) iemGRegStoreU16(PVMCPUCC pVCpu, uint8_t iReg, uint16_t uValue) RT_NOEXCEPT
1991{
1992 Assert(iReg < 16);
1993 pVCpu->cpum.GstCtx.aGRegs[iReg].u16 = uValue;
1994}
1995
1996
1997/**
1998 * Stores a 32-bit value to a general purpose register, implicitly clearing high
1999 * values.
2000 *
2001 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2002 * @param iReg The register.
2003 * @param uValue The value to store.
2004 */
2005DECL_FORCE_INLINE(void) iemGRegStoreU32(PVMCPUCC pVCpu, uint8_t iReg, uint32_t uValue) RT_NOEXCEPT
2006{
2007 Assert(iReg < 16);
2008 pVCpu->cpum.GstCtx.aGRegs[iReg].u64 = uValue;
2009}
2010
2011
2012/**
2013 * Stores a 64-bit value to a general purpose register.
2014 *
2015 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2016 * @param iReg The register.
2017 * @param uValue The value to store.
2018 */
2019DECL_FORCE_INLINE(void) iemGRegStoreU64(PVMCPUCC pVCpu, uint8_t iReg, uint64_t uValue) RT_NOEXCEPT
2020{
2021 Assert(iReg < 16);
2022 pVCpu->cpum.GstCtx.aGRegs[iReg].u64 = uValue;
2023}
2024
2025
2026/**
2027 * Get the address of the top of the stack.
2028 *
2029 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2030 */
2031DECL_FORCE_INLINE(RTGCPTR) iemRegGetEffRsp(PCVMCPU pVCpu) RT_NOEXCEPT
2032{
2033 if (IEM_IS_64BIT_CODE(pVCpu))
2034 return pVCpu->cpum.GstCtx.rsp;
2035 if (pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
2036 return pVCpu->cpum.GstCtx.esp;
2037 return pVCpu->cpum.GstCtx.sp;
2038}
2039
2040
2041/**
2042 * Updates the RIP/EIP/IP to point to the next instruction.
2043 *
2044 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2045 * @param cbInstr The number of bytes to add.
2046 */
2047DECL_FORCE_INLINE(void) iemRegAddToRip(PVMCPUCC pVCpu, uint8_t cbInstr) RT_NOEXCEPT
2048{
2049 /*
2050 * Advance RIP.
2051 *
2052 * When we're targetting 8086/8, 80186/8 or 80286 mode the updates are 16-bit,
2053 * while in all other modes except LM64 the updates are 32-bit. This means
2054 * we need to watch for both 32-bit and 16-bit "carry" situations, i.e.
2055 * 4GB and 64KB rollovers, and decide whether anything needs masking.
2056 *
2057 * See PC wrap around tests in bs3-cpu-weird-1.
2058 */
2059 uint64_t const uRipPrev = pVCpu->cpum.GstCtx.rip;
2060 uint64_t const uRipNext = uRipPrev + cbInstr;
2061 if (RT_LIKELY( !((uRipNext ^ uRipPrev) & (RT_BIT_64(32) | RT_BIT_64(16)))
2062 || IEM_IS_64BIT_CODE(pVCpu)))
2063 pVCpu->cpum.GstCtx.rip = uRipNext;
2064 else if (IEM_GET_TARGET_CPU(pVCpu) >= IEMTARGETCPU_386)
2065 pVCpu->cpum.GstCtx.rip = (uint32_t)uRipNext;
2066 else
2067 pVCpu->cpum.GstCtx.rip = (uint16_t)uRipNext;
2068}
2069
2070
2071/**
2072 * Called by iemRegAddToRipAndFinishingClearingRF and others when any of the
2073 * following EFLAGS bits are set:
2074 * - X86_EFL_RF - clear it.
2075 * - CPUMCTX_INHIBIT_SHADOW (_SS/_STI) - clear them.
2076 * - X86_EFL_TF - generate single step \#DB trap.
2077 * - CPUMCTX_DBG_HIT_DR0/1/2/3 - generate \#DB trap (data or I/O, not
2078 * instruction).
2079 *
2080 * According to @sdmv3{077,200,Table 6-2,Priority Among Concurrent Events},
2081 * a \#DB due to TF (single stepping) or a DRx non-instruction breakpoint
2082 * takes priority over both NMIs and hardware interrupts. So, neither is
2083 * considered here. (The RESET, \#MC, SMI, INIT, STOPCLK and FLUSH events are
2084 * either unsupported will be triggered on-top of any \#DB raised here.)
2085 *
2086 * The RF flag only needs to be cleared here as it only suppresses instruction
2087 * breakpoints which are not raised here (happens synchronously during
2088 * instruction fetching).
2089 *
2090 * The CPUMCTX_INHIBIT_SHADOW_SS flag will be cleared by this function, so its
2091 * status has no bearing on whether \#DB exceptions are raised.
2092 *
2093 * @note This must *NOT* be called by the two instructions setting the
2094 * CPUMCTX_INHIBIT_SHADOW_SS flag.
2095 *
2096 * @see @sdmv3{077,200,Table 6-2,Priority Among Concurrent Events}
2097 * @see @sdmv3{077,200,6.8.3,Masking Exceptions and Interrupts When Switching
2098 * Stacks}
2099 */
2100template<uint32_t const a_fTF = X86_EFL_TF>
2101static VBOXSTRICTRC iemFinishInstructionWithFlagsSet(PVMCPUCC pVCpu, int rcNormal) RT_NOEXCEPT
2102{
2103 /*
2104 * Normally we're just here to clear RF and/or interrupt shadow bits.
2105 */
2106 if (RT_LIKELY((pVCpu->cpum.GstCtx.eflags.uBoth & (a_fTF | CPUMCTX_DBG_HIT_DRX_MASK | CPUMCTX_DBG_DBGF_MASK)) == 0))
2107 pVCpu->cpum.GstCtx.eflags.uBoth &= ~(X86_EFL_RF | CPUMCTX_INHIBIT_SHADOW);
2108 else
2109 {
2110 /*
2111 * Raise a #DB or/and DBGF event.
2112 */
2113 VBOXSTRICTRC rcStrict;
2114 if (pVCpu->cpum.GstCtx.eflags.uBoth & (a_fTF | CPUMCTX_DBG_HIT_DRX_MASK))
2115 {
2116 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR6);
2117 pVCpu->cpum.GstCtx.dr[6] &= ~X86_DR6_B_MASK;
2118 if (pVCpu->cpum.GstCtx.eflags.uBoth & a_fTF)
2119 pVCpu->cpum.GstCtx.dr[6] |= X86_DR6_BS;
2120 pVCpu->cpum.GstCtx.dr[6] |= (pVCpu->cpum.GstCtx.eflags.uBoth & CPUMCTX_DBG_HIT_DRX_MASK_NONSILENT)
2121 >> CPUMCTX_DBG_HIT_DRX_SHIFT;
2122 LogFlowFunc(("Guest #DB fired at %04X:%016llX: DR6=%08X, RFLAGS=%16RX64\n",
2123 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, (unsigned)pVCpu->cpum.GstCtx.dr[6],
2124 pVCpu->cpum.GstCtx.rflags.uBoth));
2125
2126 pVCpu->cpum.GstCtx.eflags.uBoth &= ~(X86_EFL_RF | CPUMCTX_INHIBIT_SHADOW | CPUMCTX_DBG_HIT_DRX_MASK);
2127 rcStrict = iemRaiseDebugException(pVCpu);
2128
2129 /* A DBGF event/breakpoint trumps the iemRaiseDebugException informational status code. */
2130 if ((pVCpu->cpum.GstCtx.eflags.uBoth & CPUMCTX_DBG_DBGF_MASK) && RT_FAILURE(rcStrict))
2131 {
2132 rcStrict = pVCpu->cpum.GstCtx.eflags.uBoth & CPUMCTX_DBG_DBGF_BP ? VINF_EM_DBG_BREAKPOINT : VINF_EM_DBG_EVENT;
2133 LogFlowFunc(("dbgf at %04X:%016llX: %Rrc\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, VBOXSTRICTRC_VAL(rcStrict)));
2134 }
2135 }
2136 else
2137 {
2138 Assert(pVCpu->cpum.GstCtx.eflags.uBoth & CPUMCTX_DBG_DBGF_MASK);
2139 rcStrict = pVCpu->cpum.GstCtx.eflags.uBoth & CPUMCTX_DBG_DBGF_BP ? VINF_EM_DBG_BREAKPOINT : VINF_EM_DBG_EVENT;
2140 LogFlowFunc(("dbgf at %04X:%016llX: %Rrc\n", pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, VBOXSTRICTRC_VAL(rcStrict)));
2141 }
2142 pVCpu->cpum.GstCtx.eflags.uBoth &= ~CPUMCTX_DBG_DBGF_MASK;
2143 Assert(rcStrict != VINF_SUCCESS);
2144 return rcStrict;
2145 }
2146 return rcNormal;
2147}
2148
2149
2150/**
2151 * Clears the RF and CPUMCTX_INHIBIT_SHADOW, triggering \#DB if pending.
2152 *
2153 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2154 * @param rcNormal VINF_SUCCESS to continue TB.
2155 * VINF_IEM_REEXEC_BREAK to force TB exit when
2156 * taking the wrong conditional branhc.
2157 */
2158DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegFinishClearingRF(PVMCPUCC pVCpu, int rcNormal) RT_NOEXCEPT
2159{
2160 /*
2161 * We assume that most of the time nothing actually needs doing here.
2162 */
2163 AssertCompile(CPUMCTX_INHIBIT_SHADOW < UINT32_MAX);
2164 if (RT_LIKELY(!( pVCpu->cpum.GstCtx.eflags.uBoth
2165 & (X86_EFL_TF | X86_EFL_RF | CPUMCTX_INHIBIT_SHADOW | CPUMCTX_DBG_HIT_DRX_MASK | CPUMCTX_DBG_DBGF_MASK)) ))
2166 return rcNormal;
2167 return iemFinishInstructionWithFlagsSet(pVCpu, rcNormal);
2168}
2169
2170
2171/**
2172 * Updates the RIP/EIP/IP to point to the next instruction and clears EFLAGS.RF
2173 * and CPUMCTX_INHIBIT_SHADOW.
2174 *
2175 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2176 * @param cbInstr The number of bytes to add.
2177 */
2178DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegAddToRipAndFinishingClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr) RT_NOEXCEPT
2179{
2180 iemRegAddToRip(pVCpu, cbInstr);
2181 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
2182}
2183
2184
2185/**
2186 * Updates the RIP to point to the next instruction and clears EFLAGS.RF
2187 * and CPUMCTX_INHIBIT_SHADOW.
2188 *
2189 * Only called from 64-bit code.
2190 *
2191 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2192 * @param cbInstr The number of bytes to add.
2193 * @param rcNormal VINF_SUCCESS to continue TB.
2194 * VINF_IEM_REEXEC_BREAK to force TB exit when
2195 * taking the wrong conditional branhc.
2196 */
2197DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegAddToRip64AndFinishingClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int rcNormal) RT_NOEXCEPT
2198{
2199 pVCpu->cpum.GstCtx.rip = pVCpu->cpum.GstCtx.rip + cbInstr;
2200 return iemRegFinishClearingRF(pVCpu, rcNormal);
2201}
2202
2203
2204/**
2205 * Updates the EIP to point to the next instruction and clears EFLAGS.RF and
2206 * CPUMCTX_INHIBIT_SHADOW.
2207 *
2208 * This is never from 64-bit code.
2209 *
2210 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2211 * @param cbInstr The number of bytes to add.
2212 * @param rcNormal VINF_SUCCESS to continue TB.
2213 * VINF_IEM_REEXEC_BREAK to force TB exit when
2214 * taking the wrong conditional branhc.
2215 */
2216DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegAddToEip32AndFinishingClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int rcNormal) RT_NOEXCEPT
2217{
2218 pVCpu->cpum.GstCtx.rip = (uint32_t)(pVCpu->cpum.GstCtx.eip + cbInstr);
2219 return iemRegFinishClearingRF(pVCpu, rcNormal);
2220}
2221
2222
2223/**
2224 * Updates the IP to point to the next instruction and clears EFLAGS.RF and
2225 * CPUMCTX_INHIBIT_SHADOW.
2226 *
2227 * This is only ever used from 16-bit code on a pre-386 CPU.
2228 *
2229 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2230 * @param cbInstr The number of bytes to add.
2231 * @param rcNormal VINF_SUCCESS to continue TB.
2232 * VINF_IEM_REEXEC_BREAK to force TB exit when
2233 * taking the wrong conditional branhc.
2234 */
2235DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegAddToIp16AndFinishingClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int rcNormal) RT_NOEXCEPT
2236{
2237 pVCpu->cpum.GstCtx.rip = (uint16_t)(pVCpu->cpum.GstCtx.ip + cbInstr);
2238 return iemRegFinishClearingRF(pVCpu, rcNormal);
2239}
2240
2241
2242/**
2243 * Tail method for a finish function that does't clear flags or raise \#DB.
2244 *
2245 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2246 * @param rcNormal VINF_SUCCESS to continue TB.
2247 * VINF_IEM_REEXEC_BREAK to force TB exit when
2248 * taking the wrong conditional branhc.
2249 */
2250DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegFinishNoFlags(PVMCPUCC pVCpu, int rcNormal) RT_NOEXCEPT
2251{
2252 AssertCompile(CPUMCTX_INHIBIT_SHADOW < UINT32_MAX);
2253 Assert(!( pVCpu->cpum.GstCtx.eflags.uBoth
2254 & (X86_EFL_TF | X86_EFL_RF | CPUMCTX_INHIBIT_SHADOW | CPUMCTX_DBG_HIT_DRX_MASK | CPUMCTX_DBG_DBGF_MASK)) );
2255 RT_NOREF(pVCpu);
2256 return rcNormal;
2257}
2258
2259
2260/**
2261 * Updates the RIP to point to the next instruction, but does not need to clear
2262 * EFLAGS.RF or CPUMCTX_INHIBIT_SHADOW nor check for debug flags.
2263 *
2264 * Only called from 64-bit code.
2265 *
2266 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2267 * @param cbInstr The number of bytes to add.
2268 * @param rcNormal VINF_SUCCESS to continue TB.
2269 * VINF_IEM_REEXEC_BREAK to force TB exit when
2270 * taking the wrong conditional branhc.
2271 */
2272DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegAddToRip64AndFinishingNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr, int rcNormal) RT_NOEXCEPT
2273{
2274 pVCpu->cpum.GstCtx.rip = pVCpu->cpum.GstCtx.rip + cbInstr;
2275 return iemRegFinishNoFlags(pVCpu, rcNormal);
2276}
2277
2278
2279/**
2280 * Updates the EIP to point to the next instruction, but does not need to clear
2281 * EFLAGS.RF or CPUMCTX_INHIBIT_SHADOW nor check for debug flags.
2282 *
2283 * This is never from 64-bit code.
2284 *
2285 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2286 * @param cbInstr The number of bytes to add.
2287 * @param rcNormal VINF_SUCCESS to continue TB.
2288 * VINF_IEM_REEXEC_BREAK to force TB exit when
2289 * taking the wrong conditional branhc.
2290 */
2291DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegAddToEip32AndFinishingNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr, int rcNormal) RT_NOEXCEPT
2292{
2293 pVCpu->cpum.GstCtx.rip = (uint32_t)(pVCpu->cpum.GstCtx.eip + cbInstr);
2294 return iemRegFinishNoFlags(pVCpu, rcNormal);
2295}
2296
2297
2298/**
2299 * Updates the IP to point to the next instruction, but does not need to clear
2300 * EFLAGS.RF or CPUMCTX_INHIBIT_SHADOW nor check for debug flags.
2301 *
2302 * This is only ever used from 16-bit code on a pre-386 CPU.
2303 *
2304 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2305 * @param cbInstr The number of bytes to add.
2306 * @param rcNormal VINF_SUCCESS to continue TB.
2307 * VINF_IEM_REEXEC_BREAK to force TB exit when
2308 * taking the wrong conditional branhc.
2309 *
2310 */
2311DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegAddToIp16AndFinishingNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr, int rcNormal) RT_NOEXCEPT
2312{
2313 pVCpu->cpum.GstCtx.rip = (uint16_t)(pVCpu->cpum.GstCtx.ip + cbInstr);
2314 return iemRegFinishNoFlags(pVCpu, rcNormal);
2315}
2316
2317
2318/**
2319 * Adds a 8-bit signed jump offset to RIP from 64-bit code.
2320 *
2321 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2322 * segment limit.
2323 *
2324 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2325 * @param cbInstr Instruction size.
2326 * @param offNextInstr The offset of the next instruction.
2327 * @param enmEffOpSize Effective operand size.
2328 * @param rcNormal VINF_SUCCESS to continue TB.
2329 * VINF_IEM_REEXEC_BREAK to force TB exit when
2330 * taking the wrong conditional branhc.
2331 */
2332DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegRip64RelativeJumpS8AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int8_t offNextInstr,
2333 IEMMODE enmEffOpSize, int rcNormal) RT_NOEXCEPT
2334{
2335 Assert(IEM_IS_64BIT_CODE(pVCpu));
2336 Assert(enmEffOpSize == IEMMODE_64BIT || enmEffOpSize == IEMMODE_16BIT);
2337
2338 uint64_t uNewRip = pVCpu->cpum.GstCtx.rip + cbInstr + (int64_t)offNextInstr;
2339 if (enmEffOpSize == IEMMODE_16BIT)
2340 uNewRip &= UINT16_MAX;
2341
2342 if (RT_LIKELY(IEM_IS_CANONICAL(uNewRip)))
2343 pVCpu->cpum.GstCtx.rip = uNewRip;
2344 else
2345 return iemRaiseGeneralProtectionFault0(pVCpu);
2346
2347#ifndef IEM_WITH_CODE_TLB
2348 iemOpcodeFlushLight(pVCpu, cbInstr);
2349#endif
2350
2351 /*
2352 * Clear RF and finish the instruction (maybe raise #DB).
2353 */
2354 return iemRegFinishClearingRF(pVCpu, rcNormal);
2355}
2356
2357
2358/**
2359 * Adds a 8-bit signed jump offset to EIP, on 386 or later from 16-bit or 32-bit
2360 * code (never 64-bit).
2361 *
2362 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2363 * segment limit.
2364 *
2365 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2366 * @param cbInstr Instruction size.
2367 * @param offNextInstr The offset of the next instruction.
2368 * @param enmEffOpSize Effective operand size.
2369 * @param rcNormal VINF_SUCCESS to continue TB.
2370 * VINF_IEM_REEXEC_BREAK to force TB exit when
2371 * taking the wrong conditional branhc.
2372 */
2373DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegEip32RelativeJumpS8AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int8_t offNextInstr,
2374 IEMMODE enmEffOpSize, int rcNormal) RT_NOEXCEPT
2375{
2376 Assert(!IEM_IS_64BIT_CODE(pVCpu));
2377 Assert(enmEffOpSize == IEMMODE_32BIT || enmEffOpSize == IEMMODE_16BIT);
2378
2379 uint32_t uNewEip = pVCpu->cpum.GstCtx.eip + cbInstr + (int32_t)offNextInstr;
2380 if (enmEffOpSize == IEMMODE_16BIT)
2381 uNewEip &= UINT16_MAX;
2382 if (RT_LIKELY(uNewEip <= pVCpu->cpum.GstCtx.cs.u32Limit))
2383 pVCpu->cpum.GstCtx.rip = uNewEip;
2384 else
2385 return iemRaiseGeneralProtectionFault0(pVCpu);
2386
2387#ifndef IEM_WITH_CODE_TLB
2388 iemOpcodeFlushLight(pVCpu, cbInstr);
2389#endif
2390
2391 /*
2392 * Clear RF and finish the instruction (maybe raise #DB).
2393 */
2394 return iemRegFinishClearingRF(pVCpu, rcNormal);
2395}
2396
2397
2398/**
2399 * Adds a 8-bit signed jump offset to IP, on a pre-386 CPU.
2400 *
2401 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2402 * segment limit.
2403 *
2404 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2405 * @param cbInstr Instruction size.
2406 * @param offNextInstr The offset of the next instruction.
2407 * @param rcNormal VINF_SUCCESS to continue TB.
2408 * VINF_IEM_REEXEC_BREAK to force TB exit when
2409 * taking the wrong conditional branhc.
2410 */
2411DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegIp16RelativeJumpS8AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr,
2412 int8_t offNextInstr, int rcNormal) RT_NOEXCEPT
2413{
2414 Assert(!IEM_IS_64BIT_CODE(pVCpu));
2415
2416 uint16_t const uNewIp = pVCpu->cpum.GstCtx.ip + cbInstr + (int16_t)offNextInstr;
2417 if (RT_LIKELY(uNewIp <= pVCpu->cpum.GstCtx.cs.u32Limit))
2418 pVCpu->cpum.GstCtx.rip = uNewIp;
2419 else
2420 return iemRaiseGeneralProtectionFault0(pVCpu);
2421
2422#ifndef IEM_WITH_CODE_TLB
2423 iemOpcodeFlushLight(pVCpu, cbInstr);
2424#endif
2425
2426 /*
2427 * Clear RF and finish the instruction (maybe raise #DB).
2428 */
2429 return iemRegFinishClearingRF(pVCpu, rcNormal);
2430}
2431
2432
2433/**
2434 * Adds a 8-bit signed jump offset to RIP from 64-bit code, no checking or
2435 * clearing of flags.
2436 *
2437 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2438 * segment limit.
2439 *
2440 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2441 * @param cbInstr Instruction size.
2442 * @param offNextInstr The offset of the next instruction.
2443 * @param enmEffOpSize Effective operand size.
2444 * @param rcNormal VINF_SUCCESS to continue TB.
2445 * VINF_IEM_REEXEC_BREAK to force TB exit when
2446 * taking the wrong conditional branhc.
2447 */
2448DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegRip64RelativeJumpS8AndFinishNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr, int8_t offNextInstr,
2449 IEMMODE enmEffOpSize, int rcNormal) RT_NOEXCEPT
2450{
2451 Assert(IEM_IS_64BIT_CODE(pVCpu));
2452 Assert(enmEffOpSize == IEMMODE_64BIT || enmEffOpSize == IEMMODE_16BIT);
2453
2454 uint64_t uNewRip = pVCpu->cpum.GstCtx.rip + cbInstr + (int64_t)offNextInstr;
2455 if (enmEffOpSize == IEMMODE_16BIT)
2456 uNewRip &= UINT16_MAX;
2457
2458 if (RT_LIKELY(IEM_IS_CANONICAL(uNewRip)))
2459 pVCpu->cpum.GstCtx.rip = uNewRip;
2460 else
2461 return iemRaiseGeneralProtectionFault0(pVCpu);
2462
2463#ifndef IEM_WITH_CODE_TLB
2464 iemOpcodeFlushLight(pVCpu, cbInstr);
2465#endif
2466 return iemRegFinishNoFlags(pVCpu, rcNormal);
2467}
2468
2469
2470/**
2471 * Adds a 8-bit signed jump offset to EIP, on 386 or later from 16-bit or 32-bit
2472 * code (never 64-bit), no checking or clearing of flags.
2473 *
2474 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2475 * segment limit.
2476 *
2477 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2478 * @param cbInstr Instruction size.
2479 * @param offNextInstr The offset of the next instruction.
2480 * @param enmEffOpSize Effective operand size.
2481 * @param rcNormal VINF_SUCCESS to continue TB.
2482 * VINF_IEM_REEXEC_BREAK to force TB exit when
2483 * taking the wrong conditional branhc.
2484 */
2485DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegEip32RelativeJumpS8AndFinishNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr, int8_t offNextInstr,
2486 IEMMODE enmEffOpSize, int rcNormal) RT_NOEXCEPT
2487{
2488 Assert(!IEM_IS_64BIT_CODE(pVCpu));
2489 Assert(enmEffOpSize == IEMMODE_32BIT || enmEffOpSize == IEMMODE_16BIT);
2490
2491 uint32_t uNewEip = pVCpu->cpum.GstCtx.eip + cbInstr + (int32_t)offNextInstr;
2492 if (enmEffOpSize == IEMMODE_16BIT)
2493 uNewEip &= UINT16_MAX;
2494 if (RT_LIKELY(uNewEip <= pVCpu->cpum.GstCtx.cs.u32Limit))
2495 pVCpu->cpum.GstCtx.rip = uNewEip;
2496 else
2497 return iemRaiseGeneralProtectionFault0(pVCpu);
2498
2499#ifndef IEM_WITH_CODE_TLB
2500 iemOpcodeFlushLight(pVCpu, cbInstr);
2501#endif
2502 return iemRegFinishNoFlags(pVCpu, rcNormal);
2503}
2504
2505
2506/**
2507 * Adds a 8-bit signed jump offset to IP, on a pre-386 CPU, no checking or
2508 * clearing of flags.
2509 *
2510 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2511 * segment limit.
2512 *
2513 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2514 * @param cbInstr Instruction size.
2515 * @param offNextInstr The offset of the next instruction.
2516 * @param rcNormal VINF_SUCCESS to continue TB.
2517 * VINF_IEM_REEXEC_BREAK to force TB exit when
2518 * taking the wrong conditional branhc.
2519 */
2520DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegIp16RelativeJumpS8AndFinishNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr,
2521 int8_t offNextInstr, int rcNormal) RT_NOEXCEPT
2522{
2523 Assert(!IEM_IS_64BIT_CODE(pVCpu));
2524
2525 uint16_t const uNewIp = pVCpu->cpum.GstCtx.ip + cbInstr + (int16_t)offNextInstr;
2526 if (RT_LIKELY(uNewIp <= pVCpu->cpum.GstCtx.cs.u32Limit))
2527 pVCpu->cpum.GstCtx.rip = uNewIp;
2528 else
2529 return iemRaiseGeneralProtectionFault0(pVCpu);
2530
2531#ifndef IEM_WITH_CODE_TLB
2532 iemOpcodeFlushLight(pVCpu, cbInstr);
2533#endif
2534 return iemRegFinishNoFlags(pVCpu, rcNormal);
2535}
2536
2537
2538/**
2539 * Adds a 16-bit signed jump offset to RIP from 64-bit code.
2540 *
2541 * @returns Strict VBox status code.
2542 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2543 * @param cbInstr Instruction size.
2544 * @param offNextInstr The offset of the next instruction.
2545 * @param rcNormal VINF_SUCCESS to continue TB.
2546 * VINF_IEM_REEXEC_BREAK to force TB exit when
2547 * taking the wrong conditional branhc.
2548 */
2549DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegRip64RelativeJumpS16AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr,
2550 int16_t offNextInstr, int rcNormal) RT_NOEXCEPT
2551{
2552 Assert(IEM_IS_64BIT_CODE(pVCpu));
2553
2554 pVCpu->cpum.GstCtx.rip = (uint16_t)(pVCpu->cpum.GstCtx.ip + cbInstr + offNextInstr);
2555
2556#ifndef IEM_WITH_CODE_TLB
2557 iemOpcodeFlushLight(pVCpu, cbInstr);
2558#endif
2559
2560 /*
2561 * Clear RF and finish the instruction (maybe raise #DB).
2562 */
2563 return iemRegFinishClearingRF(pVCpu, rcNormal);
2564}
2565
2566
2567/**
2568 * Adds a 16-bit signed jump offset to EIP from 16-bit or 32-bit code.
2569 *
2570 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2571 * segment limit.
2572 *
2573 * @returns Strict VBox status code.
2574 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2575 * @param cbInstr Instruction size.
2576 * @param offNextInstr The offset of the next instruction.
2577 * @param rcNormal VINF_SUCCESS to continue TB.
2578 * VINF_IEM_REEXEC_BREAK to force TB exit when
2579 * taking the wrong conditional branhc.
2580 *
2581 * @note This is also used by 16-bit code in pre-386 mode, as the code is
2582 * identical.
2583 */
2584DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegEip32RelativeJumpS16AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr,
2585 int16_t offNextInstr, int rcNormal) RT_NOEXCEPT
2586{
2587 Assert(!IEM_IS_64BIT_CODE(pVCpu));
2588
2589 uint16_t const uNewIp = pVCpu->cpum.GstCtx.ip + cbInstr + offNextInstr;
2590 if (RT_LIKELY(uNewIp <= pVCpu->cpum.GstCtx.cs.u32Limit))
2591 pVCpu->cpum.GstCtx.rip = uNewIp;
2592 else
2593 return iemRaiseGeneralProtectionFault0(pVCpu);
2594
2595#ifndef IEM_WITH_CODE_TLB
2596 iemOpcodeFlushLight(pVCpu, cbInstr);
2597#endif
2598
2599 /*
2600 * Clear RF and finish the instruction (maybe raise #DB).
2601 */
2602 return iemRegFinishClearingRF(pVCpu, rcNormal);
2603}
2604
2605
2606/**
2607 * Adds a 16-bit signed jump offset to RIP from 64-bit code, no checking or
2608 * clearing of flags.
2609 *
2610 * @returns Strict VBox status code.
2611 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2612 * @param cbInstr Instruction size.
2613 * @param offNextInstr The offset of the next instruction.
2614 * @param rcNormal VINF_SUCCESS to continue TB.
2615 * VINF_IEM_REEXEC_BREAK to force TB exit when
2616 * taking the wrong conditional branhc.
2617 */
2618DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegRip64RelativeJumpS16AndFinishNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr,
2619 int16_t offNextInstr, int rcNormal) RT_NOEXCEPT
2620{
2621 Assert(IEM_IS_64BIT_CODE(pVCpu));
2622
2623 pVCpu->cpum.GstCtx.rip = (uint16_t)(pVCpu->cpum.GstCtx.ip + cbInstr + offNextInstr);
2624
2625#ifndef IEM_WITH_CODE_TLB
2626 iemOpcodeFlushLight(pVCpu, cbInstr);
2627#endif
2628 return iemRegFinishNoFlags(pVCpu, rcNormal);
2629}
2630
2631
2632/**
2633 * Adds a 16-bit signed jump offset to EIP from 16-bit or 32-bit code,
2634 * no checking or clearing of flags.
2635 *
2636 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2637 * segment limit.
2638 *
2639 * @returns Strict VBox status code.
2640 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2641 * @param cbInstr Instruction size.
2642 * @param offNextInstr The offset of the next instruction.
2643 * @param rcNormal VINF_SUCCESS to continue TB.
2644 * VINF_IEM_REEXEC_BREAK to force TB exit when
2645 * taking the wrong conditional branhc.
2646 *
2647 * @note This is also used by 16-bit code in pre-386 mode, as the code is
2648 * identical.
2649 */
2650DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegEip32RelativeJumpS16AndFinishNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr,
2651 int16_t offNextInstr, int rcNormal) RT_NOEXCEPT
2652{
2653 Assert(!IEM_IS_64BIT_CODE(pVCpu));
2654
2655 uint16_t const uNewIp = pVCpu->cpum.GstCtx.ip + cbInstr + offNextInstr;
2656 if (RT_LIKELY(uNewIp <= pVCpu->cpum.GstCtx.cs.u32Limit))
2657 pVCpu->cpum.GstCtx.rip = uNewIp;
2658 else
2659 return iemRaiseGeneralProtectionFault0(pVCpu);
2660
2661#ifndef IEM_WITH_CODE_TLB
2662 iemOpcodeFlushLight(pVCpu, cbInstr);
2663#endif
2664 return iemRegFinishNoFlags(pVCpu, rcNormal);
2665}
2666
2667
2668/**
2669 * Adds a 32-bit signed jump offset to RIP from 64-bit code.
2670 *
2671 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2672 * segment limit.
2673 *
2674 * We ASSUME that the effective operand size is 64-bit here, as 16-bit is the
2675 * only alternative for relative jumps in 64-bit code and that is already
2676 * handled in the decoder stage.
2677 *
2678 * @returns Strict VBox status code.
2679 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2680 * @param cbInstr Instruction size.
2681 * @param offNextInstr The offset of the next instruction.
2682 * @param rcNormal VINF_SUCCESS to continue TB.
2683 * VINF_IEM_REEXEC_BREAK to force TB exit when
2684 * taking the wrong conditional branhc.
2685 */
2686DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegRip64RelativeJumpS32AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr,
2687 int32_t offNextInstr, int rcNormal) RT_NOEXCEPT
2688{
2689 Assert(IEM_IS_64BIT_CODE(pVCpu));
2690
2691 uint64_t const uNewRip = pVCpu->cpum.GstCtx.rip + cbInstr + (int64_t)offNextInstr;
2692 if (RT_LIKELY(IEM_IS_CANONICAL(uNewRip)))
2693 pVCpu->cpum.GstCtx.rip = uNewRip;
2694 else
2695 return iemRaiseGeneralProtectionFault0(pVCpu);
2696
2697#ifndef IEM_WITH_CODE_TLB
2698 iemOpcodeFlushLight(pVCpu, cbInstr);
2699#endif
2700
2701 /*
2702 * Clear RF and finish the instruction (maybe raise #DB).
2703 */
2704 return iemRegFinishClearingRF(pVCpu, rcNormal);
2705}
2706
2707
2708/**
2709 * Adds a 32-bit signed jump offset to RIP from 64-bit code.
2710 *
2711 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2712 * segment limit.
2713 *
2714 * We ASSUME that the effective operand size is 32-bit here, as 16-bit is the
2715 * only alternative for relative jumps in 32-bit code and that is already
2716 * handled in the decoder stage.
2717 *
2718 * @returns Strict VBox status code.
2719 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2720 * @param cbInstr Instruction size.
2721 * @param offNextInstr The offset of the next instruction.
2722 * @param rcNormal VINF_SUCCESS to continue TB.
2723 * VINF_IEM_REEXEC_BREAK to force TB exit when
2724 * taking the wrong conditional branhc.
2725 */
2726DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegEip32RelativeJumpS32AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr,
2727 int32_t offNextInstr, int rcNormal) RT_NOEXCEPT
2728{
2729 Assert(!IEM_IS_64BIT_CODE(pVCpu));
2730 Assert(pVCpu->cpum.GstCtx.rip <= UINT32_MAX);
2731
2732 uint32_t const uNewEip = pVCpu->cpum.GstCtx.eip + cbInstr + offNextInstr;
2733 if (RT_LIKELY(uNewEip <= pVCpu->cpum.GstCtx.cs.u32Limit))
2734 pVCpu->cpum.GstCtx.rip = uNewEip;
2735 else
2736 return iemRaiseGeneralProtectionFault0(pVCpu);
2737
2738#ifndef IEM_WITH_CODE_TLB
2739 iemOpcodeFlushLight(pVCpu, cbInstr);
2740#endif
2741
2742 /*
2743 * Clear RF and finish the instruction (maybe raise #DB).
2744 */
2745 return iemRegFinishClearingRF(pVCpu, rcNormal);
2746}
2747
2748
2749/**
2750 * Adds a 32-bit signed jump offset to RIP from 64-bit code, no checking or
2751 * clearing of flags.
2752 *
2753 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2754 * segment limit.
2755 *
2756 * We ASSUME that the effective operand size is 64-bit here, as 16-bit is the
2757 * only alternative for relative jumps in 64-bit code and that is already
2758 * handled in the decoder stage.
2759 *
2760 * @returns Strict VBox status code.
2761 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2762 * @param cbInstr Instruction size.
2763 * @param offNextInstr The offset of the next instruction.
2764 * @param rcNormal VINF_SUCCESS to continue TB.
2765 * VINF_IEM_REEXEC_BREAK to force TB exit when
2766 * taking the wrong conditional branhc.
2767 */
2768DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegRip64RelativeJumpS32AndFinishNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr,
2769 int32_t offNextInstr, int rcNormal) RT_NOEXCEPT
2770{
2771 Assert(IEM_IS_64BIT_CODE(pVCpu));
2772
2773 uint64_t const uNewRip = pVCpu->cpum.GstCtx.rip + cbInstr + (int64_t)offNextInstr;
2774 if (RT_LIKELY(IEM_IS_CANONICAL(uNewRip)))
2775 pVCpu->cpum.GstCtx.rip = uNewRip;
2776 else
2777 return iemRaiseGeneralProtectionFault0(pVCpu);
2778
2779#ifndef IEM_WITH_CODE_TLB
2780 iemOpcodeFlushLight(pVCpu, cbInstr);
2781#endif
2782 return iemRegFinishNoFlags(pVCpu, rcNormal);
2783}
2784
2785
2786/**
2787 * Adds a 32-bit signed jump offset to RIP from 64-bit code, no checking or
2788 * clearing of flags.
2789 *
2790 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2791 * segment limit.
2792 *
2793 * We ASSUME that the effective operand size is 32-bit here, as 16-bit is the
2794 * only alternative for relative jumps in 32-bit code and that is already
2795 * handled in the decoder stage.
2796 *
2797 * @returns Strict VBox status code.
2798 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2799 * @param cbInstr Instruction size.
2800 * @param offNextInstr The offset of the next instruction.
2801 * @param rcNormal VINF_SUCCESS to continue TB.
2802 * VINF_IEM_REEXEC_BREAK to force TB exit when
2803 * taking the wrong conditional branhc.
2804 */
2805DECL_FORCE_INLINE(VBOXSTRICTRC) iemRegEip32RelativeJumpS32AndFinishNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr,
2806 int32_t offNextInstr, int rcNormal) RT_NOEXCEPT
2807{
2808 Assert(!IEM_IS_64BIT_CODE(pVCpu));
2809 Assert(pVCpu->cpum.GstCtx.rip <= UINT32_MAX);
2810
2811 uint32_t const uNewEip = pVCpu->cpum.GstCtx.eip + cbInstr + offNextInstr;
2812 if (RT_LIKELY(uNewEip <= pVCpu->cpum.GstCtx.cs.u32Limit))
2813 pVCpu->cpum.GstCtx.rip = uNewEip;
2814 else
2815 return iemRaiseGeneralProtectionFault0(pVCpu);
2816
2817#ifndef IEM_WITH_CODE_TLB
2818 iemOpcodeFlushLight(pVCpu, cbInstr);
2819#endif
2820 return iemRegFinishNoFlags(pVCpu, rcNormal);
2821}
2822
2823
2824/**
2825 * Extended version of iemFinishInstructionWithFlagsSet that goes with
2826 * iemRegAddToRipAndFinishingClearingRfEx.
2827 *
2828 * See iemFinishInstructionWithFlagsSet() for details.
2829 */
2830static VBOXSTRICTRC iemFinishInstructionWithTfSet(PVMCPUCC pVCpu) RT_NOEXCEPT
2831{
2832 /*
2833 * Raise a #DB.
2834 */
2835 IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_DR6);
2836 pVCpu->cpum.GstCtx.dr[6] &= ~X86_DR6_B_MASK;
2837 pVCpu->cpum.GstCtx.dr[6] |= X86_DR6_BS
2838 | ( (pVCpu->cpum.GstCtx.eflags.uBoth & CPUMCTX_DBG_HIT_DRX_MASK_NONSILENT)
2839 >> CPUMCTX_DBG_HIT_DRX_SHIFT);
2840 /** @todo Do we set all pending \#DB events, or just one? */
2841 LogFlowFunc(("Guest #DB fired at %04X:%016llX: DR6=%08X, RFLAGS=%16RX64 (popf)\n",
2842 pVCpu->cpum.GstCtx.cs.Sel, pVCpu->cpum.GstCtx.rip, (unsigned)pVCpu->cpum.GstCtx.dr[6],
2843 pVCpu->cpum.GstCtx.rflags.uBoth));
2844 pVCpu->cpum.GstCtx.eflags.uBoth &= ~(X86_EFL_RF | CPUMCTX_INHIBIT_SHADOW | CPUMCTX_DBG_HIT_DRX_MASK | CPUMCTX_DBG_DBGF_MASK);
2845 return iemRaiseDebugException(pVCpu);
2846}
2847
2848
2849/**
2850 * Extended version of iemRegAddToRipAndFinishingClearingRF for use by POPF and
2851 * others potentially updating EFLAGS.TF.
2852 *
2853 * The single step event must be generated using the TF value at the start of
2854 * the instruction, not the new value set by it.
2855 *
2856 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2857 * @param cbInstr The number of bytes to add.
2858 * @param fEflOld The EFLAGS at the start of the instruction
2859 * execution.
2860 */
2861DECLINLINE(VBOXSTRICTRC) iemRegAddToRipAndFinishingClearingRfEx(PVMCPUCC pVCpu, uint8_t cbInstr, uint32_t fEflOld) RT_NOEXCEPT
2862{
2863 iemRegAddToRip(pVCpu, cbInstr);
2864 if (!(fEflOld & X86_EFL_TF))
2865 {
2866 /* Specialized iemRegFinishClearingRF edition here that doesn't check X86_EFL_TF. */
2867 AssertCompile(CPUMCTX_INHIBIT_SHADOW < UINT32_MAX);
2868 if (RT_LIKELY(!( pVCpu->cpum.GstCtx.eflags.uBoth
2869 & (X86_EFL_RF | CPUMCTX_INHIBIT_SHADOW | CPUMCTX_DBG_HIT_DRX_MASK | CPUMCTX_DBG_DBGF_MASK)) ))
2870 return VINF_SUCCESS;
2871 return iemFinishInstructionWithFlagsSet<0 /*a_fTF*/>(pVCpu, VINF_SUCCESS); /* TF=0, so ignore it. */
2872 }
2873 return iemFinishInstructionWithTfSet(pVCpu);
2874}
2875
2876
2877#ifndef IEM_WITH_OPAQUE_DECODER_STATE
2878/**
2879 * Updates the RIP/EIP/IP to point to the next instruction and clears EFLAGS.RF.
2880 *
2881 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2882 */
2883DECLINLINE(VBOXSTRICTRC) iemRegUpdateRipAndFinishClearingRF(PVMCPUCC pVCpu) RT_NOEXCEPT
2884{
2885 return iemRegAddToRipAndFinishingClearingRF(pVCpu, IEM_GET_INSTR_LEN(pVCpu));
2886}
2887#endif
2888
2889
2890#ifdef IEM_WITH_CODE_TLB
2891
2892/**
2893 * Performs a near jump to the specified address, no checking or clearing of
2894 * flags
2895 *
2896 * May raise a \#GP(0) if the new IP outside the code segment limit.
2897 *
2898 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2899 * @param uNewIp The new IP value.
2900 */
2901DECLINLINE(VBOXSTRICTRC) iemRegRipJumpU16AndFinishNoFlags(PVMCPUCC pVCpu, uint16_t uNewIp) RT_NOEXCEPT
2902{
2903 if (RT_LIKELY( uNewIp <= pVCpu->cpum.GstCtx.cs.u32Limit
2904 || IEM_IS_64BIT_CODE(pVCpu) /* no limit checks in 64-bit mode */))
2905 pVCpu->cpum.GstCtx.rip = uNewIp;
2906 else
2907 return iemRaiseGeneralProtectionFault0(pVCpu);
2908 return iemRegFinishNoFlags(pVCpu, VINF_SUCCESS);
2909}
2910
2911
2912/**
2913 * Performs a near jump to the specified address, no checking or clearing of
2914 * flags
2915 *
2916 * May raise a \#GP(0) if the new RIP is outside the code segment limit.
2917 *
2918 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2919 * @param uNewEip The new EIP value.
2920 */
2921DECLINLINE(VBOXSTRICTRC) iemRegRipJumpU32AndFinishNoFlags(PVMCPUCC pVCpu, uint32_t uNewEip) RT_NOEXCEPT
2922{
2923 Assert(pVCpu->cpum.GstCtx.rip <= UINT32_MAX);
2924 Assert(!IEM_IS_64BIT_CODE(pVCpu));
2925 if (RT_LIKELY(uNewEip <= pVCpu->cpum.GstCtx.cs.u32Limit))
2926 pVCpu->cpum.GstCtx.rip = uNewEip;
2927 else
2928 return iemRaiseGeneralProtectionFault0(pVCpu);
2929 return iemRegFinishNoFlags(pVCpu, VINF_SUCCESS);
2930}
2931
2932
2933/**
2934 * Performs a near jump to the specified address, no checking or clearing of
2935 * flags.
2936 *
2937 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
2938 * segment limit.
2939 *
2940 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2941 * @param uNewRip The new RIP value.
2942 */
2943DECLINLINE(VBOXSTRICTRC) iemRegRipJumpU64AndFinishNoFlags(PVMCPUCC pVCpu, uint64_t uNewRip) RT_NOEXCEPT
2944{
2945 Assert(IEM_IS_64BIT_CODE(pVCpu));
2946 if (RT_LIKELY(IEM_IS_CANONICAL(uNewRip)))
2947 pVCpu->cpum.GstCtx.rip = uNewRip;
2948 else
2949 return iemRaiseGeneralProtectionFault0(pVCpu);
2950 return iemRegFinishNoFlags(pVCpu, VINF_SUCCESS);
2951}
2952
2953#endif /* IEM_WITH_CODE_TLB */
2954
2955/**
2956 * Performs a near jump to the specified address.
2957 *
2958 * May raise a \#GP(0) if the new IP outside the code segment limit.
2959 *
2960 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2961 * @param uNewIp The new IP value.
2962 * @param cbInstr The instruction length, for flushing in the non-TLB case.
2963 */
2964DECLINLINE(VBOXSTRICTRC) iemRegRipJumpU16AndFinishClearingRF(PVMCPUCC pVCpu, uint16_t uNewIp, uint8_t cbInstr) RT_NOEXCEPT
2965{
2966 if (RT_LIKELY( uNewIp <= pVCpu->cpum.GstCtx.cs.u32Limit
2967 || IEM_IS_64BIT_CODE(pVCpu) /* no limit checks in 64-bit mode */))
2968 pVCpu->cpum.GstCtx.rip = uNewIp;
2969 else
2970 return iemRaiseGeneralProtectionFault0(pVCpu);
2971#ifndef IEM_WITH_CODE_TLB
2972 iemOpcodeFlushLight(pVCpu, cbInstr);
2973#else
2974 RT_NOREF_PV(cbInstr);
2975#endif
2976 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
2977}
2978
2979
2980/**
2981 * Performs a near jump to the specified address.
2982 *
2983 * May raise a \#GP(0) if the new RIP is outside the code segment limit.
2984 *
2985 * @param pVCpu The cross context virtual CPU structure of the calling thread.
2986 * @param uNewEip The new EIP value.
2987 * @param cbInstr The instruction length, for flushing in the non-TLB case.
2988 */
2989DECLINLINE(VBOXSTRICTRC) iemRegRipJumpU32AndFinishClearingRF(PVMCPUCC pVCpu, uint32_t uNewEip, uint8_t cbInstr) RT_NOEXCEPT
2990{
2991 Assert(pVCpu->cpum.GstCtx.rip <= UINT32_MAX);
2992 Assert(!IEM_IS_64BIT_CODE(pVCpu));
2993 if (RT_LIKELY(uNewEip <= pVCpu->cpum.GstCtx.cs.u32Limit))
2994 pVCpu->cpum.GstCtx.rip = uNewEip;
2995 else
2996 return iemRaiseGeneralProtectionFault0(pVCpu);
2997#ifndef IEM_WITH_CODE_TLB
2998 iemOpcodeFlushLight(pVCpu, cbInstr);
2999#else
3000 RT_NOREF_PV(cbInstr);
3001#endif
3002 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
3003}
3004
3005
3006/**
3007 * Performs a near jump to the specified address.
3008 *
3009 * May raise a \#GP(0) if the new RIP is non-canonical or outside the code
3010 * segment limit.
3011 *
3012 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3013 * @param uNewRip The new RIP value.
3014 * @param cbInstr The instruction length, for flushing in the non-TLB case.
3015 */
3016DECLINLINE(VBOXSTRICTRC) iemRegRipJumpU64AndFinishClearingRF(PVMCPUCC pVCpu, uint64_t uNewRip, uint8_t cbInstr) RT_NOEXCEPT
3017{
3018 Assert(IEM_IS_64BIT_CODE(pVCpu));
3019 if (RT_LIKELY(IEM_IS_CANONICAL(uNewRip)))
3020 pVCpu->cpum.GstCtx.rip = uNewRip;
3021 else
3022 return iemRaiseGeneralProtectionFault0(pVCpu);
3023#ifndef IEM_WITH_CODE_TLB
3024 iemOpcodeFlushLight(pVCpu, cbInstr);
3025#else
3026 RT_NOREF_PV(cbInstr);
3027#endif
3028 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
3029}
3030
3031
3032/**
3033 * Implements a 16-bit relative call, no checking or clearing of
3034 * flags.
3035 *
3036 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3037 * @param cbInstr The instruction length.
3038 * @param offDisp The 16-bit displacement.
3039 */
3040DECL_FORCE_INLINE(VBOXSTRICTRC)
3041iemRegRipRelativeCallS16AndFinishNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr, int16_t offDisp) RT_NOEXCEPT
3042{
3043 uint16_t const uOldIp = pVCpu->cpum.GstCtx.ip + cbInstr;
3044 uint16_t const uNewIp = uOldIp + offDisp;
3045 if ( uNewIp <= pVCpu->cpum.GstCtx.cs.u32Limit
3046 || IEM_IS_64BIT_CODE(pVCpu) /* no CS limit checks in 64-bit mode */)
3047 { /* likely */ }
3048 else
3049 return iemRaiseGeneralProtectionFault0(pVCpu);
3050
3051 VBOXSTRICTRC rcStrict = iemMemStackPushU16(pVCpu, uOldIp);
3052 if (rcStrict == VINF_SUCCESS)
3053 { /* likely */ }
3054 else
3055 return rcStrict;
3056
3057 pVCpu->cpum.GstCtx.rip = uNewIp;
3058#ifndef IEM_WITH_CODE_TLB
3059 iemOpcodeFlushLight(pVCpu, cbInstr);
3060#endif
3061 return iemRegFinishNoFlags(pVCpu, VINF_SUCCESS);
3062}
3063
3064
3065/**
3066 * Implements a 16-bit relative call.
3067 *
3068 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3069 * @param cbInstr The instruction length.
3070 * @param offDisp The 16-bit displacement.
3071 */
3072DECL_FORCE_INLINE(VBOXSTRICTRC)
3073iemRegRipRelativeCallS16AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int16_t offDisp) RT_NOEXCEPT
3074{
3075 uint16_t const uOldIp = pVCpu->cpum.GstCtx.ip + cbInstr;
3076 uint16_t const uNewIp = uOldIp + offDisp;
3077 if ( uNewIp <= pVCpu->cpum.GstCtx.cs.u32Limit
3078 || IEM_IS_64BIT_CODE(pVCpu) /* no CS limit checks in 64-bit mode */)
3079 { /* likely */ }
3080 else
3081 return iemRaiseGeneralProtectionFault0(pVCpu);
3082
3083 VBOXSTRICTRC rcStrict = iemMemStackPushU16(pVCpu, uOldIp);
3084 if (rcStrict == VINF_SUCCESS)
3085 { /* likely */ }
3086 else
3087 return rcStrict;
3088
3089 pVCpu->cpum.GstCtx.rip = uNewIp;
3090#ifndef IEM_WITH_CODE_TLB
3091 iemOpcodeFlushLight(pVCpu, cbInstr);
3092#endif
3093 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
3094}
3095
3096
3097/**
3098 * Implements a 32-bit relative call, no checking or clearing of flags.
3099 *
3100 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3101 * @param cbInstr The instruction length.
3102 * @param offDisp The 32-bit displacement.
3103 */
3104DECL_FORCE_INLINE(VBOXSTRICTRC)
3105iemRegEip32RelativeCallS32AndFinishNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr, int32_t offDisp) RT_NOEXCEPT
3106{
3107 Assert(pVCpu->cpum.GstCtx.rip <= UINT32_MAX); Assert(!IEM_IS_64BIT_CODE(pVCpu));
3108
3109 uint32_t const uOldRip = pVCpu->cpum.GstCtx.eip + cbInstr;
3110 uint32_t const uNewRip = uOldRip + offDisp;
3111 if (uNewRip <= pVCpu->cpum.GstCtx.cs.u32Limit)
3112 { /* likely */ }
3113 else
3114 return iemRaiseGeneralProtectionFault0(pVCpu);
3115
3116 VBOXSTRICTRC rcStrict = iemMemStackPushU32(pVCpu, uOldRip);
3117 if (rcStrict == VINF_SUCCESS)
3118 { /* likely */ }
3119 else
3120 return rcStrict;
3121
3122 pVCpu->cpum.GstCtx.rip = uNewRip;
3123#ifndef IEM_WITH_CODE_TLB
3124 iemOpcodeFlushLight(pVCpu, cbInstr);
3125#endif
3126 return iemRegFinishNoFlags(pVCpu, VINF_SUCCESS);
3127}
3128
3129
3130/**
3131 * Implements a 32-bit relative call.
3132 *
3133 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3134 * @param cbInstr The instruction length.
3135 * @param offDisp The 32-bit displacement.
3136 */
3137DECL_FORCE_INLINE(VBOXSTRICTRC)
3138iemRegEip32RelativeCallS32AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int32_t offDisp) RT_NOEXCEPT
3139{
3140 Assert(pVCpu->cpum.GstCtx.rip <= UINT32_MAX); Assert(!IEM_IS_64BIT_CODE(pVCpu));
3141
3142 uint32_t const uOldRip = pVCpu->cpum.GstCtx.eip + cbInstr;
3143 uint32_t const uNewRip = uOldRip + offDisp;
3144 if (uNewRip <= pVCpu->cpum.GstCtx.cs.u32Limit)
3145 { /* likely */ }
3146 else
3147 return iemRaiseGeneralProtectionFault0(pVCpu);
3148
3149 VBOXSTRICTRC rcStrict = iemMemStackPushU32(pVCpu, uOldRip);
3150 if (rcStrict == VINF_SUCCESS)
3151 { /* likely */ }
3152 else
3153 return rcStrict;
3154
3155 pVCpu->cpum.GstCtx.rip = uNewRip;
3156#ifndef IEM_WITH_CODE_TLB
3157 iemOpcodeFlushLight(pVCpu, cbInstr);
3158#endif
3159 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
3160}
3161
3162
3163/**
3164 * Implements a 64-bit relative call, no checking or clearing of flags.
3165 *
3166 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3167 * @param cbInstr The instruction length.
3168 * @param offDisp The 64-bit displacement.
3169 */
3170DECL_FORCE_INLINE(VBOXSTRICTRC)
3171iemRegRip64RelativeCallS64AndFinishNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr, int64_t offDisp) RT_NOEXCEPT
3172{
3173 uint64_t const uOldRip = pVCpu->cpum.GstCtx.rip + cbInstr;
3174 uint64_t const uNewRip = uOldRip + (int64_t)offDisp;
3175 if (IEM_IS_CANONICAL(uNewRip))
3176 { /* likely */ }
3177 else
3178 return iemRaiseNotCanonical(pVCpu);
3179
3180 VBOXSTRICTRC rcStrict = iemMemStackPushU64(pVCpu, uOldRip);
3181 if (rcStrict == VINF_SUCCESS)
3182 { /* likely */ }
3183 else
3184 return rcStrict;
3185
3186 pVCpu->cpum.GstCtx.rip = uNewRip;
3187#ifndef IEM_WITH_CODE_TLB
3188 iemOpcodeFlushLight(pVCpu, cbInstr);
3189#endif
3190 return iemRegFinishNoFlags(pVCpu, VINF_SUCCESS);
3191}
3192
3193
3194/**
3195 * Implements a 64-bit relative call.
3196 *
3197 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3198 * @param cbInstr The instruction length.
3199 * @param offDisp The 64-bit displacement.
3200 */
3201DECL_FORCE_INLINE(VBOXSTRICTRC)
3202iemRegRip64RelativeCallS64AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, int64_t offDisp) RT_NOEXCEPT
3203{
3204 uint64_t const uOldRip = pVCpu->cpum.GstCtx.rip + cbInstr;
3205 uint64_t const uNewRip = uOldRip + (int64_t)offDisp;
3206 if (IEM_IS_CANONICAL(uNewRip))
3207 { /* likely */ }
3208 else
3209 return iemRaiseNotCanonical(pVCpu);
3210
3211 VBOXSTRICTRC rcStrict = iemMemStackPushU64(pVCpu, uOldRip);
3212 if (rcStrict == VINF_SUCCESS)
3213 { /* likely */ }
3214 else
3215 return rcStrict;
3216
3217 pVCpu->cpum.GstCtx.rip = uNewRip;
3218#ifndef IEM_WITH_CODE_TLB
3219 iemOpcodeFlushLight(pVCpu, cbInstr);
3220#endif
3221 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
3222}
3223
3224
3225/**
3226 * Implements an 16-bit indirect call, no checking or clearing of
3227 * flags.
3228 *
3229 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3230 * @param cbInstr The instruction length.
3231 * @param uNewRip The new RIP value.
3232 */
3233DECL_FORCE_INLINE(VBOXSTRICTRC)
3234iemRegIp16IndirectCallU16AndFinishNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t uNewRip) RT_NOEXCEPT
3235{
3236 uint16_t const uOldRip = pVCpu->cpum.GstCtx.ip + cbInstr;
3237 if (uNewRip <= pVCpu->cpum.GstCtx.cs.u32Limit)
3238 { /* likely */ }
3239 else
3240 return iemRaiseGeneralProtectionFault0(pVCpu);
3241
3242 VBOXSTRICTRC rcStrict = iemMemStackPushU16(pVCpu, uOldRip);
3243 if (rcStrict == VINF_SUCCESS)
3244 { /* likely */ }
3245 else
3246 return rcStrict;
3247
3248 pVCpu->cpum.GstCtx.rip = uNewRip;
3249#ifndef IEM_WITH_CODE_TLB
3250 iemOpcodeFlushLight(pVCpu, cbInstr);
3251#endif
3252 return iemRegFinishNoFlags(pVCpu, VINF_SUCCESS);
3253}
3254
3255
3256/**
3257 * Implements an 16-bit indirect call, no checking or clearing of
3258 * flags.
3259 *
3260 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3261 * @param cbInstr The instruction length.
3262 * @param uNewRip The new RIP value.
3263 */
3264DECL_FORCE_INLINE(VBOXSTRICTRC)
3265iemRegEip32IndirectCallU16AndFinishNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t uNewRip) RT_NOEXCEPT
3266{
3267 uint16_t const uOldRip = pVCpu->cpum.GstCtx.ip + cbInstr;
3268 if (uNewRip <= pVCpu->cpum.GstCtx.cs.u32Limit)
3269 { /* likely */ }
3270 else
3271 return iemRaiseGeneralProtectionFault0(pVCpu);
3272
3273 VBOXSTRICTRC rcStrict = iemMemStackPushU16(pVCpu, uOldRip);
3274 if (rcStrict == VINF_SUCCESS)
3275 { /* likely */ }
3276 else
3277 return rcStrict;
3278
3279 pVCpu->cpum.GstCtx.rip = uNewRip;
3280#ifndef IEM_WITH_CODE_TLB
3281 iemOpcodeFlushLight(pVCpu, cbInstr);
3282#endif
3283 return iemRegFinishNoFlags(pVCpu, VINF_SUCCESS);
3284}
3285
3286
3287/**
3288 * Implements an 16-bit indirect call.
3289 *
3290 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3291 * @param cbInstr The instruction length.
3292 * @param uNewRip The new RIP value.
3293 */
3294DECL_FORCE_INLINE(VBOXSTRICTRC)
3295iemRegIp16IndirectCallU16AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t uNewRip) RT_NOEXCEPT
3296{
3297 uint16_t const uOldRip = pVCpu->cpum.GstCtx.ip + cbInstr;
3298 if (uNewRip <= pVCpu->cpum.GstCtx.cs.u32Limit)
3299 { /* likely */ }
3300 else
3301 return iemRaiseGeneralProtectionFault0(pVCpu);
3302
3303 VBOXSTRICTRC rcStrict = iemMemStackPushU16(pVCpu, uOldRip);
3304 if (rcStrict == VINF_SUCCESS)
3305 { /* likely */ }
3306 else
3307 return rcStrict;
3308
3309 pVCpu->cpum.GstCtx.rip = uNewRip;
3310#ifndef IEM_WITH_CODE_TLB
3311 iemOpcodeFlushLight(pVCpu, cbInstr);
3312#endif
3313 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
3314}
3315
3316
3317/**
3318 * Implements an 16-bit indirect call.
3319 *
3320 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3321 * @param cbInstr The instruction length.
3322 * @param uNewRip The new RIP value.
3323 */
3324DECL_FORCE_INLINE(VBOXSTRICTRC)
3325iemRegEip32IndirectCallU16AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t uNewRip) RT_NOEXCEPT
3326{
3327 uint16_t const uOldRip = pVCpu->cpum.GstCtx.ip + cbInstr;
3328 if (uNewRip <= pVCpu->cpum.GstCtx.cs.u32Limit)
3329 { /* likely */ }
3330 else
3331 return iemRaiseGeneralProtectionFault0(pVCpu);
3332
3333 VBOXSTRICTRC rcStrict = iemMemStackPushU16(pVCpu, uOldRip);
3334 if (rcStrict == VINF_SUCCESS)
3335 { /* likely */ }
3336 else
3337 return rcStrict;
3338
3339 pVCpu->cpum.GstCtx.rip = uNewRip;
3340#ifndef IEM_WITH_CODE_TLB
3341 iemOpcodeFlushLight(pVCpu, cbInstr);
3342#endif
3343 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
3344}
3345
3346
3347/**
3348 * Implements an 32-bit indirect call, no checking or clearing of
3349 * flags.
3350 *
3351 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3352 * @param cbInstr The instruction length.
3353 * @param uNewRip The new RIP value.
3354 */
3355DECL_FORCE_INLINE(VBOXSTRICTRC)
3356iemRegEip32IndirectCallU32AndFinishNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr, uint32_t uNewRip) RT_NOEXCEPT
3357{
3358 uint32_t const uOldRip = pVCpu->cpum.GstCtx.eip + cbInstr;
3359 if (uNewRip <= pVCpu->cpum.GstCtx.cs.u32Limit)
3360 { /* likely */ }
3361 else
3362 return iemRaiseGeneralProtectionFault0(pVCpu);
3363
3364 VBOXSTRICTRC rcStrict = iemMemStackPushU32(pVCpu, uOldRip);
3365 if (rcStrict == VINF_SUCCESS)
3366 { /* likely */ }
3367 else
3368 return rcStrict;
3369
3370 pVCpu->cpum.GstCtx.rip = uNewRip;
3371#ifndef IEM_WITH_CODE_TLB
3372 iemOpcodeFlushLight(pVCpu, cbInstr);
3373#endif
3374 return iemRegFinishNoFlags(pVCpu, VINF_SUCCESS);
3375}
3376
3377
3378/**
3379 * Implements an 32-bit indirect call.
3380 *
3381 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3382 * @param cbInstr The instruction length.
3383 * @param uNewRip The new RIP value.
3384 */
3385DECL_FORCE_INLINE(VBOXSTRICTRC)
3386iemRegEip32IndirectCallU32AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, uint32_t uNewRip) RT_NOEXCEPT
3387{
3388 uint32_t const uOldRip = pVCpu->cpum.GstCtx.eip + cbInstr;
3389 if (uNewRip <= pVCpu->cpum.GstCtx.cs.u32Limit)
3390 { /* likely */ }
3391 else
3392 return iemRaiseGeneralProtectionFault0(pVCpu);
3393
3394 VBOXSTRICTRC rcStrict = iemMemStackPushU32(pVCpu, uOldRip);
3395 if (rcStrict == VINF_SUCCESS)
3396 { /* likely */ }
3397 else
3398 return rcStrict;
3399
3400 pVCpu->cpum.GstCtx.rip = uNewRip;
3401#ifndef IEM_WITH_CODE_TLB
3402 iemOpcodeFlushLight(pVCpu, cbInstr);
3403#endif
3404 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
3405}
3406
3407
3408/**
3409 * Implements an 64-bit indirect call, no checking or clearing of
3410 * flags.
3411 *
3412 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3413 * @param cbInstr The instruction length.
3414 * @param uNewRip The new RIP value.
3415 */
3416DECL_FORCE_INLINE(VBOXSTRICTRC)
3417iemRegRip64IndirectCallU64AndFinishNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr, uint64_t uNewRip) RT_NOEXCEPT
3418{
3419 uint64_t const uOldRip = pVCpu->cpum.GstCtx.rip + cbInstr;
3420 if (IEM_IS_CANONICAL(uNewRip))
3421 { /* likely */ }
3422 else
3423 return iemRaiseGeneralProtectionFault0(pVCpu);
3424
3425 VBOXSTRICTRC rcStrict = iemMemStackPushU64(pVCpu, uOldRip);
3426 if (rcStrict == VINF_SUCCESS)
3427 { /* likely */ }
3428 else
3429 return rcStrict;
3430
3431 pVCpu->cpum.GstCtx.rip = uNewRip;
3432#ifndef IEM_WITH_CODE_TLB
3433 iemOpcodeFlushLight(pVCpu, cbInstr);
3434#endif
3435 return iemRegFinishNoFlags(pVCpu, VINF_SUCCESS);
3436}
3437
3438
3439/**
3440 * Implements an 64-bit indirect call.
3441 *
3442 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3443 * @param cbInstr The instruction length.
3444 * @param uNewRip The new RIP value.
3445 */
3446DECL_FORCE_INLINE(VBOXSTRICTRC)
3447iemRegRip64IndirectCallU64AndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, uint64_t uNewRip) RT_NOEXCEPT
3448{
3449 uint64_t const uOldRip = pVCpu->cpum.GstCtx.rip + cbInstr;
3450 if (IEM_IS_CANONICAL(uNewRip))
3451 { /* likely */ }
3452 else
3453 return iemRaiseGeneralProtectionFault0(pVCpu);
3454
3455 VBOXSTRICTRC rcStrict = iemMemStackPushU64(pVCpu, uOldRip);
3456 if (rcStrict == VINF_SUCCESS)
3457 { /* likely */ }
3458 else
3459 return rcStrict;
3460
3461 pVCpu->cpum.GstCtx.rip = uNewRip;
3462#ifndef IEM_WITH_CODE_TLB
3463 iemOpcodeFlushLight(pVCpu, cbInstr);
3464#endif
3465 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
3466}
3467
3468
3469
3470/**
3471 * Adds to the stack pointer.
3472 *
3473 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3474 * @param cbToAdd The number of bytes to add (8-bit!).
3475 */
3476DECLINLINE(void) iemRegAddToRsp(PVMCPUCC pVCpu, uint8_t cbToAdd) RT_NOEXCEPT
3477{
3478 if (IEM_IS_64BIT_CODE(pVCpu))
3479 pVCpu->cpum.GstCtx.rsp += cbToAdd;
3480 else if (pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
3481 pVCpu->cpum.GstCtx.esp += cbToAdd;
3482 else
3483 pVCpu->cpum.GstCtx.sp += cbToAdd;
3484}
3485
3486
3487/**
3488 * Subtracts from the stack pointer.
3489 *
3490 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3491 * @param cbToSub The number of bytes to subtract (8-bit!).
3492 */
3493DECLINLINE(void) iemRegSubFromRsp(PVMCPUCC pVCpu, uint8_t cbToSub) RT_NOEXCEPT
3494{
3495 if (IEM_IS_64BIT_CODE(pVCpu))
3496 pVCpu->cpum.GstCtx.rsp -= cbToSub;
3497 else if (pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
3498 pVCpu->cpum.GstCtx.esp -= cbToSub;
3499 else
3500 pVCpu->cpum.GstCtx.sp -= cbToSub;
3501}
3502
3503
3504/**
3505 * Adds to the temporary stack pointer.
3506 *
3507 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3508 * @param pTmpRsp The temporary SP/ESP/RSP to update.
3509 * @param cbToAdd The number of bytes to add (16-bit).
3510 */
3511DECLINLINE(void) iemRegAddToRspEx(PCVMCPU pVCpu, PRTUINT64U pTmpRsp, uint16_t cbToAdd) RT_NOEXCEPT
3512{
3513 if (IEM_IS_64BIT_CODE(pVCpu))
3514 pTmpRsp->u += cbToAdd;
3515 else if (pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
3516 pTmpRsp->DWords.dw0 += cbToAdd;
3517 else
3518 pTmpRsp->Words.w0 += cbToAdd;
3519}
3520
3521
3522/**
3523 * Subtracts from the temporary stack pointer.
3524 *
3525 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3526 * @param pTmpRsp The temporary SP/ESP/RSP to update.
3527 * @param cbToSub The number of bytes to subtract.
3528 * @remarks The @a cbToSub argument *MUST* be 16-bit, iemCImpl_enter is
3529 * expecting that.
3530 */
3531DECLINLINE(void) iemRegSubFromRspEx(PCVMCPU pVCpu, PRTUINT64U pTmpRsp, uint16_t cbToSub) RT_NOEXCEPT
3532{
3533 if (IEM_IS_64BIT_CODE(pVCpu))
3534 pTmpRsp->u -= cbToSub;
3535 else if (pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
3536 pTmpRsp->DWords.dw0 -= cbToSub;
3537 else
3538 pTmpRsp->Words.w0 -= cbToSub;
3539}
3540
3541
3542/**
3543 * Calculates the effective stack address for a push of the specified size as
3544 * well as the new RSP value (upper bits may be masked).
3545 *
3546 * @returns Effective stack addressf for the push.
3547 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3548 * @param cbItem The size of the stack item to pop.
3549 * @param puNewRsp Where to return the new RSP value.
3550 */
3551DECLINLINE(RTGCPTR) iemRegGetRspForPush(PCVMCPU pVCpu, uint8_t cbItem, uint64_t *puNewRsp) RT_NOEXCEPT
3552{
3553 RTUINT64U uTmpRsp;
3554 RTGCPTR GCPtrTop;
3555 uTmpRsp.u = pVCpu->cpum.GstCtx.rsp;
3556
3557 if (IEM_IS_64BIT_CODE(pVCpu))
3558 GCPtrTop = uTmpRsp.u -= cbItem;
3559 else if (pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
3560 GCPtrTop = uTmpRsp.DWords.dw0 -= cbItem;
3561 else
3562 GCPtrTop = uTmpRsp.Words.w0 -= cbItem;
3563 *puNewRsp = uTmpRsp.u;
3564 return GCPtrTop;
3565}
3566
3567
3568/**
3569 * Gets the current stack pointer and calculates the value after a pop of the
3570 * specified size.
3571 *
3572 * @returns Current stack pointer.
3573 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3574 * @param cbItem The size of the stack item to pop.
3575 * @param puNewRsp Where to return the new RSP value.
3576 */
3577DECLINLINE(RTGCPTR) iemRegGetRspForPop(PCVMCPU pVCpu, uint8_t cbItem, uint64_t *puNewRsp) RT_NOEXCEPT
3578{
3579 RTUINT64U uTmpRsp;
3580 RTGCPTR GCPtrTop;
3581 uTmpRsp.u = pVCpu->cpum.GstCtx.rsp;
3582
3583 if (IEM_IS_64BIT_CODE(pVCpu))
3584 {
3585 GCPtrTop = uTmpRsp.u;
3586 uTmpRsp.u += cbItem;
3587 }
3588 else if (pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
3589 {
3590 GCPtrTop = uTmpRsp.DWords.dw0;
3591 uTmpRsp.DWords.dw0 += cbItem;
3592 }
3593 else
3594 {
3595 GCPtrTop = uTmpRsp.Words.w0;
3596 uTmpRsp.Words.w0 += cbItem;
3597 }
3598 *puNewRsp = uTmpRsp.u;
3599 return GCPtrTop;
3600}
3601
3602
3603/**
3604 * Calculates the effective stack address for a push of the specified size as
3605 * well as the new temporary RSP value (upper bits may be masked).
3606 *
3607 * @returns Effective stack addressf for the push.
3608 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3609 * @param pTmpRsp The temporary stack pointer. This is updated.
3610 * @param cbItem The size of the stack item to pop.
3611 */
3612DECLINLINE(RTGCPTR) iemRegGetRspForPushEx(PCVMCPU pVCpu, PRTUINT64U pTmpRsp, uint8_t cbItem) RT_NOEXCEPT
3613{
3614 RTGCPTR GCPtrTop;
3615
3616 if (IEM_IS_64BIT_CODE(pVCpu))
3617 GCPtrTop = pTmpRsp->u -= cbItem;
3618 else if (pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
3619 GCPtrTop = pTmpRsp->DWords.dw0 -= cbItem;
3620 else
3621 GCPtrTop = pTmpRsp->Words.w0 -= cbItem;
3622 return GCPtrTop;
3623}
3624
3625
3626/**
3627 * Gets the effective stack address for a pop of the specified size and
3628 * calculates and updates the temporary RSP.
3629 *
3630 * @returns Current stack pointer.
3631 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3632 * @param pTmpRsp The temporary stack pointer. This is updated.
3633 * @param cbItem The size of the stack item to pop.
3634 */
3635DECLINLINE(RTGCPTR) iemRegGetRspForPopEx(PCVMCPU pVCpu, PRTUINT64U pTmpRsp, uint8_t cbItem) RT_NOEXCEPT
3636{
3637 RTGCPTR GCPtrTop;
3638 if (IEM_IS_64BIT_CODE(pVCpu))
3639 {
3640 GCPtrTop = pTmpRsp->u;
3641 pTmpRsp->u += cbItem;
3642 }
3643 else if (pVCpu->cpum.GstCtx.ss.Attr.n.u1DefBig)
3644 {
3645 GCPtrTop = pTmpRsp->DWords.dw0;
3646 pTmpRsp->DWords.dw0 += cbItem;
3647 }
3648 else
3649 {
3650 GCPtrTop = pTmpRsp->Words.w0;
3651 pTmpRsp->Words.w0 += cbItem;
3652 }
3653 return GCPtrTop;
3654}
3655
3656
3657/** Common body for iemRegRipNearReturnAndFinishClearingRF()
3658 * and iemRegRipNearReturnAndFinishNoFlags(). */
3659template<bool a_fWithFlags>
3660DECL_FORCE_INLINE(VBOXSTRICTRC)
3661iemRegRipNearReturnCommon(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t cbPop, IEMMODE enmEffOpSize) RT_NOEXCEPT
3662{
3663 /* Fetch the new RIP from the stack. */
3664 VBOXSTRICTRC rcStrict;
3665 RTUINT64U NewRip;
3666 RTUINT64U NewRsp;
3667 NewRsp.u = pVCpu->cpum.GstCtx.rsp;
3668 switch (enmEffOpSize)
3669 {
3670 case IEMMODE_16BIT:
3671 NewRip.u = 0;
3672 rcStrict = iemMemStackPopU16Ex(pVCpu, &NewRip.Words.w0, &NewRsp);
3673 break;
3674 case IEMMODE_32BIT:
3675 NewRip.u = 0;
3676 rcStrict = iemMemStackPopU32Ex(pVCpu, &NewRip.DWords.dw0, &NewRsp);
3677 break;
3678 case IEMMODE_64BIT:
3679 rcStrict = iemMemStackPopU64Ex(pVCpu, &NewRip.u, &NewRsp);
3680 break;
3681 IEM_NOT_REACHED_DEFAULT_CASE_RET();
3682 }
3683 if (rcStrict != VINF_SUCCESS)
3684 return rcStrict;
3685
3686 /* Check the new ew RIP before loading it. */
3687 /** @todo Should test this as the intel+amd pseudo code doesn't mention half
3688 * of it. The canonical test is performed here and for call. */
3689 if (enmEffOpSize != IEMMODE_64BIT)
3690 {
3691 if (RT_LIKELY(NewRip.DWords.dw0 <= pVCpu->cpum.GstCtx.cs.u32Limit))
3692 { /* likely */ }
3693 else
3694 {
3695 Log(("retn newrip=%llx - out of bounds (%x) -> #GP\n", NewRip.u, pVCpu->cpum.GstCtx.cs.u32Limit));
3696 return iemRaiseSelectorBounds(pVCpu, X86_SREG_CS, IEM_ACCESS_INSTRUCTION);
3697 }
3698 }
3699 else
3700 {
3701 if (RT_LIKELY(IEM_IS_CANONICAL(NewRip.u)))
3702 { /* likely */ }
3703 else
3704 {
3705 Log(("retn newrip=%llx - not canonical -> #GP\n", NewRip.u));
3706 return iemRaiseNotCanonical(pVCpu);
3707 }
3708 }
3709
3710 /* Apply cbPop */
3711 if (cbPop)
3712 iemRegAddToRspEx(pVCpu, &NewRsp, cbPop);
3713
3714 /* Commit it. */
3715 pVCpu->cpum.GstCtx.rip = NewRip.u;
3716 pVCpu->cpum.GstCtx.rsp = NewRsp.u;
3717
3718 /* Flush the prefetch buffer. */
3719#ifndef IEM_WITH_CODE_TLB
3720 iemOpcodeFlushLight(pVCpu, cbInstr);
3721#endif
3722 RT_NOREF(cbInstr);
3723
3724
3725 if (a_fWithFlags)
3726 return iemRegFinishClearingRF(pVCpu, VINF_SUCCESS);
3727 return iemRegFinishNoFlags(pVCpu, VINF_SUCCESS);
3728}
3729
3730
3731/**
3732 * Implements retn and retn imm16.
3733 *
3734 * @param pVCpu The cross context virtual CPU structure of the
3735 * calling thread.
3736 * @param cbInstr The current instruction length.
3737 * @param enmEffOpSize The effective operand size. This is constant.
3738 * @param cbPop The amount of arguments to pop from the stack
3739 * (bytes). This can be constant (zero).
3740 */
3741DECL_FORCE_INLINE(VBOXSTRICTRC)
3742iemRegRipNearReturnAndFinishClearingRF(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t cbPop, IEMMODE enmEffOpSize) RT_NOEXCEPT
3743{
3744 return iemRegRipNearReturnCommon<true /*a_fWithFlags*/>(pVCpu, cbInstr, cbPop, enmEffOpSize);
3745}
3746
3747
3748/**
3749 * Implements retn and retn imm16, no checking or clearing of
3750 * flags.
3751 *
3752 * @param pVCpu The cross context virtual CPU structure of the
3753 * calling thread.
3754 * @param cbInstr The current instruction length.
3755 * @param enmEffOpSize The effective operand size. This is constant.
3756 * @param cbPop The amount of arguments to pop from the stack
3757 * (bytes). This can be constant (zero).
3758 */
3759DECL_FORCE_INLINE(VBOXSTRICTRC)
3760iemRegRipNearReturnAndFinishNoFlags(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t cbPop, IEMMODE enmEffOpSize) RT_NOEXCEPT
3761{
3762 return iemRegRipNearReturnCommon<false /*a_fWithFlags*/>(pVCpu, cbInstr, cbPop, enmEffOpSize);
3763}
3764
3765/** @} */
3766
3767
3768/** @name FPU access and helpers.
3769 *
3770 * @{
3771 */
3772
3773
3774/**
3775 * Hook for preparing to use the host FPU.
3776 *
3777 * This is necessary in ring-0 and raw-mode context (nop in ring-3).
3778 *
3779 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3780 */
3781DECLINLINE(void) iemFpuPrepareUsage(PVMCPUCC pVCpu) RT_NOEXCEPT
3782{
3783#ifdef IN_RING3
3784 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_FPU_REM);
3785#else
3786 CPUMRZFpuStatePrepareHostCpuForUse(pVCpu);
3787#endif
3788 IEM_CTX_IMPORT_NORET(pVCpu, CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE | CPUMCTX_EXTRN_XCRx);
3789}
3790
3791
3792/**
3793 * Hook for preparing to use the host FPU for SSE.
3794 *
3795 * This is necessary in ring-0 and raw-mode context (nop in ring-3).
3796 *
3797 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3798 */
3799DECLINLINE(void) iemFpuPrepareUsageSse(PVMCPUCC pVCpu) RT_NOEXCEPT
3800{
3801 iemFpuPrepareUsage(pVCpu);
3802}
3803
3804
3805/**
3806 * Hook for preparing to use the host FPU for AVX.
3807 *
3808 * This is necessary in ring-0 and raw-mode context (nop in ring-3).
3809 *
3810 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3811 */
3812DECLINLINE(void) iemFpuPrepareUsageAvx(PVMCPUCC pVCpu) RT_NOEXCEPT
3813{
3814 iemFpuPrepareUsage(pVCpu);
3815}
3816
3817
3818/**
3819 * Hook for actualizing the guest FPU state before the interpreter reads it.
3820 *
3821 * This is necessary in ring-0 and raw-mode context (nop in ring-3).
3822 *
3823 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3824 */
3825DECLINLINE(void) iemFpuActualizeStateForRead(PVMCPUCC pVCpu) RT_NOEXCEPT
3826{
3827#ifdef IN_RING3
3828 NOREF(pVCpu);
3829#else
3830 CPUMRZFpuStateActualizeForRead(pVCpu);
3831#endif
3832 IEM_CTX_IMPORT_NORET(pVCpu, CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE | CPUMCTX_EXTRN_XCRx);
3833}
3834
3835
3836/**
3837 * Hook for actualizing the guest FPU state before the interpreter changes it.
3838 *
3839 * This is necessary in ring-0 and raw-mode context (nop in ring-3).
3840 *
3841 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3842 */
3843DECLINLINE(void) iemFpuActualizeStateForChange(PVMCPUCC pVCpu) RT_NOEXCEPT
3844{
3845#ifdef IN_RING3
3846 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_FPU_REM);
3847#else
3848 CPUMRZFpuStateActualizeForChange(pVCpu);
3849#endif
3850 IEM_CTX_IMPORT_NORET(pVCpu, CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE | CPUMCTX_EXTRN_XCRx);
3851}
3852
3853
3854/**
3855 * Hook for actualizing the guest XMM0..15 and MXCSR register state for read
3856 * only.
3857 *
3858 * This is necessary in ring-0 and raw-mode context (nop in ring-3).
3859 *
3860 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3861 */
3862DECLINLINE(void) iemFpuActualizeSseStateForRead(PVMCPUCC pVCpu) RT_NOEXCEPT
3863{
3864#if defined(IN_RING3) || defined(VBOX_WITH_KERNEL_USING_XMM)
3865 NOREF(pVCpu);
3866#else
3867 CPUMRZFpuStateActualizeSseForRead(pVCpu);
3868#endif
3869 IEM_CTX_IMPORT_NORET(pVCpu, CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE | CPUMCTX_EXTRN_XCRx);
3870}
3871
3872
3873/**
3874 * Hook for actualizing the guest XMM0..15 and MXCSR register state for
3875 * read+write.
3876 *
3877 * This is necessary in ring-0 and raw-mode context (nop in ring-3).
3878 *
3879 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3880 */
3881DECLINLINE(void) iemFpuActualizeSseStateForChange(PVMCPUCC pVCpu) RT_NOEXCEPT
3882{
3883#if defined(IN_RING3) || defined(VBOX_WITH_KERNEL_USING_XMM)
3884 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_FPU_REM);
3885#else
3886 CPUMRZFpuStateActualizeForChange(pVCpu);
3887#endif
3888 IEM_CTX_IMPORT_NORET(pVCpu, CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE | CPUMCTX_EXTRN_XCRx);
3889
3890 /* Make sure any changes are loaded the next time around. */
3891 pVCpu->cpum.GstCtx.XState.Hdr.bmXState |= XSAVE_C_SSE;
3892}
3893
3894
3895/**
3896 * Hook for actualizing the guest YMM0..15 and MXCSR register state for read
3897 * only.
3898 *
3899 * This is necessary in ring-0 and raw-mode context (nop in ring-3).
3900 *
3901 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3902 */
3903DECLINLINE(void) iemFpuActualizeAvxStateForRead(PVMCPUCC pVCpu) RT_NOEXCEPT
3904{
3905#ifdef IN_RING3
3906 NOREF(pVCpu);
3907#else
3908 CPUMRZFpuStateActualizeAvxForRead(pVCpu);
3909#endif
3910 IEM_CTX_IMPORT_NORET(pVCpu, CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE | CPUMCTX_EXTRN_XCRx);
3911}
3912
3913
3914/**
3915 * Hook for actualizing the guest YMM0..15 and MXCSR register state for
3916 * read+write.
3917 *
3918 * This is necessary in ring-0 and raw-mode context (nop in ring-3).
3919 *
3920 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3921 */
3922DECLINLINE(void) iemFpuActualizeAvxStateForChange(PVMCPUCC pVCpu) RT_NOEXCEPT
3923{
3924#ifdef IN_RING3
3925 CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_FPU_REM);
3926#else
3927 CPUMRZFpuStateActualizeForChange(pVCpu);
3928#endif
3929 IEM_CTX_IMPORT_NORET(pVCpu, CPUMCTX_EXTRN_X87 | CPUMCTX_EXTRN_SSE_AVX | CPUMCTX_EXTRN_OTHER_XSAVE | CPUMCTX_EXTRN_XCRx);
3930
3931 /* Just assume we're going to make changes to the SSE and YMM_HI parts. */
3932 pVCpu->cpum.GstCtx.XState.Hdr.bmXState |= XSAVE_C_YMM | XSAVE_C_SSE;
3933}
3934
3935
3936/**
3937 * Stores a QNaN value into a FPU register.
3938 *
3939 * @param pReg Pointer to the register.
3940 */
3941DECLINLINE(void) iemFpuStoreQNan(PRTFLOAT80U pReg) RT_NOEXCEPT
3942{
3943 pReg->au32[0] = UINT32_C(0x00000000);
3944 pReg->au32[1] = UINT32_C(0xc0000000);
3945 pReg->au16[4] = UINT16_C(0xffff);
3946}
3947
3948
3949/**
3950 * Updates the FOP, FPU.CS and FPUIP registers, extended version.
3951 *
3952 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3953 * @param pFpuCtx The FPU context.
3954 * @param uFpuOpcode The FPU opcode value (see IEMCPU::uFpuOpcode).
3955 */
3956DECLINLINE(void) iemFpuUpdateOpcodeAndIpWorkerEx(PVMCPUCC pVCpu, PX86FXSTATE pFpuCtx, uint16_t uFpuOpcode) RT_NOEXCEPT
3957{
3958 Assert(uFpuOpcode != UINT16_MAX);
3959 pFpuCtx->FOP = uFpuOpcode;
3960 /** @todo x87.CS and FPUIP needs to be kept seperately. */
3961 if (IEM_IS_REAL_OR_V86_MODE(pVCpu))
3962 {
3963 /** @todo Testcase: making assumptions about how FPUIP and FPUDP are handled
3964 * happens in real mode here based on the fnsave and fnstenv images. */
3965 pFpuCtx->CS = 0;
3966 pFpuCtx->FPUIP = pVCpu->cpum.GstCtx.eip | ((uint32_t)pVCpu->cpum.GstCtx.cs.Sel << 4);
3967 }
3968 else if (!IEM_IS_LONG_MODE(pVCpu))
3969 {
3970 pFpuCtx->CS = pVCpu->cpum.GstCtx.cs.Sel;
3971 pFpuCtx->FPUIP = pVCpu->cpum.GstCtx.rip;
3972 }
3973 else
3974 *(uint64_t *)&pFpuCtx->FPUIP = pVCpu->cpum.GstCtx.rip;
3975}
3976
3977
3978/**
3979 * Marks the specified stack register as free (for FFREE).
3980 *
3981 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3982 * @param iStReg The register to free.
3983 */
3984DECLINLINE(void) iemFpuStackFree(PVMCPUCC pVCpu, uint8_t iStReg) RT_NOEXCEPT
3985{
3986 Assert(iStReg < 8);
3987 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
3988 uint8_t iReg = (X86_FSW_TOP_GET(pFpuCtx->FSW) + iStReg) & X86_FSW_TOP_SMASK;
3989 pFpuCtx->FTW &= ~RT_BIT(iReg);
3990}
3991
3992
3993/**
3994 * Increments FSW.TOP, i.e. pops an item off the stack without freeing it.
3995 *
3996 * @param pVCpu The cross context virtual CPU structure of the calling thread.
3997 */
3998DECLINLINE(void) iemFpuStackIncTop(PVMCPUCC pVCpu) RT_NOEXCEPT
3999{
4000 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
4001 uint16_t uFsw = pFpuCtx->FSW;
4002 uint16_t uTop = uFsw & X86_FSW_TOP_MASK;
4003 uTop = (uTop + (1 << X86_FSW_TOP_SHIFT)) & X86_FSW_TOP_MASK;
4004 uFsw &= ~X86_FSW_TOP_MASK;
4005 uFsw |= uTop;
4006 pFpuCtx->FSW = uFsw;
4007}
4008
4009
4010/**
4011 * Decrements FSW.TOP, i.e. push an item off the stack without storing anything.
4012 *
4013 * @param pVCpu The cross context virtual CPU structure of the calling thread.
4014 */
4015DECLINLINE(void) iemFpuStackDecTop(PVMCPUCC pVCpu) RT_NOEXCEPT
4016{
4017 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
4018 uint16_t uFsw = pFpuCtx->FSW;
4019 uint16_t uTop = uFsw & X86_FSW_TOP_MASK;
4020 uTop = (uTop + (7 << X86_FSW_TOP_SHIFT)) & X86_FSW_TOP_MASK;
4021 uFsw &= ~X86_FSW_TOP_MASK;
4022 uFsw |= uTop;
4023 pFpuCtx->FSW = uFsw;
4024}
4025
4026
4027
4028
4029DECLINLINE(int) iemFpuStRegNotEmpty(PVMCPUCC pVCpu, uint8_t iStReg) RT_NOEXCEPT
4030{
4031 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
4032 uint16_t iReg = (X86_FSW_TOP_GET(pFpuCtx->FSW) + iStReg) & X86_FSW_TOP_SMASK;
4033 if (pFpuCtx->FTW & RT_BIT(iReg))
4034 return VINF_SUCCESS;
4035 return VERR_NOT_FOUND;
4036}
4037
4038
4039DECLINLINE(int) iemFpuStRegNotEmptyRef(PVMCPUCC pVCpu, uint8_t iStReg, PCRTFLOAT80U *ppRef) RT_NOEXCEPT
4040{
4041 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
4042 uint16_t iReg = (X86_FSW_TOP_GET(pFpuCtx->FSW) + iStReg) & X86_FSW_TOP_SMASK;
4043 if (pFpuCtx->FTW & RT_BIT(iReg))
4044 {
4045 *ppRef = &pFpuCtx->aRegs[iStReg].r80;
4046 return VINF_SUCCESS;
4047 }
4048 return VERR_NOT_FOUND;
4049}
4050
4051
4052DECLINLINE(int) iemFpu2StRegsNotEmptyRef(PVMCPUCC pVCpu, uint8_t iStReg0, PCRTFLOAT80U *ppRef0,
4053 uint8_t iStReg1, PCRTFLOAT80U *ppRef1) RT_NOEXCEPT
4054{
4055 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
4056 uint16_t iTop = X86_FSW_TOP_GET(pFpuCtx->FSW);
4057 uint16_t iReg0 = (iTop + iStReg0) & X86_FSW_TOP_SMASK;
4058 uint16_t iReg1 = (iTop + iStReg1) & X86_FSW_TOP_SMASK;
4059 if ((pFpuCtx->FTW & (RT_BIT(iReg0) | RT_BIT(iReg1))) == (RT_BIT(iReg0) | RT_BIT(iReg1)))
4060 {
4061 *ppRef0 = &pFpuCtx->aRegs[iStReg0].r80;
4062 *ppRef1 = &pFpuCtx->aRegs[iStReg1].r80;
4063 return VINF_SUCCESS;
4064 }
4065 return VERR_NOT_FOUND;
4066}
4067
4068
4069DECLINLINE(int) iemFpu2StRegsNotEmptyRefFirst(PVMCPUCC pVCpu, uint8_t iStReg0, PCRTFLOAT80U *ppRef0, uint8_t iStReg1) RT_NOEXCEPT
4070{
4071 PX86FXSTATE pFpuCtx = &pVCpu->cpum.GstCtx.XState.x87;
4072 uint16_t iTop = X86_FSW_TOP_GET(pFpuCtx->FSW);
4073 uint16_t iReg0 = (iTop + iStReg0) & X86_FSW_TOP_SMASK;
4074 uint16_t iReg1 = (iTop + iStReg1) & X86_FSW_TOP_SMASK;
4075 if ((pFpuCtx->FTW & (RT_BIT(iReg0) | RT_BIT(iReg1))) == (RT_BIT(iReg0) | RT_BIT(iReg1)))
4076 {
4077 *ppRef0 = &pFpuCtx->aRegs[iStReg0].r80;
4078 return VINF_SUCCESS;
4079 }
4080 return VERR_NOT_FOUND;
4081}
4082
4083
4084/**
4085 * Rotates the stack registers when setting new TOS.
4086 *
4087 * @param pFpuCtx The FPU context.
4088 * @param iNewTop New TOS value.
4089 * @remarks We only do this to speed up fxsave/fxrstor which
4090 * arrange the FP registers in stack order.
4091 * MUST be done before writing the new TOS (FSW).
4092 */
4093DECLINLINE(void) iemFpuRotateStackSetTop(PX86FXSTATE pFpuCtx, uint16_t iNewTop) RT_NOEXCEPT
4094{
4095 uint16_t iOldTop = X86_FSW_TOP_GET(pFpuCtx->FSW);
4096 RTFLOAT80U ar80Temp[8];
4097
4098 if (iOldTop == iNewTop)
4099 return;
4100
4101 /* Unscrew the stack and get it into 'native' order. */
4102 ar80Temp[0] = pFpuCtx->aRegs[(8 - iOldTop + 0) & X86_FSW_TOP_SMASK].r80;
4103 ar80Temp[1] = pFpuCtx->aRegs[(8 - iOldTop + 1) & X86_FSW_TOP_SMASK].r80;
4104 ar80Temp[2] = pFpuCtx->aRegs[(8 - iOldTop + 2) & X86_FSW_TOP_SMASK].r80;
4105 ar80Temp[3] = pFpuCtx->aRegs[(8 - iOldTop + 3) & X86_FSW_TOP_SMASK].r80;
4106 ar80Temp[4] = pFpuCtx->aRegs[(8 - iOldTop + 4) & X86_FSW_TOP_SMASK].r80;
4107 ar80Temp[5] = pFpuCtx->aRegs[(8 - iOldTop + 5) & X86_FSW_TOP_SMASK].r80;
4108 ar80Temp[6] = pFpuCtx->aRegs[(8 - iOldTop + 6) & X86_FSW_TOP_SMASK].r80;
4109 ar80Temp[7] = pFpuCtx->aRegs[(8 - iOldTop + 7) & X86_FSW_TOP_SMASK].r80;
4110
4111 /* Now rotate the stack to the new position. */
4112 pFpuCtx->aRegs[0].r80 = ar80Temp[(iNewTop + 0) & X86_FSW_TOP_SMASK];
4113 pFpuCtx->aRegs[1].r80 = ar80Temp[(iNewTop + 1) & X86_FSW_TOP_SMASK];
4114 pFpuCtx->aRegs[2].r80 = ar80Temp[(iNewTop + 2) & X86_FSW_TOP_SMASK];
4115 pFpuCtx->aRegs[3].r80 = ar80Temp[(iNewTop + 3) & X86_FSW_TOP_SMASK];
4116 pFpuCtx->aRegs[4].r80 = ar80Temp[(iNewTop + 4) & X86_FSW_TOP_SMASK];
4117 pFpuCtx->aRegs[5].r80 = ar80Temp[(iNewTop + 5) & X86_FSW_TOP_SMASK];
4118 pFpuCtx->aRegs[6].r80 = ar80Temp[(iNewTop + 6) & X86_FSW_TOP_SMASK];
4119 pFpuCtx->aRegs[7].r80 = ar80Temp[(iNewTop + 7) & X86_FSW_TOP_SMASK];
4120}
4121
4122
4123/**
4124 * Updates the FPU exception status after FCW is changed.
4125 *
4126 * @param pFpuCtx The FPU context.
4127 */
4128DECLINLINE(void) iemFpuRecalcExceptionStatus(PX86FXSTATE pFpuCtx) RT_NOEXCEPT
4129{
4130 uint16_t u16Fsw = pFpuCtx->FSW;
4131 if ((u16Fsw & X86_FSW_XCPT_MASK) & ~(pFpuCtx->FCW & X86_FCW_XCPT_MASK))
4132 u16Fsw |= X86_FSW_ES | X86_FSW_B;
4133 else
4134 u16Fsw &= ~(X86_FSW_ES | X86_FSW_B);
4135 pFpuCtx->FSW = u16Fsw;
4136}
4137
4138
4139/**
4140 * Calculates the full FTW (FPU tag word) for use in FNSTENV and FNSAVE.
4141 *
4142 * @returns The full FTW.
4143 * @param pFpuCtx The FPU context.
4144 */
4145DECLINLINE(uint16_t) iemFpuCalcFullFtw(PCX86FXSTATE pFpuCtx) RT_NOEXCEPT
4146{
4147 uint8_t const u8Ftw = (uint8_t)pFpuCtx->FTW;
4148 uint16_t u16Ftw = 0;
4149 unsigned const iTop = X86_FSW_TOP_GET(pFpuCtx->FSW);
4150 for (unsigned iSt = 0; iSt < 8; iSt++)
4151 {
4152 unsigned const iReg = (iSt + iTop) & 7;
4153 if (!(u8Ftw & RT_BIT(iReg)))
4154 u16Ftw |= 3 << (iReg * 2); /* empty */
4155 else
4156 {
4157 uint16_t uTag;
4158 PCRTFLOAT80U const pr80Reg = &pFpuCtx->aRegs[iSt].r80;
4159 if (pr80Reg->s.uExponent == 0x7fff)
4160 uTag = 2; /* Exponent is all 1's => Special. */
4161 else if (pr80Reg->s.uExponent == 0x0000)
4162 {
4163 if (pr80Reg->s.uMantissa == 0x0000)
4164 uTag = 1; /* All bits are zero => Zero. */
4165 else
4166 uTag = 2; /* Must be special. */
4167 }
4168 else if (pr80Reg->s.uMantissa & RT_BIT_64(63)) /* The J bit. */
4169 uTag = 0; /* Valid. */
4170 else
4171 uTag = 2; /* Must be special. */
4172
4173 u16Ftw |= uTag << (iReg * 2);
4174 }
4175 }
4176
4177 return u16Ftw;
4178}
4179
4180
4181/**
4182 * Converts a full FTW to a compressed one (for use in FLDENV and FRSTOR).
4183 *
4184 * @returns The compressed FTW.
4185 * @param u16FullFtw The full FTW to convert.
4186 */
4187DECLINLINE(uint16_t) iemFpuCompressFtw(uint16_t u16FullFtw) RT_NOEXCEPT
4188{
4189 uint8_t u8Ftw = 0;
4190 for (unsigned i = 0; i < 8; i++)
4191 {
4192 if ((u16FullFtw & 3) != 3 /*empty*/)
4193 u8Ftw |= RT_BIT(i);
4194 u16FullFtw >>= 2;
4195 }
4196
4197 return u8Ftw;
4198}
4199
4200/** @} */
4201
4202
4203/** @name Memory access.
4204 *
4205 * @{
4206 */
4207
4208
4209/**
4210 * Checks whether alignment checks are enabled or not.
4211 *
4212 * @returns true if enabled, false if not.
4213 * @param pVCpu The cross context virtual CPU structure of the calling thread.
4214 */
4215DECLINLINE(bool) iemMemAreAlignmentChecksEnabled(PVMCPUCC pVCpu) RT_NOEXCEPT
4216{
4217#if 0
4218 AssertCompile(X86_CR0_AM == X86_EFL_AC);
4219 return IEM_GET_CPL(pVCpu) == 3
4220 && (((uint32_t)pVCpu->cpum.GstCtx.cr0 & pVCpu->cpum.GstCtx.eflags.u) & X86_CR0_AM);
4221#else
4222 return RT_BOOL(pVCpu->iem.s.fExec & IEM_F_X86_AC);
4223#endif
4224}
4225
4226/**
4227 * Checks if the given segment can be written to, raise the appropriate
4228 * exception if not.
4229 *
4230 * @returns VBox strict status code.
4231 *
4232 * @param pVCpu The cross context virtual CPU structure of the calling thread.
4233 * @param pHid Pointer to the hidden register.
4234 * @param iSegReg The register number.
4235 * @param pu64BaseAddr Where to return the base address to use for the
4236 * segment. (In 64-bit code it may differ from the
4237 * base in the hidden segment.)
4238 */
4239DECLINLINE(VBOXSTRICTRC) iemMemSegCheckWriteAccessEx(PVMCPUCC pVCpu, PCCPUMSELREGHID pHid,
4240 uint8_t iSegReg, uint64_t *pu64BaseAddr) RT_NOEXCEPT
4241{
4242 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SREG_FROM_IDX(iSegReg));
4243
4244 if (IEM_IS_64BIT_CODE(pVCpu))
4245 *pu64BaseAddr = iSegReg < X86_SREG_FS ? 0 : pHid->u64Base;
4246 else
4247 {
4248 if (!pHid->Attr.n.u1Present)
4249 {
4250 uint16_t uSel = iemSRegFetchU16(pVCpu, iSegReg);
4251 AssertRelease(uSel == 0);
4252 LogEx(LOG_GROUP_IEM,("iemMemSegCheckWriteAccessEx: %#x (index %u) - bad selector -> #GP\n", uSel, iSegReg));
4253 return iemRaiseGeneralProtectionFault0(pVCpu);
4254 }
4255
4256 if ( ( (pHid->Attr.n.u4Type & X86_SEL_TYPE_CODE)
4257 || !(pHid->Attr.n.u4Type & X86_SEL_TYPE_WRITE) )
4258 && !IEM_IS_64BIT_CODE(pVCpu) )
4259 return iemRaiseSelectorInvalidAccess(pVCpu, iSegReg, IEM_ACCESS_DATA_W);
4260 *pu64BaseAddr = pHid->u64Base;
4261 }
4262 return VINF_SUCCESS;
4263}
4264
4265
4266/**
4267 * Checks if the given segment can be read from, raise the appropriate
4268 * exception if not.
4269 *
4270 * @returns VBox strict status code.
4271 *
4272 * @param pVCpu The cross context virtual CPU structure of the calling thread.
4273 * @param pHid Pointer to the hidden register.
4274 * @param iSegReg The register number.
4275 * @param pu64BaseAddr Where to return the base address to use for the
4276 * segment. (In 64-bit code it may differ from the
4277 * base in the hidden segment.)
4278 */
4279DECLINLINE(VBOXSTRICTRC) iemMemSegCheckReadAccessEx(PVMCPUCC pVCpu, PCCPUMSELREGHID pHid,
4280 uint8_t iSegReg, uint64_t *pu64BaseAddr) RT_NOEXCEPT
4281{
4282 IEM_CTX_ASSERT(pVCpu, CPUMCTX_EXTRN_SREG_FROM_IDX(iSegReg));
4283
4284 if (IEM_IS_64BIT_CODE(pVCpu))
4285 *pu64BaseAddr = iSegReg < X86_SREG_FS ? 0 : pHid->u64Base;
4286 else
4287 {
4288 if (!pHid->Attr.n.u1Present)
4289 {
4290 uint16_t uSel = iemSRegFetchU16(pVCpu, iSegReg);
4291 AssertRelease(uSel == 0);
4292 LogEx(LOG_GROUP_IEM,("iemMemSegCheckReadAccessEx: %#x (index %u) - bad selector -> #GP\n", uSel, iSegReg));
4293 return iemRaiseGeneralProtectionFault0(pVCpu);
4294 }
4295
4296 if ((pHid->Attr.n.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ)) == X86_SEL_TYPE_CODE)
4297 return iemRaiseSelectorInvalidAccess(pVCpu, iSegReg, IEM_ACCESS_DATA_R);
4298 *pu64BaseAddr = pHid->u64Base;
4299 }
4300 return VINF_SUCCESS;
4301}
4302
4303
4304/**
4305 * Maps a physical page.
4306 *
4307 * @returns VBox status code (see PGMR3PhysTlbGCPhys2Ptr).
4308 * @param pVCpu The cross context virtual CPU structure of the calling thread.
4309 * @param GCPhysMem The physical address.
4310 * @param fAccess The intended access.
4311 * @param ppvMem Where to return the mapping address.
4312 * @param pLock The PGM lock.
4313 */
4314DECLINLINE(int) iemMemPageMap(PVMCPUCC pVCpu, RTGCPHYS GCPhysMem, uint32_t fAccess,
4315 void **ppvMem, PPGMPAGEMAPLOCK pLock) RT_NOEXCEPT
4316{
4317#ifdef IEM_LOG_MEMORY_WRITES
4318 if (fAccess & IEM_ACCESS_TYPE_WRITE)
4319 return VERR_PGM_PHYS_TLB_CATCH_ALL;
4320#endif
4321
4322 /** @todo This API may require some improving later. A private deal with PGM
4323 * regarding locking and unlocking needs to be struct. A couple of TLBs
4324 * living in PGM, but with publicly accessible inlined access methods
4325 * could perhaps be an even better solution. */
4326 int rc = PGMPhysIemGCPhys2Ptr(pVCpu->CTX_SUFF(pVM), pVCpu,
4327 GCPhysMem,
4328 RT_BOOL(fAccess & IEM_ACCESS_TYPE_WRITE),
4329 RT_BOOL(pVCpu->iem.s.fExec & IEM_F_BYPASS_HANDLERS),
4330 ppvMem,
4331 pLock);
4332 /*Log(("PGMPhysIemGCPhys2Ptr %Rrc pLock=%.*Rhxs\n", rc, sizeof(*pLock), pLock));*/
4333 AssertMsg(rc == VINF_SUCCESS || RT_FAILURE_NP(rc), ("%Rrc\n", rc));
4334
4335 return rc;
4336}
4337
4338
4339/**
4340 * Unmap a page previously mapped by iemMemPageMap.
4341 *
4342 * @param pVCpu The cross context virtual CPU structure of the calling thread.
4343 * @param GCPhysMem The physical address.
4344 * @param fAccess The intended access.
4345 * @param pvMem What iemMemPageMap returned.
4346 * @param pLock The PGM lock.
4347 */
4348DECLINLINE(void) iemMemPageUnmap(PVMCPUCC pVCpu, RTGCPHYS GCPhysMem, uint32_t fAccess,
4349 const void *pvMem, PPGMPAGEMAPLOCK pLock) RT_NOEXCEPT
4350{
4351 NOREF(pVCpu);
4352 NOREF(GCPhysMem);
4353 NOREF(fAccess);
4354 NOREF(pvMem);
4355 PGMPhysReleasePageMappingLock(pVCpu->CTX_SUFF(pVM), pLock);
4356}
4357
4358#ifdef IEM_WITH_SETJMP
4359
4360/** @todo slim this down */
4361DECL_INLINE_THROW(RTGCPTR) iemMemApplySegmentToReadJmp(PVMCPUCC pVCpu, uint8_t iSegReg,
4362 size_t cbMem, RTGCPTR GCPtrMem) IEM_NOEXCEPT_MAY_LONGJMP
4363{
4364 Assert(cbMem >= 1);
4365 Assert(iSegReg < X86_SREG_COUNT);
4366
4367 /*
4368 * 64-bit mode is simpler.
4369 */
4370 if (IEM_IS_64BIT_CODE(pVCpu))
4371 {
4372 if (iSegReg >= X86_SREG_FS && iSegReg != UINT8_MAX)
4373 {
4374 IEM_CTX_IMPORT_JMP(pVCpu, CPUMCTX_EXTRN_SREG_FROM_IDX(iSegReg));
4375 PCPUMSELREGHID const pSel = iemSRegGetHid(pVCpu, iSegReg);
4376 GCPtrMem += pSel->u64Base;
4377 }
4378
4379 if (RT_LIKELY(X86_IS_CANONICAL(GCPtrMem) && X86_IS_CANONICAL(GCPtrMem + cbMem - 1)))
4380 return GCPtrMem;
4381 iemRaiseGeneralProtectionFault0Jmp(pVCpu);
4382 }
4383 /*
4384 * 16-bit and 32-bit segmentation.
4385 */
4386 else if (iSegReg != UINT8_MAX)
4387 {
4388 /** @todo Does this apply to segments with 4G-1 limit? */
4389 uint32_t const GCPtrLast32 = (uint32_t)GCPtrMem + (uint32_t)cbMem - 1;
4390 if (RT_LIKELY(GCPtrLast32 >= (uint32_t)GCPtrMem))
4391 {
4392 IEM_CTX_IMPORT_JMP(pVCpu, CPUMCTX_EXTRN_SREG_FROM_IDX(iSegReg));
4393 PCPUMSELREGHID const pSel = iemSRegGetHid(pVCpu, iSegReg);
4394 switch (pSel->Attr.u & ( X86DESCATTR_P | X86DESCATTR_UNUSABLE
4395 | X86_SEL_TYPE_READ | X86_SEL_TYPE_WRITE /* same as read */
4396 | X86_SEL_TYPE_DOWN | X86_SEL_TYPE_CONF /* same as down */
4397 | X86_SEL_TYPE_CODE))
4398 {
4399 case X86DESCATTR_P: /* readonly data, expand up */
4400 case X86DESCATTR_P | X86_SEL_TYPE_WRITE: /* writable data, expand up */
4401 case X86DESCATTR_P | X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ: /* code, read-only */
4402 case X86DESCATTR_P | X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ | X86_SEL_TYPE_CONF: /* conforming code, read-only */
4403 /* expand up */
4404 if (RT_LIKELY(GCPtrLast32 <= pSel->u32Limit))
4405 return (uint32_t)GCPtrMem + (uint32_t)pSel->u64Base;
4406 Log10(("iemMemApplySegmentToReadJmp: out of bounds %#x..%#x vs %#x\n",
4407 (uint32_t)GCPtrMem, GCPtrLast32, pSel->u32Limit));
4408 break;
4409
4410 case X86DESCATTR_P | X86_SEL_TYPE_DOWN: /* readonly data, expand down */
4411 case X86DESCATTR_P | X86_SEL_TYPE_DOWN | X86_SEL_TYPE_WRITE: /* writable data, expand down */
4412 /* expand down */
4413 if (RT_LIKELY( (uint32_t)GCPtrMem > pSel->u32Limit
4414 && ( pSel->Attr.n.u1DefBig
4415 || GCPtrLast32 <= UINT32_C(0xffff)) ))
4416 return (uint32_t)GCPtrMem + (uint32_t)pSel->u64Base;
4417 Log10(("iemMemApplySegmentToReadJmp: expand down out of bounds %#x..%#x vs %#x..%#x\n",
4418 (uint32_t)GCPtrMem, GCPtrLast32, pSel->u32Limit, pSel->Attr.n.u1DefBig ? UINT32_MAX : UINT16_MAX));
4419 break;
4420
4421 default:
4422 Log10(("iemMemApplySegmentToReadJmp: bad selector %#x\n", pSel->Attr.u));
4423 iemRaiseSelectorInvalidAccessJmp(pVCpu, iSegReg, IEM_ACCESS_DATA_R);
4424 break;
4425 }
4426 }
4427 Log10(("iemMemApplySegmentToReadJmp: out of bounds %#x..%#x\n",(uint32_t)GCPtrMem, GCPtrLast32));
4428 iemRaiseSelectorBoundsJmp(pVCpu, iSegReg, IEM_ACCESS_DATA_R);
4429 }
4430 /*
4431 * 32-bit flat address.
4432 */
4433 else
4434 return GCPtrMem;
4435}
4436
4437
4438/** @todo slim this down */
4439DECL_INLINE_THROW(RTGCPTR) iemMemApplySegmentToWriteJmp(PVMCPUCC pVCpu, uint8_t iSegReg, size_t cbMem,
4440 RTGCPTR GCPtrMem) IEM_NOEXCEPT_MAY_LONGJMP
4441{
4442 Assert(cbMem >= 1);
4443 Assert(iSegReg < X86_SREG_COUNT);
4444
4445 /*
4446 * 64-bit mode is simpler.
4447 */
4448 if (IEM_IS_64BIT_CODE(pVCpu))
4449 {
4450 if (iSegReg >= X86_SREG_FS)
4451 {
4452 IEM_CTX_IMPORT_JMP(pVCpu, CPUMCTX_EXTRN_SREG_FROM_IDX(iSegReg));
4453 PCPUMSELREGHID pSel = iemSRegGetHid(pVCpu, iSegReg);
4454 GCPtrMem += pSel->u64Base;
4455 }
4456
4457 if (RT_LIKELY(X86_IS_CANONICAL(GCPtrMem) && X86_IS_CANONICAL(GCPtrMem + cbMem - 1)))
4458 return GCPtrMem;
4459 }
4460 /*
4461 * 16-bit and 32-bit segmentation.
4462 */
4463 else
4464 {
4465 Assert(GCPtrMem <= UINT32_MAX);
4466 IEM_CTX_IMPORT_JMP(pVCpu, CPUMCTX_EXTRN_SREG_FROM_IDX(iSegReg));
4467 PCPUMSELREGHID pSel = iemSRegGetHid(pVCpu, iSegReg);
4468 uint32_t const fRelevantAttrs = pSel->Attr.u & ( X86DESCATTR_P | X86DESCATTR_UNUSABLE
4469 | X86_SEL_TYPE_CODE | X86_SEL_TYPE_WRITE | X86_SEL_TYPE_DOWN);
4470 if ( fRelevantAttrs == (X86DESCATTR_P | X86_SEL_TYPE_WRITE) /* data, expand up */
4471 /** @todo explore exactly how the CS stuff works in real mode. See also
4472 * http://www.rcollins.org/Productivity/DescriptorCache.html and
4473 * http://www.rcollins.org/ddj/Aug98/Aug98.html for some insight. */
4474 || (iSegReg == X86_SREG_CS && IEM_IS_REAL_OR_V86_MODE(pVCpu)) ) /* Ignored for CS. */ /** @todo testcase! */
4475 {
4476 /* expand up */
4477 uint32_t const GCPtrLast32 = (uint32_t)GCPtrMem + (uint32_t)cbMem - 1;
4478 if (RT_LIKELY( GCPtrLast32 <= pSel->u32Limit
4479 && GCPtrLast32 >= (uint32_t)GCPtrMem))
4480 return (uint32_t)GCPtrMem + (uint32_t)pSel->u64Base;
4481 iemRaiseSelectorBoundsJmp(pVCpu, iSegReg, IEM_ACCESS_DATA_W);
4482 }
4483 else if (fRelevantAttrs == (X86DESCATTR_P | X86_SEL_TYPE_WRITE | X86_SEL_TYPE_DOWN)) /* data, expand up */
4484 {
4485 /* expand down - the uppger boundary is defined by the B bit, not G. */
4486 uint32_t GCPtrLast32 = (uint32_t)GCPtrMem + (uint32_t)cbMem - 1;
4487 if (RT_LIKELY( (uint32_t)GCPtrMem >= pSel->u32Limit
4488 && (pSel->Attr.n.u1DefBig || GCPtrLast32 <= UINT32_C(0xffff))
4489 && GCPtrLast32 >= (uint32_t)GCPtrMem))
4490 return (uint32_t)GCPtrMem + (uint32_t)pSel->u64Base;
4491 iemRaiseSelectorBoundsJmp(pVCpu, iSegReg, IEM_ACCESS_DATA_W);
4492 }
4493 else
4494 iemRaiseSelectorInvalidAccessJmp(pVCpu, iSegReg, IEM_ACCESS_DATA_W);
4495 }
4496 iemRaiseGeneralProtectionFault0Jmp(pVCpu);
4497}
4498
4499#endif /* IEM_WITH_SETJMP */
4500
4501/**
4502 * Fakes a long mode stack selector for SS = 0.
4503 *
4504 * @param pDescSs Where to return the fake stack descriptor.
4505 * @param uDpl The DPL we want.
4506 */
4507DECLINLINE(void) iemMemFakeStackSelDesc(PIEMSELDESC pDescSs, uint32_t uDpl) RT_NOEXCEPT
4508{
4509 pDescSs->Long.au64[0] = 0;
4510 pDescSs->Long.au64[1] = 0;
4511 pDescSs->Long.Gen.u4Type = X86_SEL_TYPE_RW_ACC;
4512 pDescSs->Long.Gen.u1DescType = 1; /* 1 = code / data, 0 = system. */
4513 pDescSs->Long.Gen.u2Dpl = uDpl;
4514 pDescSs->Long.Gen.u1Present = 1;
4515 pDescSs->Long.Gen.u1Long = 1;
4516}
4517
4518
4519/*
4520 * Unmap helpers.
4521 */
4522
4523#ifdef IEM_WITH_SETJMP
4524
4525DECL_INLINE_THROW(void) iemMemCommitAndUnmapRwJmp(PVMCPUCC pVCpu, uint8_t bMapInfo) IEM_NOEXCEPT_MAY_LONGJMP
4526{
4527# if defined(IEM_WITH_DATA_TLB) && defined(IN_RING3)
4528 if (RT_LIKELY(bMapInfo == 0))
4529 return;
4530# endif
4531 iemMemCommitAndUnmapRwSafeJmp(pVCpu, bMapInfo);
4532}
4533
4534
4535DECL_INLINE_THROW(void) iemMemCommitAndUnmapAtJmp(PVMCPUCC pVCpu, uint8_t bMapInfo) IEM_NOEXCEPT_MAY_LONGJMP
4536{
4537# if defined(IEM_WITH_DATA_TLB) && defined(IN_RING3)
4538 if (RT_LIKELY(bMapInfo == 0))
4539 return;
4540# endif
4541 iemMemCommitAndUnmapAtSafeJmp(pVCpu, bMapInfo);
4542}
4543
4544
4545DECL_INLINE_THROW(void) iemMemCommitAndUnmapWoJmp(PVMCPUCC pVCpu, uint8_t bMapInfo) IEM_NOEXCEPT_MAY_LONGJMP
4546{
4547# if defined(IEM_WITH_DATA_TLB) && defined(IN_RING3)
4548 if (RT_LIKELY(bMapInfo == 0))
4549 return;
4550# endif
4551 iemMemCommitAndUnmapWoSafeJmp(pVCpu, bMapInfo);
4552}
4553
4554
4555DECL_INLINE_THROW(void) iemMemCommitAndUnmapRoJmp(PVMCPUCC pVCpu, uint8_t bMapInfo) IEM_NOEXCEPT_MAY_LONGJMP
4556{
4557# if defined(IEM_WITH_DATA_TLB) && defined(IN_RING3)
4558 if (RT_LIKELY(bMapInfo == 0))
4559 return;
4560# endif
4561 iemMemCommitAndUnmapRoSafeJmp(pVCpu, bMapInfo);
4562}
4563
4564DECLINLINE(void) iemMemRollbackAndUnmapWo(PVMCPUCC pVCpu, uint8_t bMapInfo) RT_NOEXCEPT
4565{
4566# if defined(IEM_WITH_DATA_TLB) && defined(IN_RING3)
4567 if (RT_LIKELY(bMapInfo == 0))
4568 return;
4569# endif
4570 iemMemRollbackAndUnmapWoSafe(pVCpu, bMapInfo);
4571}
4572
4573#endif /* IEM_WITH_SETJMP */
4574
4575
4576/*
4577 * Instantiate R/W inline templates.
4578 */
4579
4580/** @def TMPL_MEM_CHECK_UNALIGNED_WITHIN_PAGE_OK
4581 * Used to check if an unaligned access is if within the page and won't
4582 * trigger an \#AC.
4583 *
4584 * This can also be used to deal with misaligned accesses on platforms that are
4585 * senstive to such if desires.
4586 */
4587#if 1
4588# define TMPL_MEM_CHECK_UNALIGNED_WITHIN_PAGE_OK(a_pVCpu, a_GCPtrEff, a_TmplMemType) \
4589 ( ((a_GCPtrEff) & GUEST_PAGE_OFFSET_MASK) <= GUEST_PAGE_SIZE - sizeof(a_TmplMemType) \
4590 && !((a_pVCpu)->iem.s.fExec & IEM_F_X86_AC) )
4591#else
4592# define TMPL_MEM_CHECK_UNALIGNED_WITHIN_PAGE_OK(a_pVCpu, a_GCPtrEff, a_TmplMemType) 0
4593#endif
4594
4595#define TMPL_MEM_WITH_ATOMIC_MAPPING
4596
4597#define TMPL_MEM_TYPE uint8_t
4598#define TMPL_MEM_TYPE_ALIGN 0
4599#define TMPL_MEM_TYPE_SIZE 1
4600#define TMPL_MEM_FN_SUFF U8
4601#define TMPL_MEM_FMT_TYPE "%#04x"
4602#define TMPL_MEM_FMT_DESC "byte"
4603#include "../VMMAll/IEMAllMemRWTmplInline.cpp.h"
4604
4605#define TMPL_MEM_WITH_STACK
4606
4607#define TMPL_MEM_TYPE uint16_t
4608#define TMPL_MEM_TYPE_ALIGN 1
4609#define TMPL_MEM_TYPE_SIZE 2
4610#define TMPL_MEM_FN_SUFF U16
4611#define TMPL_MEM_FMT_TYPE "%#06x"
4612#define TMPL_MEM_FMT_DESC "word"
4613#include "../VMMAll/IEMAllMemRWTmplInline.cpp.h"
4614
4615#define TMPL_WITH_PUSH_SREG
4616#define TMPL_MEM_TYPE uint32_t
4617#define TMPL_MEM_TYPE_ALIGN 3
4618#define TMPL_MEM_TYPE_SIZE 4
4619#define TMPL_MEM_FN_SUFF U32
4620#define TMPL_MEM_FMT_TYPE "%#010x"
4621#define TMPL_MEM_FMT_DESC "dword"
4622#include "../VMMAll/IEMAllMemRWTmplInline.cpp.h"
4623#undef TMPL_WITH_PUSH_SREG
4624
4625#define TMPL_MEM_TYPE uint64_t
4626#define TMPL_MEM_TYPE_ALIGN 7
4627#define TMPL_MEM_TYPE_SIZE 8
4628#define TMPL_MEM_FN_SUFF U64
4629#define TMPL_MEM_FMT_TYPE "%#018RX64"
4630#define TMPL_MEM_FMT_DESC "qword"
4631#include "../VMMAll/IEMAllMemRWTmplInline.cpp.h"
4632
4633#undef TMPL_MEM_WITH_STACK
4634#undef TMPL_MEM_WITH_ATOMIC_MAPPING
4635
4636#define TMPL_MEM_NO_MAPPING /* currently sticky */
4637
4638#define TMPL_MEM_NO_STORE
4639#define TMPL_MEM_TYPE uint32_t
4640#define TMPL_MEM_TYPE_ALIGN 0
4641#define TMPL_MEM_TYPE_SIZE 4
4642#define TMPL_MEM_FN_SUFF U32NoAc
4643#define TMPL_MEM_FMT_TYPE "%#010x"
4644#define TMPL_MEM_FMT_DESC "dword"
4645#include "../VMMAll/IEMAllMemRWTmplInline.cpp.h"
4646
4647#define TMPL_MEM_NO_STORE
4648#define TMPL_MEM_TYPE uint64_t
4649#define TMPL_MEM_TYPE_ALIGN 0
4650#define TMPL_MEM_TYPE_SIZE 8
4651#define TMPL_MEM_FN_SUFF U64NoAc
4652#define TMPL_MEM_FMT_TYPE "%#018RX64"
4653#define TMPL_MEM_FMT_DESC "qword"
4654#include "../VMMAll/IEMAllMemRWTmplInline.cpp.h"
4655
4656#define TMPL_MEM_NO_STORE
4657#define TMPL_MEM_TYPE uint64_t
4658#define TMPL_MEM_TYPE_ALIGN 15
4659#define TMPL_MEM_TYPE_SIZE 8
4660#define TMPL_MEM_FN_SUFF U64AlignedU128
4661#define TMPL_MEM_FMT_TYPE "%#018RX64"
4662#define TMPL_MEM_FMT_DESC "qword"
4663#include "../VMMAll/IEMAllMemRWTmplInline.cpp.h"
4664
4665#undef TMPL_MEM_NO_MAPPING
4666
4667#define TMPL_MEM_TYPE RTFLOAT80U
4668#define TMPL_MEM_TYPE_ALIGN 7
4669#define TMPL_MEM_TYPE_SIZE 10
4670#define TMPL_MEM_FN_SUFF R80
4671#define TMPL_MEM_FMT_TYPE "%.10Rhxs"
4672#define TMPL_MEM_FMT_DESC "tword"
4673#include "../VMMAll/IEMAllMemRWTmplInline.cpp.h"
4674
4675#define TMPL_MEM_TYPE RTPBCD80U
4676#define TMPL_MEM_TYPE_ALIGN 7 /** @todo RTPBCD80U alignment testcase */
4677#define TMPL_MEM_TYPE_SIZE 10
4678#define TMPL_MEM_FN_SUFF D80
4679#define TMPL_MEM_FMT_TYPE "%.10Rhxs"
4680#define TMPL_MEM_FMT_DESC "tword"
4681#include "../VMMAll/IEMAllMemRWTmplInline.cpp.h"
4682
4683#define TMPL_MEM_WITH_ATOMIC_MAPPING
4684#define TMPL_MEM_TYPE RTUINT128U
4685#define TMPL_MEM_TYPE_ALIGN 15
4686#define TMPL_MEM_TYPE_SIZE 16
4687#define TMPL_MEM_FN_SUFF U128
4688#define TMPL_MEM_FMT_TYPE "%.16Rhxs"
4689#define TMPL_MEM_FMT_DESC "dqword"
4690#include "../VMMAll/IEMAllMemRWTmplInline.cpp.h"
4691#undef TMPL_MEM_WITH_ATOMIC_MAPPING
4692
4693#define TMPL_MEM_NO_MAPPING
4694#define TMPL_MEM_TYPE RTUINT128U
4695#define TMPL_MEM_TYPE_ALIGN 0
4696#define TMPL_MEM_TYPE_SIZE 16
4697#define TMPL_MEM_FN_SUFF U128NoAc
4698#define TMPL_MEM_FMT_TYPE "%.16Rhxs"
4699#define TMPL_MEM_FMT_DESC "dqword"
4700#include "../VMMAll/IEMAllMemRWTmplInline.cpp.h"
4701#undef TMPL_MEM_NO_MAPPING
4702
4703
4704/* Every template relying on unaligned accesses inside a page not being okay should go below. */
4705#undef TMPL_MEM_CHECK_UNALIGNED_WITHIN_PAGE_OK
4706#define TMPL_MEM_CHECK_UNALIGNED_WITHIN_PAGE_OK(a_pVCpu, a_GCPtrEff, a_TmplMemType) 0
4707
4708#define TMPL_MEM_NO_MAPPING
4709#define TMPL_MEM_TYPE RTUINT128U
4710#define TMPL_MEM_TYPE_ALIGN 15
4711#define TMPL_MEM_TYPE_SIZE 16
4712#define TMPL_MEM_FN_SUFF U128AlignedSse
4713#define TMPL_MEM_FMT_TYPE "%.16Rhxs"
4714#define TMPL_MEM_FMT_DESC "dqword"
4715#include "../VMMAll/IEMAllMemRWTmplInline.cpp.h"
4716#undef TMPL_MEM_NO_MAPPING
4717
4718#define TMPL_MEM_NO_MAPPING
4719#define TMPL_MEM_TYPE RTUINT256U
4720#define TMPL_MEM_TYPE_ALIGN 0
4721#define TMPL_MEM_TYPE_SIZE 32
4722#define TMPL_MEM_FN_SUFF U256NoAc
4723#define TMPL_MEM_FMT_TYPE "%.32Rhxs"
4724#define TMPL_MEM_FMT_DESC "qqword"
4725#include "../VMMAll/IEMAllMemRWTmplInline.cpp.h"
4726#undef TMPL_MEM_NO_MAPPING
4727
4728#define TMPL_MEM_NO_MAPPING
4729#define TMPL_MEM_TYPE RTUINT256U
4730#define TMPL_MEM_TYPE_ALIGN 31
4731#define TMPL_MEM_TYPE_SIZE 32
4732#define TMPL_MEM_FN_SUFF U256AlignedAvx
4733#define TMPL_MEM_FMT_TYPE "%.32Rhxs"
4734#define TMPL_MEM_FMT_DESC "qqword"
4735#include "../VMMAll/IEMAllMemRWTmplInline.cpp.h"
4736#undef TMPL_MEM_NO_MAPPING
4737
4738#undef TMPL_MEM_CHECK_UNALIGNED_WITHIN_PAGE_OK
4739
4740/** @} */
4741
4742
4743#ifdef VBOX_WITH_NESTED_HWVIRT_VMX
4744
4745/**
4746 * Gets CR0 fixed-0 bits in VMX operation.
4747 *
4748 * We do this rather than fetching what we report to the guest (in
4749 * IA32_VMX_CR0_FIXED0 MSR) because real hardware (and so do we) report the same
4750 * values regardless of whether unrestricted-guest feature is available on the CPU.
4751 *
4752 * @returns CR0 fixed-0 bits.
4753 * @param pVCpu The cross context virtual CPU structure.
4754 * @param fVmxNonRootMode Whether the CR0 fixed-0 bits for VMX non-root mode
4755 * must be returned. When @c false, the CR0 fixed-0
4756 * bits for VMX root mode is returned.
4757 *
4758 */
4759DECLINLINE(uint64_t) iemVmxGetCr0Fixed0(PCVMCPUCC pVCpu, bool fVmxNonRootMode) RT_NOEXCEPT
4760{
4761 Assert(IEM_VMX_IS_ROOT_MODE(pVCpu));
4762
4763 PCVMXMSRS pMsrs = &pVCpu->cpum.GstCtx.hwvirt.vmx.Msrs;
4764 if ( fVmxNonRootMode
4765 && (pMsrs->ProcCtls2.n.allowed1 & VMX_PROC_CTLS2_UNRESTRICTED_GUEST))
4766 return VMX_V_CR0_FIXED0_UX;
4767 return VMX_V_CR0_FIXED0;
4768}
4769
4770
4771# ifdef XAPIC_OFF_END /* Requires VBox/apic.h to be included before IEMInline.h. */
4772/**
4773 * Sets virtual-APIC write emulation as pending.
4774 *
4775 * @param pVCpu The cross context virtual CPU structure.
4776 * @param offApic The offset in the virtual-APIC page that was written.
4777 */
4778DECLINLINE(void) iemVmxVirtApicSetPendingWrite(PVMCPUCC pVCpu, uint16_t offApic) RT_NOEXCEPT
4779{
4780 Assert(offApic < XAPIC_OFF_END + 4);
4781
4782 /*
4783 * Record the currently updated APIC offset, as we need this later for figuring
4784 * out whether to perform TPR, EOI or self-IPI virtualization as well as well
4785 * as for supplying the exit qualification when causing an APIC-write VM-exit.
4786 */
4787 pVCpu->cpum.GstCtx.hwvirt.vmx.offVirtApicWrite = offApic;
4788
4789 /*
4790 * Flag that we need to perform virtual-APIC write emulation (TPR/PPR/EOI/Self-IPI
4791 * virtualization or APIC-write emulation).
4792 */
4793 if (!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE))
4794 VMCPU_FF_SET(pVCpu, VMCPU_FF_VMX_APIC_WRITE);
4795}
4796# endif /* XAPIC_OFF_END */
4797
4798#endif /* VBOX_WITH_NESTED_HWVIRT_VMX */
4799
4800#if defined(IEM_WITH_TLB_TRACE) && defined(IN_RING3)
4801/**
4802 * Adds an entry to the TLB trace buffer.
4803 *
4804 * @note Don't use directly, only via the IEMTLBTRACE_XXX macros.
4805 */
4806DECLINLINE(void) iemTlbTrace(PVMCPU pVCpu, IEMTLBTRACETYPE enmType, uint64_t u64Param, uint64_t u64Param2 = 0,
4807 uint8_t bParam = 0, uint32_t u32Param = 0/*, uint16_t u16Param = 0 */)
4808{
4809 uint32_t const fMask = RT_BIT_32(pVCpu->iem.s.cTlbTraceEntriesShift) - 1;
4810 PIEMTLBTRACEENTRY const pEntry = &pVCpu->iem.s.paTlbTraceEntries[pVCpu->iem.s.idxTlbTraceEntry++ & fMask];
4811 pEntry->u64Param = u64Param;
4812 pEntry->u64Param2 = u64Param2;
4813 pEntry->u16Param = 0; //u16Param;
4814 pEntry->u32Param = u32Param;
4815 pEntry->bParam = bParam;
4816 pEntry->enmType = enmType;
4817 pEntry->rip = pVCpu->cpum.GstCtx.rip + pVCpu->cpum.GstCtx.cs.u64Base;
4818}
4819#endif
4820
4821#endif /* !VMM_INCLUDED_SRC_include_IEMInline_h */
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