~ubuntu-branches/ubuntu/saucy/bochs/saucy-proposed

« back to all changes in this revision

Viewing changes to cpu/vmexit.cc

  • Committer: Bazaar Package Importer
  • Author(s): David Futcher
  • Date: 2009-04-30 07:46:11 UTC
  • mfrom: (1.1.11 upstream) (4.1.7 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090430074611-6dih80a5mk2uvxhk
Tags: 2.3.7+20090416-1ubuntu1
* Merge from debian unstable (LP: #370427), remaining changes:
  - debian/patches/12_no-ssp.patch: Build bios with -fno-stack-protector
  - Add Replaces/Conflicts for bochsbios-qemu (<< 2.3.6-2)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/////////////////////////////////////////////////////////////////////////
 
2
// $Id: vmexit.cc,v 1.5 2009/02/17 19:20:47 sshwarts Exp $
 
3
/////////////////////////////////////////////////////////////////////////
 
4
//
 
5
//   Copyright (c) 2009 Stanislav Shwartsman
 
6
//          Written by Stanislav Shwartsman [sshwarts at sourceforge net]
 
7
//
 
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.
 
12
//
 
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.
 
17
//
 
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
 
21
//
 
22
/////////////////////////////////////////////////////////////////////////
 
23
 
 
24
#define NEED_CPU_REG_SHORTCUTS 1
 
25
#include "bochs.h"
 
26
#include "cpu.h"
 
27
#define LOG_THIS BX_CPU_THIS_PTR
 
28
 
 
29
#if BX_SUPPORT_X86_64==0
 
30
// Make life easier for merging cpu64 and cpu32 code.
 
31
#define RDI EDI
 
32
#define RSI ESI
 
33
#endif
 
34
 
 
35
#if BX_SUPPORT_VMX
 
36
 
 
37
Bit32u gen_instruction_info(bxInstruction_c *i, Bit32u reason)
 
38
{
 
39
  Bit32u instr_info = 0;
 
40
 
 
41
  switch(reason) {
 
42
    case VMX_VMEXIT_VMREAD:
 
43
    case VMX_VMEXIT_VMWRITE:
 
44
      instr_info |= i->nnn() << 28;
 
45
      break;
 
46
 
 
47
    default:
 
48
      break;
 
49
  }
 
50
 
 
51
  // --------------------------------------
 
52
  //  instruction information field format
 
53
  // --------------------------------------
 
54
  //
 
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)
 
59
  // [14:11] | Reserved
 
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
 
66
  //
 
67
  if (i->modC0()) {
 
68
    // reg/reg format
 
69
    instr_info |= (1 << 10) | (i->rm() << 3);
 
70
  }
 
71
  else {
 
72
    // memory format
 
73
    if (i->as64L())
 
74
        instr_info |= 1 << 8;
 
75
    else if (i->as32L())
 
76
        instr_info |= 1 << 7;
 
77
 
 
78
    instr_info |= i->seg() << 15;
 
79
 
 
80
    if (i->sibIndex() != BX_NIL_REGISTER)
 
81
        instr_info |= i->sibScale() | (i->sibIndex() << 18);
 
82
    else
 
83
        instr_info |= 1 << 22; // index invalid
 
84
 
 
85
    if (i->sibBase() != BX_NIL_REGISTER)
 
86
        instr_info |= i->sibBase() << 23;
 
87
    else
 
88
        instr_info |= 1 << 27; // base invalid
 
89
  }
 
90
 
 
91
  return instr_info;
 
92
}
 
93
 
 
94
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_Instruction(bxInstruction_c *i, Bit32u reason)
 
95
{
 
96
  Bit64u qualification = 0;
 
97
  Bit32u instr_info = 0;
 
98
 
 
99
  switch(reason) {
 
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
 
105
      break;
 
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;
 
116
#endif
 
117
      instr_info = gen_instruction_info(i, reason);
 
118
 
 
119
      VMwrite32(VMCS_32BIT_VMEXIT_INSTRUCTION_INFO, instr_info);
 
120
      break;
 
121
 
 
122
    default:
 
123
      BX_PANIC(("VMexit_Instruction reason %d", reason));
 
124
  }
 
125
 
 
126
  VMexit(i, reason, qualification);
 
127
}
 
128
 
 
129
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_HLT(bxInstruction_c *i)
 
130
{
 
131
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
132
 
 
133
  if (VMEXIT(VMX_VM_EXEC_CTRL2_HLT_VMEXIT))
 
134
  {
 
135
    BX_ERROR(("VMEXIT: HLT"));
 
136
    VMexit(i, VMX_VMEXIT_HLT, 0);
 
137
  }
 
138
}
 
139
 
 
140
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_PAUSE(bxInstruction_c *i)
 
141
{
 
142
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
143
 
 
144
  if (VMEXIT(VMX_VM_EXEC_CTRL2_PAUSE_VMEXIT))
 
145
  {
 
146
    BX_ERROR(("VMEXIT: PAUSE"));
 
147
    VMexit(i, VMX_VMEXIT_PAUSE, 0);
 
148
  }
 
149
}
 
150
 
 
151
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_INVLPG(bxInstruction_c *i, bx_address laddr)
 
152
{
 
153
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
154
 
 
155
  if (VMEXIT(VMX_VM_EXEC_CTRL2_INVLPG_VMEXIT))
 
156
  {
 
157
    BX_ERROR(("VMEXIT: INVLPG 0x" FMT_ADDRX, laddr));
 
158
    VMexit(i, VMX_VMEXIT_INVLPG, laddr);
 
159
  }
 
160
}
 
161
 
 
162
Bit64s BX_CPU_C::VMX_TSC_Offset(void)
 
163
{
 
164
  if (! BX_CPU_THIS_PTR in_vmx_guest) return 0;
 
165
 
 
166
  if (VMEXIT(VMX_VM_EXEC_CTRL2_TSC_OFFSET))
 
167
    return (Bit64s) BX_CPU_THIS_PTR vmcs.tsc_offset;
 
168
  else
 
169
    return 0;
 
170
}
 
171
 
 
172
 
 
173
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_RDTSC(bxInstruction_c *i)
 
174
{
 
175
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
176
 
 
177
  if (VMEXIT(VMX_VM_EXEC_CTRL2_RDTSC_VMEXIT))
 
178
  {
 
179
    BX_ERROR(("VMEXIT: RDTSC"));
 
180
    VMexit(i, VMX_VMEXIT_RDTSC, 0);
 
181
  }
 
182
}
 
183
 
 
184
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_RDPMC(bxInstruction_c *i)
 
185
{
 
186
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
187
 
 
188
  if (VMEXIT(VMX_VM_EXEC_CTRL2_RDPMC_VMEXIT))
 
189
  {
 
190
    BX_ERROR(("VMEXIT: RDPMC"));
 
191
    VMexit(i, VMX_VMEXIT_RDPMC, 0);
 
192
  }
 
193
}
 
194
 
 
195
#if BX_SUPPORT_MONITOR_MWAIT
 
196
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_MONITOR(bxInstruction_c *i)
 
197
{
 
198
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
199
 
 
200
  if (VMEXIT(VMX_VM_EXEC_CTRL2_MONITOR_VMEXIT))
 
201
  {
 
202
    BX_ERROR(("VMEXIT: MONITOR"));
 
203
    VMexit(i, VMX_VMEXIT_MONITOR, 0);
 
204
  }
 
205
}
 
206
 
 
207
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_MWAIT(bxInstruction_c *i)
 
208
{
 
209
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
210
 
 
211
  if (VMEXIT(VMX_VM_EXEC_CTRL2_MWAIT_VMEXIT))
 
212
  {
 
213
    BX_ERROR(("VMEXIT: MWAIT"));
 
214
    VMexit(i, VMX_VMEXIT_MWAIT, 0);
 
215
  }
 
216
}
 
217
#endif
 
218
 
 
219
void BX_CPU_C::VMexit_ExtInterrupt(void)
 
220
{
 
221
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
222
 
 
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);
 
228
    }
 
229
  }
 
230
}
 
231
 
 
232
void BX_CPU_C::VMexit_Event(bxInstruction_c *i, unsigned type, unsigned vector, Bit16u errcode, bx_bool errcode_valid, Bit64u qualification)
 
233
{
 
234
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
235
 
 
236
  VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
 
237
  bx_bool vmexit = 0;
 
238
  VMX_vmexit_reason reason = VMX_VMEXIT_EXCEPTION_NMI;
 
239
 
 
240
  switch(type) {
 
241
    case BX_EXTERNAL_INTERRUPT:
 
242
      reason = VMX_VMEXIT_EXTERNAL_INTERRUPT;
 
243
      if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_EXTERNAL_INTERRUPT_VMEXIT))
 
244
         vmexit = 1;
 
245
      break;
 
246
 
 
247
    case BX_NMI:
 
248
      if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_NMI_VMEXIT))
 
249
         vmexit = 1;
 
250
      break;
 
251
 
 
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);
 
261
      }
 
262
      else {
 
263
         vmexit = (vm->vm_exceptions_bitmap >> vector) & 1;
 
264
      }
 
265
      break;
 
266
 
 
267
    case BX_SOFTWARE_INTERRUPT:
 
268
      break; // no VMEXIT on software interrupt
 
269
 
 
270
    default:
 
271
      BX_ERROR(("VMexit_Event: unknown event type %d", type));
 
272
  }
 
273
 
 
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
 
283
  //
 
284
 
 
285
  if (! vmexit) {
 
286
    // record IDT vectoring information 
 
287
    vm->idt_vector_error_code = errcode;
 
288
    vm->idt_vector_info = vector | (type << 8);
 
289
    if (errcode_valid)
 
290
      vm->idt_vector_info |= (1 << 11); // error code delivered
 
291
    return;
 
292
  }
 
293
 
 
294
  BX_ERROR(("VMEXIT: exception 0x%02x error code = 0x%04x", vector, errcode));
 
295
 
 
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
 
300
 
 
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;
 
304
 
 
305
  Bit32u interruption_info = vector | (type << 8);
 
306
  if (errcode_valid)
 
307
    interruption_info |= (1 << 11); // error code delivered
 
308
  interruption_info   |= (1 << 31); // valid
 
309
 
 
310
  VMwrite32(VMCS_32BIT_VMEXIT_INTERRUPTION_INFO, interruption_info);
 
311
  VMwrite32(VMCS_32BIT_VMEXIT_INTERRUPTION_ERR_CODE, errcode);
 
312
 
 
313
  VMexit(i, reason, qualification);
 
314
}
 
315
 
 
316
void BX_CPU_C::VMexit_TripleFault(void)
 
317
{
 
318
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
319
 
 
320
  BX_ERROR(("VMEXIT: triple fault"));
 
321
 
 
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;
 
325
 
 
326
  VMexit(0, VMX_VMEXIT_TRIPLE_FAULT, 0);
 
327
}
 
328
 
 
329
void BX_CPP_AttrRegparmN(3) BX_CPU_C::VMexit_TaskSwitch(bxInstruction_c *i, Bit16u tss_selector, unsigned source)
 
330
{
 
331
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
332
 
 
333
  BX_ERROR(("VMEXIT: task switch"));
 
334
 
 
335
  VMexit(i, VMX_VMEXIT_TASK_SWITCH, tss_selector | (source << 30));
 
336
}
 
337
 
 
338
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_SoftwareInterrupt(bxInstruction_c *i)
 
339
{
 
340
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
341
}
 
342
 
 
343
void BX_CPP_AttrRegparmN(3) BX_CPU_C::VMexit_MSR(bxInstruction_c *i, unsigned op, Bit32u msr)
 
344
{
 
345
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
346
 
 
347
  bx_bool vmexit = 0;
 
348
  if (! VMEXIT(VMX_VM_EXEC_CTRL2_MSR_BITMAPS)) vmexit = 1;
 
349
  else {
 
350
    VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
 
351
    Bit8u field;
 
352
 
 
353
    if (msr & 0xC0000000) {
 
354
       if (msr > 0xC0001FFF) vmexit = 1;
 
355
       else {
 
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)))
 
361
            vmexit = 1;
 
362
       }
 
363
    }
 
364
    else {
 
365
       if (msr > 0x00001FFF) vmexit = 1;
 
366
       else {
 
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)))
 
372
            vmexit = 1;
 
373
       }
 
374
    }
 
375
  }
 
376
 
 
377
  if (vmexit) {
 
378
     BX_ERROR(("VMEXIT: %sMSR 0x%08x", (op == VMX_VMEXIT_RDMSR) ? "RD" : "WR", msr));
 
379
     VMexit(i, op, 0);
 
380
  }
 
381
}
 
382
 
 
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)
 
387
 
 
388
void BX_CPP_AttrRegparmN(3) BX_CPU_C::VMexit_IO(bxInstruction_c *i, unsigned port, unsigned len)
 
389
{
 
390
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
391
 
 
392
  BX_ASSERT((port <= 0xFFFF));
 
393
 
 
394
  bool vmexit = 0;
 
395
 
 
396
  if (VMEXIT(VMX_VM_EXEC_CTRL2_IO_BITMAPS)) {
 
397
     // always VMEXIT on port "wrap around" case
 
398
     if (port + len > 0x10000) vmexit = 1;
 
399
     else {
 
400
        bx_phy_address pAddr = BX_CPU_THIS_PTR vmcs.io_bitmap_addr[(port >> 15) & 1] + ((port & 0x7fff) >> 4);
 
401
        Bit16u bitmap;
 
402
        access_read_physical(pAddr, 2, (Bit8u*) &bitmap);
 
403
        BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 2, BX_READ, (Bit8u*) &bitmap);
 
404
 
 
405
        for (unsigned n = port; n < port + len; n++) {
 
406
           if (bitmap & (1 << (n & 15))) {
 
407
              vmexit = 1;
 
408
              break;
 
409
           }
 
410
        }
 
411
     }
 
412
  }
 
413
  else if (VMEXIT(VMX_VM_EXEC_CTRL2_IO_VMEXIT)) vmexit = 1;
 
414
 
 
415
  if (vmexit) {
 
416
     BX_ERROR(("VMEXIT: I/O port 0x%04x", port));
 
417
 
 
418
     Bit32u qualification = 0;
 
419
 
 
420
     switch(i->b1()) {
 
421
       case 0xe4: // IN_ALIb
 
422
       case 0xe5: // IN_AXIb, IN_EAXIb
 
423
         qualification = VMX_VMEXIT_IO_PORTIN | VMX_VMEXIT_IO_INSTR_IMM;
 
424
         break;
 
425
 
 
426
       case 0xe6: // OUT_IbAL
 
427
       case 0xe7: // OUT_IbAX, OUT_IbEAX
 
428
         qualification = VMX_VMEXIT_IO_INSTR_IMM;
 
429
         break;
 
430
 
 
431
       case 0xec: // IN_ALDX
 
432
       case 0xed: // IN_AXDX, IN_EAXDX
 
433
         qualification = VMX_VMEXIT_IO_PORTIN; // no immediate
 
434
         break;
 
435
 
 
436
       case 0xee: // OUT_DXAL
 
437
       case 0xef: // OUT_DXAX, OUT_DXEAX
 
438
         qualification = 0; // PORTOUT, no immediate
 
439
         break;
 
440
 
 
441
       case 0x6c: // INSB_YbDX
 
442
       case 0x6d: // INSW_YwDX, INSD_YdDX
 
443
         qualification = VMX_VMEXIT_IO_PORTIN | VMX_VMEXIT_IO_INSTR_STRING;
 
444
         if (i->repUsedL())
 
445
            qualification |= VMX_VMEXIT_IO_INSTR_REP;
 
446
         break;
 
447
 
 
448
       case 0x6e: // OUTSB_DXXb
 
449
       case 0x6f: // OUTSW_DXXw, OUTSD_DXXd
 
450
         qualification = VMX_VMEXIT_IO_INSTR_STRING; // PORTOUT
 
451
         if (i->repUsedL())
 
452
            qualification |= VMX_VMEXIT_IO_INSTR_REP;
 
453
         break;
 
454
 
 
455
       default:
 
456
         BX_PANIC(("VMexit_IO: I/O instruction b1()=%x unknown", i->b1()));
 
457
     }
 
458
 
 
459
     if (qualification & VMX_VMEXIT_IO_INSTR_STRING) {
 
460
       bx_address asize_mask = BX_CONST64(0xffffffffffffffff), laddr;
 
461
       if (! i->as64L()) {
 
462
          if (i->as32L()) asize_mask = 0xffffffff;
 
463
          else asize_mask = 0xffff;
 
464
       }
 
465
 
 
466
       if (qualification & VMX_VMEXIT_IO_PORTIN)
 
467
          laddr = BX_CPU_THIS_PTR get_laddr(BX_SEG_REG_ES, RDI & asize_mask);
 
468
       else  // PORTOUT
 
469
          laddr = BX_CPU_THIS_PTR get_laddr(i->seg(), RSI & asize_mask);
 
470
 
 
471
       VMwrite64(VMCS_GUEST_LINEAR_ADDR, laddr);
 
472
     }
 
473
 
 
474
     VMexit(i, VMX_VMEXIT_IO_INSTRUCTION, qualification | (len-1) | (port << 16));
 
475
  }
 
476
}
 
477
 
 
478
//
 
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
 
490
//
 
491
 
 
492
bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_CLTS(bxInstruction_c *i)
 
493
{
 
494
  if (! BX_CPU_THIS_PTR in_vmx_guest) return 0;
 
495
 
 
496
  VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
 
497
 
 
498
  if (vm->vm_cr0_mask & vm->vm_cr0_read_shadow & 0x8)
 
499
  {
 
500
    BX_ERROR(("VMEXIT: CLTS"));
 
501
 
 
502
    // all rest of the fields cleared to zero
 
503
    Bit64u qualification = VMX_VMEXIT_CR_ACCESS_CLTS << 4;
 
504
 
 
505
    VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
 
506
  }
 
507
 
 
508
  if ((vm->vm_cr0_mask & 0x8) != 0 && (vm->vm_cr0_read_shadow & 0x8) == 0)
 
509
    return 1; /* do not clear CR0.TS */
 
510
  else
 
511
    return 0;
 
512
}
 
513
 
 
514
Bit32u BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_LMSW(bxInstruction_c *i, Bit32u msw)
 
515
{
 
516
  if (! BX_CPU_THIS_PTR in_vmx_guest) return msw;
 
517
 
 
518
  VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
 
519
  Bit32u mask = vm->vm_cr0_mask & 0xF; /* LMSW affects only low 4 bits */
 
520
  bx_bool vmexit = 0;
 
521
 
 
522
  if ((mask & msw & 0x1) != 0 && (vm->vm_cr0_read_shadow & 0x1) == 0)
 
523
    vmexit = 1;
 
524
 
 
525
  if ((mask & vm->vm_cr0_read_shadow & 0xE) != (mask & msw & 0xE))
 
526
    vmexit = 1;
 
527
 
 
528
  if (vmexit) {
 
529
    BX_ERROR(("VMEXIT: CR0 write by LMSW of value 0x%04x", msw));
 
530
 
 
531
    Bit64u qualification = VMX_VMEXIT_CR_ACCESS_LMSW << 4;
 
532
    qualification |= msw << 16;
 
533
    if (! i->modC0()) {
 
534
       qualification |= (1 << 6); // memory operand
 
535
       VMwrite64(VMCS_GUEST_LINEAR_ADDR, BX_CPU_THIS_PTR get_laddr(i->seg(), RMAddr(i)));
 
536
    }
 
537
 
 
538
    VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
 
539
  }
 
540
 
 
541
  // keep untouched all the bits set in CR0 mask
 
542
  return (BX_CPU_THIS_PTR cr0.get32() & mask) | (msw & ~mask);
 
543
}
 
544
 
 
545
bx_address BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_CR0_Write(bxInstruction_c *i, bx_address val)
 
546
{
 
547
  if (! BX_CPU_THIS_PTR in_vmx_guest) return val;
 
548
 
 
549
  VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
 
550
 
 
551
  if ((vm->vm_cr0_mask & vm->vm_cr0_read_shadow) != (vm->vm_cr0_mask & val))
 
552
  {
 
553
    BX_ERROR(("VMEXIT: CR0 write"));
 
554
    Bit64u qualification = i->rm() << 8;
 
555
    VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
 
556
  }
 
557
 
 
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);
 
560
}
 
561
 
 
562
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_CR3_Read(bxInstruction_c *i)
 
563
{
 
564
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
565
 
 
566
  if (VMEXIT(VMX_VM_EXEC_CTRL2_CR3_READ_VMEXIT)) {
 
567
    BX_ERROR(("VMEXIT: CR3 read"));
 
568
 
 
569
    Bit64u qualification = 3 | (VMX_VMEXIT_CR_ACCESS_CR_READ << 4);
 
570
    qualification |= (i->rm() << 8);
 
571
 
 
572
    VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
 
573
  }
 
574
}
 
575
 
 
576
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_CR3_Write(bxInstruction_c *i, bx_address val)
 
577
{
 
578
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
579
 
 
580
  VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
 
581
 
 
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;
 
585
    }
 
586
 
 
587
    BX_ERROR(("VMEXIT: CR3 write"));
 
588
    Bit64u qualification = 3 | (i->rm() << 8);
 
589
    VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
 
590
  }
 
591
}
 
592
 
 
593
bx_address BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_CR4_Write(bxInstruction_c *i, bx_address val)
 
594
{
 
595
  if (! BX_CPU_THIS_PTR in_vmx_guest) return val;
 
596
 
 
597
  VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
 
598
 
 
599
  if ((vm->vm_cr4_mask & vm->vm_cr4_read_shadow) != (vm->vm_cr4_mask & val))
 
600
  {
 
601
    BX_ERROR(("VMEXIT: CR4 write"));
 
602
    Bit64u qualification = 4 | (i->rm() << 8);
 
603
    VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
 
604
  }
 
605
 
 
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);
 
608
}
 
609
 
 
610
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_CR8_Read(bxInstruction_c *i)
 
611
{
 
612
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
613
 
 
614
  if (VMEXIT(VMX_VM_EXEC_CTRL2_CR8_READ_VMEXIT)) {
 
615
    BX_ERROR(("VMEXIT: CR8 read"));
 
616
 
 
617
    Bit64u qualification = 8 | (VMX_VMEXIT_CR_ACCESS_CR_READ << 4);
 
618
    qualification |= (i->rm() << 8);
 
619
 
 
620
    VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
 
621
  }
 
622
}
 
623
 
 
624
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_CR8_Write(bxInstruction_c *i)
 
625
{
 
626
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
627
 
 
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);
 
632
  }
 
633
}
 
634
 
 
635
//
 
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
 
644
//
 
645
 
 
646
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_DR_Access(bxInstruction_c *i, unsigned read)
 
647
{
 
648
  if (! BX_CPU_THIS_PTR in_vmx_guest) return;
 
649
 
 
650
  if (VMEXIT(VMX_VM_EXEC_CTRL2_DRx_ACCESS_VMEXIT))
 
651
  {
 
652
    BX_ERROR(("VMEXIT: DR%d %s access", i->nnn(), read ? "READ" : "WRITE"));
 
653
 
 
654
    Bit64u qualification = i->nnn() | (i->rm() << 8);
 
655
    if (read)
 
656
       qualification |= (1 << 4);
 
657
 
 
658
    VMexit(i, VMX_VMEXIT_DR_ACCESS, qualification);
 
659
  }
 
660
}
 
661
 
 
662
#endif // BX_SUPPORT_VMX