📄 vm86.c
字号:
case 6: return address(regs, seg, MASK16(regs->ebp) + disp); case 7: return address(regs, seg, MASK16(regs->ebx) + disp); } break; case 3: return getreg16(regs, modrm); } } return 0;}/* * Load new IDT */static intlidt(struct regs *regs, unsigned prefix, unsigned modrm){ unsigned eip = regs->eip - 3; unsigned addr = operand(prefix, regs, modrm); oldctx.idtr_limit = ((struct dtr *) addr)->size; if ((prefix & DATA32) == 0) oldctx.idtr_base = ((struct dtr *) addr)->base & 0xFFFFFF; else oldctx.idtr_base = ((struct dtr *) addr)->base; TRACE((regs, regs->eip - eip, "lidt 0x%x <%d, 0x%x>", addr, oldctx.idtr_limit, oldctx.idtr_base)); return 1;}/* * Load new GDT */static intlgdt(struct regs *regs, unsigned prefix, unsigned modrm){ unsigned eip = regs->eip - 3; unsigned addr = operand(prefix, regs, modrm); oldctx.gdtr_limit = ((struct dtr *) addr)->size; if ((prefix & DATA32) == 0) oldctx.gdtr_base = ((struct dtr *) addr)->base & 0xFFFFFF; else oldctx.gdtr_base = ((struct dtr *) addr)->base; TRACE((regs, regs->eip - eip, "lgdt 0x%x <%d, 0x%x>", addr, oldctx.gdtr_limit, oldctx.gdtr_base)); return 1;}/* * Modify CR0 either through an lmsw instruction. */static intlmsw(struct regs *regs, unsigned prefix, unsigned modrm){ unsigned eip = regs->eip - 3; unsigned ax = operand(prefix, regs, modrm) & 0xF; unsigned cr0 = (oldctx.cr0 & 0xFFFFFFF0) | ax; TRACE((regs, regs->eip - eip, "lmsw 0x%x", ax)); oldctx.cr0 = cr0 | CR0_PE | CR0_NE; if (cr0 & CR0_PE) set_mode(regs, VM86_REAL_TO_PROTECTED); return 1;}/* * We need to handle moves that address memory beyond the 64KB segment * limit that VM8086 mode enforces. */static intmovr(struct regs *regs, unsigned prefix, unsigned opc){ unsigned eip = regs->eip - 1; unsigned modrm = fetch8(regs); unsigned addr = operand(prefix, regs, modrm); unsigned val, r = (modrm >> 3) & 7; if ((modrm & 0xC0) == 0xC0) { /* * Emulate all guest instructions in protected to real mode. */ if (mode != VM86_PROTECTED_TO_REAL) return 0; } switch (opc) { case 0x88: /* addr32 mov r8, r/m8 */ val = getreg8(regs, r); TRACE((regs, regs->eip - eip, "movb %%e%s, *0x%x", rnames[r], addr)); write8(addr, val); return 1; case 0x8A: /* addr32 mov r/m8, r8 */ TRACE((regs, regs->eip - eip, "movb *0x%x, %%%s", addr, rnames[r])); setreg8(regs, r, read8(addr)); return 1; case 0x89: /* addr32 mov r16, r/m16 */ val = getreg32(regs, r); if ((modrm & 0xC0) == 0xC0) { if (prefix & DATA32) setreg32(regs, modrm & 7, val); else setreg16(regs, modrm & 7, MASK16(val)); return 1; } if (prefix & DATA32) { TRACE((regs, regs->eip - eip, "movl %%e%s, *0x%x", rnames[r], addr)); write32(addr, val); } else { TRACE((regs, regs->eip - eip, "movw %%%s, *0x%x", rnames[r], addr)); write16(addr, MASK16(val)); } return 1; case 0x8B: /* mov r/m16, r16 */ if ((modrm & 0xC0) == 0xC0) { if (prefix & DATA32) setreg32(regs, r, addr); else setreg16(regs, r, MASK16(addr)); return 1; } if (prefix & DATA32) { TRACE((regs, regs->eip - eip, "movl *0x%x, %%e%s", addr, rnames[r])); setreg32(regs, r, read32(addr)); } else { TRACE((regs, regs->eip - eip, "movw *0x%x, %%%s", addr, rnames[r])); setreg16(regs, r, read16(addr)); } return 1; case 0xC6: /* addr32 movb $imm, r/m8 */ if ((modrm >> 3) & 7) return 0; val = fetch8(regs); write8(addr, val); TRACE((regs, regs->eip - eip, "movb $0x%x, *0x%x", val, addr)); return 1; } return 0;}/* * We need to handle string moves that address memory beyond the 64KB segment * limit that VM8086 mode enforces. */static inline intmovs(struct regs *regs, unsigned prefix, unsigned opc){ unsigned eip = regs->eip - 1; unsigned sseg = segment(prefix, regs, regs->vds); unsigned dseg = regs->ves; unsigned saddr, daddr; unsigned count = 1; int incr = ((regs->eflags & EFLAGS_DF) == 0) ? 1 : -1; saddr = address(regs, sseg, regs->esi); daddr = address(regs, dseg, regs->edi); if ((prefix & REP) != 0) { count = regs->ecx; regs->ecx = 0; } switch (opc) { case 0xA4: /* movsb */ regs->esi += (incr * count); regs->edi += (incr * count); while (count-- != 0) { write8(daddr, read8(saddr)); daddr += incr; saddr += incr; } TRACE((regs, regs->eip - eip, "movsb (%%esi),%%es:(%%edi)")); break; case 0xA5: /* movsw */ if ((prefix & DATA32) == 0) { incr = 2 * incr; regs->esi += (incr * count); regs->edi += (incr * count); while (count-- != 0) { write16(daddr, read16(saddr)); daddr += incr; saddr += incr; } } else { incr = 4 * incr; regs->esi += (incr * count); regs->edi += (incr * count); while (count-- != 0) { write32(daddr, read32(saddr)); daddr += incr; saddr += incr; } } TRACE((regs, regs->eip - eip, "movsw %s(%%esi),%%es:(%%edi)")); break; } return 1;}static inline intlods(struct regs *regs, unsigned prefix, unsigned opc){ unsigned eip = regs->eip - 1; unsigned seg = segment(prefix, regs, regs->vds); unsigned addr = address(regs, seg, regs->esi); unsigned count = 1; int incr = ((regs->eflags & EFLAGS_DF) == 0) ? 1 : -1; if ((prefix & REP) != 0) { count = regs->ecx; regs->ecx = 0; } switch (opc) { case 0xAD: /* lodsw */ if ((prefix & DATA32) == 0) { incr = 2 * incr; regs->esi += (incr * count); while (count-- != 0) { setreg16(regs, 0, read16(addr)); addr += incr; } TRACE((regs, regs->eip - eip, "lodsw (%%esi),%%ax")); } else { incr = 4 * incr; regs->esi += (incr * count); while (count-- != 0) { setreg32(regs, 0, read32(addr)); addr += incr; } TRACE((regs, regs->eip - eip, "lodsw (%%esi),%%eax")); } break; } return 1;}/* * Move to and from a control register. */static intmovcr(struct regs *regs, unsigned prefix, unsigned opc){ unsigned eip = regs->eip - 2; unsigned modrm = fetch8(regs); unsigned cr = (modrm >> 3) & 7; if ((modrm & 0xC0) != 0xC0) /* only registers */ return 0; switch (opc) { case 0x20: /* mov Rd, Cd */ TRACE((regs, regs->eip - eip, "movl %%cr%d, %%eax", cr)); switch (cr) { case 0: setreg32(regs, modrm, oldctx.cr0 & ~(CR0_PE | CR0_NE)); break; case 2: setreg32(regs, modrm, get_cr2()); break; case 3: setreg32(regs, modrm, oldctx.cr3); break; case 4: setreg32(regs, modrm, oldctx.cr4); break; } break; case 0x22: /* mov Cd, Rd */ TRACE((regs, regs->eip - eip, "movl %%eax, %%cr%d", cr)); switch (cr) { case 0: oldctx.cr0 = getreg32(regs, modrm) | (CR0_PE | CR0_NE); if (getreg32(regs, modrm) & CR0_PE) set_mode(regs, VM86_REAL_TO_PROTECTED); else set_mode(regs, VM86_REAL); break; case 3: oldctx.cr3 = getreg32(regs, modrm); break; case 4: oldctx.cr4 = getreg32(regs, modrm); break; } break; } return 1;}static inline void set_eflags_ZF(unsigned mask, unsigned v1, struct regs *regs){ if ((v1 & mask) == 0) regs->eflags |= EFLAGS_ZF; else regs->eflags &= ~EFLAGS_ZF;}static void set_eflags_add(unsigned hi_bit_mask, unsigned v1, unsigned v2, unsigned result, struct regs *regs){ int bit_count; unsigned tmp; unsigned full_mask; unsigned nonsign_mask; /* Carry out of high order bit? */ if ( v1 & v2 & hi_bit_mask ) regs->eflags |= EFLAGS_CF; else regs->eflags &= ~EFLAGS_CF; /* Even parity in least significant byte? */ tmp = result & 0xff; for (bit_count = 0; tmp != 0; bit_count++) tmp &= (tmp - 1); if (bit_count & 1) regs->eflags &= ~EFLAGS_PF; else regs->eflags |= EFLAGS_PF; /* Carry out of least significant BCD digit? */ if ( v1 & v2 & (1<<3) ) regs->eflags |= EFLAGS_AF; else regs->eflags &= ~EFLAGS_AF; /* Result is zero? */ full_mask = (hi_bit_mask - 1) | hi_bit_mask; set_eflags_ZF(full_mask, result, regs); /* Sign of result? */ if ( result & hi_bit_mask ) regs->eflags |= EFLAGS_SF; else regs->eflags &= ~EFLAGS_SF; /* Carry out of highest non-sign bit? */ nonsign_mask = (hi_bit_mask >> 1) & ~hi_bit_mask; if ( v1 & v2 & hi_bit_mask ) regs->eflags |= EFLAGS_OF; else regs->eflags &= ~EFLAGS_OF;}/* * We need to handle cmp opcodes that address memory beyond the 64KB * segment limit that VM8086 mode enforces. */static intcmp(struct regs *regs, unsigned prefix, unsigned opc){ unsigned eip = regs->eip - 1; unsigned modrm = fetch8(regs); unsigned addr = operand(prefix, regs, modrm); unsigned diff, val, r = (modrm >> 3) & 7; if ((modrm & 0xC0) == 0xC0) /* no registers */ return 0; switch (opc) { case 0x39: /* addr32 cmp r16, r/m16 */ val = getreg32(regs, r); if (prefix & DATA32) { diff = read32(addr) - val; set_eflags_ZF(~0, diff, regs); TRACE((regs, regs->eip - eip, "cmp %%e%s, *0x%x (0x%x)", rnames[r], addr, diff)); } else { diff = read16(addr) - val; set_eflags_ZF(0xFFFF, diff, regs); TRACE((regs, regs->eip - eip, "cmp %%%s, *0x%x (0x%x)", rnames[r], addr, diff)); } break; /* other cmp opcodes ... */ } return 1;}/* * We need to handle test opcodes that address memory beyond the 64KB * segment limit that VM8086 mode enforces. */static inttest(struct regs *regs, unsigned prefix, unsigned opc){ unsigned eip = regs->eip - 1; unsigned modrm = fetch8(regs); unsigned addr = operand(prefix, regs, modrm); unsigned val, diff; if ((modrm & 0xC0) == 0xC0) /* no registers */ return 0; switch (opc) { case 0xF6: /* testb $imm, r/m8 */ if ((modrm >> 3) & 7) return 0; val = fetch8(regs); diff = read8(addr) & val; set_eflags_ZF(0xFF, diff, regs); TRACE((regs, regs->eip - eip, "testb $0x%x, *0x%x (0x%x)", val, addr, diff)); break; /* other test opcodes ... */ } return 1;}/* * We need to handle add opcodes that address memory beyond the 64KB * segment limit that VM8086 mode enforces. */static intadd(struct regs *regs, unsigned prefix, unsigned opc){ unsigned eip = regs->eip - 1; unsigned modrm = fetch8(regs); unsigned addr = operand(prefix, regs, modrm); unsigned r = (modrm >> 3) & 7; unsigned val1 = 0; unsigned val2 = 0; unsigned result = 0; unsigned hi_bit; if ((modrm & 0xC0) == 0xC0) /* no registers */ return 0; switch (opc) { case 0x00: /* addr32 add r8, r/m8 */ val1 = getreg8(regs, r); val2 = read8(addr); result = val1 + val2; write8(addr, result); TRACE((regs, regs->eip - eip, "addb %%e%s, *0x%x", rnames[r], addr)); break; case 0x01: /* addr32 add r16, r/m16 */ if (prefix & DATA32) { val1 = getreg32(regs, r); val2 = read32(addr); result = val1 + val2; write32(addr, result); TRACE((regs, regs->eip - eip, "addl %%e%s, *0x%x", rnames[r], addr)); } else { val1 = getreg16(regs, r); val2 = read16(addr); result = val1 + val2; write16(addr, result); TRACE((regs, regs->eip - eip, "addw %%e%s, *0x%x", rnames[r], addr)); } break; case 0x03: /* addr32 add r/m16, r16 */ if (prefix & DATA32) { val1 = getreg32(regs, r); val2 = read32(addr); result = val1 + val2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -