--- trunk/src/cpu_x86.c 2007/10/08 16:18:31 11 +++ trunk/src/cpu_x86.c 2007/10/08 16:18:38 12 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_x86.c,v 1.163 2005/06/26 22:23:42 debug Exp $ + * $Id: cpu_x86.c,v 1.169 2005/08/14 23:44:22 debug Exp $ * * x86 (and amd64) CPU emulation. * @@ -69,12 +69,10 @@ #include "memory.h" #include "symbol.h" - -extern volatile int single_step; -extern int old_show_trace_tree; -extern int old_instruction_trace; -extern int old_quiet_mode; -extern int quiet_mode; +#define DYNTRANS_DUALMODE_32 +#define DYNTRANS_32 +#define DYNTRANS_VARIABLE_INSTRUCTION_LENGTH +#include "tmp_x86_head.c" static struct x86_model models[] = x86_models; @@ -458,6 +456,32 @@ } +/* + * x86_cpu_show_full_statistics(): + * + * Show detailed statistics on opcode usage on each cpu. + */ +void x86_cpu_show_full_statistics(struct machine *m) +{ + fatal("x86_cpu_show_full_statistics(): TODO\n"); +} + + +/* + * x86_cpu_tlbdump(): + * + * Called from the debugger to dump the TLB in a readable format. + * x is the cpu number to dump, or -1 to dump all CPUs. + * + * If rawflag is nonzero, then the TLB contents isn't formated nicely, + * just dumped. + */ +void x86_cpu_tlbdump(struct machine *m, int x, int rawflag) +{ + fatal("ppc_cpu_tlbdump(): TODO\n"); +} + + /* Macro which modifies the lower part of a value, or the entire value, depending on 'mode': */ #define modify(old,new) ( \ @@ -2419,6 +2443,7 @@ } + /* * x86_cpuid(): * @@ -2498,18 +2523,6 @@ } -#define TRANSLATE_ADDRESS translate_address_x86 -#include "memory_x86.c" -#undef TRANSLATE_ADDRESS - - -#define MEMORY_RW x86_memory_rw -#define MEM_X86 -#include "memory_rw.c" -#undef MEM_X86 -#undef MEMORY_RW - - /* * x86_push(): */ @@ -3132,2327 +3145,12 @@ } -/* - * x86_cpu_run_instr(): - * - * Execute one instruction on a specific CPU. - * - * Return value is the number of instructions executed during this call, - * 0 if no instruction was executed. - */ -int x86_cpu_run_instr(struct emul *emul, struct cpu *cpu) -{ - int i, r, rep = 0, op, len, mode, omode, mode67; - int nprefixbytes = 0, success, longmode; - uint32_t imm, imm2; - unsigned char buf[16]; - unsigned char *instr = buf, *instr_orig, *really_orig_instr; - uint64_t newpc = cpu->pc; - uint64_t tmp, op1, op2; - int trap_flag_was_set = cpu->cd.x86.rflags & X86_FLAGS_TF; - - /* Check PC against breakpoints: */ - if (!single_step) - for (i=0; imachine->n_breakpoints; i++) - if (cpu->pc == cpu->machine->breakpoint_addr[i]) { - fatal("Breakpoint reached, 0x%04x:0x%llx\n", - cpu->cd.x86.s[X86_S_CS], - (long long)cpu->pc); - single_step = 1; - return 0; - } - - if (!cpu->cd.x86.descr_cache[X86_S_CS].valid) { - fatal("x86_cpu_run_instr(): Invalid CS descriptor?\n"); - cpu->running = 0; - return 0; - } - - longmode = cpu->cd.x86.efer & X86_EFER_LME; - mode = cpu->cd.x86.descr_cache[X86_S_CS].default_op_size; - omode = mode; - if (mode != 16 && mode != 32) { - fatal("x86_cpu_run_instr(): Invalid CS default op size, %i\n", - mode); - cpu->running = 0; - return 0; - } - - if (cpu->cd.x86.interrupt_asserted && - cpu->cd.x86.rflags & X86_FLAGS_IF) { - if (cause_interrupt(cpu)) - return 0; - } - - /* 16-bit BIOS emulation: */ - if (mode == 16 && ((newpc + (cpu->cd.x86.s[X86_S_CS] << 4)) & 0xff000) - == 0xf8000 && cpu->machine->prom_emulation) { - int addr = (newpc + (cpu->cd.x86.s[X86_S_CS] << 4)) & 0xfff; - if (cpu->machine->instruction_trace) - debug("(PC BIOS emulation, int 0x%02x)\n", - addr >> 4); - pc_bios_emul(cpu); - /* Approximately equivalent to 500 instructions. */ - return 500; - } - - if (cpu->cd.x86.halted) { - if (!(cpu->cd.x86.rflags & X86_FLAGS_IF)) { - fatal("[ Halting with interrupts disabled. ]\n"); - cpu->running = 0; - } - /* Treating this as more than one instruction makes us - wait less for devices. */ - return 1000; - } - - /* Read an instruction from memory: */ - cpu->cd.x86.cursegment = X86_S_CS; - cpu->cd.x86.seg_override = 0; - - r = cpu->memory_rw(cpu, cpu->mem, cpu->pc, &buf[0], sizeof(buf), - MEM_READ, CACHE_INSTRUCTION); - if (!r) { - /* This could happen if, for example, there was an - exception while we tried to read the instruction. */ - return 0; - } - - really_orig_instr = instr; /* Used to display an error message - for unimplemented instructions. */ - - if (cpu->machine->instruction_trace) - x86_cpu_disassemble_instr(cpu, instr, 1 | omode, 0, 0); - - /* For debugging: */ - if (instr[0] == 0 && instr[1] == 0 && instr[2] == 0 && instr[3] == 0) { - fatal("WARNING: Running in nothingness?\n"); - cpu->running = 0; - return 0; - } - - /* All instructions are at least one byte long :-) */ - newpc ++; - - /* Default is to use the data segment, or the stack segment: */ - cpu->cd.x86.cursegment = X86_S_DS; - mode67 = mode; - - /* Any prefix? */ - for (;;) { - if (longmode && (instr[0] & 0xf0) == 0x40) { - fatal("TODO: REX byte 0x%02x\n", instr[0]); - cpu->running = 0; - } else if (instr[0] == 0x66) { - if (mode == 16) - mode = 32; - else - mode = 16; - } else if (instr[0] == 0x67) { - if (mode67 == 16) - mode67 = 32; - else - mode67 = 16; - } else if (instr[0] == 0x26) { - cpu->cd.x86.cursegment = X86_S_ES; - cpu->cd.x86.seg_override = 1; - } else if (instr[0] == 0x2e) { - cpu->cd.x86.cursegment = X86_S_CS; - cpu->cd.x86.seg_override = 1; - } else if (instr[0] == 0x36) { - cpu->cd.x86.cursegment = X86_S_SS; - cpu->cd.x86.seg_override = 1; - } else if (instr[0] == 0x3e) { - cpu->cd.x86.cursegment = X86_S_DS; - cpu->cd.x86.seg_override = 1; - } else if (instr[0] == 0x64) { - cpu->cd.x86.cursegment = X86_S_FS; - cpu->cd.x86.seg_override = 1; - } else if (instr[0] == 0x65) { - cpu->cd.x86.cursegment = X86_S_GS; - cpu->cd.x86.seg_override = 1; - } else if (instr[0] == 0xf0) { - /* lock */ - } else if (instr[0] == 0xf2) { - rep = REP_REPNE; - } else if (instr[0] == 0xf3) { - rep = REP_REP; - } else - break; - instr ++; - newpc ++; - if (++nprefixbytes > 4) { - fatal("x86: too many prefix bytes at "); - print_csip(cpu); fatal("\n"); - cpu->running = 0; - return 0; - } - } - - op = instr[0]; - instr ++; - - if ((op & 0xf0) <= 0x30 && (op & 7) <= 5) { - success = 1; - instr_orig = instr; - switch (op & 7) { - case 4: imm = read_imm(&instr, &newpc, 8); - op1 = cpu->cd.x86.r[X86_R_AX] & 0xff; - op2 = (signed char)imm; - mode = 8; - break; - case 5: imm = read_imm(&instr, &newpc, mode); - op1 = cpu->cd.x86.r[X86_R_AX]; op2 = imm; - break; - default:success = modrm(cpu, MODRM_READ, mode, mode67, - op&1? 0 : MODRM_EIGHTBIT, &instr, &newpc,&op1,&op2); - if (!success) - return 0; - } - - if ((op & 6) == 2) { - uint64_t tmp = op1; op1 = op2; op2 = tmp; - } - - /* printf("op1=0x%x op2=0x%x => ", (int)op1, (int)op2); */ - - switch (mode) { - case 16: op1 &= 0xffff; op2 &= 0xffff; break; - case 32: op1 &= 0xffffffffULL; op2 &= 0xffffffffULL; break; - } - - switch (op & 0x38) { - case 0x00: x86_calc_flags(cpu, op1, op2, !(op & 1)? 8 : - mode, CALCFLAGS_OP_ADD); - op1 = op1 + op2; - break; - case 0x08: op1 = op1 | op2; break; - case 0x10: tmp = op2; - if (cpu->cd.x86.rflags & X86_FLAGS_CF) - tmp ++; - x86_calc_flags(cpu, op1, tmp, !(op & 1)? 8 : - mode, CALCFLAGS_OP_ADD); - op1 = op1 + tmp; - break; - case 0x18: tmp = op2; - if (cpu->cd.x86.rflags & X86_FLAGS_CF) - tmp ++; - x86_calc_flags(cpu, op1, tmp, !(op & 1)? 8 : - mode, CALCFLAGS_OP_SUB); - op1 = op1 - tmp; - break; - case 0x20: op1 = op1 & op2; break; - case 0x28: x86_calc_flags(cpu, op1, op2, !(op & 1)? 8 : - mode, CALCFLAGS_OP_SUB); - op1 = op1 - op2; break; - case 0x30: op1 = op1 ^ op2; break; - case 0x38: x86_calc_flags(cpu, op1, op2, !(op & 1)? 8 : - mode, CALCFLAGS_OP_SUB); - break; - default: - fatal("not yet\n"); - exit(1); - } - - switch (mode) { - case 16: op1 &= 0xffff; op2 &= 0xffff; break; - case 32: op1 &= 0xffffffffULL; op2 &= 0xffffffffULL; break; - } - - /* NOTE: Manual cmp for "sbb, "sub" and "cmp" instructions. */ - if ((op & 0x38) != 0x38 && (op & 0x38) != 0x28 && - (op & 0x38) != 0x18 && (op & 0x38) != 0x00 && - (op & 0x38) != 0x10) - x86_calc_flags(cpu, op1, 0, !(op & 1)? 8 : mode, - CALCFLAGS_OP_XOR); - - /* "and","or","xor" always clears CF and OF: */ - if ((op & 0x38) == 0x08 || (op & 0x38) == 0x20 || - (op & 0x38) == 0x30) { - cpu->cd.x86.rflags &= ~X86_FLAGS_CF; - cpu->cd.x86.rflags &= ~X86_FLAGS_OF; - } - - /* printf("op1=0x%x op2=0x%x\n", (int)op1, (int)op2); */ - - if ((op & 6) == 2) { - uint64_t tmp = op1; op1 = op2; op2 = tmp; - } - - /* Write back the result: (for all cases except CMP) */ - if ((op & 0x38) != 0x38) { - switch (op & 7) { - case 4: cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[ - X86_R_AX] & ~0xff) | (op1 & 0xff); - break; - case 5: cpu->cd.x86.r[X86_R_AX] = modify(cpu-> - cd.x86.r[X86_R_AX], op1); - break; - default:success = modrm(cpu, (op & 6) == 2? - MODRM_WRITE_R : MODRM_WRITE_RM, mode, - mode67, op&1? 0 : MODRM_EIGHTBIT, - &instr_orig, NULL, &op1, &op2); - if (!success) - return 0; - } - } - } else if ((op & 0xf0) < 0x20 && (op & 7) == 6) { - success = x86_push(cpu, cpu->cd.x86.s[op / 8], mode); - if (!success) - return 0; - } else if (op == 0x0f && cpu->cd.x86.model.model_number == - X86_MODEL_8086) { - uint64_t tmp; - fatal("WARNING: pop cs\n"); - if (!x86_pop(cpu, &tmp, mode)) - return 0; - reload_segment_descriptor(cpu, X86_S_CS, tmp, &newpc); - } else if (op == 0x0f) { - uint64_t tmp; - unsigned char *instr_orig_2; - int signflag, i; - imm = read_imm(&instr, &newpc, 8); - if (imm >= 0x40 && imm <= 0x4f) { /* CMOVxx */ - op = imm & 0xf; - if (!modrm(cpu, MODRM_READ, mode, mode67, - 0, &instr, &newpc, &op1, &op2)) - return 0; - success = x86_condition(cpu, op); - if (success) { - if (!modrm(cpu, MODRM_WRITE_R, mode, mode67, - MODRM_EIGHTBIT, &instr_orig, NULL, - &op2, &op1)) - return 0; - } - } else if (imm >= 0x80 && imm <= 0x8f) { - /* conditional near jump */ - op = imm & 0xf; - imm = read_imm(&instr, &newpc, mode); - success = x86_condition(cpu, op); - if (success) - newpc += imm; - } else if (imm >= 0x90 && imm <= 0x9f) { - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, mode, mode67, - MODRM_EIGHTBIT, &instr, &newpc, &op1, &op2)) - return 0; - op1 = x86_condition(cpu, imm & 0xf); - if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67, - MODRM_EIGHTBIT, &instr_orig, NULL, &op1, &op2)) - return 0; - } else { - int subop; - switch (imm) { - case 0x00: - subop = (*instr >> 3) & 0x7; - switch (subop) { - case 1: /* str */ - /* TODO: Check Prot.mode? */ - op1 = cpu->cd.x86.tr; - if (!modrm(cpu, MODRM_WRITE_RM, 16, - mode67, 0, &instr, &newpc, &op1, - &op2)) - return 0; - break; - case 2: /* lldt */ - /* TODO: Check cpl? and Prot.mode */ - if (!modrm(cpu, MODRM_READ, 16, mode67, - 0, &instr, &newpc, &op1, &op2)) - return 0; - reload_segment_descriptor(cpu, - RELOAD_LDTR, op1, &newpc); - break; - case 3: /* ltr */ - /* TODO: Check cpl=0 and Prot.mode */ - if (!modrm(cpu, MODRM_READ, 16, mode67, - 0, &instr, &newpc, &op1, &op2)) - return 0; - reload_segment_descriptor(cpu, - RELOAD_TR, op1, &newpc); - break; - default:fatal("UNIMPLEMENTED 0x%02x,0x%02x" - ",0x%02x\n", op, imm, *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, - really_orig_instr, 1 | omode, 0, 0); - cpu->running = 0; - } - break; - case 0x01: - subop = (*instr >> 3) & 0x7; - switch (subop) { - case 0: /* sgdt */ - case 1: /* sidt */ - case 2: /* lgdt */ - case 3: /* lidt */ - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, mode, - mode67, MODRM_JUST_GET_ADDR, &instr, - &newpc, &op1, &op2)) - return 0; - /* TODO/NOTE: how about errors? */ - if (subop >= 2) { - x86_load(cpu, op1, &tmp, 2); - x86_load(cpu, op1 + 2, &op2, 4); - if (mode == 16) - op2 &= 0x00ffffffULL; - } - switch (subop) { - case 0: tmp = cpu->cd.x86.gdtr_limit; - op2 = cpu->cd.x86.gdtr; - break; - case 1: tmp = cpu->cd.x86.idtr_limit; - op2 = cpu->cd.x86.idtr; - break; - case 2: cpu->cd.x86.gdtr_limit = - tmp & 0xffff; - cpu->cd.x86.gdtr = op2; - break; - case 3: cpu->cd.x86.idtr_limit = - tmp & 0xffff; - cpu->cd.x86.idtr = op2; - break; - } - if (subop < 2) { - if (mode == 16) - op2 &= 0x00ffffffULL; - x86_store(cpu, op1, tmp, 2); - x86_store(cpu, op1+2, op2, 4); - } - break; - case 4: /* smsw */ - case 6: /* lmsw */ - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, 16, mode67, - 0, &instr, &newpc, &op1, &op2)) - return 0; - if (((*instr_orig >> 3) & 0x7) == 4) { - op1 = cpu->cd.x86.cr[0] &0xffff; - if (!modrm(cpu, MODRM_WRITE_RM, - 16, mode67, 0, &instr_orig, - NULL, &op1, &op2)) - return 0; - } else { - /* lmsw cannot be used to - clear bit 0: */ - op1 |= (cpu->cd.x86.cr[0] & - X86_CR0_PE); - x86_write_cr(cpu, 0, - (cpu->cd.x86.cr[0] & ~0xf) - | (op1 & 0xf)); - } - break; - case 7: /* invlpg */ - modrm(cpu, MODRM_READ, mode, - mode67, MODRM_JUST_GET_ADDR, &instr, - &newpc, &op1, &op2); - /* TODO */ - break; - default:fatal("UNIMPLEMENTED 0x%02x,0x%02x" - ",0x%02x\n", op, imm, *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, - really_orig_instr, 1 | omode, 0, 0); - cpu->running = 0; - } - break; - case 0x06: /* CLTS */ - cpu->cd.x86.cr[0] &= ~X86_CR0_TS; - break; - case 0x08: /* INVD */ - /* TODO */ - break; - case 0x09: /* WBINVD */ - /* TODO */ - break; - case 0x0b: /* Reserved */ - x86_interrupt(cpu, 6, 0); - return 1; - case 0x20: /* MOV r/m,CRx */ - case 0x21: /* MOV r/m,DRx: TODO: is this right? */ - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, 32, mode67, - imm==0x20? MODRM_CR : MODRM_DR, &instr, - &newpc, &op1, &op2)) - return 0; - op1 = op2; - if (!modrm(cpu, MODRM_WRITE_RM, 32, mode67, - imm==0x20? MODRM_CR : MODRM_DR, &instr_orig, - NULL, &op1, &op2)) - return 0; - break; - case 0x22: /* MOV CRx,r/m */ - case 0x23: /* MOV DRx,r/m */ - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, 32, mode67, - imm==0x22? MODRM_CR : MODRM_DR, &instr, - &newpc, &op1, &op2)) - return 0; - op2 = op1; - if (!modrm(cpu, MODRM_WRITE_R, 32, mode67, - imm==0x22? MODRM_CR : MODRM_DR, &instr_orig, - NULL, &op1, &op2)) - return 0; - break; - case 0x30: /* WRMSR */ - case 0x32: /* RDMSR */ - x86_msr(cpu, imm==0x30? 1 : 0); - break; - case 0x31: /* RDTSC */ - if (cpu->cd.x86.model.model_number < - X86_MODEL_PENTIUM) - fatal("WARNING: rdtsc usually requires" - " a Pentium. continuing anyway\n"); - if (cpu->cd.x86.cr[4] & X86_CR4_TSD) - fatal("WARNING: time stamp disable:" - " TODO\n"); - cpu->cd.x86.r[X86_R_DX] = cpu->cd.x86.tsc >> 32; - cpu->cd.x86.r[X86_R_AX] = cpu->cd.x86.tsc - & 0xffffffff; - /* TODO: make this better */ - cpu->cd.x86.tsc += 1000; - break; - case 0xa0: - if (!x86_push(cpu, cpu->cd.x86.s[X86_S_FS], - mode)) - return 0; - break; - case 0xa1: - if (!x86_pop(cpu, &tmp, mode)) - return 0; - reload_segment_descriptor(cpu, X86_S_FS, - tmp, &newpc); - break; - case 0xa2: - if (!(cpu->cd.x86.rflags & X86_FLAGS_ID)) - fatal("TODO: ID bit off in flags," - " but CPUID attempted?\n"); - x86_cpuid(cpu); - break; - case 0xa4: - case 0xa5: - case 0xac: - case 0xad: - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, mode, mode67, - 0, &instr, &newpc, &op1, &op2)) - return 0; - if (imm & 1) - imm2 = cpu->cd.x86.r[X86_R_CX]; - else - imm2 = read_imm(&instr, &newpc, 8); - imm2 &= 31; - if (imm <= 0xa5) { /* SHLD */ - if (mode == 16) { - op1 <<= 16; - op1 |= (op2 & 0xffff); - } else { - op1 <<= 32; - op1 |= (op2 & 0xffffffff); - } - x86_shiftrotate(cpu, &op1, 4, imm2, - mode == 64? 64 : (mode * 2)); - op1 >>= (mode==16? 16 : 32); - } else { /* SHRD */ - if (mode == 16) { - op2 <<= 16; - op1 = (op1 & 0xffff) | op2; - } else { - op2 <<= 32; - op1 = (op1 & 0xffffffff) | op2; - } - x86_shiftrotate(cpu, &op1, 5, imm2, - mode == 64? 64 : (mode * 2)); - op1 &= (mode==16? 0xffff : 0xffffffff); - } - if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67, - 0, &instr_orig, NULL, &op1, &op2)) - return 0; - break; - case 0xa8: - if (!x86_push(cpu, cpu->cd.x86.s[X86_S_GS], - mode)) - return 0; - break; - case 0xa9: - if (!x86_pop(cpu, &tmp, mode)) - return 0; - reload_segment_descriptor(cpu, X86_S_GS, - tmp, &newpc); - break; - case 0xa3: /* BT */ - case 0xab: /* BTS */ - case 0xb3: /* BTR */ - case 0xbb: /* BTC */ - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, mode, mode67, - 0, &instr, &newpc, &op1, &op2)) - return 0; - imm2 = op2 & 31; - if (mode == 16) - imm2 &= 15; - cpu->cd.x86.rflags &= ~X86_FLAGS_CF; - if (op1 & ((uint64_t)1 << imm2)) - cpu->cd.x86.rflags |= - X86_FLAGS_CF; - switch (imm) { - case 0xab: - op1 |= ((uint64_t)1 << imm2); - break; - case 0xb3: - op1 &= ~((uint64_t)1 << imm2); - break; - case 0xbb: - op1 ^= ((uint64_t)1 << imm2); - break; - } - if (imm != 0xa3) { - if (!modrm(cpu, MODRM_WRITE_RM, mode, - mode67, 0, &instr_orig, NULL, - &op1, &op2)) - return 0; - } - break; - case 0xaf: /* imul r16/32, rm16/32 */ - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, mode, mode67, - 0, &instr, &newpc, &op1, &op2)) - return 0; - cpu->cd.x86.rflags &= X86_FLAGS_CF; - cpu->cd.x86.rflags &= X86_FLAGS_OF; - if (mode == 16) { - op2 = (int16_t)op1 * (int16_t)op2; - if (op2 >= 0x10000) - cpu->cd.x86.rflags |= - X86_FLAGS_CF | X86_FLAGS_OF; - } else { - op2 = (int32_t)op1 * (int32_t)op2; - if (op2 >= 0x100000000ULL) - cpu->cd.x86.rflags |= - X86_FLAGS_CF | X86_FLAGS_OF; - } - if (!modrm(cpu, MODRM_WRITE_R, mode, mode67, - 0, &instr_orig, NULL, &op1, &op2)) - return 0; - break; - case 0xb0: - case 0xb1: /* CMPXCHG */ - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, mode, mode67, - imm == 0xb0? MODRM_EIGHTBIT : 0, - &instr, &newpc, &op1, &op2)) - return 0; - x86_calc_flags(cpu, op1, cpu->cd.x86.r[ - X86_R_AX], imm == 0xb0? 8 : mode, - CALCFLAGS_OP_SUB); - if (cpu->cd.x86.rflags & X86_FLAGS_ZF) { - if (!modrm(cpu, MODRM_WRITE_RM, mode, - mode67, imm == 0xb0? - MODRM_EIGHTBIT : 0, - &instr_orig, NULL, &op2, &op1)) - return 0; - } else { - if (imm == 0xb0) - cpu->cd.x86.r[X86_R_AX] = - (cpu->cd.x86.r[X86_R_AX] & - ~0xff) | (op1 & 0xff); - else if (mode == 16) - cpu->cd.x86.r[X86_R_AX] = - (cpu->cd.x86.r[X86_R_AX] & - ~0xffff) | (op1 & 0xffff); - else /* 32 bit */ - cpu->cd.x86.r[X86_R_AX] = op1; - } - break; - case 0xb2: /* LSS */ - case 0xb4: /* LFS */ - case 0xb5: /* LGS */ - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, mode, mode67, - MODRM_JUST_GET_ADDR, &instr, &newpc, - &op1, &op2)) - return 0; - /* op1 is the address to load from */ - if (!x86_load(cpu, op1, &tmp, mode/8)) - return 0; - op2 = tmp; - if (!x86_load(cpu, op1 + mode/8, &tmp, 2)) - return 0; - reload_segment_descriptor(cpu, imm==0xb2? - X86_S_SS:(imm==0xb4?X86_S_FS:X86_S_GS), - tmp, &newpc); - if (!modrm(cpu, MODRM_WRITE_R, mode, mode67, - 0, &instr_orig, NULL, &op1, &op2)) - return 0; - break; - case 0xb6: - case 0xb7: /* movzx */ - case 0xbe: - case 0xbf: /* movsx */ - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, mode, mode67, - (imm&1)==0? (MODRM_EIGHTBIT | - MODRM_R_NONEIGHTBIT) : MODRM_RM_16BIT, - &instr, &newpc, &op1, &op2)) - return 0; - signflag = 0; - if (imm >= 0xbe) - signflag = 1; - op2 = op1; - if (imm & 1) { /* r32 = r16 */ - op2 &= 0xffff; - if (signflag && op2 & 0x8000) - op2 |= 0xffff0000ULL; - } else { /* r(mode) = r8 */ - op2 &= 0xff; - if (signflag && op2 & 0x80) - op2 |= 0xffffff00ULL; - } - if (!modrm(cpu, MODRM_WRITE_R, mode, mode67, - (imm&1)==0? (MODRM_EIGHTBIT | - MODRM_R_NONEIGHTBIT) : MODRM_RM_16BIT, - &instr_orig, NULL, &op1, &op2)) - return 0; - break; - case 0xba: - subop = (*instr >> 3) & 0x7; - switch (subop) { - case 4: /* BT */ - case 5: /* BTS */ - case 6: /* BTR */ - case 7: /* BTC */ - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, mode, - mode67, 0, &instr, &newpc, &op1, - &op2)) - return 0; - imm = read_imm(&instr, &newpc, 8); - imm &= 31; - if (mode == 16) - imm &= 15; - cpu->cd.x86.rflags &= ~X86_FLAGS_CF; - if (op1 & ((uint64_t)1 << imm)) - cpu->cd.x86.rflags |= - X86_FLAGS_CF; - switch (subop) { - case 5: op1 |= ((uint64_t)1 << imm); - break; - case 6: op1 &= ~((uint64_t)1 << imm); - break; - case 7: op1 ^= ((uint64_t)1 << imm); - break; - } - if (subop != 4) { - if (!modrm(cpu, MODRM_WRITE_RM, - mode, mode67, 0, - &instr_orig, NULL, - &op1, &op2)) - return 0; - } - break; - default:fatal("UNIMPLEMENTED 0x%02x,0x%02x" - ",0x%02x\n", op, imm, *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, - really_orig_instr, 1|omode, 0, 0); - cpu->running = 0; - } - break; - case 0xbc: /* bsf */ - case 0xbd: /* bsr */ - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, mode, mode67, - 0, &instr, &newpc, &op1, &op2)) - return 0; - cpu->cd.x86.rflags &= ~X86_FLAGS_ZF; - if (op1 == 0) - cpu->cd.x86.rflags |= X86_FLAGS_ZF; - i = mode - 1; - if (imm == 0xbc) - i = 0; - for (;;) { - if (op1 & ((uint64_t)1<= mode) - break; - } else { - if (--i < 0) - break; - } - } - if (!modrm(cpu, MODRM_WRITE_R, mode, mode67, - 0, &instr_orig, NULL, &op1, &op2)) - return 0; - break; - case 0xc0: /* xadd */ - case 0xc1: - instr_orig = instr_orig_2 = instr; - if (!modrm(cpu, MODRM_READ, mode, mode67, - imm == 0xc0? MODRM_EIGHTBIT : 0, - &instr, &newpc, &op1, &op2)) - return 0; - tmp = op1; op1 = op2; op2 = tmp; - x86_calc_flags(cpu, op1, op2, imm==0xc0? - 8 : mode, CALCFLAGS_OP_ADD); - op1 += op2; - if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67, - imm == 0xc0? MODRM_EIGHTBIT : 0, - &instr_orig, NULL, &op1, &op2)) - return 0; - if (!modrm(cpu, MODRM_WRITE_R, mode, mode67, - imm == 0xc0? MODRM_EIGHTBIT : 0, - &instr_orig_2, NULL, &op1, &op2)) - return 0; - break; - case 0xc7: - subop = (*instr >> 3) & 0x7; - switch (subop) { - case 1: /* CMPXCHG8B */ - if (!modrm(cpu, MODRM_READ, mode, - mode67, MODRM_JUST_GET_ADDR, &instr, - &newpc, &op1, &op2)) - return 0; - if (!x86_load(cpu, op1, &tmp, 8)) - return 0; - cpu->cd.x86.rflags &= ~X86_FLAGS_ZF; - if ((tmp >> 32) == (0xffffffffULL & - cpu->cd.x86.r[X86_R_DX]) && (tmp - & 0xffffffffULL) == (0xffffffffULL & - cpu->cd.x86.r[X86_R_AX])) { - cpu->cd.x86.rflags |= - X86_FLAGS_ZF; - tmp = ((cpu->cd.x86.r[X86_R_CX] - & 0xffffffffULL) << 32) | - (cpu->cd.x86.r[X86_R_BX] & - 0xffffffffULL); - if (!x86_store(cpu, op1, tmp,8)) - return 0; - } else { - cpu->cd.x86.r[X86_R_DX] = - tmp >> 32; - cpu->cd.x86.r[X86_R_AX] = - tmp & 0xffffffffULL; - } - break; - default:fatal("UNIMPLEMENTED 0x%02x,0x%02x" - ",0x%02x\n", op, imm, *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, - really_orig_instr, 1|omode, 0, 0); - cpu->running = 0; - } - break; - default:fatal("TODO: 0x0f,0x%02x\n", imm); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, - really_orig_instr, 1|omode, 0, 0); - cpu->running = 0; - } - } - } else if ((op & 0xf0) < 0x20 && (op & 7) == 7) { - uint64_t tmp; - success = x86_pop(cpu, &tmp, mode); - if (!success) - return 0; - reload_segment_descriptor(cpu, op/8, tmp, &newpc); - } else if (op == 0x27) { /* DAA */ - int a = (cpu->cd.x86.r[X86_R_AX] >> 4) & 0xf; - int b = cpu->cd.x86.r[X86_R_AX] & 0xf; - if (b > 9) { - b -= 10; - a ++; - } else if (cpu->cd.x86.rflags & X86_FLAGS_AF) - b += 6; - cpu->cd.x86.rflags &= ~X86_FLAGS_CF; - cpu->cd.x86.rflags &= ~X86_FLAGS_AF; - if (a*10 + b >= 100) { - cpu->cd.x86.rflags |= X86_FLAGS_CF; - cpu->cd.x86.rflags |= X86_FLAGS_AF; - a %= 10; - } - cpu->cd.x86.r[X86_R_AX] &= ~0xff; - cpu->cd.x86.r[X86_R_AX] |= ((a*16 + b) & 0xff); - } else if (op == 0x2f) { /* DAS */ - int tmp_al = cpu->cd.x86.r[X86_R_AX] & 0xff; - if ((tmp_al & 0xf) > 9 || cpu->cd.x86.rflags & X86_FLAGS_AF) { - cpu->cd.x86.r[X86_R_AX] &= ~0xff; - cpu->cd.x86.r[X86_R_AX] |= ((tmp_al - 6) & 0xff); - cpu->cd.x86.rflags |= X86_FLAGS_AF; - } else - cpu->cd.x86.rflags &= ~X86_FLAGS_AF; - if (tmp_al > 0x9f || cpu->cd.x86.rflags & X86_FLAGS_CF) { - cpu->cd.x86.r[X86_R_AX] &= ~0xff; - cpu->cd.x86.r[X86_R_AX] |= ((tmp_al - 0x60) & 0xff); - cpu->cd.x86.rflags |= X86_FLAGS_CF; - } else - cpu->cd.x86.rflags &= ~X86_FLAGS_CF; - x86_calc_flags(cpu, cpu->cd.x86.r[X86_R_AX] & 0xff, - 0, 8, CALCFLAGS_OP_XOR); - } else if (op == 0x37) { /* AAA */ - int b = cpu->cd.x86.r[X86_R_AX] & 0xf; - if (b > 9) { - cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] - & ~0xff00) | ((cpu->cd.x86.r[X86_R_AX] & - 0xff00) + 0x100); - cpu->cd.x86.rflags |= X86_FLAGS_CF | X86_FLAGS_AF; - } else { - cpu->cd.x86.rflags &= ~(X86_FLAGS_CF | X86_FLAGS_AF); - } - cpu->cd.x86.r[X86_R_AX] &= ~0xf0; - } else if (op >= 0x40 && op <= 0x4f) { - int old_cf = cpu->cd.x86.rflags & X86_FLAGS_CF; - if (op < 0x48) { - x86_calc_flags(cpu, cpu->cd.x86.r[op & 7], 1, mode, - CALCFLAGS_OP_ADD); - cpu->cd.x86.r[op & 7] = modify(cpu->cd.x86.r[op & 7], - cpu->cd.x86.r[op & 7] + 1); - } else { - x86_calc_flags(cpu, cpu->cd.x86.r[op & 7], 1, mode, - CALCFLAGS_OP_SUB); - if (mode == 16) - cpu->cd.x86.r[op & 7] = modify(cpu->cd.x86.r[op - & 7], (cpu->cd.x86.r[op & 7] & 0xffff) - 1); - else { - cpu->cd.x86.r[op & 7] --; - cpu->cd.x86.r[op & 7] &= 0xffffffffULL; - } - } - /* preserve CF: */ - cpu->cd.x86.rflags &= ~X86_FLAGS_CF; - cpu->cd.x86.rflags |= old_cf; - } else if (op >= 0x50 && op <= 0x57) { - if (!x86_push(cpu, cpu->cd.x86.r[op & 7], mode)) - return 0; - } else if (op >= 0x58 && op <= 0x5f) { - if (!x86_pop(cpu, &tmp, mode)) - return 0; - if (mode == 16) - cpu->cd.x86.r[op & 7] = (cpu->cd.x86.r[op & 7] & - ~0xffff) | (tmp & 0xffff); - else - cpu->cd.x86.r[op & 7] = tmp; - } else if (op == 0x60) { /* PUSHA/PUSHAD */ - uint64_t r[8]; - int i; - for (i=0; i<8; i++) - r[i] = cpu->cd.x86.r[i]; - for (i=0; i<8; i++) - if (!x86_push(cpu, r[i], mode)) { - fatal("TODO: failed pusha\n"); - cpu->running = 0; - return 0; - } - } else if (op == 0x61) { /* POPA/POPAD */ - uint64_t r[8]; - int i; - for (i=7; i>=0; i--) - if (!x86_pop(cpu, &r[i], mode)) { - fatal("TODO: failed popa\n"); - cpu->running = 0; - return 0; - } - for (i=0; i<8; i++) - if (i != X86_R_SP) { - if (mode == 16) - cpu->cd.x86.r[i] = (cpu->cd.x86.r[i] - & ~0xffff) | (r[i] & 0xffff); - else - cpu->cd.x86.r[i] = r[i]; - } - } else if (op == 0x68) { /* PUSH imm16/32 */ - uint64_t imm = read_imm(&instr, &newpc, mode); - if (!x86_push(cpu, imm, mode)) - return 0; - } else if (op == 0x69 || op == 0x6b) { - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, - &newpc, &op1, &op2)) - return 0; - if (op == 0x69) - imm = read_imm(&instr, &newpc, mode); - else - imm = (signed char)read_imm(&instr, &newpc, 8); - op2 = op1 * imm; - /* TODO: overflow! */ - if (!modrm(cpu, MODRM_WRITE_R, mode, mode67, 0, - &instr_orig, NULL, &op1, &op2)) - return 0; - } else if (op == 0x6a) { /* PUSH imm8 */ - uint64_t imm = (signed char)read_imm(&instr, &newpc, 8); - if (!x86_push(cpu, imm, mode)) - return 0; - } else if ((op & 0xf0) == 0x70) { - imm = read_imm(&instr, &newpc, 8); - success = x86_condition(cpu, op); - if (success) - newpc = modify(newpc, newpc + (signed char)imm); - } else if (op == 0x80 || op == 0x81) { /* add/and r/m, imm */ - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, mode, mode67, op == 0x80? - MODRM_EIGHTBIT : 0, &instr, &newpc, &op1, &op2)) - return 0; - imm = read_imm(&instr, &newpc, op==0x80? 8 : mode); - switch ((*instr_orig >> 3) & 0x7) { - case 0: x86_calc_flags(cpu, op1, imm, op==0x80? 8 : mode, - CALCFLAGS_OP_ADD); - op1 += imm; - break; - case 1: op1 |= imm; break; - case 2: tmp = imm + (cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0); - x86_calc_flags(cpu, op1, tmp, op==0x80? 8 : mode, - CALCFLAGS_OP_ADD); - op1 += tmp; - break; - case 3: tmp = imm + (cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0); - x86_calc_flags(cpu, op1, tmp, op==0x80? 8 : mode, - CALCFLAGS_OP_SUB); - op1 -= tmp; - break; - case 4: op1 &= imm; break; - case 5: x86_calc_flags(cpu, op1, imm, op==0x80? 8 : mode, - CALCFLAGS_OP_SUB); - op1 -= imm; break; - case 6: op1 ^= imm; break; - case 7: x86_calc_flags(cpu, op1, imm, op==0x80? 8 : mode, - CALCFLAGS_OP_SUB); /* cmp */ - break; - } - - if (((*instr_orig >> 3) & 0x7) != 7) { - if (((*instr_orig >> 3) & 0x7) != 0 && - ((*instr_orig >> 3) & 0x7) != 2 && - ((*instr_orig >> 3) & 0x7) != 3 && - ((*instr_orig >> 3) & 0x7) != 5) - x86_calc_flags(cpu, op1, 0, op==0x80? 8 : mode, - CALCFLAGS_OP_XOR); - - /* "and","or","xor" always clears CF and OF: */ - if (((*instr_orig >> 3) & 0x7) == 1 || - ((*instr_orig >> 3) & 0x7) == 4 || - ((*instr_orig >> 3) & 0x7) == 6) { - cpu->cd.x86.rflags &= ~X86_FLAGS_CF; - cpu->cd.x86.rflags &= ~X86_FLAGS_OF; - } - - if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67, - op == 0x80? MODRM_EIGHTBIT : 0, &instr_orig, - NULL, &op1, &op2)) - return 0; - } - } else if (op == 0x83) { /* add/and r/m1632, imm8 */ - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, mode, mode67, 0, &instr, - &newpc, &op1, &op2)) - return 0; - imm = read_imm(&instr, &newpc, 8); - switch ((*instr_orig >> 3) & 0x7) { - case 0: x86_calc_flags(cpu, op1, (signed char)imm, - mode, CALCFLAGS_OP_ADD); - op1 += (signed char)imm; - break; - case 1: op1 |= (signed char)imm; break; - case 2: tmp = (signed char)imm + - (cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0); - x86_calc_flags(cpu, op1, tmp, mode, CALCFLAGS_OP_ADD); - op1 += tmp; - break; - case 3: tmp = (signed char)imm + - (cpu->cd.x86.rflags & X86_FLAGS_CF? 1 : 0); - x86_calc_flags(cpu, op1, tmp, mode, CALCFLAGS_OP_SUB); - op1 -= tmp; - break; - case 4: op1 &= (signed char)imm; break; - case 5: x86_calc_flags(cpu, op1, (signed char)imm, mode, - CALCFLAGS_OP_SUB); - op1 -= (signed char)imm; break; - case 6: op1 ^= (signed char)imm; break; - case 7: x86_calc_flags(cpu, op1, (signed char)imm, mode, - CALCFLAGS_OP_SUB); - break; - } - if (((*instr_orig >> 3) & 0x7) != 7) { - if (((*instr_orig >> 3) & 0x7) != 0 && - ((*instr_orig >> 3) & 0x7) != 2 && - ((*instr_orig >> 3) & 0x7) != 3 && - ((*instr_orig >> 3) & 0x7) != 5) - x86_calc_flags(cpu, op1, 0, mode, - CALCFLAGS_OP_XOR); - - /* "and","or","xor" always clears CF and OF: */ - if (((*instr_orig >> 3) & 0x7) == 1 || - ((*instr_orig >> 3) & 0x7) == 4 || - ((*instr_orig >> 3) & 0x7) == 6) { - cpu->cd.x86.rflags &= ~X86_FLAGS_CF; - cpu->cd.x86.rflags &= ~X86_FLAGS_OF; - } - if (!modrm(cpu, MODRM_WRITE_RM, mode, - mode67, 0, &instr_orig, NULL, &op1, &op2)) - return 0; - } - } else if (op == 0x84 || op == 0x85) { /* TEST */ - success = modrm(cpu, MODRM_READ, mode, mode67, op == 0x84? - MODRM_EIGHTBIT : 0, &instr, &newpc, &op1, &op2); - if (!success) - return 0; - op1 &= op2; - x86_calc_flags(cpu, op1, 0, op==0x84? 8 : mode, - CALCFLAGS_OP_XOR); - cpu->cd.x86.rflags &= ~X86_FLAGS_CF; - cpu->cd.x86.rflags &= ~X86_FLAGS_OF; - } else if (op >= 0x86 && op <= 0x87) { /* XCHG */ - void *orig2 = instr_orig = instr; - success = modrm(cpu, MODRM_READ, mode, mode67, op&1? 0 : - MODRM_EIGHTBIT, &instr, &newpc, &op1, &op2); - if (!success) - return 0; - /* Note: Update the r/m first, because it may be dependant - on original register values :-) */ - success = modrm(cpu, MODRM_WRITE_RM, mode, mode67, - op == 0x86? MODRM_EIGHTBIT : 0, &instr_orig, - NULL, &op2, &op1); - instr_orig = orig2; - success = modrm(cpu, MODRM_WRITE_R, mode, mode67, - op == 0x86? MODRM_EIGHTBIT : 0, &instr_orig, - NULL, &op2, &op1); - if (!success) - return 0; - } else if (op >= 0x88 && op <= 0x8b) { /* MOV */ - instr_orig = instr; - success = modrm(cpu, MODRM_READ, mode, mode67, (op & 1) == 0? - MODRM_EIGHTBIT : 0, &instr, &newpc, &op1, &op2); - if (!success) - return 0; - if (op < 0x8a) { - success = modrm(cpu, MODRM_WRITE_RM, mode, mode67, - op == 0x88? MODRM_EIGHTBIT : 0, &instr_orig, - NULL, &op2, &op1); - } else { - success = modrm(cpu, MODRM_WRITE_R, mode, mode67, - op == 0x8a? MODRM_EIGHTBIT : 0, &instr_orig, - NULL, &op2, &op1); - } - if (!success) - return 0; - } else if (op == 0x8c || op == 0x8e) { /* MOV seg */ - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, 16, mode67, MODRM_SEG, - &instr, &newpc, &op1, &op2)) - return 0; - if (op == 0x8c) { - if (!modrm(cpu, MODRM_WRITE_RM, 16, mode67, MODRM_SEG, - &instr_orig, NULL, &op2, &op1)) - return 0; - } else { - reload_segment_descriptor(cpu, (*instr_orig >> 3) & 7, - op1 & 0xffff, &newpc); - } - } else if (op == 0x8d) { /* LEA */ - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, mode, mode67, - MODRM_JUST_GET_ADDR, &instr, &newpc, &op1, &op2)) - return 0; - op2 = op1; - if (!modrm(cpu, MODRM_WRITE_R, mode, mode67, - 0, &instr_orig, NULL, &op1, &op2)) - return 0; - } else if (op == 0x8f) { - switch ((*instr >> 3) & 0x7) { - case 0: /* POP m16/m32 */ - if (!x86_pop(cpu, &op1, mode)) - return 0; - if (!modrm(cpu, MODRM_WRITE_RM, mode, mode67, - 0, &instr, &newpc, &op1, &op2)) - return 0; - break; - default: - fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, - really_orig_instr, 1|omode, 0, 0); - cpu->running = 0; - } - } else if (op == 0x90) { /* NOP */ - } else if (op >= 0x91 && op <= 0x97) { /* XCHG */ - uint64_t tmp; - if (mode == 16) { - tmp = cpu->cd.x86.r[X86_R_AX]; - cpu->cd.x86.r[X86_R_AX] = modify( - cpu->cd.x86.r[X86_R_AX], cpu->cd.x86.r[op & 7]); - cpu->cd.x86.r[op & 7] = modify( - cpu->cd.x86.r[op & 7], tmp); - } else { - tmp = cpu->cd.x86.r[X86_R_AX]; - cpu->cd.x86.r[X86_R_AX] = cpu->cd.x86.r[op & 7]; - cpu->cd.x86.r[op & 7] = tmp; - } - } else if (op == 0x98) { /* CBW/CWDE */ - if (mode == 16) { - cpu->cd.x86.r[X86_R_AX] &= ~0xff00; - if (cpu->cd.x86.r[X86_R_AX] & 0x80) - cpu->cd.x86.r[X86_R_AX] |= 0xff00; - } else { - cpu->cd.x86.r[X86_R_AX] &= 0xffff; - if (cpu->cd.x86.r[X86_R_AX] & 0x8000) - cpu->cd.x86.r[X86_R_AX] |= 0xffff0000ULL; - } - } else if (op == 0x99) { /* CWD/CDQ */ - if (mode == 16) { - cpu->cd.x86.r[X86_R_DX] &= ~0xffff; - if (cpu->cd.x86.r[X86_R_AX] & 0x8000) - cpu->cd.x86.r[X86_R_DX] |= 0xffff; - } else { - cpu->cd.x86.r[X86_R_DX] = 0; - if (cpu->cd.x86.r[X86_R_AX] & 0x80000000ULL) - cpu->cd.x86.r[X86_R_DX] = 0xffffffff; - } - } else if (op == 0x9a) { /* CALL seg:ofs */ - uint16_t old_tr = cpu->cd.x86.tr; - imm = read_imm(&instr, &newpc, mode); - imm2 = read_imm(&instr, &newpc, 16); - if (!x86_push(cpu, cpu->cd.x86.s[X86_S_CS], mode)) - return 0; - if (!x86_push(cpu, newpc, mode)) { - fatal("TODO: push failed in CALL seg:ofs\n"); - cpu->running = 0; - return 0; - } - reload_segment_descriptor(cpu, X86_S_CS, imm2, &newpc); - if (cpu->cd.x86.tr == old_tr) - newpc = imm; - } else if (op == 0x9b) { /* WAIT */ - } else if (op == 0x9c) { /* PUSHF */ - if (!x86_push(cpu, cpu->cd.x86.rflags, mode)) - return 0; - } else if (op == 0x9d) { /* POPF */ - if (!x86_pop(cpu, &tmp, mode)) - return 0; - if (mode == 16) - cpu->cd.x86.rflags = (cpu->cd.x86.rflags & ~0xffff) - | (tmp & 0xffff); - else if (mode == 32) - cpu->cd.x86.rflags = (cpu->cd.x86.rflags & ~0xffffffff) - | (tmp & 0xffffffff); - else - cpu->cd.x86.rflags = tmp; - /* TODO: only affect some bits? */ - cpu->cd.x86.rflags |= 0x0002; - if (cpu->cd.x86.model.model_number == X86_MODEL_8086) - cpu->cd.x86.rflags |= 0xf000; - /* TODO: all these bits aren't really cleared on a 286: */ - if (cpu->cd.x86.model.model_number == X86_MODEL_80286) - cpu->cd.x86.rflags &= ~0xf000; - if (cpu->cd.x86.model.model_number == X86_MODEL_80386) - cpu->cd.x86.rflags &= ~X86_FLAGS_AC; - if (cpu->cd.x86.model.model_number == X86_MODEL_80486) - cpu->cd.x86.rflags &= ~X86_FLAGS_ID; - } else if (op == 0x9e) { /* SAHF */ - int mask = (X86_FLAGS_SF | X86_FLAGS_ZF - | X86_FLAGS_AF | X86_FLAGS_PF | X86_FLAGS_CF); - cpu->cd.x86.rflags &= ~mask; - mask &= ((cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff); - cpu->cd.x86.rflags |= mask; - } else if (op == 0x9f) { /* LAHF */ - int b = cpu->cd.x86.rflags & (X86_FLAGS_SF | X86_FLAGS_ZF - | X86_FLAGS_AF | X86_FLAGS_PF | X86_FLAGS_CF); - b |= 2; - cpu->cd.x86.r[X86_R_AX] &= ~0xff00; - cpu->cd.x86.r[X86_R_AX] |= (b << 8); - } else if (op == 0xa0) { /* MOV AL,[addr] */ - imm = read_imm(&instr, &newpc, mode67); - if (!x86_load(cpu, imm, &tmp, 1)) - return 0; - cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & ~0xff) - | (tmp & 0xff); - } else if (op == 0xa1) { /* MOV AX,[addr] */ - imm = read_imm(&instr, &newpc, mode67); - if (!x86_load(cpu, imm, &tmp, mode/8)) - return 0; - cpu->cd.x86.r[X86_R_AX] = modify(cpu->cd.x86.r[X86_R_AX], tmp); - } else if (op == 0xa2) { /* MOV [addr],AL */ - imm = read_imm(&instr, &newpc, mode67); - if (!x86_store(cpu, imm, cpu->cd.x86.r[X86_R_AX], 1)) - return 0; - } else if (op == 0xa3) { /* MOV [addr],AX */ - imm = read_imm(&instr, &newpc, mode67); - if (!x86_store(cpu, imm, cpu->cd.x86.r[X86_R_AX], mode/8)) - return 0; - } else if (op == 0xa4 || op == 0xa5 || /* MOVS */ - op == 0xa6 || op == 0xa7 || /* CMPS */ - op == 0xaa || op == 0xab || /* STOS */ - op == 0xac || op == 0xad || /* LODS */ - op == 0xae || op == 0xaf) { /* SCAS */ - int dir = 1, movs = 0, lods = 0, cmps = 0, stos = 0, scas = 0; - int origcursegment = cpu->cd.x86.cursegment; - - len = 1; - if (op & 1) - len = mode / 8; - if (op >= 0xa4 && op <= 0xa5) - movs = 1; - if (op >= 0xa6 && op <= 0xa7) - cmps = 1; - if (op >= 0xaa && op <= 0xab) - stos = 1; - if (op >= 0xac && op <= 0xad) - lods = 1; - if (op >= 0xae && op <= 0xaf) - scas = 1; - if (cpu->cd.x86.rflags & X86_FLAGS_DF) - dir = -1; - - do { - uint64_t value; - - if (rep) { - /* Abort if [e]cx already 0: */ - if (mode == 16 && (cpu->cd.x86.r[X86_R_CX] & - 0xffff) == 0) - break; - if (mode != 16 && cpu->cd.x86.r[X86_R_CX] == 0) - break; - } - - if (!stos && !scas) { - uint64_t addr = cpu->cd.x86.r[X86_R_SI]; - if (mode67 == 16) - addr &= 0xffff; - if (mode67 == 32) - addr &= 0xffffffff; - cpu->cd.x86.cursegment = origcursegment; - if (!x86_load(cpu, addr, &value, len)) - return 0; - } else - value = cpu->cd.x86.r[X86_R_AX]; - if (lods) { - if (op == 0xac) - cpu->cd.x86.r[X86_R_AX] = - (cpu->cd.x86.r[X86_R_AX] & ~0xff) - | (value & 0xff); - else if (mode == 16) - cpu->cd.x86.r[X86_R_AX] = - (cpu->cd.x86.r[X86_R_AX] & ~0xffff) - | (value & 0xffff); - else - cpu->cd.x86.r[X86_R_AX] = value; - } - - if (stos || movs) { - uint64_t addr = cpu->cd.x86.r[X86_R_DI]; - if (mode67 == 16) - addr &= 0xffff; - if (mode67 == 32) - addr &= 0xffffffff; - cpu->cd.x86.cursegment = X86_S_ES; - if (!x86_store(cpu, addr, value, len)) - return 0; - } - if (cmps || scas) { - uint64_t addr = cpu->cd.x86.r[X86_R_DI]; - if (mode67 == 16) - addr &= 0xffff; - if (mode67 == 32) - addr &= 0xffffffff; - cpu->cd.x86.cursegment = X86_S_ES; - if (!x86_load(cpu, addr, &tmp, len)) - return 0; - - x86_calc_flags(cpu, value, tmp, len*8, - CALCFLAGS_OP_SUB); - } - - if (movs || lods || cmps) { - /* Modify esi: */ - if (mode67 == 16) - cpu->cd.x86.r[X86_R_SI] = - (cpu->cd.x86.r[X86_R_SI] & ~0xffff) - | ((cpu->cd.x86.r[X86_R_SI]+len*dir) - & 0xffff); - else { - cpu->cd.x86.r[X86_R_SI] += len*dir; - if (mode67 == 32) - cpu->cd.x86.r[X86_R_SI] &= - 0xffffffff; - } - } - - if (!lods) { - /* Modify edi: */ - if (mode67 == 16) - cpu->cd.x86.r[X86_R_DI] = - (cpu->cd.x86.r[X86_R_DI] & ~0xffff) - | ((cpu->cd.x86.r[X86_R_DI]+len*dir) - & 0xffff); - else { - cpu->cd.x86.r[X86_R_DI] += len*dir; - if (mode67 == 32) - cpu->cd.x86.r[X86_R_DI] &= - 0xffffffff; - } - } - - if (rep) { - /* Decrement ecx: */ - if (mode67 == 16) - cpu->cd.x86.r[X86_R_CX] = - (cpu->cd.x86.r[X86_R_CX] & ~0xffff) - | ((cpu->cd.x86.r[X86_R_CX] - 1) - & 0xffff); - else { - cpu->cd.x86.r[X86_R_CX] --; - cpu->cd.x86.r[X86_R_CX] &= 0xffffffff; - } - if (mode67 == 16 && (cpu->cd.x86.r[X86_R_CX] & - 0xffff) == 0) - rep = 0; - if (mode67 != 16 && - cpu->cd.x86.r[X86_R_CX] == 0) - rep = 0; - - if (cmps || scas) { - if (rep == REP_REP && !( - cpu->cd.x86.rflags & X86_FLAGS_ZF)) - rep = 0; - if (rep == REP_REPNE && - cpu->cd.x86.rflags & X86_FLAGS_ZF) - rep = 0; - } - } - } while (rep); - } else if (op >= 0xa8 && op <= 0xa9) { /* TEST al/[e]ax,imm */ - op1 = cpu->cd.x86.r[X86_R_AX]; - op2 = read_imm(&instr, &newpc, op==0xa8? 8 : mode); - op1 &= op2; - x86_calc_flags(cpu, op1, 0, op==0xa8? 8 : mode, - CALCFLAGS_OP_XOR); - cpu->cd.x86.rflags &= ~X86_FLAGS_CF; - cpu->cd.x86.rflags &= ~X86_FLAGS_OF; - } else if (op >= 0xb0 && op <= 0xb3) { /* MOV Xl,imm */ - imm = read_imm(&instr, &newpc, 8); - cpu->cd.x86.r[op & 3] = (cpu->cd.x86.r[op & 3] & ~0xff) - | (imm & 0xff); - } else if (op >= 0xb4 && op <= 0xb7) { /* MOV Xh,imm */ - imm = read_imm(&instr, &newpc, 8); - cpu->cd.x86.r[op & 3] = (cpu->cd.x86.r[op & 3] & ~0xff00) - | ((imm & 0xff) << 8); - } else if (op >= 0xb8 && op <= 0xbf) { /* MOV Xx,imm */ - imm = read_imm(&instr, &newpc, mode); - cpu->cd.x86.r[op & 7] = modify(cpu->cd.x86.r[op & 7], imm); - } else if (op == 0xc0 || op == 0xc1) { /* Shift/Rotate */ - int n = 1; - instr_orig = instr; - success = modrm(cpu, MODRM_READ, mode, mode67, - op&1? 0 : MODRM_EIGHTBIT, &instr, &newpc, &op1, &op2); - if (!success) - return 0; - n = read_imm(&instr, &newpc, 8); - x86_shiftrotate(cpu, &op1, (*instr_orig >> 3) & 0x7, - n, op&1? mode : 8); - success = modrm(cpu, MODRM_WRITE_RM, mode, mode67, - op&1? 0 : MODRM_EIGHTBIT, &instr_orig, NULL, &op1, &op2); - if (!success) - return 0; - } else if (op == 0xc2 || op == 0xc3) { /* RET near */ - uint64_t popped_pc; - if (!x86_pop(cpu, &popped_pc, mode)) - return 0; - if (op == 0xc2) { - imm = read_imm(&instr, &newpc, 16); - cpu->cd.x86.r[X86_R_SP] = modify(cpu->cd.x86.r[ - X86_R_SP], cpu->cd.x86.r[X86_R_SP] + imm); - } - newpc = popped_pc; - } else if (op == 0xc4 || op == 0xc5) { /* LDS,LES */ - instr_orig = instr; - if (!modrm(cpu, MODRM_READ, mode, mode67, - MODRM_JUST_GET_ADDR, &instr, &newpc, &op1, &op2)) - return 0; - /* op1 is the address to load from */ - if (!x86_load(cpu, op1, &tmp, mode/8)) - return 0; - op2 = tmp; - if (!x86_load(cpu, op1 + mode/8, &tmp, 2)) - return 0; - reload_segment_descriptor(cpu, op==0xc4? X86_S_ES:X86_S_DS, - tmp, &newpc); - if (!modrm(cpu, MODRM_WRITE_R, mode, mode67, - 0, &instr_orig, NULL, &op1, &op2)) - return 0; - } else if (op >= 0xc6 && op <= 0xc7) { - switch ((*instr >> 3) & 0x7) { - case 0: instr_orig = instr; /* MOV r/m, imm */ - success = modrm(cpu, MODRM_READ, mode, mode67, - op == 0xc6? MODRM_EIGHTBIT : 0, &instr, - &newpc, &op1, &op2); - if (!success) - return 0; - imm = read_imm(&instr, &newpc, op == 0xc6? 8 : mode); - op1 = imm; - success = modrm(cpu, MODRM_WRITE_RM, mode, mode67, - op == 0xc6? MODRM_EIGHTBIT : 0, &instr_orig, - NULL, &op1, &op2); - if (!success) - return 0; - break; - default: - fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, - really_orig_instr, 1|omode, 0, 0); - cpu->running = 0; - } - } else if (op == 0xc8) { /* ENTER */ - uint64_t tmp_frame_ptr; - int level; - imm = read_imm(&instr, &newpc, 16); - level = read_imm(&instr, &newpc, 8); - if (!x86_push(cpu, cpu->cd.x86.r[X86_R_BP], mode)) - return 0; - tmp_frame_ptr = cpu->cd.x86.r[X86_R_SP]; - if (level > 0) { - while (level-- > 1) { - uint64_t tmpword; - cpu->cd.x86.r[X86_R_BP] = modify( - cpu->cd.x86.r[X86_R_BP], - cpu->cd.x86.r[X86_R_BP] - mode/8); - cpu->cd.x86.cursegment = X86_S_SS; - if (!x86_load(cpu, cpu->cd.x86.r[X86_R_BP], - &tmpword, mode/8)) { - fatal("TODO: load error inside" - " ENTER\n"); - cpu->running = 0; - return 0; - } - if (!x86_push(cpu, tmpword, mode)) { - fatal("TODO: push error inside" - " ENTER\n"); - cpu->running = 0; - return 0; - } - } - if (!x86_push(cpu, tmp_frame_ptr, mode)) - return 0; - } - cpu->cd.x86.r[X86_R_BP] = modify(cpu->cd.x86.r[X86_R_BP], - tmp_frame_ptr); - if (mode == 16) - cpu->cd.x86.r[X86_R_SP] = (cpu->cd.x86.r[X86_R_SP] & - ~0xffff) | ((cpu->cd.x86.r[X86_R_SP] & 0xffff) - - imm); - else - cpu->cd.x86.r[X86_R_SP] -= imm; - } else if (op == 0xc9) { /* LEAVE */ - cpu->cd.x86.r[X86_R_SP] = cpu->cd.x86.r[X86_R_BP]; - if (!x86_pop(cpu, &tmp, mode)) { - fatal("TODO: pop error inside LEAVE\n"); - cpu->running = 0; - return 0; - } - cpu->cd.x86.r[X86_R_BP] = tmp; - } else if (op == 0xca || op == 0xcb) { /* RET far */ - uint64_t tmp2; - uint16_t old_tr = cpu->cd.x86.tr; - if (op == 0xca) - imm = read_imm(&instr, &newpc, 16); - else - imm = 0; - if (!x86_pop(cpu, &tmp, mode)) - return 0; - if (!x86_pop(cpu, &tmp2, mode)) { - fatal("TODO: pop error inside RET\n"); - cpu->running = 0; - return 0; - } - cpu->cd.x86.r[X86_R_SP] = modify(cpu->cd.x86.r[X86_R_SP], - cpu->cd.x86.r[X86_R_SP] + imm); - reload_segment_descriptor(cpu, X86_S_CS, tmp2, &newpc); - if (cpu->cd.x86.tr == old_tr) - newpc = tmp; - } else if (op == 0xcc) { /* INT3 */ - cpu->pc = newpc; - return x86_interrupt(cpu, 3, 0); - } else if (op == 0xcd) { /* INT */ - imm = read_imm(&instr, &newpc, 8); - cpu->pc = newpc; - return x86_interrupt(cpu, imm, 0); - } else if (op == 0xcf) { /* IRET */ - uint64_t tmp2, tmp3; - uint16_t old_tr = cpu->cd.x86.tr; - if (!x86_pop(cpu, &tmp, mode)) - return 0; - if (!x86_pop(cpu, &tmp2, mode)) - return 0; - if (!x86_pop(cpu, &tmp3, mode)) - return 0; -debug("{ iret to 0x%04x:0x%08x }\n", (int)tmp2,(int)tmp); - tmp2 &= 0xffff; - /* TODO: only affect some bits? */ - if (mode == 16) - cpu->cd.x86.rflags = (cpu->cd.x86.rflags & ~0xffff) - | (tmp3 & 0xffff); - else - cpu->cd.x86.rflags = tmp3; - /* - * In protected mode, if we're switching back from, say, an - * interrupt handler, then we should pop the old ss:esp too: - */ - if (PROTECTED_MODE && (tmp2 & X86_PL_MASK) > - (cpu->cd.x86.s[X86_S_CS] & X86_PL_MASK)) { - uint64_t old_ss, old_esp; - if (!x86_pop(cpu, &old_esp, mode)) - return 0; - if (!x86_pop(cpu, &old_ss, mode)) - return 0; - old_ss &= 0xffff; - -printf(": : : BEFORE tmp=%016llx tmp2=%016llx tmp3=%016llx\n", -(long long)tmp, (long long)tmp2, (long long)tmp3); -/* x86_cpu_register_dump(cpu, 1, 1); */ - - reload_segment_descriptor(cpu, X86_S_SS, old_ss, - &newpc); - cpu->cd.x86.r[X86_R_SP] = old_esp; - -/* printf(": : : AFTER\n"); -x86_cpu_register_dump(cpu, 1, 1); */ - - /* AFTER popping ss, check that the pl of - the popped ss is the same as tmp2 (the new - pl in cs)! */ - if ((old_ss & X86_PL_MASK) != (tmp2 & X86_PL_MASK)) - fatal("WARNING: iret: popped ss' pl = %i," - " different from cs' pl = %i\n", - (int)(old_ss & X86_PL_MASK), - (int)(tmp2 & X86_PL_MASK)); - } - reload_segment_descriptor(cpu, X86_S_CS, tmp2, &newpc); - if (cpu->cd.x86.tr == old_tr) - newpc = tmp; - } else if (op >= 0xd0 && op <= 0xd3) { - int n = 1; - instr_orig = instr; - success = modrm(cpu, MODRM_READ, mode, mode67, - op&1? 0 : MODRM_EIGHTBIT, &instr, &newpc, &op1, &op2); - if (!success) - return 0; - if (op >= 0xd2) - n = cpu->cd.x86.r[X86_R_CX]; - x86_shiftrotate(cpu, &op1, (*instr_orig >> 3) & 0x7, - n, op&1? mode : 8); - success = modrm(cpu, MODRM_WRITE_RM, mode, mode67, - op&1? 0 : MODRM_EIGHTBIT, &instr_orig, NULL, &op1, &op2); - if (!success) - return 0; - } else if (op == 0xd4) { /* AAM */ - int al = cpu->cd.x86.r[X86_R_AX] & 0xff; - /* al should be in the range 0..81 */ - int high; - imm = read_imm(&instr, &newpc, 8); - if (imm == 0) { - fatal("[ x86: \"aam 0\" ]\n"); - cpu->running = 0; - } else { - high = al / imm; - al %= imm; - cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & - ~0xffff) | al | ((high & 0xff) << 8); - x86_calc_flags(cpu, cpu->cd.x86.r[X86_R_AX], - 0, 8, CALCFLAGS_OP_XOR); - } - } else if (op == 0xd5) { /* AAD */ - int al = cpu->cd.x86.r[X86_R_AX] & 0xff; - int ah = (cpu->cd.x86.r[X86_R_AX] >> 8) & 0xff; - imm = read_imm(&instr, &newpc, 8); - cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & ~0xffff) - | ((al + 10*ah) & 0xff); - x86_calc_flags(cpu, cpu->cd.x86.r[X86_R_AX], - 0, 8, CALCFLAGS_OP_XOR); - } else if (op == 0xd7) { /* XLAT */ - uint64_t addr = cpu->cd.x86.r[X86_R_BX]; - if (mode == 16) - addr &= 0xffff; - addr += (cpu->cd.x86.r[X86_R_AX] & 0xff); - if (!x86_load(cpu, addr, &tmp, 1)) - return 0; - cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & ~0xff) - | (tmp & 0xff); - } else if (op == 0xd9) { - int subop = (*instr >> 3) & 7; - imm = *instr; - if (subop == 5) { /* FLDCW mem16 */ - if (!modrm(cpu, MODRM_READ, 16, mode67, 0, &instr, - &newpc, &op1, &op2)) - return 0; - cpu->cd.x86.fpu_cw = op1; - } else if (subop == 7) { /* FSTCW mem16 */ - op1 = cpu->cd.x86.fpu_cw; - if (!modrm(cpu, MODRM_WRITE_RM, 16, mode67, 0, &instr, - &newpc, &op1, &op2)) - return 0; - } else { - fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, really_orig_instr, - 1 | omode, 0, 0); - cpu->running = 0; - } - } else if (op == 0xdb) { - imm = *instr; - if (imm == 0xe2) { /* FCLEX */ - read_imm(&instr, &newpc, 8); - /* TODO: actually clear exceptions */ - } else if (imm == 0xe3) { /* FINIT */ - read_imm(&instr, &newpc, 8); - /* TODO: actually init? */ - } else if (imm == 0xe4) { /* FSETPM */ - read_imm(&instr, &newpc, 8); - } else { - fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, really_orig_instr, - 1 | omode, 0, 0); - cpu->running = 0; - } - } else if (op == 0xdd) { - int subop = (*instr >> 3) & 7; - imm = *instr; - if (subop == 7) { /* FSTSW mem16 */ - op1 = cpu->cd.x86.fpu_sw; - if (!modrm(cpu, MODRM_WRITE_RM, 16, mode67, 0, &instr, - &newpc, &op1, &op2)) - return 0; - } else { - fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, really_orig_instr, - 1 | omode, 0, 0); - cpu->running = 0; - } - } else if (op == 0xdf) { - imm = *instr; - if (imm == 0xe0) { /* FSTSW */ - read_imm(&instr, &newpc, 8); - cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & - ~0xffff) | (cpu->cd.x86.fpu_sw & 0xffff); - } else { - fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, really_orig_instr, - 1 | omode, 0, 0); - cpu->running = 0; - } - } else if (op == 0xe4 || op == 0xe5 /* IN imm,AL or AX/EAX */ - || op == 0x6c || op == 0x6d) { /* INSB or INSW/INSD */ - unsigned char databuf[8]; - int port_nr, ins = 0, len = 1, dir = 1; - if (op == 0x6c || op == 0x6d) { - port_nr = cpu->cd.x86.r[X86_R_DX] & 0xffff; - ins = 1; - } else - port_nr = read_imm(&instr, &newpc, 8); - if (op & 1) - len = mode/8; - if (cpu->cd.x86.rflags & X86_FLAGS_DF) - dir = -1; - do { - cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE+port_nr, - &databuf[0], len, MEM_READ, CACHE_NONE | PHYSICAL); - - if (ins) { - uint64_t addr = cpu->cd.x86.r[X86_R_DI]; - uint32_t value = databuf[0] + (databuf[1] << 8) - + (databuf[2] << 16) + (databuf[3] << 24); - if (mode67 == 16) - addr &= 0xffff; - if (mode67 == 32) - addr &= 0xffffffff; - cpu->cd.x86.cursegment = X86_S_ES; - if (!x86_store(cpu, addr, value, len)) - return 0; - - /* Advance (e)di: */ - if (mode67 == 16) - cpu->cd.x86.r[X86_R_DI] = - (cpu->cd.x86.r[X86_R_DI] & ~0xffff) - | ((cpu->cd.x86.r[X86_R_DI]+len*dir) - & 0xffff); - else { - cpu->cd.x86.r[X86_R_DI] += len*dir; - if (mode67 == 32) - cpu->cd.x86.r[X86_R_DI] &= - 0xffffffff; - } - - if (rep) { - /* Decrement ecx: */ - if (mode67 == 16) - cpu->cd.x86.r[X86_R_CX] = - (cpu->cd.x86.r[X86_R_CX] & - ~0xffff) | ((cpu->cd.x86.r[ - X86_R_CX] - 1) & 0xffff); - else { - cpu->cd.x86.r[X86_R_CX] --; - cpu->cd.x86.r[X86_R_CX] &= - 0xffffffff; - } - if (mode67 == 16 && (cpu->cd.x86.r[ - X86_R_CX] & 0xffff) == 0) - rep = 0; - if (mode67 != 16 && - cpu->cd.x86.r[X86_R_CX] == 0) - rep = 0; - } - } else { - if (len == 1) - cpu->cd.x86.r[X86_R_AX] = - (cpu->cd.x86.r[X86_R_AX] & - ~0xff) | databuf[0]; - else if (len == 2) - cpu->cd.x86.r[X86_R_AX] = - (cpu->cd.x86.r[X86_R_AX] & ~0xffff) - | databuf[0] | (databuf[1] << 8); - else if (len == 4) - cpu->cd.x86.r[X86_R_AX] = databuf[0] | - (databuf[1] << 8) | (databuf[2] - << 16) | (databuf[3] << 24); - } - } while (rep); - } else if (op == 0xe6 || op == 0xe7 /* OUT imm,AL or AX/EAX */ - || op == 0x6e || op == 0x6f) { /* OUTSB or OUTSW/OUTSD */ - unsigned char databuf[8]; - int port_nr, outs = 0, len = 1, dir = 1; - if (op == 0x6e || op == 0x6f) { - port_nr = cpu->cd.x86.r[X86_R_DX] & 0xffff; - outs = 1; - } else - port_nr = read_imm(&instr, &newpc, 8); - if (op & 1) - len = mode/8; - if (cpu->cd.x86.rflags & X86_FLAGS_DF) - dir = -1; - do { - if (outs) { - int i; - uint64_t addr = cpu->cd.x86.r[X86_R_DI]; - uint64_t value; - if (mode67 == 16) - addr &= 0xffff; - if (mode67 == 32) - addr &= 0xffffffff; - cpu->cd.x86.cursegment = X86_S_ES; - if (!x86_load(cpu, addr, &value, len)) - return 0; - - /* Advance (e)di: */ - if (mode67 == 16) - cpu->cd.x86.r[X86_R_DI] = - (cpu->cd.x86.r[X86_R_DI] & ~0xffff) - | ((cpu->cd.x86.r[X86_R_DI]+len*dir) - & 0xffff); - else { - cpu->cd.x86.r[X86_R_DI] += len*dir; - if (mode67 == 32) - cpu->cd.x86.r[X86_R_DI] &= - 0xffffffff; - } - - for (i=0; i<8; i++) - databuf[i] = value >> (i*8); - - if (rep) { - /* Decrement ecx: */ - if (mode67 == 16) - cpu->cd.x86.r[X86_R_CX] = - (cpu->cd.x86.r[X86_R_CX] & - ~0xffff) | ((cpu->cd.x86.r[ - X86_R_CX] - 1) & 0xffff); - else { - cpu->cd.x86.r[X86_R_CX] --; - cpu->cd.x86.r[X86_R_CX] &= - 0xffffffff; - } - if (mode67 == 16 && (cpu->cd.x86.r[ - X86_R_CX] & 0xffff) == 0) - rep = 0; - if (mode67 != 16 && - cpu->cd.x86.r[X86_R_CX] == 0) - rep = 0; - } - } else { - int i; - for (i=0; i<8; i++) - databuf[i] = cpu->cd.x86.r[X86_R_AX] - >> (i*8); - } - - cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE+port_nr, - &databuf[0], len, MEM_WRITE, CACHE_NONE | PHYSICAL); - } while (rep); - } else if (op == 0xe8 || op == 0xe9) { /* CALL/JMP near */ - imm = read_imm(&instr, &newpc, mode); - if (mode == 16) - imm = (int16_t)imm; - if (mode == 32) - imm = (int32_t)imm; - if (op == 0xe8) { - if (!x86_push(cpu, newpc, mode)) - return 0; - } - newpc += imm; - } else if (op == 0xea) { /* JMP seg:ofs */ - uint16_t old_tr = cpu->cd.x86.tr; - imm = read_imm(&instr, &newpc, mode); - imm2 = read_imm(&instr, &newpc, 16); - reload_segment_descriptor(cpu, X86_S_CS, imm2, &newpc); - if (cpu->cd.x86.tr == old_tr) - newpc = imm; - } else if ((op >= 0xe0 && op <= 0xe3) || op == 0xeb) { /* LOOP,JMP */ - int perform_jump = 0; - imm = read_imm(&instr, &newpc, 8); - switch (op) { - case 0xe0: /* loopnz */ - case 0xe1: /* loopz */ - case 0xe2: /* loop */ - /* NOTE: address size attribute, not operand size? */ - if (mode67 == 16) - cpu->cd.x86.r[X86_R_CX] = (~0xffff & - cpu->cd.x86.r[X86_R_CX]) | - ((cpu->cd.x86.r[X86_R_CX] - 1) & 0xffff); - else - cpu->cd.x86.r[X86_R_CX] --; - if (mode67 == 16 && (cpu->cd.x86.r[X86_R_CX] & - 0xffff) != 0) - perform_jump = 1; - if (mode67 == 32 && cpu->cd.x86.r[X86_R_CX] != 0) - perform_jump = 1; - if (op == 0xe0 && cpu->cd.x86.rflags & X86_FLAGS_ZF) - perform_jump = 0; - if (op == 0xe1 && (!cpu->cd.x86.rflags & X86_FLAGS_ZF)) - perform_jump = 0; - break; - case 0xe3: /* jcxz/jecxz */ - if (mode67 == 16 && (cpu->cd.x86.r[X86_R_CX] & 0xffff) - == 0) - perform_jump = 1; - if (mode67 != 16 && (cpu->cd.x86.r[X86_R_CX] & - 0xffffffffULL) == 0) - perform_jump = 1; - break; - case 0xeb: /* jmp */ - perform_jump = 1; - break; - } - if (perform_jump) - newpc += (signed char)imm; - } else if (op == 0xec || op == 0xed) { /* IN DX,AL or AX/EAX */ - unsigned char databuf[8]; - cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE + - (cpu->cd.x86.r[X86_R_DX] & 0xffff), &databuf[0], - op == 0xec? 1 : (mode/8), MEM_READ, CACHE_NONE | PHYSICAL); - if (op == 0xec) - cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & - ~0xff) | databuf[0]; - else if (op == 0xed && mode == 16) - cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[X86_R_AX] & - ~0xffff) | databuf[0] | (databuf[1] << 8); - else if (op == 0xed && mode == 32) - cpu->cd.x86.r[X86_R_AX] = databuf[0] | - (databuf[1] << 8) | (databuf[2] << 16) | - (databuf[3] << 24); - } else if (op == 0xee || op == 0xef) { /* OUT DX,AL or AX/EAX */ - unsigned char databuf[8]; - databuf[0] = cpu->cd.x86.r[X86_R_AX]; - if (op == 0xef) { - databuf[1] = cpu->cd.x86.r[X86_R_AX] >> 8; - if (mode >= 32) { - databuf[2] = cpu->cd.x86.r[X86_R_AX] >> 16; - databuf[3] = cpu->cd.x86.r[X86_R_AX] >> 24; - } - } - cpu->memory_rw(cpu, cpu->mem, X86_IO_BASE + - (cpu->cd.x86.r[X86_R_DX] & 0xffff), &databuf[0], - op == 0xee? 1 : (mode/8), MEM_WRITE, CACHE_NONE | PHYSICAL); - } else if (op == 0xf4) { /* HLT */ - cpu->cd.x86.halted = 1; - } else if (op == 0xf5) { /* CMC */ - cpu->cd.x86.rflags ^= X86_FLAGS_CF; - } else if (op == 0xf8) { /* CLC */ - cpu->cd.x86.rflags &= ~X86_FLAGS_CF; - } else if (op == 0xf9) { /* STC */ - cpu->cd.x86.rflags |= X86_FLAGS_CF; - } else if (op == 0xfa) { /* CLI */ - cpu->cd.x86.rflags &= ~X86_FLAGS_IF; - } else if (op == 0xfb) { /* STI */ - cpu->cd.x86.rflags |= X86_FLAGS_IF; - } else if (op == 0xfc) { /* CLD */ - cpu->cd.x86.rflags &= ~X86_FLAGS_DF; - } else if (op == 0xfd) { /* STD */ - cpu->cd.x86.rflags |= X86_FLAGS_DF; - } else if (op == 0xf6 || op == 0xf7) { /* MUL, DIV etc */ - uint64_t res; - int unsigned_op = 1; - switch ((*instr >> 3) & 0x7) { - case 0: /* test */ - success = modrm(cpu, MODRM_READ, mode, mode67, - op == 0xf6? MODRM_EIGHTBIT : 0, &instr, - &newpc, &op1, &op2); - if (!success) - return 0; - op2 = read_imm(&instr, &newpc, op==0xf6? 8 : mode); - op1 &= op2; - x86_calc_flags(cpu, op1, 0, op==0xf6? 8 : mode, - CALCFLAGS_OP_XOR); - break; - case 2: /* not */ - case 3: /* neg */ - instr_orig = instr; - success = modrm(cpu, MODRM_READ, mode, mode67, - op == 0xf6? MODRM_EIGHTBIT : 0, &instr, - &newpc, &op1, &op2); - if (!success) - return 0; - switch ((*instr_orig >> 3) & 0x7) { - case 2: op1 ^= 0xffffffffffffffffULL; break; - case 3: x86_calc_flags(cpu, 0, op1, - op == 0xf6? 8 : mode, CALCFLAGS_OP_SUB); - op1 = 0 - op1; - cpu->cd.x86.rflags &= ~X86_FLAGS_CF; - if (op1 != 0) - cpu->cd.x86.rflags |= X86_FLAGS_CF; - break; - } - success = modrm(cpu, MODRM_WRITE_RM, mode, mode67, - op == 0xf6? MODRM_EIGHTBIT : 0, &instr_orig, - NULL, &op1, &op2); - if (!success) - return 0; - break; - case 5: /* imul */ - unsigned_op = 0; - case 4: /* mul */ - success = modrm(cpu, MODRM_READ, mode, mode67, - op == 0xf6? MODRM_EIGHTBIT : 0, &instr, - &newpc, &op1, &op2); - if (!success) - return 0; - cpu->cd.x86.rflags &= ~X86_FLAGS_CF; - cpu->cd.x86.rflags &= ~X86_FLAGS_OF; - if (op == 0xf6) { - if (unsigned_op) - res = (cpu->cd.x86.r[X86_R_AX] & 0xff) - * (op1 & 0xff); - else - res = (int16_t)(signed char)(cpu->cd. - x86.r[X86_R_AX] & 0xff) * (int16_t) - (signed char)(op1 & 0xff); - cpu->cd.x86.r[X86_R_AX] = (cpu->cd.x86.r[ - X86_R_AX] & ~0xffff) | (res & 0xffff); - if ((res & 0xffff) >= 0x100) - cpu->cd.x86.rflags |= X86_FLAGS_CF - | X86_FLAGS_OF; - } else if (mode == 16) { - if (unsigned_op) - res = (cpu->cd.x86.r[X86_R_AX] & 0xffff) - * (op1 & 0xffff); - else - res = (int32_t)(int16_t)(cpu->cd.x86.r[ - X86_R_AX] & 0xffff) * (int32_t) - (int16_t)(op1 & 0xffff); - cpu->cd.x86.r[X86_R_AX] = modify(cpu-> - cd.x86.r[X86_R_AX], res & 0xffff); - cpu->cd.x86.r[X86_R_DX] = modify(cpu->cd.x86 - .r[X86_R_DX], (res>>16) & 0xffff); - if ((res & 0xffffffff) >= 0x10000) - cpu->cd.x86.rflags |= X86_FLAGS_CF - | X86_FLAGS_OF; - } else if (mode == 32) { - if (unsigned_op) - res = (cpu->cd.x86.r[X86_R_AX] & - 0xffffffff) * (op1 & 0xffffffff); - else - res = (int64_t)(int32_t)(cpu->cd.x86.r[ - X86_R_AX] & 0xffffffff) * (int64_t) - (int32_t)(op1 & 0xffffffff); - cpu->cd.x86.r[X86_R_AX] = res & 0xffffffff; - cpu->cd.x86.r[X86_R_DX] = (res >> 32) & - 0xffffffff; - if (res >= 0x100000000ULL) - cpu->cd.x86.rflags |= X86_FLAGS_CF - | X86_FLAGS_OF; - } - break; - case 7: /* idiv */ - unsigned_op = 0; - case 6: /* div */ - success = modrm(cpu, MODRM_READ, mode, mode67, - op == 0xf6? MODRM_EIGHTBIT : 0, &instr, - &newpc, &op1, &op2); - if (!success) - return 0; - if (op1 == 0) { - fatal("TODO: division by zero\n"); - cpu->running = 0; - break; - } - if (op == 0xf6) { - int al, ah; - if (unsigned_op) { - al = (cpu->cd.x86.r[X86_R_AX] & - 0xffff) / op1; - ah = (cpu->cd.x86.r[X86_R_AX] & - 0xffff) % op1; - } else { - al = (int16_t)(cpu->cd.x86.r[ - X86_R_AX] & 0xffff) / (int16_t)op1; - ah = (int16_t)(cpu->cd.x86.r[ - X86_R_AX] & 0xffff) % (int16_t)op1; - } - cpu->cd.x86.r[X86_R_AX] = modify( - cpu->cd.x86.r[X86_R_AX], (ah<<8) + al); - } else if (mode == 16) { - uint64_t a = (cpu->cd.x86.r[X86_R_AX] & 0xffff) - + ((cpu->cd.x86.r[X86_R_DX] & 0xffff)<<16); - uint32_t ax, dx; - if (unsigned_op) { - ax = a / op1, dx = a % op1; - } else { - ax = (int32_t)a / (int32_t)op1; - dx = (int32_t)a % (int32_t)op1; - } - cpu->cd.x86.r[X86_R_AX] = modify( - cpu->cd.x86.r[X86_R_AX], ax); - cpu->cd.x86.r[X86_R_DX] = modify( - cpu->cd.x86.r[X86_R_DX], dx); - } else if (mode == 32) { - uint64_t a = (cpu->cd.x86.r[X86_R_AX] & - 0xffffffffULL) + ((cpu->cd.x86.r[ - X86_R_DX] & 0xffffffffULL) << 32); - uint32_t eax, edx; - if (unsigned_op) { - eax = (uint64_t)a / (uint32_t)op1; - edx = (uint64_t)a % (uint32_t)op1; - } else { - eax = (int64_t)a / (int32_t)op1; - edx = (int64_t)a % (int32_t)op1; - } - cpu->cd.x86.r[X86_R_AX] = eax; - cpu->cd.x86.r[X86_R_DX] = edx; - } - break; - default: - fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, - really_orig_instr, 1|omode, 0, 0); - cpu->running = 0; - } - } else if (op == 0xfe || op == 0xff) { /* INC, DEC etc */ - int old_cf; - switch ((*instr >> 3) & 0x7) { - case 0: - case 1: instr_orig = instr; - success = modrm(cpu, MODRM_READ, mode, mode67, - op == 0xfe? MODRM_EIGHTBIT : 0, &instr, - &newpc, &op1, &op2); - if (!success) - return 0; - old_cf = cpu->cd.x86.rflags & X86_FLAGS_CF; - switch ((*instr_orig >> 3) & 0x7) { - case 0: x86_calc_flags(cpu, op1, 1, op==0xfe? 8 : mode, - CALCFLAGS_OP_ADD); - op1 ++; - break; /* inc */ - case 1: x86_calc_flags(cpu, op1, 1, op==0xfe? 8 : mode, - CALCFLAGS_OP_SUB); - op1 --; - break; /* dec */ - } - success = modrm(cpu, MODRM_WRITE_RM, mode, mode67, - op == 0xfe? MODRM_EIGHTBIT : 0, &instr_orig, - NULL, &op1, &op2); - if (!success) - return 0; - /* preserve CF: */ - cpu->cd.x86.rflags &= ~X86_FLAGS_CF; - cpu->cd.x86.rflags |= old_cf; - break; - case 2: if (op == 0xfe) { - fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, - *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, - really_orig_instr, 1|omode, 0, 0); - cpu->running = 0; - } else { - success = modrm(cpu, MODRM_READ, mode, mode67, - 0, &instr, &newpc, &op1, &op2); - if (!success) - return 0; - /* Push return [E]IP */ - if (!x86_push(cpu, newpc, mode)) - return 0; - newpc = op1; - } - break; - case 3: if (op == 0xfe) { - fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, - *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, - really_orig_instr, 1|omode, 0, 0); - cpu->running = 0; - } else { - uint16_t old_tr = cpu->cd.x86.tr; - uint64_t tmp1, tmp2; - success = modrm(cpu, MODRM_READ, mode, mode67, - MODRM_JUST_GET_ADDR, &instr, - &newpc, &op1, &op2); - if (!success) - return 0; - /* Load a far address from op1: */ - if (!x86_load(cpu, op1, &tmp1, mode/8)) - return 0; - if (!x86_load(cpu, op1 + (mode/8), &tmp2, 2)) - return 0; - /* Push return CS:[E]IP */ - if (!x86_push(cpu, cpu->cd.x86.s[X86_S_CS], - mode)) - return 0; - if (!x86_push(cpu, newpc, mode)) { - fatal("TODO: push failed, call " - "far indirect?\n"); - cpu->running = 0; - return 0; - } - reload_segment_descriptor(cpu, X86_S_CS, - tmp2, &newpc); - if (cpu->cd.x86.tr == old_tr) - newpc = tmp1; - } - break; - case 4: if (op == 0xfe) { - fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, - *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, - really_orig_instr, 1|omode, 0, 0); - cpu->running = 0; - } else { - success = modrm(cpu, MODRM_READ, mode, mode67, - 0, &instr, &newpc, &op1, &op2); - if (!success) - return 0; - newpc = op1; - } - break; - case 5: if (op == 0xfe) { - fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, - *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, - really_orig_instr, 1|omode, 0, 0); - cpu->running = 0; - } else { - uint16_t old_tr = cpu->cd.x86.tr; - uint64_t tmp1, tmp2; - success = modrm(cpu, MODRM_READ, mode, mode67, - MODRM_JUST_GET_ADDR, &instr, - &newpc, &op1, &op2); - if (!success) - return 0; - /* Load a far address from op1: */ - if (!x86_load(cpu, op1, &tmp1, mode/8)) - return 0; - if (!x86_load(cpu, op1 + (mode/8), &tmp2, 2)) - return 0; - reload_segment_descriptor(cpu, X86_S_CS, - tmp2, &newpc); - if (cpu->cd.x86.tr == old_tr) - newpc = tmp1; - } - break; - case 6: if (op == 0xfe) { - fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, - *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, - really_orig_instr, 1|omode, 0, 0); - cpu->running = 0; - } else { - instr_orig = instr; - success = modrm(cpu, MODRM_READ, mode, mode67, - 0, &instr, &newpc, &op1, &op2); - if (!success) - return 0; - if (!x86_push(cpu, op1, mode)) - return 0; - } - break; - default: - fatal("UNIMPLEMENTED 0x%02x,0x%02x\n", op, *instr); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, - really_orig_instr, 1|omode, 0, 0); - cpu->running = 0; - } - } else { - fatal("x86_cpu_run_instr(): unimplemented opcode 0x%02x" - " at ", op); print_csip(cpu); fatal("\n"); - quiet_mode = 0; - x86_cpu_disassemble_instr(cpu, - really_orig_instr, 1|omode, 0, 0); - cpu->running = 0; - return 0; - } - - /* Wrap-around and update [E]IP: */ - cpu->pc = newpc & (((uint64_t)1 << (cpu->cd.x86.descr_cache[ - X86_S_CS].default_op_size)) - 1); - - if (trap_flag_was_set) { - if (REAL_MODE) { - x86_interrupt(cpu, 1, 0); - } else { - fatal("TRAP flag in protected mode?\n"); - cpu->running = 0; - } - } - - return 1; -} - +#define TRANSLATE_ADDRESS translate_address_x86 +#include "memory_x86.c" +#undef TRANSLATE_ADDRESS -#define CPU_RUN x86_cpu_run -#define CPU_RINSTR x86_cpu_run_instr -#define CPU_RUN_X86 -#include "cpu_run.c" -#undef CPU_RINSTR -#undef CPU_RUN_X86 -#undef CPU_RUN +#include "tmp_x86_tail.c" -/* - * x86_cpu_family_init(): - * - * Fill in the cpu_family struct for x86. - */ -int x86_cpu_family_init(struct cpu_family *fp) -{ - fp->name = "x86"; - fp->cpu_new = x86_cpu_new; - fp->list_available_types = x86_cpu_list_available_types; - fp->register_match = x86_cpu_register_match; - fp->disassemble_instr = x86_cpu_disassemble_instr; - fp->register_dump = x86_cpu_register_dump; - fp->run = x86_cpu_run; - fp->dumpinfo = x86_cpu_dumpinfo; - /* fp->show_full_statistics = x86_cpu_show_full_statistics; */ - /* fp->tlbdump = x86_cpu_tlbdump; */ - fp->interrupt = x86_cpu_interrupt; - fp->interrupt_ack = x86_cpu_interrupt_ack; - return 1; -} #endif /* ENABLE_X86 */