1
/////////////////////////////////////////////////////////////////////////
2
// $Id: vmexit.cc,v 1.5 2009/02/17 19:20:47 sshwarts Exp $
3
/////////////////////////////////////////////////////////////////////////
5
// Copyright (c) 2009 Stanislav Shwartsman
6
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
8
// This library is free software; you can redistribute it and/or
9
// modify it under the terms of the GNU Lesser General Public
10
// License as published by the Free Software Foundation; either
11
// version 2 of the License, or (at your option) any later version.
13
// This library is distributed in the hope that it will be useful,
14
// but WITHOUT ANY WARRANTY; without even the implied warranty of
15
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
// Lesser General Public License for more details.
18
// You should have received a copy of the GNU Lesser General Public
19
// License along with this library; if not, write to the Free Software
20
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA
22
/////////////////////////////////////////////////////////////////////////
24
#define NEED_CPU_REG_SHORTCUTS 1
27
#define LOG_THIS BX_CPU_THIS_PTR
29
#if BX_SUPPORT_X86_64==0
30
// Make life easier for merging cpu64 and cpu32 code.
37
Bit32u gen_instruction_info(bxInstruction_c *i, Bit32u reason)
39
Bit32u instr_info = 0;
42
case VMX_VMEXIT_VMREAD:
43
case VMX_VMEXIT_VMWRITE:
44
instr_info |= i->nnn() << 28;
51
// --------------------------------------
52
// instruction information field format
53
// --------------------------------------
55
// [.2:.0] | Memory operand scale field (encoded)
56
// [.6:.3] | Reg1, undefined when memory operand
57
// [.9:.7] | Memory operand address size
58
// [10:10] | Memory/Register format (0 - mem, 1 - reg)
60
// [17:15] | Memory operand segment register field
61
// [21:18] | Memory operand index field
62
// [22:22] | Memory operand index field invalid
63
// [26:23] | Memory operand base field
64
// [27:27] | Memory operand base field invalid
65
// [31:28] | Reg2, if exists
69
instr_info |= (1 << 10) | (i->rm() << 3);
78
instr_info |= i->seg() << 15;
80
if (i->sibIndex() != BX_NIL_REGISTER)
81
instr_info |= i->sibScale() | (i->sibIndex() << 18);
83
instr_info |= 1 << 22; // index invalid
85
if (i->sibBase() != BX_NIL_REGISTER)
86
instr_info |= i->sibBase() << 23;
88
instr_info |= 1 << 27; // base invalid
94
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_Instruction(bxInstruction_c *i, Bit32u reason)
96
Bit64u qualification = 0;
97
Bit32u instr_info = 0;
100
case VMX_VMEXIT_VMCALL:
101
case VMX_VMEXIT_VMLAUNCH:
102
case VMX_VMEXIT_VMRESUME:
103
case VMX_VMEXIT_VMXOFF:
104
// do not have VMEXIT instruction info
106
case VMX_VMEXIT_VMREAD:
107
case VMX_VMEXIT_VMWRITE:
108
case VMX_VMEXIT_VMPTRLD:
109
case VMX_VMEXIT_VMPTRST:
110
case VMX_VMEXIT_VMCLEAR:
111
case VMX_VMEXIT_VMXON:
112
qualification = (Bit64u) ((bx_address) i->displ32s());
113
#if BX_SUPPORT_X86_64
114
if (i->sibBase() == BX_64BIT_REG_RIP)
115
qualification += RIP;
117
instr_info = gen_instruction_info(i, reason);
119
VMwrite32(VMCS_32BIT_VMEXIT_INSTRUCTION_INFO, instr_info);
123
BX_PANIC(("VMexit_Instruction reason %d", reason));
126
VMexit(i, reason, qualification);
129
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_HLT(bxInstruction_c *i)
131
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
133
if (VMEXIT(VMX_VM_EXEC_CTRL2_HLT_VMEXIT))
135
BX_ERROR(("VMEXIT: HLT"));
136
VMexit(i, VMX_VMEXIT_HLT, 0);
140
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_PAUSE(bxInstruction_c *i)
142
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
144
if (VMEXIT(VMX_VM_EXEC_CTRL2_PAUSE_VMEXIT))
146
BX_ERROR(("VMEXIT: PAUSE"));
147
VMexit(i, VMX_VMEXIT_PAUSE, 0);
151
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_INVLPG(bxInstruction_c *i, bx_address laddr)
153
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
155
if (VMEXIT(VMX_VM_EXEC_CTRL2_INVLPG_VMEXIT))
157
BX_ERROR(("VMEXIT: INVLPG 0x" FMT_ADDRX, laddr));
158
VMexit(i, VMX_VMEXIT_INVLPG, laddr);
162
Bit64s BX_CPU_C::VMX_TSC_Offset(void)
164
if (! BX_CPU_THIS_PTR in_vmx_guest) return 0;
166
if (VMEXIT(VMX_VM_EXEC_CTRL2_TSC_OFFSET))
167
return (Bit64s) BX_CPU_THIS_PTR vmcs.tsc_offset;
173
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_RDTSC(bxInstruction_c *i)
175
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
177
if (VMEXIT(VMX_VM_EXEC_CTRL2_RDTSC_VMEXIT))
179
BX_ERROR(("VMEXIT: RDTSC"));
180
VMexit(i, VMX_VMEXIT_RDTSC, 0);
184
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_RDPMC(bxInstruction_c *i)
186
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
188
if (VMEXIT(VMX_VM_EXEC_CTRL2_RDPMC_VMEXIT))
190
BX_ERROR(("VMEXIT: RDPMC"));
191
VMexit(i, VMX_VMEXIT_RDPMC, 0);
195
#if BX_SUPPORT_MONITOR_MWAIT
196
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_MONITOR(bxInstruction_c *i)
198
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
200
if (VMEXIT(VMX_VM_EXEC_CTRL2_MONITOR_VMEXIT))
202
BX_ERROR(("VMEXIT: MONITOR"));
203
VMexit(i, VMX_VMEXIT_MONITOR, 0);
207
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_MWAIT(bxInstruction_c *i)
209
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
211
if (VMEXIT(VMX_VM_EXEC_CTRL2_MWAIT_VMEXIT))
213
BX_ERROR(("VMEXIT: MWAIT"));
214
VMexit(i, VMX_VMEXIT_MWAIT, 0);
219
void BX_CPU_C::VMexit_ExtInterrupt(void)
221
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
223
if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_EXTERNAL_INTERRUPT_VMEXIT)) {
224
if (! PIN_VMEXIT(VMX_VMEXIT_CTRL1_INTA_ON_VMEXIT)) {
225
// interrupt wasn't acknowledged and still pending, interruption info is invalid
226
VMwrite32(VMCS_32BIT_VMEXIT_INTERRUPTION_INFO, 0);
227
VMexit(0, VMX_VMEXIT_EXTERNAL_INTERRUPT, 0);
232
void BX_CPU_C::VMexit_Event(bxInstruction_c *i, unsigned type, unsigned vector, Bit16u errcode, bx_bool errcode_valid, Bit64u qualification)
234
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
236
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
238
VMX_vmexit_reason reason = VMX_VMEXIT_EXCEPTION_NMI;
241
case BX_EXTERNAL_INTERRUPT:
242
reason = VMX_VMEXIT_EXTERNAL_INTERRUPT;
243
if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_EXTERNAL_INTERRUPT_VMEXIT))
248
if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_NMI_VMEXIT))
252
case BX_PRIVILEGED_SOFTWARE_INTERRUPT:
253
case BX_SOFTWARE_EXCEPTION:
254
case BX_HARDWARE_EXCEPTION:
255
BX_ASSERT((vector < BX_CPU_HANDLED_EXCEPTIONS));
256
if (vector == BX_PF_EXCEPTION) {
257
// page faults are specially treated
258
bx_bool err_match = ((errcode & vm->vm_pf_mask) == vm->vm_pf_match);
259
bx_bool bitmap = (vm->vm_exceptions_bitmap >> BX_PF_EXCEPTION) & 1;
260
vmexit = (err_match == bitmap);
263
vmexit = (vm->vm_exceptions_bitmap >> vector) & 1;
267
case BX_SOFTWARE_INTERRUPT:
268
break; // no VMEXIT on software interrupt
271
BX_ERROR(("VMexit_Event: unknown event type %d", type));
274
// ----------------------------------------------------
275
// VMExit interruption info
276
// ----------------------------------------------------
277
// [.7:.0] | Interrupt/Exception vector
278
// [10:.8] | Interrupt/Exception type
279
// [11:11] | error code pushed to the stack
280
// [12:12] | NMI unblocking due to IRET
281
// [30:13] | reserved
282
// [31:31] | interruption info valid
286
// record IDT vectoring information
287
vm->idt_vector_error_code = errcode;
288
vm->idt_vector_info = vector | (type << 8);
290
vm->idt_vector_info |= (1 << 11); // error code delivered
294
BX_ERROR(("VMEXIT: exception 0x%02x error code = 0x%04x", vector, errcode));
296
// VMEXIT is not considered to occur during event delivery if it results
297
// in a double fault exception that causes VMEXIT directly
298
if (vector == BX_DF_EXCEPTION)
299
BX_CPU_THIS_PTR in_event = 0; // clear in_event indication on #DF
301
// qualifcation for debug exceptions similar to debug_trap field
302
if (vector == BX_DB_EXCEPTION)
303
qualification = BX_CPU_THIS_PTR debug_trap & 0x0000600f;
305
Bit32u interruption_info = vector | (type << 8);
307
interruption_info |= (1 << 11); // error code delivered
308
interruption_info |= (1 << 31); // valid
310
VMwrite32(VMCS_32BIT_VMEXIT_INTERRUPTION_INFO, interruption_info);
311
VMwrite32(VMCS_32BIT_VMEXIT_INTERRUPTION_ERR_CODE, errcode);
313
VMexit(i, reason, qualification);
316
void BX_CPU_C::VMexit_TripleFault(void)
318
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
320
BX_ERROR(("VMEXIT: triple fault"));
322
// VMEXIT is not considered to occur during event delivery if it results
323
// in a triple fault exception (that causes VMEXIT directly)
324
BX_CPU_THIS_PTR in_event = 0;
326
VMexit(0, VMX_VMEXIT_TRIPLE_FAULT, 0);
329
void BX_CPP_AttrRegparmN(3) BX_CPU_C::VMexit_TaskSwitch(bxInstruction_c *i, Bit16u tss_selector, unsigned source)
331
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
333
BX_ERROR(("VMEXIT: task switch"));
335
VMexit(i, VMX_VMEXIT_TASK_SWITCH, tss_selector | (source << 30));
338
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_SoftwareInterrupt(bxInstruction_c *i)
340
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
343
void BX_CPP_AttrRegparmN(3) BX_CPU_C::VMexit_MSR(bxInstruction_c *i, unsigned op, Bit32u msr)
345
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
348
if (! VMEXIT(VMX_VM_EXEC_CTRL2_MSR_BITMAPS)) vmexit = 1;
350
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
353
if (msr & 0xC0000000) {
354
if (msr > 0xC0001FFF) vmexit = 1;
356
// check MSR-HI bitmaps
357
bx_phy_address pAddr = vm->msr_bitmap_addr + (msr >> 3) + 1024 + (op == VMX_VMEXIT_RDMSR) ? 0 : 2048;
358
access_read_physical(pAddr, 1, &field);
359
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_READ, &field);
360
if (field & (1 << (msr & 7)))
365
if (msr > 0x00001FFF) vmexit = 1;
367
// check MSR-LO bitmaps
368
bx_phy_address pAddr = vm->msr_bitmap_addr + (msr >> 3) + (op == VMX_VMEXIT_RDMSR) ? 0 : 2048;
369
access_read_physical(pAddr, 1, &field);
370
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_READ, &field);
371
if (field & (1 << (msr & 7)))
378
BX_ERROR(("VMEXIT: %sMSR 0x%08x", (op == VMX_VMEXIT_RDMSR) ? "RD" : "WR", msr));
383
#define VMX_VMEXIT_IO_PORTIN (1 << 3)
384
#define VMX_VMEXIT_IO_INSTR_STRING (1 << 4)
385
#define VMX_VMEXIT_IO_INSTR_REP (1 << 5)
386
#define VMX_VMEXIT_IO_INSTR_IMM (1 << 6)
388
void BX_CPP_AttrRegparmN(3) BX_CPU_C::VMexit_IO(bxInstruction_c *i, unsigned port, unsigned len)
390
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
392
BX_ASSERT((port <= 0xFFFF));
396
if (VMEXIT(VMX_VM_EXEC_CTRL2_IO_BITMAPS)) {
397
// always VMEXIT on port "wrap around" case
398
if (port + len > 0x10000) vmexit = 1;
400
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcs.io_bitmap_addr[(port >> 15) & 1] + ((port & 0x7fff) >> 4);
402
access_read_physical(pAddr, 2, (Bit8u*) &bitmap);
403
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 2, BX_READ, (Bit8u*) &bitmap);
405
for (unsigned n = port; n < port + len; n++) {
406
if (bitmap & (1 << (n & 15))) {
413
else if (VMEXIT(VMX_VM_EXEC_CTRL2_IO_VMEXIT)) vmexit = 1;
416
BX_ERROR(("VMEXIT: I/O port 0x%04x", port));
418
Bit32u qualification = 0;
421
case 0xe4: // IN_ALIb
422
case 0xe5: // IN_AXIb, IN_EAXIb
423
qualification = VMX_VMEXIT_IO_PORTIN | VMX_VMEXIT_IO_INSTR_IMM;
426
case 0xe6: // OUT_IbAL
427
case 0xe7: // OUT_IbAX, OUT_IbEAX
428
qualification = VMX_VMEXIT_IO_INSTR_IMM;
431
case 0xec: // IN_ALDX
432
case 0xed: // IN_AXDX, IN_EAXDX
433
qualification = VMX_VMEXIT_IO_PORTIN; // no immediate
436
case 0xee: // OUT_DXAL
437
case 0xef: // OUT_DXAX, OUT_DXEAX
438
qualification = 0; // PORTOUT, no immediate
441
case 0x6c: // INSB_YbDX
442
case 0x6d: // INSW_YwDX, INSD_YdDX
443
qualification = VMX_VMEXIT_IO_PORTIN | VMX_VMEXIT_IO_INSTR_STRING;
445
qualification |= VMX_VMEXIT_IO_INSTR_REP;
448
case 0x6e: // OUTSB_DXXb
449
case 0x6f: // OUTSW_DXXw, OUTSD_DXXd
450
qualification = VMX_VMEXIT_IO_INSTR_STRING; // PORTOUT
452
qualification |= VMX_VMEXIT_IO_INSTR_REP;
456
BX_PANIC(("VMexit_IO: I/O instruction b1()=%x unknown", i->b1()));
459
if (qualification & VMX_VMEXIT_IO_INSTR_STRING) {
460
bx_address asize_mask = BX_CONST64(0xffffffffffffffff), laddr;
462
if (i->as32L()) asize_mask = 0xffffffff;
463
else asize_mask = 0xffff;
466
if (qualification & VMX_VMEXIT_IO_PORTIN)
467
laddr = BX_CPU_THIS_PTR get_laddr(BX_SEG_REG_ES, RDI & asize_mask);
469
laddr = BX_CPU_THIS_PTR get_laddr(i->seg(), RSI & asize_mask);
471
VMwrite64(VMCS_GUEST_LINEAR_ADDR, laddr);
474
VMexit(i, VMX_VMEXIT_IO_INSTRUCTION, qualification | (len-1) | (port << 16));
479
// ----------------------------------------------------------------
480
// Exit qualification for CR access
481
// ----------------------------------------------------------------
482
// [.3:.0] | Number of CR register (CR0, CR3, CR4, CR8)
483
// [.5:.4] | CR access type (0 - MOV to CR, 1 - MOV from CR, 2 - CLTS, 3 - LMSW)
484
// [.6:.6] | LMSW operand reg/mem (cleared for CR access and CLTS)
485
// [.7:.7] | reserved
486
// [11:.8] | Source Operand Register for CR access (cleared for CLTS and LMSW)
487
// [15:12] | reserved
488
// [31:16] | LMSW source data (cleared for CR access and CLTS)
489
// [63:32] | reserved
492
bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_CLTS(bxInstruction_c *i)
494
if (! BX_CPU_THIS_PTR in_vmx_guest) return 0;
496
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
498
if (vm->vm_cr0_mask & vm->vm_cr0_read_shadow & 0x8)
500
BX_ERROR(("VMEXIT: CLTS"));
502
// all rest of the fields cleared to zero
503
Bit64u qualification = VMX_VMEXIT_CR_ACCESS_CLTS << 4;
505
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
508
if ((vm->vm_cr0_mask & 0x8) != 0 && (vm->vm_cr0_read_shadow & 0x8) == 0)
509
return 1; /* do not clear CR0.TS */
514
Bit32u BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_LMSW(bxInstruction_c *i, Bit32u msw)
516
if (! BX_CPU_THIS_PTR in_vmx_guest) return msw;
518
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
519
Bit32u mask = vm->vm_cr0_mask & 0xF; /* LMSW affects only low 4 bits */
522
if ((mask & msw & 0x1) != 0 && (vm->vm_cr0_read_shadow & 0x1) == 0)
525
if ((mask & vm->vm_cr0_read_shadow & 0xE) != (mask & msw & 0xE))
529
BX_ERROR(("VMEXIT: CR0 write by LMSW of value 0x%04x", msw));
531
Bit64u qualification = VMX_VMEXIT_CR_ACCESS_LMSW << 4;
532
qualification |= msw << 16;
534
qualification |= (1 << 6); // memory operand
535
VMwrite64(VMCS_GUEST_LINEAR_ADDR, BX_CPU_THIS_PTR get_laddr(i->seg(), RMAddr(i)));
538
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
541
// keep untouched all the bits set in CR0 mask
542
return (BX_CPU_THIS_PTR cr0.get32() & mask) | (msw & ~mask);
545
bx_address BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_CR0_Write(bxInstruction_c *i, bx_address val)
547
if (! BX_CPU_THIS_PTR in_vmx_guest) return val;
549
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
551
if ((vm->vm_cr0_mask & vm->vm_cr0_read_shadow) != (vm->vm_cr0_mask & val))
553
BX_ERROR(("VMEXIT: CR0 write"));
554
Bit64u qualification = i->rm() << 8;
555
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
558
// keep untouched all the bits set in CR0 mask
559
return (BX_CPU_THIS_PTR cr0.get32() & vm->vm_cr0_mask) | (val & ~vm->vm_cr0_mask);
562
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_CR3_Read(bxInstruction_c *i)
564
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
566
if (VMEXIT(VMX_VM_EXEC_CTRL2_CR3_READ_VMEXIT)) {
567
BX_ERROR(("VMEXIT: CR3 read"));
569
Bit64u qualification = 3 | (VMX_VMEXIT_CR_ACCESS_CR_READ << 4);
570
qualification |= (i->rm() << 8);
572
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
576
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_CR3_Write(bxInstruction_c *i, bx_address val)
578
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
580
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
582
if (VMEXIT(VMX_VM_EXEC_CTRL2_CR3_WRITE_VMEXIT)) {
583
for (unsigned n=0; n < vm->vm_cr3_target_cnt; n++) {
584
if (vm->vm_cr3_target_value[n] == val) return;
587
BX_ERROR(("VMEXIT: CR3 write"));
588
Bit64u qualification = 3 | (i->rm() << 8);
589
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
593
bx_address BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_CR4_Write(bxInstruction_c *i, bx_address val)
595
if (! BX_CPU_THIS_PTR in_vmx_guest) return val;
597
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
599
if ((vm->vm_cr4_mask & vm->vm_cr4_read_shadow) != (vm->vm_cr4_mask & val))
601
BX_ERROR(("VMEXIT: CR4 write"));
602
Bit64u qualification = 4 | (i->rm() << 8);
603
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
606
// keep untouched all the bits set in CR4 mask
607
return (BX_CPU_THIS_PTR cr4.get32() & vm->vm_cr4_mask) | (val & ~vm->vm_cr4_mask);
610
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_CR8_Read(bxInstruction_c *i)
612
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
614
if (VMEXIT(VMX_VM_EXEC_CTRL2_CR8_READ_VMEXIT)) {
615
BX_ERROR(("VMEXIT: CR8 read"));
617
Bit64u qualification = 8 | (VMX_VMEXIT_CR_ACCESS_CR_READ << 4);
618
qualification |= (i->rm() << 8);
620
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
624
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_CR8_Write(bxInstruction_c *i)
626
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
628
if (VMEXIT(VMX_VM_EXEC_CTRL2_CR8_WRITE_VMEXIT)) {
629
BX_ERROR(("VMEXIT: CR8 write"));
630
Bit64u qualification = 8 | (i->rm() << 8);
631
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
636
// ----------------------------------------------------------------
637
// Exit qualification for DR access
638
// ----------------------------------------------------------------
639
// [.3:.0] | Number of DR register
640
// [.4:.4] | DR access type (0 - MOV to DR, 1 - MOV from DR)
641
// [.7:.5] | reserved
642
// [11:.8] | Source Operand Register
643
// [63:12] | reserved
646
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_DR_Access(bxInstruction_c *i, unsigned read)
648
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
650
if (VMEXIT(VMX_VM_EXEC_CTRL2_DRx_ACCESS_VMEXIT))
652
BX_ERROR(("VMEXIT: DR%d %s access", i->nnn(), read ? "READ" : "WRITE"));
654
Bit64u qualification = i->nnn() | (i->rm() << 8);
656
qualification |= (1 << 4);
658
VMexit(i, VMX_VMEXIT_DR_ACCESS, qualification);
662
#endif // BX_SUPPORT_VMX