Warning, cross-references for /kernel/vm/vm86.c need to be fixed.
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #include "arch/i386.h"
0019 #include "vm/vm86.h"
0020 #include "kernel.h"
0021 #include "util/printf.h"
0022
0023 #define DEBUG_VM86 4
0024
0025 #if DEBUG_VM86 > 0
0026 #define DLOG(fmt,...) DLOG_PREFIX("vm86",fmt,##__VA_ARGS__)
0027 #else
0028 #define DLOG(fmt,...) ;
0029 #endif
0030
0031 #define com1_printf logger_printf
0032
0033
0034 vm86_farptr vmx_vm86_IVT[256];
0035
0036 void
0037 vmx_vm86_global_init (void)
0038 {
0039 extern uint32 vmx_vm86_pgt[1024];
0040
0041 vmx_vm86_pgt[0] = 7;
0042 flush_tlb_all ();
0043
0044
0045 memcpy ((uint8 *) vmx_vm86_IVT, (uint8 *) 0x0, 256*sizeof(vm86_farptr));
0046 #if DEBUG_VM86 > 3
0047 int i,j;
0048
0049 for (i=0;i<4;i++) {
0050 logger_printf (" ");
0051 for (j=0;j<8;j++) {
0052 logger_printf ("IVT[0x%.02X]=%.04X:%.04X ",
0053 i*8 + j, vmx_vm86_IVT[i*8+j].segm, vmx_vm86_IVT[i*8+j].offs);
0054 }
0055 logger_printf ("\n");
0056 }
0057 #endif
0058
0059
0060 flush_tlb_all ();
0061 }
0062
0063
0064 static inline void
0065 inc_ip (uint8 *eip, uint32 amount)
0066 {
0067 vm86_farptr new_ip;
0068 new_ip = LIN32_TO_FP (eip + amount);
0069 vmwrite (new_ip.offs, VMXENC_GUEST_RIP);
0070 vmwrite (new_ip.segm, VMXENC_GUEST_CS_SEL);
0071 vmwrite (new_ip.segm << 4, VMXENC_GUEST_CS_BASE);
0072 }
0073
0074 static inline void
0075 upd_ip (uint32 amount)
0076 {
0077 uint16 ip = vmread (VMXENC_GUEST_RIP) & 0xFFFF;
0078 uint16 cs = vmread (VMXENC_GUEST_CS_SEL) & 0xFFFF;
0079 uint8 *eip = REAL_TO_LIN32 (cs, ip, uint8);
0080 inc_ip (eip, amount);
0081 }
0082
0083 struct _modrm_byte
0084 {
0085 uint8 rm : 3;
0086 uint8 reg : 3;
0087 uint8 mod : 2;
0088 };
0089
0090 static void
0091 decode_modrm_32 (uint8 *eip, uint8 *reg_op, bool *has_sib, uint8 *rm,
0092 uint8 *disp_size, uint32 *disp)
0093 {
0094 struct _modrm_byte modrm = *((struct _modrm_byte *) eip);
0095
0096
0097 *has_sib = modrm.mod < 3 && modrm.rm == 4;
0098
0099
0100 switch (modrm.mod) {
0101 case 0:
0102 if (modrm.rm == 5) {
0103 *disp_size = 4;
0104 *disp = *((uint32 *) (eip + (*has_sib ? 2 : 1)));
0105 } else {
0106 *disp_size = 0;
0107 *disp = 0;
0108 }
0109 break;
0110 case 1:
0111 *disp_size = 1;
0112 *disp = *((eip + (*has_sib ? 2 : 1)));
0113 break;
0114 case 2:
0115 *disp_size = 4;
0116 *disp = *((uint32 *) (eip + (*has_sib ? 2 : 1)));
0117 break;
0118 case 3:
0119 *disp_size = 0;
0120 *disp = 0;
0121 break;
0122 }
0123
0124 *reg_op = modrm.reg;
0125 *rm = modrm.rm;
0126 }
0127
0128
0129
0130 static sint32
0131 pick_segment_regs (void)
0132 {
0133 uint32 i, cs_i = 0, ds_i = 0;
0134 descriptor *ad;
0135 descriptor *ad_bas = (descriptor *) vmread (VMXENC_GUEST_GDTR_BASE);
0136 descriptor *ad_lim =
0137 (descriptor *)(((uint8 *)ad_bas) + vmread (VMXENC_GUEST_GDTR_LIMIT) + 1);
0138
0139 #if DEBUG_VM86 > 1
0140 com1_printf (" pick_segment_regs: ad_bas = %p ad_lim = %p\n",
0141 ad_bas, ad_lim);
0142 #endif
0143 for (i = 0, ad = ad_bas; ad < ad_lim; i++, ad++) {
0144 #if DEBUG_VM86 > 1
0145 com1_printf (" i=%.02X dpl=%.01X type=%.01X\n", i, ad->uDPL, ad->uType);
0146 #endif
0147 if (!cs_i) {
0148
0149 if (ad->uDPL == 0 && (ad->uType & 0x8))
0150 cs_i = i;
0151 }
0152 if (!ds_i) {
0153
0154 if (ad->uDPL == 0 && !(ad->uType & 0x8))
0155 ds_i = i;
0156 }
0157 }
0158
0159 ad = ad_bas;
0160 if (cs_i && ds_i) {
0161 uint32 cs_base, ds_base;
0162 uint32 cs_limit, ds_limit;
0163
0164 #define ACCESS(ad) \
0165 (( 0x01 << 0x00 ) | \
0166 ( (ad).uType << 0x00 ) | \
0167 ( (ad).uDPL << 0x05 ) | \
0168 ( (ad).fPresent << 0x07 ) | \
0169 ( (ad).f << 0x0C ) | \
0170 ( (ad).f0 << 0x0D ) | \
0171 ( (ad).fX << 0x0E ) | \
0172 ( (ad).fGranularity << 0x0F ))
0173 vmwrite (ACCESS (ad[cs_i]), VMXENC_GUEST_CS_ACCESS);
0174 vmwrite (ACCESS (ad[ds_i]), VMXENC_GUEST_SS_ACCESS);
0175 vmwrite (ACCESS (ad[ds_i]), VMXENC_GUEST_DS_ACCESS);
0176 vmwrite (ACCESS (ad[ds_i]), VMXENC_GUEST_ES_ACCESS);
0177 vmwrite (ACCESS (ad[ds_i]), VMXENC_GUEST_FS_ACCESS);
0178 vmwrite (ACCESS (ad[ds_i]), VMXENC_GUEST_GS_ACCESS);
0179
0180 cs_base = (ad[cs_i].pBase0 |
0181 (ad[cs_i].pBase1 << 16) |
0182 (ad[cs_i].pBase2 << 24));
0183 ds_base = (ad[ds_i].pBase0 |
0184 (ad[ds_i].pBase1 << 16) |
0185 (ad[ds_i].pBase2 << 24));
0186
0187 cs_limit = (ad[cs_i].uLimit0 | (ad[cs_i].uLimit1 << 16));
0188 if (ad[cs_i].fGranularity) {
0189 cs_limit <<= 12;
0190 cs_limit |= 0xFFF;
0191 }
0192 ds_limit = (ad[ds_i].uLimit0 | (ad[ds_i].uLimit1 << 16));
0193 if (ad[ds_i].fGranularity) {
0194 ds_limit <<= 12;
0195 ds_limit |= 0xFFF;
0196 }
0197
0198 vmwrite (cs_i << 3, VMXENC_GUEST_CS_SEL);
0199 vmwrite (ds_i << 3, VMXENC_GUEST_SS_SEL);
0200 vmwrite (ds_i << 3, VMXENC_GUEST_DS_SEL);
0201 vmwrite (ds_i << 3, VMXENC_GUEST_ES_SEL);
0202 vmwrite (ds_i << 3, VMXENC_GUEST_FS_SEL);
0203 vmwrite (ds_i << 3, VMXENC_GUEST_GS_SEL);
0204
0205 vmwrite (cs_base, VMXENC_GUEST_CS_BASE);
0206 vmwrite (ds_base, VMXENC_GUEST_SS_BASE);
0207 vmwrite (ds_base, VMXENC_GUEST_DS_BASE);
0208 vmwrite (ds_base, VMXENC_GUEST_ES_BASE);
0209 vmwrite (ds_base, VMXENC_GUEST_FS_BASE);
0210 vmwrite (ds_base, VMXENC_GUEST_GS_BASE);
0211
0212 vmwrite (cs_limit, VMXENC_GUEST_CS_LIMIT);
0213 vmwrite (ds_limit, VMXENC_GUEST_SS_LIMIT);
0214 vmwrite (ds_limit, VMXENC_GUEST_DS_LIMIT);
0215 vmwrite (ds_limit, VMXENC_GUEST_ES_LIMIT);
0216 vmwrite (ds_limit, VMXENC_GUEST_FS_LIMIT);
0217 vmwrite (ds_limit, VMXENC_GUEST_GS_LIMIT);
0218
0219 #if DEBUG_VM86 > 1
0220 com1_printf (" CS=%.04X CS.base=%p CS.limit=%p CS.access=%.02X\n"
0221 " DS=%.04X DS.base=%p DS.limit=%p DS.access=%.02X\n",
0222 cs_i << 3, cs_base, cs_limit, vmread (VMXENC_GUEST_CS_ACCESS),
0223 ds_i << 3, ds_base, ds_limit, vmread (VMXENC_GUEST_DS_ACCESS));
0224 #endif
0225
0226 return 0;
0227 } else
0228 return -1;
0229 }
0230
0231 sint32
0232 vmx_vm86_handle_GPF (virtual_machine *vm)
0233 {
0234 bool a32 = FALSE, o32 = FALSE, rep = FALSE, repnz = FALSE;
0235 uint16 ip = vmread (VMXENC_GUEST_RIP) & 0xFFFF;
0236 uint16 cs = vmread (VMXENC_GUEST_CS_SEL) & 0xFFFF;
0237 uint16 sp = vmread (VMXENC_GUEST_RSP) & 0xFFFF;
0238 uint16 ss = vmread (VMXENC_GUEST_SS_SEL) & 0xFFFF;
0239 uint32 eflags = vmread (VMXENC_GUEST_RFLAGS) & 0xFFFFFFFF;
0240 uint8 *eip = REAL_TO_LIN32 (cs, ip, uint8);
0241 uint16 *stk = REAL_TO_LIN32 (ss, sp, uint16);
0242
0243 #if DEBUG_VM86 > 3
0244 com1_printf ("vmx_vm86_handle_GPF: CS:IP = %.04X:%.04X (I=%0.02X) SS:SP = %.04X:%.04X (ESP=%.08X)\n", cs, ip, eip[0], ss, sp, (uint32) stk);
0245 #endif
0246
0247 parse:
0248 switch (eip[0]) {
0249 case 0xF0:
0250 break;
0251 case 0x26:
0252 case 0x2E:
0253 case 0x36:
0254 case 0x3E:
0255 case 0x64:
0256 case 0x65:
0257 break;
0258 case 0x66:
0259 o32 = TRUE;
0260 eip++;
0261 goto parse;
0262 case 0x67:
0263 a32 = TRUE;
0264 eip++;
0265 goto parse;
0266 case 0xF2:
0267 repnz = TRUE;
0268 eip++;
0269 goto parse;
0270 case 0xF3:
0271 rep = TRUE;
0272 eip++;
0273 goto parse;
0274 case 0xCD:
0275 {
0276 uint8 vec = eip[1];
0277 vm86_farptr dest = vmx_vm86_IVT[vec];
0278 vm86_farptr new_stk;
0279 #if DEBUG_VM86 > 3
0280 com1_printf (" interrupt to vector %.02X farjump to CS:IP = %.04X:%.04X\n",
0281 vec, dest.segm, dest.offs);
0282 #endif
0283
0284 stk -= 3;
0285 new_stk = LIN32_TO_FP (stk);
0286
0287 vmwrite (new_stk.offs, VMXENC_GUEST_RSP);
0288 vmwrite (new_stk.segm, VMXENC_GUEST_SS_SEL);
0289 vmwrite (new_stk.segm << 4, VMXENC_GUEST_SS_BASE);
0290
0291 stk[0] = LIN32_TO_FP (eip + 2).offs;
0292 stk[1] = LIN32_TO_FP (eip + 2).segm;
0293 stk[2] = (uint16) eflags;
0294
0295 if (eflags & F_VIF)
0296 stk[2] |= F_IF;
0297 else
0298 stk[2] &= ~F_IF;
0299 #if DEBUG_VM86 > 3
0300 com1_printf (" New SS:SP = %.04X:%.04X IRET CS:IP = %.04X:%.04X FL = %.04X\n",
0301 new_stk.segm, new_stk.offs,
0302 stk[1], stk[0], stk[2]);
0303 #endif
0304
0305 eflags &= ~F_VIF;
0306 vmwrite (eflags, VMXENC_GUEST_RFLAGS);
0307
0308 vmwrite (dest.offs, VMXENC_GUEST_RIP);
0309 vmwrite (dest.segm, VMXENC_GUEST_CS_SEL);
0310 vmwrite (dest.segm << 4, VMXENC_GUEST_CS_BASE);
0311 return 0;
0312 }
0313 case 0x9C:
0314 if (o32) {
0315 stk -= 2;
0316 *((uint32 *) stk) = eflags & 0xDFF;
0317 if (eflags & F_VIF)
0318 *((uint32 *) stk) |= F_IF;
0319 else
0320 *((uint32 *) stk) &= ~F_IF;
0321 } else {
0322 stk--;
0323 *stk = (uint16) eflags & 0xDFF;
0324 if (eflags & F_VIF)
0325 *stk |= F_IF;
0326 else
0327 *stk &= ~F_IF;
0328 }
0329 #if DEBUG_VM86 > 3
0330 com1_printf (" PUSHF New SS:SP = %.04X:%.04X wrote FL = %.08X\n",
0331 LIN32_TO_FP (stk).segm, LIN32_TO_FP (stk).offs,
0332 *((uint32 *) stk) & (o32 ? ~0 : 0xFFFF));
0333 #endif
0334
0335 vmwrite (LIN32_TO_FP (eip + 1).offs, VMXENC_GUEST_RIP);
0336 vmwrite (LIN32_TO_FP (eip + 1).segm, VMXENC_GUEST_CS_SEL);
0337 vmwrite ((LIN32_TO_FP (eip + 1).segm) << 4, VMXENC_GUEST_CS_BASE);
0338
0339 vmwrite (LIN32_TO_FP (stk).offs, VMXENC_GUEST_RSP);
0340 vmwrite (LIN32_TO_FP (stk).segm, VMXENC_GUEST_SS_SEL);
0341 vmwrite ((LIN32_TO_FP (stk).segm) << 4, VMXENC_GUEST_SS_BASE);
0342 return 0;
0343 case 0x9D:
0344 {
0345 uint32 new_eflags;
0346 uint32 f_if = *stk & F_IF;
0347 if (o32) {
0348
0349 new_eflags = *((uint32 *) stk) & 0xDFF;
0350 stk += 2;
0351 } else {
0352 new_eflags = *stk & 0xDFF;
0353 stk++;
0354 }
0355
0356 new_eflags |= (eflags & (~0xDFF));
0357
0358 if (f_if)
0359 new_eflags |= F_VIF;
0360 else
0361 new_eflags &= ~F_VIF;
0362 vmwrite (new_eflags, VMXENC_GUEST_RFLAGS);
0363 #if DEBUG_VM86 > 3
0364 com1_printf (" POPF New SS:SP = %.04X:%.04X wrote FL = %.08X\n",
0365 LIN32_TO_FP (stk).segm, LIN32_TO_FP (stk).offs,
0366 new_eflags & (o32 ? ~0 : 0xFFFF));
0367 #endif
0368
0369 inc_ip (eip, 1);
0370
0371 vmwrite (LIN32_TO_FP (stk).offs, VMXENC_GUEST_RSP);
0372 vmwrite (LIN32_TO_FP (stk).segm, VMXENC_GUEST_SS_SEL);
0373 vmwrite ((LIN32_TO_FP (stk).segm) << 4, VMXENC_GUEST_SS_BASE);
0374 return 0;
0375 }
0376 case 0xCF:
0377 {
0378
0379 uint32 new_eflags = stk[2] & 0xDFF;
0380 uint32 f_if = stk[2] & F_IF;
0381 vm86_farptr new_eip = { .segm = stk[1], .offs = stk[0] };
0382
0383
0384 new_eflags |= (eflags & (~0xDFF));
0385
0386 if (f_if)
0387 new_eflags |= F_VIF;
0388 else
0389 new_eflags &= ~F_VIF;
0390
0391
0392 vmwrite (new_eip.offs, VMXENC_GUEST_RIP);
0393 vmwrite (new_eip.segm, VMXENC_GUEST_CS_SEL);
0394 vmwrite (new_eip.segm << 4, VMXENC_GUEST_CS_BASE);
0395
0396 vmwrite (new_eflags, VMXENC_GUEST_RFLAGS);
0397
0398 stk += 3;
0399 vmwrite (LIN32_TO_FP (stk).offs, VMXENC_GUEST_RSP);
0400 vmwrite (LIN32_TO_FP (stk).segm, VMXENC_GUEST_SS_SEL);
0401 vmwrite ((LIN32_TO_FP (stk).segm) << 4, VMXENC_GUEST_SS_BASE);
0402 #if DEBUG_VM86 > 3
0403 com1_printf (" IRET to CS:IP = %.04X:%.04X SS:SP = %.04X:%.04X FL = %.08X\n",
0404 new_eip.segm, new_eip.offs,
0405 LIN32_TO_FP (stk).segm, LIN32_TO_FP (stk).offs,
0406 new_eflags);
0407 #endif
0408 return 0;
0409 }
0410 case 0xFA:
0411 #if DEBUG_VM86 > 3
0412 com1_printf (" CLI\n");
0413 #endif
0414 eflags &= ~F_VIF;
0415
0416 vmwrite (LIN32_TO_FP (eip + 1).offs, VMXENC_GUEST_RIP);
0417 vmwrite (LIN32_TO_FP (eip + 1).segm, VMXENC_GUEST_CS_SEL);
0418 vmwrite ((LIN32_TO_FP (eip + 1).segm) << 4, VMXENC_GUEST_CS_BASE);
0419 vmwrite (eflags, VMXENC_GUEST_RFLAGS);
0420 return 0;
0421 case 0xFB:
0422 #if DEBUG_VM86 > 3
0423 com1_printf (" STI\n");
0424 #endif
0425 eflags |= F_VIF;
0426
0427 vmwrite (LIN32_TO_FP (eip + 1).offs, VMXENC_GUEST_RIP);
0428 vmwrite (LIN32_TO_FP (eip + 1).segm, VMXENC_GUEST_CS_SEL);
0429 vmwrite ((LIN32_TO_FP (eip + 1).segm) << 4, VMXENC_GUEST_CS_BASE);
0430 vmwrite (eflags, VMXENC_GUEST_RFLAGS);
0431 return 0;
0432 case 0xE4:
0433 case 0xE5:
0434 case 0xEC:
0435 case 0xED:
0436 case 0x6C:
0437 case 0x6D:
0438 {
0439 uint16 port;
0440 uint8 isize = 1;
0441
0442 if (*eip == 0xE4 || *eip == 0xE5) {
0443
0444 port = eip[1];
0445 isize++;
0446 } else
0447
0448 port = vm->guest_regs.edx & 0xFFFF;
0449
0450 if (o32 &&
0451 (*eip == 0xE5 ||
0452 *eip == 0xED)) {
0453
0454 vm->guest_regs.eax = inl(port);
0455 inc_ip (eip, isize);
0456 #if DEBUG_VM86 > 3
0457 com1_printf (" %.08X = inl (%.04X)\n", vm->guest_regs.eax, port);
0458 #endif
0459 return 0;
0460 } else if (*eip == 0xE5 || *eip == 0xED) {
0461
0462 vm->guest_regs.eax |= 0xFFFF & inw (port);
0463 inc_ip (eip, isize);
0464 #if DEBUG_VM86 > 3
0465 com1_printf (" %.04X = inw (%.04X)\n", vm->guest_regs.eax & 0xFFFF, port);
0466 #endif
0467 return 0;
0468 } else if (*eip == 0xE4 || *eip == 0xEC) {
0469
0470 vm->guest_regs.eax |= 0xFF & inb (port);
0471 inc_ip (eip, isize);
0472 #if DEBUG_VM86 > 3
0473 com1_printf (" %.02X = inb (%.04X)\n", vm->guest_regs.eax & 0xFF, port);
0474 #endif
0475 return 0;
0476 } else {
0477 uint8 *dst;
0478 uint16 cx = 1;
0479
0480
0481 if (a32) {
0482
0483 dst = (uint8 *) vm->guest_regs.edi;
0484
0485 } else {
0486
0487 dst = REAL_TO_LIN32 (vmread (VMXENC_GUEST_ES_SEL),
0488 vm->guest_regs.edi & 0xFFFF,
0489 uint8);
0490 }
0491
0492 if (rep) {
0493 cx = vm->guest_regs.ecx & 0xFFFF;
0494 }
0495
0496 if (o32 && *eip == 0x6D) {
0497
0498 if (eflags & F_DF)
0499 insl_rev (port, dst, cx);
0500 else
0501 insl (port, dst, cx);
0502 #if DEBUG_VM86 > 3
0503 com1_printf (" insl (%.04X, %p, %.04X) DF=%.01X\n",
0504 port, dst, cx, !!(eflags & F_DF));
0505 #endif
0506 } else if (*eip == 0x6D) {
0507
0508 if (eflags & F_DF)
0509 insw_rev (port, dst, cx);
0510 else
0511 insw (port, dst, cx);
0512 #if DEBUG_VM86 > 3
0513 com1_printf (" insw (%.04X, %p, %.04X) DF=%.01X\n",
0514 port, dst, cx, !!(eflags & F_DF));
0515 #endif
0516
0517 } else if (*eip == 0x6C) {
0518
0519 if (eflags & F_DF)
0520 insb_rev (port, dst, cx);
0521 else
0522 insb (port, dst, cx);
0523 #if DEBUG_VM86 > 3
0524 com1_printf (" insb (%.04X, %p, %.04X) DF=%.01X\n",
0525 port, dst, cx, !!(eflags & F_DF));
0526 #endif
0527 }
0528
0529 inc_ip (eip, isize);
0530 return 0;
0531 }
0532 break;
0533 }
0534 case 0xE6:
0535 case 0xE7:
0536 case 0xEE:
0537 case 0xEF:
0538 case 0x6E:
0539 case 0x6F:
0540 {
0541 uint16 port;
0542 uint8 isize = 1;
0543
0544 if (*eip == 0xE6 || *eip == 0xE7) {
0545
0546 port = eip[1];
0547 isize++;
0548 } else
0549
0550 port = vm->guest_regs.edx & 0xFFFF;
0551
0552 if (o32 &&
0553 (*eip == 0xE7 ||
0554 *eip == 0xEF)) {
0555
0556 outl (vm->guest_regs.eax, port);
0557 inc_ip (eip, isize);
0558 #if DEBUG_VM86 > 3
0559 com1_printf (" outl (%.08X, %.04X)\n", vm->guest_regs.eax, port);
0560 #endif
0561 return 0;
0562 } else if (*eip == 0xE7 || *eip == 0xEF) {
0563
0564 outw (vm->guest_regs.eax & 0xFFFF, port);
0565 inc_ip (eip, isize);
0566 #if DEBUG_VM86 > 3
0567 com1_printf (" outw (%.04X, %.04X)\n", vm->guest_regs.eax & 0xFFFF, port);
0568 #endif
0569 return 0;
0570 } else if (*eip == 0xE6 || *eip == 0xEE) {
0571
0572 outb (vm->guest_regs.eax & 0xFF, port);
0573 inc_ip (eip, isize);
0574 #if DEBUG_VM86 > 3
0575 com1_printf (" outb (%.02X, %.04X)\n", vm->guest_regs.eax & 0xFF, port);
0576 #endif
0577 return 0;
0578 } else {
0579 uint8 *src;
0580 uint16 cx = 1;
0581
0582
0583 if (a32) {
0584
0585 src = (uint8 *) vm->guest_regs.esi;
0586
0587 } else {
0588
0589 src = REAL_TO_LIN32 (vmread (VMXENC_GUEST_DS_SEL),
0590 vm->guest_regs.esi & 0xFFFF,
0591 uint8);
0592 }
0593
0594 if (rep) {
0595 cx = vm->guest_regs.ecx & 0xFFFF;
0596 }
0597
0598 if (o32 && *eip == 0x6F) {
0599
0600 if (eflags & F_DF)
0601 outsl_rev (port, src, cx);
0602 else
0603 outsl (port, src, cx);
0604 #if DEBUG_VM86 > 3
0605 com1_printf (" outsl (%.04X, %p, %.04X) DF=%.01X\n",
0606 port, src, cx, !!(eflags & F_DF));
0607 #endif
0608 } else if (*eip == 0x6F) {
0609
0610 if (eflags & F_DF)
0611 outsw_rev (port, src, cx);
0612 else
0613 outsw (port, src, cx);
0614 #if DEBUG_VM86 > 3
0615 com1_printf (" outsw (%.04X, %p, %.04X) DF=%.01X\n",
0616 port, src, cx, !!(eflags & F_DF));
0617 #endif
0618
0619 } else if (*eip == 0x6E) {
0620
0621 if (eflags & F_DF)
0622 outsb_rev (port, src, cx);
0623 else
0624 outsb (port, src, cx);
0625 #if DEBUG_VM86 > 3
0626 com1_printf (" outsb (%.04X, %p, %.04X) DF=%.01X\n",
0627 port, src, cx, !!(eflags & F_DF));
0628 #endif
0629 }
0630
0631 inc_ip (eip, isize);
0632 return 0;
0633 }
0634
0635 break;
0636 }
0637 case 0xF4:
0638 #if DEBUG_VM86 > 3
0639 com1_printf (" HLT\n");
0640 #endif
0641 return -1;
0642
0643
0644 case 0x0F:
0645 eip++;
0646 switch (*eip) {
0647 case 0x01:
0648 {
0649 uint8 reg_op, disp_size, rm;
0650 uint16 limit;
0651 uint32 disp, base;
0652 bool has_sib;
0653 eip++;
0654 decode_modrm_32 (eip, ®_op, &has_sib, &rm, &disp_size, &disp);
0655 if (reg_op == 2 &&
0656 a32 && o32) {
0657
0658 if (rm == 5) {
0659
0660 limit = *((uint16 *) disp);
0661 base = *((uint32 *) (disp + 2));
0662 } else {
0663 limit = 0;
0664 base = 0;
0665 }
0666 #if DEBUG_VM86 > 1
0667 com1_printf (" LGDT base=%.08X limit=%.04X\n", base, limit);
0668 #endif
0669 vmwrite (base, VMXENC_GUEST_GDTR_BASE);
0670 vmwrite (limit, VMXENC_GUEST_GDTR_LIMIT);
0671 inc_ip (eip, 1 + (has_sib ? 1 : 0) + disp_size);
0672 return 0;
0673 } else if (reg_op == 3) {
0674 #if DEBUG_VM86 > 1
0675 com1_printf (" LIDT\n");
0676 #endif
0677 }
0678 break;
0679 }
0680 #define VM86_CR0_MASK (~0x80000001)
0681 case 0x20:
0682 {
0683 uint8 reg_op, disp_size, rm;
0684 uint32 disp;
0685 bool has_sib;
0686 eip++;
0687 decode_modrm_32 (eip, ®_op, &has_sib, &rm, &disp_size, &disp);
0688 #if DEBUG_VM86 > 1
0689 com1_printf (" MOVL %%CR0, %%%s CR0=%.08X\n",
0690 VM_REG_NAME (rm), vmread (VMXENC_GUEST_CR0) & (VM86_CR0_MASK));
0691 #endif
0692 VM_REG (rm) = (vmread (VMXENC_GUEST_CR0) & VM86_CR0_MASK);
0693 inc_ip (eip, 1);
0694 return 0;
0695 }
0696 case 0x22:
0697 {
0698 uint8 reg_op, disp_size, rm;
0699 uint32 disp, new_cr0;
0700 bool has_sib;
0701
0702 eip++;
0703 decode_modrm_32 (eip, ®_op, &has_sib, &rm, &disp_size, &disp);
0704 new_cr0 = VM_REG (rm);
0705 if (new_cr0 & 0x1) {
0706
0707
0708 vm->realmode = FALSE;
0709 vmwrite (vmread (VMXENC_GUEST_RFLAGS) & (~F_VM), VMXENC_GUEST_RFLAGS);
0710 if (pick_segment_regs () < 0) {
0711 #if DEBUG_VM86 > 1
0712 com1_printf (" failed to pick segment registers.\n");
0713 #endif
0714 return -1;
0715 }
0716
0717
0718
0719
0720 eip++;
0721 if (eip[0] == 0x66 && eip[1] == 0xEA) {
0722 uint32 offs = *((uint32 *) (eip + 2));
0723 uint16 segm = *((uint16 *) (eip + 6));
0724 descriptor *ad = (descriptor *) vmread (VMXENC_GUEST_GDTR_BASE);
0725 uint32 cs_access = ACCESS (ad[segm >> 3]);
0726 uint32 cs_base =
0727 ad[segm >> 3].pBase0 |
0728 (ad[segm >> 3].pBase1 << 8) |
0729 (ad[segm >> 3].pBase2 << 16);
0730 uint32 cs_limit = (ad[segm >> 3].uLimit0 | (ad[segm >> 3].uLimit1 << 16));
0731 if (ad[segm >> 3].fGranularity) {
0732 cs_limit <<= 12;
0733 cs_limit |= 0xFFF;
0734 }
0735
0736 vmwrite (offs, VMXENC_GUEST_RIP);
0737 vmwrite (segm, VMXENC_GUEST_CS_SEL);
0738 vmwrite (cs_access, VMXENC_GUEST_CS_ACCESS);
0739 vmwrite (cs_base, VMXENC_GUEST_CS_BASE);
0740 vmwrite (cs_limit, VMXENC_GUEST_CS_LIMIT);
0741 #if DEBUG_VM86 > 1
0742 com1_printf (" P-mode enabled: FAR JUMP to %.04X:%p"
0743 " access=%.02X base=%p limit=%p\n",
0744 segm, offs, cs_access, cs_base, cs_limit);
0745 #endif
0746 } else {
0747 #if DEBUG_VM86 > 1
0748 com1_printf (" invalid P-mode toggle: not followed by FAR JUMP.\n");
0749 #endif
0750 return -1;
0751 }
0752
0753 } else
0754 inc_ip (eip, 1);
0755 new_cr0 |= ~VM86_CR0_MASK;
0756 vmwrite (new_cr0, VMXENC_GUEST_CR0);
0757 #if DEBUG_VM86 > 1
0758 com1_printf (" MOVL %%%s, %%CR0 new CR0=%.08X CS=%.04X GDTR=%.08X:%.04X\n",
0759 VM_REG_NAME (rm), new_cr0, vmread (VMXENC_GUEST_CS_SEL),
0760 vmread (VMXENC_GUEST_GDTR_BASE), vmread (VMXENC_GUEST_GDTR_LIMIT));
0761 #endif
0762
0763 return 0;
0764 }
0765 }
0766
0767 default:
0768 #if DEBUG_VM86 > 1
0769 com1_printf (" Unknown opcode %.02X\n", eip[0]);
0770 #endif
0771 break;
0772 }
0773
0774 return -1;
0775 }
0776 #undef ACCESS
0777
0778
0779
0780
0781
0782
0783
0784
0785
0786
0787