127458df8SWei Liu /* 227458df8SWei Liu * Copyright (C) 2016 Veertu Inc, 327458df8SWei Liu * Copyright (C) 2017 Google Inc, 427458df8SWei Liu * 527458df8SWei Liu * This program is free software; you can redistribute it and/or 627458df8SWei Liu * modify it under the terms of the GNU Lesser General Public 727458df8SWei Liu * License as published by the Free Software Foundation; either 827458df8SWei Liu * version 2.1 of the License, or (at your option) any later version. 927458df8SWei Liu * 1027458df8SWei Liu * This program is distributed in the hope that it will be useful, 1127458df8SWei Liu * but WITHOUT ANY WARRANTY; without even the implied warranty of 1227458df8SWei Liu * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1327458df8SWei Liu * Lesser General Public License for more details. 1427458df8SWei Liu * 1527458df8SWei Liu * You should have received a copy of the GNU Lesser General Public 1627458df8SWei Liu * License along with this program; if not, see <http://www.gnu.org/licenses/>. 1727458df8SWei Liu */ 1827458df8SWei Liu 1927458df8SWei Liu ///////////////////////////////////////////////////////////////////////// 2027458df8SWei Liu // 2127458df8SWei Liu // Copyright (C) 2001-2012 The Bochs Project 2227458df8SWei Liu // 2327458df8SWei Liu // This library is free software; you can redistribute it and/or 2427458df8SWei Liu // modify it under the terms of the GNU Lesser General Public 2527458df8SWei Liu // License as published by the Free Software Foundation; either 2627458df8SWei Liu // version 2.1 of the License, or (at your option) any later version. 2727458df8SWei Liu // 2827458df8SWei Liu // This library is distributed in the hope that it will be useful, 2927458df8SWei Liu // but WITHOUT ANY WARRANTY; without even the implied warranty of 3027458df8SWei Liu // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 3127458df8SWei Liu // Lesser General Public License for more details. 3227458df8SWei Liu // 3327458df8SWei Liu // You should have received a copy of the GNU Lesser General Public 3427458df8SWei Liu // License along with this library; if not, write to the Free Software 3527458df8SWei Liu // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA B 02110-1301 USA 3627458df8SWei Liu ///////////////////////////////////////////////////////////////////////// 3727458df8SWei Liu 3827458df8SWei Liu #include "qemu/osdep.h" 3927458df8SWei Liu #include "panic.h" 4027458df8SWei Liu #include "x86_decode.h" 4127458df8SWei Liu #include "x86.h" 4227458df8SWei Liu #include "x86_emu.h" 4327458df8SWei Liu #include "x86_flags.h" 4427458df8SWei Liu 4527458df8SWei Liu #define EXEC_2OP_FLAGS_CMD(env, decode, cmd, FLAGS_FUNC, save_res) \ 4627458df8SWei Liu { \ 4727458df8SWei Liu fetch_operands(env, decode, 2, true, true, false); \ 4827458df8SWei Liu switch (decode->operand_size) { \ 4927458df8SWei Liu case 1: \ 5027458df8SWei Liu { \ 5127458df8SWei Liu uint8_t v1 = (uint8_t)decode->op[0].val; \ 5227458df8SWei Liu uint8_t v2 = (uint8_t)decode->op[1].val; \ 5327458df8SWei Liu uint8_t diff = v1 cmd v2; \ 5427458df8SWei Liu if (save_res) { \ 55*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], diff, 1); \ 5627458df8SWei Liu } \ 5727458df8SWei Liu FLAGS_FUNC##8(env, v1, v2, diff); \ 5827458df8SWei Liu break; \ 5927458df8SWei Liu } \ 6027458df8SWei Liu case 2: \ 6127458df8SWei Liu { \ 6227458df8SWei Liu uint16_t v1 = (uint16_t)decode->op[0].val; \ 6327458df8SWei Liu uint16_t v2 = (uint16_t)decode->op[1].val; \ 6427458df8SWei Liu uint16_t diff = v1 cmd v2; \ 6527458df8SWei Liu if (save_res) { \ 66*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], diff, 2); \ 6727458df8SWei Liu } \ 6827458df8SWei Liu FLAGS_FUNC##16(env, v1, v2, diff); \ 6927458df8SWei Liu break; \ 7027458df8SWei Liu } \ 7127458df8SWei Liu case 4: \ 7227458df8SWei Liu { \ 7327458df8SWei Liu uint32_t v1 = (uint32_t)decode->op[0].val; \ 7427458df8SWei Liu uint32_t v2 = (uint32_t)decode->op[1].val; \ 7527458df8SWei Liu uint32_t diff = v1 cmd v2; \ 7627458df8SWei Liu if (save_res) { \ 77*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], diff, 4); \ 7827458df8SWei Liu } \ 7927458df8SWei Liu FLAGS_FUNC##32(env, v1, v2, diff); \ 8027458df8SWei Liu break; \ 8127458df8SWei Liu } \ 8227458df8SWei Liu default: \ 8327458df8SWei Liu VM_PANIC("bad size\n"); \ 8427458df8SWei Liu } \ 8527458df8SWei Liu } \ 8627458df8SWei Liu 8727458df8SWei Liu target_ulong read_reg(CPUX86State *env, int reg, int size) 8827458df8SWei Liu { 8927458df8SWei Liu switch (size) { 9027458df8SWei Liu case 1: 9127458df8SWei Liu return x86_reg(env, reg)->lx; 9227458df8SWei Liu case 2: 9327458df8SWei Liu return x86_reg(env, reg)->rx; 9427458df8SWei Liu case 4: 9527458df8SWei Liu return x86_reg(env, reg)->erx; 9627458df8SWei Liu case 8: 9727458df8SWei Liu return x86_reg(env, reg)->rrx; 9827458df8SWei Liu default: 9927458df8SWei Liu abort(); 10027458df8SWei Liu } 10127458df8SWei Liu return 0; 10227458df8SWei Liu } 10327458df8SWei Liu 10427458df8SWei Liu void write_reg(CPUX86State *env, int reg, target_ulong val, int size) 10527458df8SWei Liu { 10627458df8SWei Liu switch (size) { 10727458df8SWei Liu case 1: 10827458df8SWei Liu x86_reg(env, reg)->lx = val; 10927458df8SWei Liu break; 11027458df8SWei Liu case 2: 11127458df8SWei Liu x86_reg(env, reg)->rx = val; 11227458df8SWei Liu break; 11327458df8SWei Liu case 4: 11427458df8SWei Liu x86_reg(env, reg)->rrx = (uint32_t)val; 11527458df8SWei Liu break; 11627458df8SWei Liu case 8: 11727458df8SWei Liu x86_reg(env, reg)->rrx = val; 11827458df8SWei Liu break; 11927458df8SWei Liu default: 12027458df8SWei Liu abort(); 12127458df8SWei Liu } 12227458df8SWei Liu } 12327458df8SWei Liu 124*77a2dba4SPaolo Bonzini target_ulong read_val_from_reg(void *reg_ptr, int size) 12527458df8SWei Liu { 12627458df8SWei Liu target_ulong val; 12727458df8SWei Liu 12827458df8SWei Liu switch (size) { 12927458df8SWei Liu case 1: 13027458df8SWei Liu val = *(uint8_t *)reg_ptr; 13127458df8SWei Liu break; 13227458df8SWei Liu case 2: 13327458df8SWei Liu val = *(uint16_t *)reg_ptr; 13427458df8SWei Liu break; 13527458df8SWei Liu case 4: 13627458df8SWei Liu val = *(uint32_t *)reg_ptr; 13727458df8SWei Liu break; 13827458df8SWei Liu case 8: 13927458df8SWei Liu val = *(uint64_t *)reg_ptr; 14027458df8SWei Liu break; 14127458df8SWei Liu default: 14227458df8SWei Liu abort(); 14327458df8SWei Liu } 14427458df8SWei Liu return val; 14527458df8SWei Liu } 14627458df8SWei Liu 147*77a2dba4SPaolo Bonzini void write_val_to_reg(void *reg_ptr, target_ulong val, int size) 14827458df8SWei Liu { 14927458df8SWei Liu switch (size) { 15027458df8SWei Liu case 1: 15127458df8SWei Liu *(uint8_t *)reg_ptr = val; 15227458df8SWei Liu break; 15327458df8SWei Liu case 2: 15427458df8SWei Liu *(uint16_t *)reg_ptr = val; 15527458df8SWei Liu break; 15627458df8SWei Liu case 4: 15727458df8SWei Liu *(uint64_t *)reg_ptr = (uint32_t)val; 15827458df8SWei Liu break; 15927458df8SWei Liu case 8: 16027458df8SWei Liu *(uint64_t *)reg_ptr = val; 16127458df8SWei Liu break; 16227458df8SWei Liu default: 16327458df8SWei Liu abort(); 16427458df8SWei Liu } 16527458df8SWei Liu } 16627458df8SWei Liu 167*77a2dba4SPaolo Bonzini static void write_val_to_mem(CPUX86State *env, target_ulong ptr, target_ulong val, int size) 16827458df8SWei Liu { 169*77a2dba4SPaolo Bonzini emul_ops->write_mem(env_cpu(env), &val, ptr, size); 17027458df8SWei Liu } 17127458df8SWei Liu 172*77a2dba4SPaolo Bonzini void write_val_ext(CPUX86State *env, struct x86_decode_op *decode, target_ulong val, int size) 17327458df8SWei Liu { 174*77a2dba4SPaolo Bonzini if (decode->type == X86_VAR_REG) { 175*77a2dba4SPaolo Bonzini write_val_to_reg(decode->regptr, val, size); 176*77a2dba4SPaolo Bonzini } else { 177*77a2dba4SPaolo Bonzini write_val_to_mem(env, decode->addr, val, size); 17827458df8SWei Liu } 17927458df8SWei Liu } 18027458df8SWei Liu 18127458df8SWei Liu uint8_t *read_mmio(CPUX86State *env, target_ulong ptr, int bytes) 18227458df8SWei Liu { 18327458df8SWei Liu emul_ops->read_mem(env_cpu(env), env->emu_mmio_buf, ptr, bytes); 18427458df8SWei Liu return env->emu_mmio_buf; 18527458df8SWei Liu } 18627458df8SWei Liu 18727458df8SWei Liu 188*77a2dba4SPaolo Bonzini static target_ulong read_val_from_mem(CPUX86State *env, target_long ptr, int size) 18927458df8SWei Liu { 19027458df8SWei Liu target_ulong val; 19127458df8SWei Liu uint8_t *mmio_ptr; 19227458df8SWei Liu 19327458df8SWei Liu mmio_ptr = read_mmio(env, ptr, size); 19427458df8SWei Liu switch (size) { 19527458df8SWei Liu case 1: 19627458df8SWei Liu val = *(uint8_t *)mmio_ptr; 19727458df8SWei Liu break; 19827458df8SWei Liu case 2: 19927458df8SWei Liu val = *(uint16_t *)mmio_ptr; 20027458df8SWei Liu break; 20127458df8SWei Liu case 4: 20227458df8SWei Liu val = *(uint32_t *)mmio_ptr; 20327458df8SWei Liu break; 20427458df8SWei Liu case 8: 20527458df8SWei Liu val = *(uint64_t *)mmio_ptr; 20627458df8SWei Liu break; 20727458df8SWei Liu default: 20827458df8SWei Liu VM_PANIC("bad size\n"); 20927458df8SWei Liu break; 21027458df8SWei Liu } 21127458df8SWei Liu return val; 21227458df8SWei Liu } 21327458df8SWei Liu 214*77a2dba4SPaolo Bonzini target_ulong read_val_ext(CPUX86State *env, struct x86_decode_op *decode, int size) 215*77a2dba4SPaolo Bonzini { 216*77a2dba4SPaolo Bonzini if (decode->type == X86_VAR_REG) { 217*77a2dba4SPaolo Bonzini return read_val_from_reg(decode->regptr, size); 218*77a2dba4SPaolo Bonzini } else { 219*77a2dba4SPaolo Bonzini return read_val_from_mem(env, decode->addr, size); 220*77a2dba4SPaolo Bonzini } 221*77a2dba4SPaolo Bonzini } 222*77a2dba4SPaolo Bonzini 22327458df8SWei Liu static void fetch_operands(CPUX86State *env, struct x86_decode *decode, 22427458df8SWei Liu int n, bool val_op0, bool val_op1, bool val_op2) 22527458df8SWei Liu { 22627458df8SWei Liu int i; 22727458df8SWei Liu bool calc_val[3] = {val_op0, val_op1, val_op2}; 22827458df8SWei Liu 22927458df8SWei Liu for (i = 0; i < n; i++) { 23027458df8SWei Liu switch (decode->op[i].type) { 23127458df8SWei Liu case X86_VAR_IMMEDIATE: 23227458df8SWei Liu break; 23327458df8SWei Liu case X86_VAR_REG: 234*77a2dba4SPaolo Bonzini VM_PANIC_ON(!decode->op[i].regptr); 23527458df8SWei Liu if (calc_val[i]) { 236*77a2dba4SPaolo Bonzini decode->op[i].val = read_val_from_reg(decode->op[i].regptr, 23727458df8SWei Liu decode->operand_size); 23827458df8SWei Liu } 23927458df8SWei Liu break; 24027458df8SWei Liu case X86_VAR_RM: 24127458df8SWei Liu calc_modrm_operand(env, decode, &decode->op[i]); 24227458df8SWei Liu if (calc_val[i]) { 243*77a2dba4SPaolo Bonzini decode->op[i].val = read_val_ext(env, &decode->op[i], 24427458df8SWei Liu decode->operand_size); 24527458df8SWei Liu } 24627458df8SWei Liu break; 24727458df8SWei Liu case X86_VAR_OFFSET: 248*77a2dba4SPaolo Bonzini decode->op[i].addr = decode_linear_addr(env, decode, 249*77a2dba4SPaolo Bonzini decode->op[i].addr, 25027458df8SWei Liu R_DS); 25127458df8SWei Liu if (calc_val[i]) { 252*77a2dba4SPaolo Bonzini decode->op[i].val = read_val_ext(env, &decode->op[i], 25327458df8SWei Liu decode->operand_size); 25427458df8SWei Liu } 25527458df8SWei Liu break; 25627458df8SWei Liu default: 25727458df8SWei Liu break; 25827458df8SWei Liu } 25927458df8SWei Liu } 26027458df8SWei Liu } 26127458df8SWei Liu 26227458df8SWei Liu static void exec_mov(CPUX86State *env, struct x86_decode *decode) 26327458df8SWei Liu { 26427458df8SWei Liu fetch_operands(env, decode, 2, false, true, false); 265*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], decode->op[1].val, 26627458df8SWei Liu decode->operand_size); 26727458df8SWei Liu 26827458df8SWei Liu env->eip += decode->len; 26927458df8SWei Liu } 27027458df8SWei Liu 27127458df8SWei Liu static void exec_add(CPUX86State *env, struct x86_decode *decode) 27227458df8SWei Liu { 27327458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, +, SET_FLAGS_OSZAPC_ADD, true); 27427458df8SWei Liu env->eip += decode->len; 27527458df8SWei Liu } 27627458df8SWei Liu 27727458df8SWei Liu static void exec_or(CPUX86State *env, struct x86_decode *decode) 27827458df8SWei Liu { 27927458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, |, SET_FLAGS_OSZAPC_LOGIC, true); 28027458df8SWei Liu env->eip += decode->len; 28127458df8SWei Liu } 28227458df8SWei Liu 28327458df8SWei Liu static void exec_adc(CPUX86State *env, struct x86_decode *decode) 28427458df8SWei Liu { 28527458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, +get_CF(env)+, SET_FLAGS_OSZAPC_ADD, true); 28627458df8SWei Liu env->eip += decode->len; 28727458df8SWei Liu } 28827458df8SWei Liu 28927458df8SWei Liu static void exec_sbb(CPUX86State *env, struct x86_decode *decode) 29027458df8SWei Liu { 29127458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, -get_CF(env)-, SET_FLAGS_OSZAPC_SUB, true); 29227458df8SWei Liu env->eip += decode->len; 29327458df8SWei Liu } 29427458df8SWei Liu 29527458df8SWei Liu static void exec_and(CPUX86State *env, struct x86_decode *decode) 29627458df8SWei Liu { 29727458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, &, SET_FLAGS_OSZAPC_LOGIC, true); 29827458df8SWei Liu env->eip += decode->len; 29927458df8SWei Liu } 30027458df8SWei Liu 30127458df8SWei Liu static void exec_sub(CPUX86State *env, struct x86_decode *decode) 30227458df8SWei Liu { 30327458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, true); 30427458df8SWei Liu env->eip += decode->len; 30527458df8SWei Liu } 30627458df8SWei Liu 30727458df8SWei Liu static void exec_xor(CPUX86State *env, struct x86_decode *decode) 30827458df8SWei Liu { 30927458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, ^, SET_FLAGS_OSZAPC_LOGIC, true); 31027458df8SWei Liu env->eip += decode->len; 31127458df8SWei Liu } 31227458df8SWei Liu 31327458df8SWei Liu static void exec_neg(CPUX86State *env, struct x86_decode *decode) 31427458df8SWei Liu { 31527458df8SWei Liu /*EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false);*/ 31627458df8SWei Liu int32_t val; 31727458df8SWei Liu fetch_operands(env, decode, 2, true, true, false); 31827458df8SWei Liu 31927458df8SWei Liu val = 0 - sign(decode->op[1].val, decode->operand_size); 320*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[1], val, decode->operand_size); 32127458df8SWei Liu 32227458df8SWei Liu if (4 == decode->operand_size) { 32327458df8SWei Liu SET_FLAGS_OSZAPC_SUB32(env, 0, 0 - val, val); 32427458df8SWei Liu } else if (2 == decode->operand_size) { 32527458df8SWei Liu SET_FLAGS_OSZAPC_SUB16(env, 0, 0 - val, val); 32627458df8SWei Liu } else if (1 == decode->operand_size) { 32727458df8SWei Liu SET_FLAGS_OSZAPC_SUB8(env, 0, 0 - val, val); 32827458df8SWei Liu } else { 32927458df8SWei Liu VM_PANIC("bad op size\n"); 33027458df8SWei Liu } 33127458df8SWei Liu 33227458df8SWei Liu /*lflags_to_rflags(env);*/ 33327458df8SWei Liu env->eip += decode->len; 33427458df8SWei Liu } 33527458df8SWei Liu 33627458df8SWei Liu static void exec_cmp(CPUX86State *env, struct x86_decode *decode) 33727458df8SWei Liu { 33827458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); 33927458df8SWei Liu env->eip += decode->len; 34027458df8SWei Liu } 34127458df8SWei Liu 34227458df8SWei Liu static void exec_inc(CPUX86State *env, struct x86_decode *decode) 34327458df8SWei Liu { 34427458df8SWei Liu decode->op[1].type = X86_VAR_IMMEDIATE; 34527458df8SWei Liu decode->op[1].val = 0; 34627458df8SWei Liu 34727458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, +1+, SET_FLAGS_OSZAP_ADD, true); 34827458df8SWei Liu 34927458df8SWei Liu env->eip += decode->len; 35027458df8SWei Liu } 35127458df8SWei Liu 35227458df8SWei Liu static void exec_dec(CPUX86State *env, struct x86_decode *decode) 35327458df8SWei Liu { 35427458df8SWei Liu decode->op[1].type = X86_VAR_IMMEDIATE; 35527458df8SWei Liu decode->op[1].val = 0; 35627458df8SWei Liu 35727458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, -1-, SET_FLAGS_OSZAP_SUB, true); 35827458df8SWei Liu env->eip += decode->len; 35927458df8SWei Liu } 36027458df8SWei Liu 36127458df8SWei Liu static void exec_tst(CPUX86State *env, struct x86_decode *decode) 36227458df8SWei Liu { 36327458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, &, SET_FLAGS_OSZAPC_LOGIC, false); 36427458df8SWei Liu env->eip += decode->len; 36527458df8SWei Liu } 36627458df8SWei Liu 36727458df8SWei Liu static void exec_not(CPUX86State *env, struct x86_decode *decode) 36827458df8SWei Liu { 36927458df8SWei Liu fetch_operands(env, decode, 1, true, false, false); 37027458df8SWei Liu 371*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], ~decode->op[0].val, 37227458df8SWei Liu decode->operand_size); 37327458df8SWei Liu env->eip += decode->len; 37427458df8SWei Liu } 37527458df8SWei Liu 37627458df8SWei Liu void exec_movzx(CPUX86State *env, struct x86_decode *decode) 37727458df8SWei Liu { 37827458df8SWei Liu int src_op_size; 37927458df8SWei Liu int op_size = decode->operand_size; 38027458df8SWei Liu 38127458df8SWei Liu fetch_operands(env, decode, 1, false, false, false); 38227458df8SWei Liu 38327458df8SWei Liu if (0xb6 == decode->opcode[1]) { 38427458df8SWei Liu src_op_size = 1; 38527458df8SWei Liu } else { 38627458df8SWei Liu src_op_size = 2; 38727458df8SWei Liu } 38827458df8SWei Liu decode->operand_size = src_op_size; 38927458df8SWei Liu calc_modrm_operand(env, decode, &decode->op[1]); 390*77a2dba4SPaolo Bonzini decode->op[1].val = read_val_ext(env, &decode->op[1], src_op_size); 391*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], decode->op[1].val, op_size); 39227458df8SWei Liu 39327458df8SWei Liu env->eip += decode->len; 39427458df8SWei Liu } 39527458df8SWei Liu 39627458df8SWei Liu static void exec_out(CPUX86State *env, struct x86_decode *decode) 39727458df8SWei Liu { 39827458df8SWei Liu switch (decode->opcode[0]) { 39927458df8SWei Liu case 0xe6: 40027458df8SWei Liu emul_ops->handle_io(env_cpu(env), decode->op[0].val, &AL(env), 1, 1, 1); 40127458df8SWei Liu break; 40227458df8SWei Liu case 0xe7: 40327458df8SWei Liu emul_ops->handle_io(env_cpu(env), decode->op[0].val, &RAX(env), 1, 40427458df8SWei Liu decode->operand_size, 1); 40527458df8SWei Liu break; 40627458df8SWei Liu case 0xee: 40727458df8SWei Liu emul_ops->handle_io(env_cpu(env), DX(env), &AL(env), 1, 1, 1); 40827458df8SWei Liu break; 40927458df8SWei Liu case 0xef: 41027458df8SWei Liu emul_ops->handle_io(env_cpu(env), DX(env), &RAX(env), 1, 41127458df8SWei Liu decode->operand_size, 1); 41227458df8SWei Liu break; 41327458df8SWei Liu default: 41427458df8SWei Liu VM_PANIC("Bad out opcode\n"); 41527458df8SWei Liu break; 41627458df8SWei Liu } 41727458df8SWei Liu env->eip += decode->len; 41827458df8SWei Liu } 41927458df8SWei Liu 42027458df8SWei Liu static void exec_in(CPUX86State *env, struct x86_decode *decode) 42127458df8SWei Liu { 42227458df8SWei Liu target_ulong val = 0; 42327458df8SWei Liu switch (decode->opcode[0]) { 42427458df8SWei Liu case 0xe4: 42527458df8SWei Liu emul_ops->handle_io(env_cpu(env), decode->op[0].val, &AL(env), 0, 1, 1); 42627458df8SWei Liu break; 42727458df8SWei Liu case 0xe5: 42827458df8SWei Liu emul_ops->handle_io(env_cpu(env), decode->op[0].val, &val, 0, 42927458df8SWei Liu decode->operand_size, 1); 43027458df8SWei Liu if (decode->operand_size == 2) { 43127458df8SWei Liu AX(env) = val; 43227458df8SWei Liu } else { 43327458df8SWei Liu RAX(env) = (uint32_t)val; 43427458df8SWei Liu } 43527458df8SWei Liu break; 43627458df8SWei Liu case 0xec: 43727458df8SWei Liu emul_ops->handle_io(env_cpu(env), DX(env), &AL(env), 0, 1, 1); 43827458df8SWei Liu break; 43927458df8SWei Liu case 0xed: 44027458df8SWei Liu emul_ops->handle_io(env_cpu(env), DX(env), &val, 0, 44127458df8SWei Liu decode->operand_size, 1); 44227458df8SWei Liu if (decode->operand_size == 2) { 44327458df8SWei Liu AX(env) = val; 44427458df8SWei Liu } else { 44527458df8SWei Liu RAX(env) = (uint32_t)val; 44627458df8SWei Liu } 44727458df8SWei Liu 44827458df8SWei Liu break; 44927458df8SWei Liu default: 45027458df8SWei Liu VM_PANIC("Bad in opcode\n"); 45127458df8SWei Liu break; 45227458df8SWei Liu } 45327458df8SWei Liu 45427458df8SWei Liu env->eip += decode->len; 45527458df8SWei Liu } 45627458df8SWei Liu 45727458df8SWei Liu static inline void string_increment_reg(CPUX86State *env, int reg, 45827458df8SWei Liu struct x86_decode *decode) 45927458df8SWei Liu { 46027458df8SWei Liu target_ulong val = read_reg(env, reg, decode->addressing_size); 46127458df8SWei Liu if (env->eflags & DF_MASK) { 46227458df8SWei Liu val -= decode->operand_size; 46327458df8SWei Liu } else { 46427458df8SWei Liu val += decode->operand_size; 46527458df8SWei Liu } 46627458df8SWei Liu write_reg(env, reg, val, decode->addressing_size); 46727458df8SWei Liu } 46827458df8SWei Liu 46927458df8SWei Liu static inline void string_rep(CPUX86State *env, struct x86_decode *decode, 47027458df8SWei Liu void (*func)(CPUX86State *env, 47127458df8SWei Liu struct x86_decode *ins), int rep) 47227458df8SWei Liu { 47327458df8SWei Liu target_ulong rcx = read_reg(env, R_ECX, decode->addressing_size); 47427458df8SWei Liu while (rcx--) { 47527458df8SWei Liu func(env, decode); 47627458df8SWei Liu write_reg(env, R_ECX, rcx, decode->addressing_size); 47727458df8SWei Liu if ((PREFIX_REP == rep) && !get_ZF(env)) { 47827458df8SWei Liu break; 47927458df8SWei Liu } 48027458df8SWei Liu if ((PREFIX_REPN == rep) && get_ZF(env)) { 48127458df8SWei Liu break; 48227458df8SWei Liu } 48327458df8SWei Liu } 48427458df8SWei Liu } 48527458df8SWei Liu 48627458df8SWei Liu static void exec_ins_single(CPUX86State *env, struct x86_decode *decode) 48727458df8SWei Liu { 48827458df8SWei Liu target_ulong addr = linear_addr_size(env_cpu(env), RDI(env), 48927458df8SWei Liu decode->addressing_size, R_ES); 49027458df8SWei Liu 49127458df8SWei Liu emul_ops->handle_io(env_cpu(env), DX(env), env->emu_mmio_buf, 0, 49227458df8SWei Liu decode->operand_size, 1); 49327458df8SWei Liu emul_ops->write_mem(env_cpu(env), env->emu_mmio_buf, addr, 49427458df8SWei Liu decode->operand_size); 49527458df8SWei Liu 49627458df8SWei Liu string_increment_reg(env, R_EDI, decode); 49727458df8SWei Liu } 49827458df8SWei Liu 49927458df8SWei Liu static void exec_ins(CPUX86State *env, struct x86_decode *decode) 50027458df8SWei Liu { 50127458df8SWei Liu if (decode->rep) { 50227458df8SWei Liu string_rep(env, decode, exec_ins_single, 0); 50327458df8SWei Liu } else { 50427458df8SWei Liu exec_ins_single(env, decode); 50527458df8SWei Liu } 50627458df8SWei Liu 50727458df8SWei Liu env->eip += decode->len; 50827458df8SWei Liu } 50927458df8SWei Liu 51027458df8SWei Liu static void exec_outs_single(CPUX86State *env, struct x86_decode *decode) 51127458df8SWei Liu { 51227458df8SWei Liu target_ulong addr = decode_linear_addr(env, decode, RSI(env), R_DS); 51327458df8SWei Liu 51427458df8SWei Liu emul_ops->read_mem(env_cpu(env), env->emu_mmio_buf, addr, 51527458df8SWei Liu decode->operand_size); 51627458df8SWei Liu emul_ops->handle_io(env_cpu(env), DX(env), env->emu_mmio_buf, 1, 51727458df8SWei Liu decode->operand_size, 1); 51827458df8SWei Liu 51927458df8SWei Liu string_increment_reg(env, R_ESI, decode); 52027458df8SWei Liu } 52127458df8SWei Liu 52227458df8SWei Liu static void exec_outs(CPUX86State *env, struct x86_decode *decode) 52327458df8SWei Liu { 52427458df8SWei Liu if (decode->rep) { 52527458df8SWei Liu string_rep(env, decode, exec_outs_single, 0); 52627458df8SWei Liu } else { 52727458df8SWei Liu exec_outs_single(env, decode); 52827458df8SWei Liu } 52927458df8SWei Liu 53027458df8SWei Liu env->eip += decode->len; 53127458df8SWei Liu } 53227458df8SWei Liu 53327458df8SWei Liu static void exec_movs_single(CPUX86State *env, struct x86_decode *decode) 53427458df8SWei Liu { 53527458df8SWei Liu target_ulong src_addr; 53627458df8SWei Liu target_ulong dst_addr; 53727458df8SWei Liu target_ulong val; 53827458df8SWei Liu 53927458df8SWei Liu src_addr = decode_linear_addr(env, decode, RSI(env), R_DS); 54027458df8SWei Liu dst_addr = linear_addr_size(env_cpu(env), RDI(env), 54127458df8SWei Liu decode->addressing_size, R_ES); 54227458df8SWei Liu 543*77a2dba4SPaolo Bonzini val = read_val_from_mem(env, src_addr, decode->operand_size); 544*77a2dba4SPaolo Bonzini write_val_to_mem(env, dst_addr, val, decode->operand_size); 54527458df8SWei Liu 54627458df8SWei Liu string_increment_reg(env, R_ESI, decode); 54727458df8SWei Liu string_increment_reg(env, R_EDI, decode); 54827458df8SWei Liu } 54927458df8SWei Liu 55027458df8SWei Liu static void exec_movs(CPUX86State *env, struct x86_decode *decode) 55127458df8SWei Liu { 55227458df8SWei Liu if (decode->rep) { 55327458df8SWei Liu string_rep(env, decode, exec_movs_single, 0); 55427458df8SWei Liu } else { 55527458df8SWei Liu exec_movs_single(env, decode); 55627458df8SWei Liu } 55727458df8SWei Liu 55827458df8SWei Liu env->eip += decode->len; 55927458df8SWei Liu } 56027458df8SWei Liu 56127458df8SWei Liu static void exec_cmps_single(CPUX86State *env, struct x86_decode *decode) 56227458df8SWei Liu { 56327458df8SWei Liu target_ulong src_addr; 56427458df8SWei Liu target_ulong dst_addr; 56527458df8SWei Liu 56627458df8SWei Liu src_addr = decode_linear_addr(env, decode, RSI(env), R_DS); 56727458df8SWei Liu dst_addr = linear_addr_size(env_cpu(env), RDI(env), 56827458df8SWei Liu decode->addressing_size, R_ES); 56927458df8SWei Liu 57027458df8SWei Liu decode->op[0].type = X86_VAR_IMMEDIATE; 571*77a2dba4SPaolo Bonzini decode->op[0].val = read_val_from_mem(env, src_addr, decode->operand_size); 57227458df8SWei Liu decode->op[1].type = X86_VAR_IMMEDIATE; 573*77a2dba4SPaolo Bonzini decode->op[1].val = read_val_from_mem(env, dst_addr, decode->operand_size); 57427458df8SWei Liu 57527458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); 57627458df8SWei Liu 57727458df8SWei Liu string_increment_reg(env, R_ESI, decode); 57827458df8SWei Liu string_increment_reg(env, R_EDI, decode); 57927458df8SWei Liu } 58027458df8SWei Liu 58127458df8SWei Liu static void exec_cmps(CPUX86State *env, struct x86_decode *decode) 58227458df8SWei Liu { 58327458df8SWei Liu if (decode->rep) { 58427458df8SWei Liu string_rep(env, decode, exec_cmps_single, decode->rep); 58527458df8SWei Liu } else { 58627458df8SWei Liu exec_cmps_single(env, decode); 58727458df8SWei Liu } 58827458df8SWei Liu env->eip += decode->len; 58927458df8SWei Liu } 59027458df8SWei Liu 59127458df8SWei Liu 59227458df8SWei Liu static void exec_stos_single(CPUX86State *env, struct x86_decode *decode) 59327458df8SWei Liu { 59427458df8SWei Liu target_ulong addr; 59527458df8SWei Liu target_ulong val; 59627458df8SWei Liu 59727458df8SWei Liu addr = linear_addr_size(env_cpu(env), RDI(env), 59827458df8SWei Liu decode->addressing_size, R_ES); 59927458df8SWei Liu val = read_reg(env, R_EAX, decode->operand_size); 60027458df8SWei Liu emul_ops->write_mem(env_cpu(env), &val, addr, decode->operand_size); 60127458df8SWei Liu 60227458df8SWei Liu string_increment_reg(env, R_EDI, decode); 60327458df8SWei Liu } 60427458df8SWei Liu 60527458df8SWei Liu 60627458df8SWei Liu static void exec_stos(CPUX86State *env, struct x86_decode *decode) 60727458df8SWei Liu { 60827458df8SWei Liu if (decode->rep) { 60927458df8SWei Liu string_rep(env, decode, exec_stos_single, 0); 61027458df8SWei Liu } else { 61127458df8SWei Liu exec_stos_single(env, decode); 61227458df8SWei Liu } 61327458df8SWei Liu 61427458df8SWei Liu env->eip += decode->len; 61527458df8SWei Liu } 61627458df8SWei Liu 61727458df8SWei Liu static void exec_scas_single(CPUX86State *env, struct x86_decode *decode) 61827458df8SWei Liu { 61927458df8SWei Liu target_ulong addr; 62027458df8SWei Liu 62127458df8SWei Liu addr = linear_addr_size(env_cpu(env), RDI(env), 62227458df8SWei Liu decode->addressing_size, R_ES); 62327458df8SWei Liu decode->op[1].type = X86_VAR_IMMEDIATE; 62427458df8SWei Liu emul_ops->read_mem(env_cpu(env), &decode->op[1].val, addr, decode->operand_size); 62527458df8SWei Liu 62627458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); 62727458df8SWei Liu string_increment_reg(env, R_EDI, decode); 62827458df8SWei Liu } 62927458df8SWei Liu 63027458df8SWei Liu static void exec_scas(CPUX86State *env, struct x86_decode *decode) 63127458df8SWei Liu { 63227458df8SWei Liu decode->op[0].type = X86_VAR_REG; 63327458df8SWei Liu decode->op[0].reg = R_EAX; 63427458df8SWei Liu if (decode->rep) { 63527458df8SWei Liu string_rep(env, decode, exec_scas_single, decode->rep); 63627458df8SWei Liu } else { 63727458df8SWei Liu exec_scas_single(env, decode); 63827458df8SWei Liu } 63927458df8SWei Liu 64027458df8SWei Liu env->eip += decode->len; 64127458df8SWei Liu } 64227458df8SWei Liu 64327458df8SWei Liu static void exec_lods_single(CPUX86State *env, struct x86_decode *decode) 64427458df8SWei Liu { 64527458df8SWei Liu target_ulong addr; 64627458df8SWei Liu target_ulong val = 0; 64727458df8SWei Liu 64827458df8SWei Liu addr = decode_linear_addr(env, decode, RSI(env), R_DS); 64927458df8SWei Liu emul_ops->read_mem(env_cpu(env), &val, addr, decode->operand_size); 65027458df8SWei Liu write_reg(env, R_EAX, val, decode->operand_size); 65127458df8SWei Liu 65227458df8SWei Liu string_increment_reg(env, R_ESI, decode); 65327458df8SWei Liu } 65427458df8SWei Liu 65527458df8SWei Liu static void exec_lods(CPUX86State *env, struct x86_decode *decode) 65627458df8SWei Liu { 65727458df8SWei Liu if (decode->rep) { 65827458df8SWei Liu string_rep(env, decode, exec_lods_single, 0); 65927458df8SWei Liu } else { 66027458df8SWei Liu exec_lods_single(env, decode); 66127458df8SWei Liu } 66227458df8SWei Liu 66327458df8SWei Liu env->eip += decode->len; 66427458df8SWei Liu } 66527458df8SWei Liu 66627458df8SWei Liu void x86_emul_raise_exception(CPUX86State *env, int exception_index, int error_code) 66727458df8SWei Liu { 66827458df8SWei Liu env->exception_nr = exception_index; 66927458df8SWei Liu env->error_code = error_code; 67027458df8SWei Liu env->has_error_code = true; 67127458df8SWei Liu env->exception_injected = 1; 67227458df8SWei Liu } 67327458df8SWei Liu 67427458df8SWei Liu static void exec_rdmsr(CPUX86State *env, struct x86_decode *decode) 67527458df8SWei Liu { 67627458df8SWei Liu emul_ops->simulate_rdmsr(env_cpu(env)); 67727458df8SWei Liu env->eip += decode->len; 67827458df8SWei Liu } 67927458df8SWei Liu 68027458df8SWei Liu static void exec_wrmsr(CPUX86State *env, struct x86_decode *decode) 68127458df8SWei Liu { 68227458df8SWei Liu emul_ops->simulate_wrmsr(env_cpu(env)); 68327458df8SWei Liu env->eip += decode->len; 68427458df8SWei Liu } 68527458df8SWei Liu 68627458df8SWei Liu /* 68727458df8SWei Liu * flag: 68827458df8SWei Liu * 0 - bt, 1 - btc, 2 - bts, 3 - btr 68927458df8SWei Liu */ 69027458df8SWei Liu static void do_bt(CPUX86State *env, struct x86_decode *decode, int flag) 69127458df8SWei Liu { 69227458df8SWei Liu int32_t displacement; 69327458df8SWei Liu uint8_t index; 69427458df8SWei Liu bool cf; 69527458df8SWei Liu int mask = (4 == decode->operand_size) ? 0x1f : 0xf; 69627458df8SWei Liu 69727458df8SWei Liu VM_PANIC_ON(decode->rex.rex); 69827458df8SWei Liu 69927458df8SWei Liu fetch_operands(env, decode, 2, false, true, false); 70027458df8SWei Liu index = decode->op[1].val & mask; 70127458df8SWei Liu 70227458df8SWei Liu if (decode->op[0].type != X86_VAR_REG) { 70327458df8SWei Liu if (4 == decode->operand_size) { 70427458df8SWei Liu displacement = ((int32_t) (decode->op[1].val & 0xffffffe0)) / 32; 705*77a2dba4SPaolo Bonzini decode->op[0].addr += 4 * displacement; 70627458df8SWei Liu } else if (2 == decode->operand_size) { 70727458df8SWei Liu displacement = ((int16_t) (decode->op[1].val & 0xfff0)) / 16; 708*77a2dba4SPaolo Bonzini decode->op[0].addr += 2 * displacement; 70927458df8SWei Liu } else { 71027458df8SWei Liu VM_PANIC("bt 64bit\n"); 71127458df8SWei Liu } 71227458df8SWei Liu } 713*77a2dba4SPaolo Bonzini decode->op[0].val = read_val_ext(env, &decode->op[0], 71427458df8SWei Liu decode->operand_size); 71527458df8SWei Liu cf = (decode->op[0].val >> index) & 0x01; 71627458df8SWei Liu 71727458df8SWei Liu switch (flag) { 71827458df8SWei Liu case 0: 71927458df8SWei Liu set_CF(env, cf); 72027458df8SWei Liu return; 72127458df8SWei Liu case 1: 72227458df8SWei Liu decode->op[0].val ^= (1u << index); 72327458df8SWei Liu break; 72427458df8SWei Liu case 2: 72527458df8SWei Liu decode->op[0].val |= (1u << index); 72627458df8SWei Liu break; 72727458df8SWei Liu case 3: 72827458df8SWei Liu decode->op[0].val &= ~(1u << index); 72927458df8SWei Liu break; 73027458df8SWei Liu } 731*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], decode->op[0].val, 73227458df8SWei Liu decode->operand_size); 73327458df8SWei Liu set_CF(env, cf); 73427458df8SWei Liu } 73527458df8SWei Liu 73627458df8SWei Liu static void exec_bt(CPUX86State *env, struct x86_decode *decode) 73727458df8SWei Liu { 73827458df8SWei Liu do_bt(env, decode, 0); 73927458df8SWei Liu env->eip += decode->len; 74027458df8SWei Liu } 74127458df8SWei Liu 74227458df8SWei Liu static void exec_btc(CPUX86State *env, struct x86_decode *decode) 74327458df8SWei Liu { 74427458df8SWei Liu do_bt(env, decode, 1); 74527458df8SWei Liu env->eip += decode->len; 74627458df8SWei Liu } 74727458df8SWei Liu 74827458df8SWei Liu static void exec_btr(CPUX86State *env, struct x86_decode *decode) 74927458df8SWei Liu { 75027458df8SWei Liu do_bt(env, decode, 3); 75127458df8SWei Liu env->eip += decode->len; 75227458df8SWei Liu } 75327458df8SWei Liu 75427458df8SWei Liu static void exec_bts(CPUX86State *env, struct x86_decode *decode) 75527458df8SWei Liu { 75627458df8SWei Liu do_bt(env, decode, 2); 75727458df8SWei Liu env->eip += decode->len; 75827458df8SWei Liu } 75927458df8SWei Liu 76027458df8SWei Liu void exec_shl(CPUX86State *env, struct x86_decode *decode) 76127458df8SWei Liu { 76227458df8SWei Liu uint8_t count; 76327458df8SWei Liu int of = 0, cf = 0; 76427458df8SWei Liu 76527458df8SWei Liu fetch_operands(env, decode, 2, true, true, false); 76627458df8SWei Liu 76727458df8SWei Liu count = decode->op[1].val; 76827458df8SWei Liu count &= 0x1f; /* count is masked to 5 bits*/ 76927458df8SWei Liu if (!count) { 77027458df8SWei Liu goto exit; 77127458df8SWei Liu } 77227458df8SWei Liu 77327458df8SWei Liu switch (decode->operand_size) { 77427458df8SWei Liu case 1: 77527458df8SWei Liu { 77627458df8SWei Liu uint8_t res = 0; 77727458df8SWei Liu if (count <= 8) { 77827458df8SWei Liu res = (decode->op[0].val << count); 77927458df8SWei Liu cf = (decode->op[0].val >> (8 - count)) & 0x1; 78027458df8SWei Liu of = cf ^ (res >> 7); 78127458df8SWei Liu } 78227458df8SWei Liu 783*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], res, 1); 78427458df8SWei Liu SET_FLAGS_OSZAPC_LOGIC8(env, 0, 0, res); 78527458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 78627458df8SWei Liu break; 78727458df8SWei Liu } 78827458df8SWei Liu case 2: 78927458df8SWei Liu { 79027458df8SWei Liu uint16_t res = 0; 79127458df8SWei Liu 79227458df8SWei Liu /* from bochs */ 79327458df8SWei Liu if (count <= 16) { 79427458df8SWei Liu res = (decode->op[0].val << count); 79527458df8SWei Liu cf = (decode->op[0].val >> (16 - count)) & 0x1; 79627458df8SWei Liu of = cf ^ (res >> 15); /* of = cf ^ result15 */ 79727458df8SWei Liu } 79827458df8SWei Liu 799*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], res, 2); 80027458df8SWei Liu SET_FLAGS_OSZAPC_LOGIC16(env, 0, 0, res); 80127458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 80227458df8SWei Liu break; 80327458df8SWei Liu } 80427458df8SWei Liu case 4: 80527458df8SWei Liu { 80627458df8SWei Liu uint32_t res = decode->op[0].val << count; 80727458df8SWei Liu 808*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], res, 4); 80927458df8SWei Liu SET_FLAGS_OSZAPC_LOGIC32(env, 0, 0, res); 81027458df8SWei Liu cf = (decode->op[0].val >> (32 - count)) & 0x1; 81127458df8SWei Liu of = cf ^ (res >> 31); /* of = cf ^ result31 */ 81227458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 81327458df8SWei Liu break; 81427458df8SWei Liu } 81527458df8SWei Liu default: 81627458df8SWei Liu abort(); 81727458df8SWei Liu } 81827458df8SWei Liu 81927458df8SWei Liu exit: 82027458df8SWei Liu /* lflags_to_rflags(env); */ 82127458df8SWei Liu env->eip += decode->len; 82227458df8SWei Liu } 82327458df8SWei Liu 82427458df8SWei Liu void exec_movsx(CPUX86State *env, struct x86_decode *decode) 82527458df8SWei Liu { 82627458df8SWei Liu int src_op_size; 82727458df8SWei Liu int op_size = decode->operand_size; 82827458df8SWei Liu 82927458df8SWei Liu fetch_operands(env, decode, 2, false, false, false); 83027458df8SWei Liu 83127458df8SWei Liu if (0xbe == decode->opcode[1]) { 83227458df8SWei Liu src_op_size = 1; 83327458df8SWei Liu } else { 83427458df8SWei Liu src_op_size = 2; 83527458df8SWei Liu } 83627458df8SWei Liu 83727458df8SWei Liu decode->operand_size = src_op_size; 83827458df8SWei Liu calc_modrm_operand(env, decode, &decode->op[1]); 839*77a2dba4SPaolo Bonzini decode->op[1].val = sign(read_val_ext(env, &decode->op[1], src_op_size), 84027458df8SWei Liu src_op_size); 84127458df8SWei Liu 842*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], decode->op[1].val, op_size); 84327458df8SWei Liu 84427458df8SWei Liu env->eip += decode->len; 84527458df8SWei Liu } 84627458df8SWei Liu 84727458df8SWei Liu void exec_ror(CPUX86State *env, struct x86_decode *decode) 84827458df8SWei Liu { 84927458df8SWei Liu uint8_t count; 85027458df8SWei Liu 85127458df8SWei Liu fetch_operands(env, decode, 2, true, true, false); 85227458df8SWei Liu count = decode->op[1].val; 85327458df8SWei Liu 85427458df8SWei Liu switch (decode->operand_size) { 85527458df8SWei Liu case 1: 85627458df8SWei Liu { 85727458df8SWei Liu uint32_t bit6, bit7; 85827458df8SWei Liu uint8_t res; 85927458df8SWei Liu 86027458df8SWei Liu if ((count & 0x07) == 0) { 86127458df8SWei Liu if (count & 0x18) { 86227458df8SWei Liu bit6 = ((uint8_t)decode->op[0].val >> 6) & 1; 86327458df8SWei Liu bit7 = ((uint8_t)decode->op[0].val >> 7) & 1; 86427458df8SWei Liu SET_FLAGS_OxxxxC(env, bit6 ^ bit7, bit7); 86527458df8SWei Liu } 86627458df8SWei Liu } else { 86727458df8SWei Liu count &= 0x7; /* use only bottom 3 bits */ 86827458df8SWei Liu res = ((uint8_t)decode->op[0].val >> count) | 86927458df8SWei Liu ((uint8_t)decode->op[0].val << (8 - count)); 870*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], res, 1); 87127458df8SWei Liu bit6 = (res >> 6) & 1; 87227458df8SWei Liu bit7 = (res >> 7) & 1; 87327458df8SWei Liu /* set eflags: ROR count affects the following flags: C, O */ 87427458df8SWei Liu SET_FLAGS_OxxxxC(env, bit6 ^ bit7, bit7); 87527458df8SWei Liu } 87627458df8SWei Liu break; 87727458df8SWei Liu } 87827458df8SWei Liu case 2: 87927458df8SWei Liu { 88027458df8SWei Liu uint32_t bit14, bit15; 88127458df8SWei Liu uint16_t res; 88227458df8SWei Liu 88327458df8SWei Liu if ((count & 0x0f) == 0) { 88427458df8SWei Liu if (count & 0x10) { 88527458df8SWei Liu bit14 = ((uint16_t)decode->op[0].val >> 14) & 1; 88627458df8SWei Liu bit15 = ((uint16_t)decode->op[0].val >> 15) & 1; 88727458df8SWei Liu /* of = result14 ^ result15 */ 88827458df8SWei Liu SET_FLAGS_OxxxxC(env, bit14 ^ bit15, bit15); 88927458df8SWei Liu } 89027458df8SWei Liu } else { 89127458df8SWei Liu count &= 0x0f; /* use only 4 LSB's */ 89227458df8SWei Liu res = ((uint16_t)decode->op[0].val >> count) | 89327458df8SWei Liu ((uint16_t)decode->op[0].val << (16 - count)); 894*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], res, 2); 89527458df8SWei Liu 89627458df8SWei Liu bit14 = (res >> 14) & 1; 89727458df8SWei Liu bit15 = (res >> 15) & 1; 89827458df8SWei Liu /* of = result14 ^ result15 */ 89927458df8SWei Liu SET_FLAGS_OxxxxC(env, bit14 ^ bit15, bit15); 90027458df8SWei Liu } 90127458df8SWei Liu break; 90227458df8SWei Liu } 90327458df8SWei Liu case 4: 90427458df8SWei Liu { 90527458df8SWei Liu uint32_t bit31, bit30; 90627458df8SWei Liu uint32_t res; 90727458df8SWei Liu 90827458df8SWei Liu count &= 0x1f; 90927458df8SWei Liu if (count) { 91027458df8SWei Liu res = ((uint32_t)decode->op[0].val >> count) | 91127458df8SWei Liu ((uint32_t)decode->op[0].val << (32 - count)); 912*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], res, 4); 91327458df8SWei Liu 91427458df8SWei Liu bit31 = (res >> 31) & 1; 91527458df8SWei Liu bit30 = (res >> 30) & 1; 91627458df8SWei Liu /* of = result30 ^ result31 */ 91727458df8SWei Liu SET_FLAGS_OxxxxC(env, bit30 ^ bit31, bit31); 91827458df8SWei Liu } 91927458df8SWei Liu break; 92027458df8SWei Liu } 92127458df8SWei Liu } 92227458df8SWei Liu env->eip += decode->len; 92327458df8SWei Liu } 92427458df8SWei Liu 92527458df8SWei Liu void exec_rol(CPUX86State *env, struct x86_decode *decode) 92627458df8SWei Liu { 92727458df8SWei Liu uint8_t count; 92827458df8SWei Liu 92927458df8SWei Liu fetch_operands(env, decode, 2, true, true, false); 93027458df8SWei Liu count = decode->op[1].val; 93127458df8SWei Liu 93227458df8SWei Liu switch (decode->operand_size) { 93327458df8SWei Liu case 1: 93427458df8SWei Liu { 93527458df8SWei Liu uint32_t bit0, bit7; 93627458df8SWei Liu uint8_t res; 93727458df8SWei Liu 93827458df8SWei Liu if ((count & 0x07) == 0) { 93927458df8SWei Liu if (count & 0x18) { 94027458df8SWei Liu bit0 = ((uint8_t)decode->op[0].val & 1); 94127458df8SWei Liu bit7 = ((uint8_t)decode->op[0].val >> 7); 94227458df8SWei Liu SET_FLAGS_OxxxxC(env, bit0 ^ bit7, bit0); 94327458df8SWei Liu } 94427458df8SWei Liu } else { 94527458df8SWei Liu count &= 0x7; /* use only lowest 3 bits */ 94627458df8SWei Liu res = ((uint8_t)decode->op[0].val << count) | 94727458df8SWei Liu ((uint8_t)decode->op[0].val >> (8 - count)); 94827458df8SWei Liu 949*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], res, 1); 95027458df8SWei Liu /* set eflags: 95127458df8SWei Liu * ROL count affects the following flags: C, O 95227458df8SWei Liu */ 95327458df8SWei Liu bit0 = (res & 1); 95427458df8SWei Liu bit7 = (res >> 7); 95527458df8SWei Liu SET_FLAGS_OxxxxC(env, bit0 ^ bit7, bit0); 95627458df8SWei Liu } 95727458df8SWei Liu break; 95827458df8SWei Liu } 95927458df8SWei Liu case 2: 96027458df8SWei Liu { 96127458df8SWei Liu uint32_t bit0, bit15; 96227458df8SWei Liu uint16_t res; 96327458df8SWei Liu 96427458df8SWei Liu if ((count & 0x0f) == 0) { 96527458df8SWei Liu if (count & 0x10) { 96627458df8SWei Liu bit0 = ((uint16_t)decode->op[0].val & 0x1); 96727458df8SWei Liu bit15 = ((uint16_t)decode->op[0].val >> 15); 96827458df8SWei Liu /* of = cf ^ result15 */ 96927458df8SWei Liu SET_FLAGS_OxxxxC(env, bit0 ^ bit15, bit0); 97027458df8SWei Liu } 97127458df8SWei Liu } else { 97227458df8SWei Liu count &= 0x0f; /* only use bottom 4 bits */ 97327458df8SWei Liu res = ((uint16_t)decode->op[0].val << count) | 97427458df8SWei Liu ((uint16_t)decode->op[0].val >> (16 - count)); 97527458df8SWei Liu 976*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], res, 2); 97727458df8SWei Liu bit0 = (res & 0x1); 97827458df8SWei Liu bit15 = (res >> 15); 97927458df8SWei Liu /* of = cf ^ result15 */ 98027458df8SWei Liu SET_FLAGS_OxxxxC(env, bit0 ^ bit15, bit0); 98127458df8SWei Liu } 98227458df8SWei Liu break; 98327458df8SWei Liu } 98427458df8SWei Liu case 4: 98527458df8SWei Liu { 98627458df8SWei Liu uint32_t bit0, bit31; 98727458df8SWei Liu uint32_t res; 98827458df8SWei Liu 98927458df8SWei Liu count &= 0x1f; 99027458df8SWei Liu if (count) { 99127458df8SWei Liu res = ((uint32_t)decode->op[0].val << count) | 99227458df8SWei Liu ((uint32_t)decode->op[0].val >> (32 - count)); 99327458df8SWei Liu 994*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], res, 4); 99527458df8SWei Liu bit0 = (res & 0x1); 99627458df8SWei Liu bit31 = (res >> 31); 99727458df8SWei Liu /* of = cf ^ result31 */ 99827458df8SWei Liu SET_FLAGS_OxxxxC(env, bit0 ^ bit31, bit0); 99927458df8SWei Liu } 100027458df8SWei Liu break; 100127458df8SWei Liu } 100227458df8SWei Liu } 100327458df8SWei Liu env->eip += decode->len; 100427458df8SWei Liu } 100527458df8SWei Liu 100627458df8SWei Liu 100727458df8SWei Liu void exec_rcl(CPUX86State *env, struct x86_decode *decode) 100827458df8SWei Liu { 100927458df8SWei Liu uint8_t count; 101027458df8SWei Liu int of = 0, cf = 0; 101127458df8SWei Liu 101227458df8SWei Liu fetch_operands(env, decode, 2, true, true, false); 101327458df8SWei Liu count = decode->op[1].val & 0x1f; 101427458df8SWei Liu 101527458df8SWei Liu switch (decode->operand_size) { 101627458df8SWei Liu case 1: 101727458df8SWei Liu { 101827458df8SWei Liu uint8_t op1_8 = decode->op[0].val; 101927458df8SWei Liu uint8_t res; 102027458df8SWei Liu count %= 9; 102127458df8SWei Liu if (!count) { 102227458df8SWei Liu break; 102327458df8SWei Liu } 102427458df8SWei Liu 102527458df8SWei Liu if (1 == count) { 102627458df8SWei Liu res = (op1_8 << 1) | get_CF(env); 102727458df8SWei Liu } else { 102827458df8SWei Liu res = (op1_8 << count) | (get_CF(env) << (count - 1)) | 102927458df8SWei Liu (op1_8 >> (9 - count)); 103027458df8SWei Liu } 103127458df8SWei Liu 1032*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], res, 1); 103327458df8SWei Liu 103427458df8SWei Liu cf = (op1_8 >> (8 - count)) & 0x01; 103527458df8SWei Liu of = cf ^ (res >> 7); /* of = cf ^ result7 */ 103627458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 103727458df8SWei Liu break; 103827458df8SWei Liu } 103927458df8SWei Liu case 2: 104027458df8SWei Liu { 104127458df8SWei Liu uint16_t res; 104227458df8SWei Liu uint16_t op1_16 = decode->op[0].val; 104327458df8SWei Liu 104427458df8SWei Liu count %= 17; 104527458df8SWei Liu if (!count) { 104627458df8SWei Liu break; 104727458df8SWei Liu } 104827458df8SWei Liu 104927458df8SWei Liu if (1 == count) { 105027458df8SWei Liu res = (op1_16 << 1) | get_CF(env); 105127458df8SWei Liu } else if (count == 16) { 105227458df8SWei Liu res = (get_CF(env) << 15) | (op1_16 >> 1); 105327458df8SWei Liu } else { /* 2..15 */ 105427458df8SWei Liu res = (op1_16 << count) | (get_CF(env) << (count - 1)) | 105527458df8SWei Liu (op1_16 >> (17 - count)); 105627458df8SWei Liu } 105727458df8SWei Liu 1058*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], res, 2); 105927458df8SWei Liu 106027458df8SWei Liu cf = (op1_16 >> (16 - count)) & 0x1; 106127458df8SWei Liu of = cf ^ (res >> 15); /* of = cf ^ result15 */ 106227458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 106327458df8SWei Liu break; 106427458df8SWei Liu } 106527458df8SWei Liu case 4: 106627458df8SWei Liu { 106727458df8SWei Liu uint32_t res; 106827458df8SWei Liu uint32_t op1_32 = decode->op[0].val; 106927458df8SWei Liu 107027458df8SWei Liu if (!count) { 107127458df8SWei Liu break; 107227458df8SWei Liu } 107327458df8SWei Liu 107427458df8SWei Liu if (1 == count) { 107527458df8SWei Liu res = (op1_32 << 1) | get_CF(env); 107627458df8SWei Liu } else { 107727458df8SWei Liu res = (op1_32 << count) | (get_CF(env) << (count - 1)) | 107827458df8SWei Liu (op1_32 >> (33 - count)); 107927458df8SWei Liu } 108027458df8SWei Liu 1081*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], res, 4); 108227458df8SWei Liu 108327458df8SWei Liu cf = (op1_32 >> (32 - count)) & 0x1; 108427458df8SWei Liu of = cf ^ (res >> 31); /* of = cf ^ result31 */ 108527458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 108627458df8SWei Liu break; 108727458df8SWei Liu } 108827458df8SWei Liu } 108927458df8SWei Liu env->eip += decode->len; 109027458df8SWei Liu } 109127458df8SWei Liu 109227458df8SWei Liu void exec_rcr(CPUX86State *env, struct x86_decode *decode) 109327458df8SWei Liu { 109427458df8SWei Liu uint8_t count; 109527458df8SWei Liu int of = 0, cf = 0; 109627458df8SWei Liu 109727458df8SWei Liu fetch_operands(env, decode, 2, true, true, false); 109827458df8SWei Liu count = decode->op[1].val & 0x1f; 109927458df8SWei Liu 110027458df8SWei Liu switch (decode->operand_size) { 110127458df8SWei Liu case 1: 110227458df8SWei Liu { 110327458df8SWei Liu uint8_t op1_8 = decode->op[0].val; 110427458df8SWei Liu uint8_t res; 110527458df8SWei Liu 110627458df8SWei Liu count %= 9; 110727458df8SWei Liu if (!count) { 110827458df8SWei Liu break; 110927458df8SWei Liu } 111027458df8SWei Liu res = (op1_8 >> count) | (get_CF(env) << (8 - count)) | 111127458df8SWei Liu (op1_8 << (9 - count)); 111227458df8SWei Liu 1113*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], res, 1); 111427458df8SWei Liu 111527458df8SWei Liu cf = (op1_8 >> (count - 1)) & 0x1; 111627458df8SWei Liu of = (((res << 1) ^ res) >> 7) & 0x1; /* of = result6 ^ result7 */ 111727458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 111827458df8SWei Liu break; 111927458df8SWei Liu } 112027458df8SWei Liu case 2: 112127458df8SWei Liu { 112227458df8SWei Liu uint16_t op1_16 = decode->op[0].val; 112327458df8SWei Liu uint16_t res; 112427458df8SWei Liu 112527458df8SWei Liu count %= 17; 112627458df8SWei Liu if (!count) { 112727458df8SWei Liu break; 112827458df8SWei Liu } 112927458df8SWei Liu res = (op1_16 >> count) | (get_CF(env) << (16 - count)) | 113027458df8SWei Liu (op1_16 << (17 - count)); 113127458df8SWei Liu 1132*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], res, 2); 113327458df8SWei Liu 113427458df8SWei Liu cf = (op1_16 >> (count - 1)) & 0x1; 113527458df8SWei Liu of = ((uint16_t)((res << 1) ^ res) >> 15) & 0x1; /* of = result15 ^ 113627458df8SWei Liu result14 */ 113727458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 113827458df8SWei Liu break; 113927458df8SWei Liu } 114027458df8SWei Liu case 4: 114127458df8SWei Liu { 114227458df8SWei Liu uint32_t res; 114327458df8SWei Liu uint32_t op1_32 = decode->op[0].val; 114427458df8SWei Liu 114527458df8SWei Liu if (!count) { 114627458df8SWei Liu break; 114727458df8SWei Liu } 114827458df8SWei Liu 114927458df8SWei Liu if (1 == count) { 115027458df8SWei Liu res = (op1_32 >> 1) | (get_CF(env) << 31); 115127458df8SWei Liu } else { 115227458df8SWei Liu res = (op1_32 >> count) | (get_CF(env) << (32 - count)) | 115327458df8SWei Liu (op1_32 << (33 - count)); 115427458df8SWei Liu } 115527458df8SWei Liu 1156*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], res, 4); 115727458df8SWei Liu 115827458df8SWei Liu cf = (op1_32 >> (count - 1)) & 0x1; 115927458df8SWei Liu of = ((res << 1) ^ res) >> 31; /* of = result30 ^ result31 */ 116027458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 116127458df8SWei Liu break; 116227458df8SWei Liu } 116327458df8SWei Liu } 116427458df8SWei Liu env->eip += decode->len; 116527458df8SWei Liu } 116627458df8SWei Liu 116727458df8SWei Liu static void exec_xchg(CPUX86State *env, struct x86_decode *decode) 116827458df8SWei Liu { 116927458df8SWei Liu fetch_operands(env, decode, 2, true, true, false); 117027458df8SWei Liu 1171*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[0], decode->op[1].val, 117227458df8SWei Liu decode->operand_size); 1173*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[1], decode->op[0].val, 117427458df8SWei Liu decode->operand_size); 117527458df8SWei Liu 117627458df8SWei Liu env->eip += decode->len; 117727458df8SWei Liu } 117827458df8SWei Liu 117927458df8SWei Liu static void exec_xadd(CPUX86State *env, struct x86_decode *decode) 118027458df8SWei Liu { 118127458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, +, SET_FLAGS_OSZAPC_ADD, true); 1182*77a2dba4SPaolo Bonzini write_val_ext(env, &decode->op[1], decode->op[0].val, 118327458df8SWei Liu decode->operand_size); 118427458df8SWei Liu 118527458df8SWei Liu env->eip += decode->len; 118627458df8SWei Liu } 118727458df8SWei Liu 118827458df8SWei Liu static struct cmd_handler { 118927458df8SWei Liu enum x86_decode_cmd cmd; 119027458df8SWei Liu void (*handler)(CPUX86State *env, struct x86_decode *ins); 119127458df8SWei Liu } handlers[] = { 119227458df8SWei Liu {X86_DECODE_CMD_INVL, NULL,}, 119327458df8SWei Liu {X86_DECODE_CMD_MOV, exec_mov}, 119427458df8SWei Liu {X86_DECODE_CMD_ADD, exec_add}, 119527458df8SWei Liu {X86_DECODE_CMD_OR, exec_or}, 119627458df8SWei Liu {X86_DECODE_CMD_ADC, exec_adc}, 119727458df8SWei Liu {X86_DECODE_CMD_SBB, exec_sbb}, 119827458df8SWei Liu {X86_DECODE_CMD_AND, exec_and}, 119927458df8SWei Liu {X86_DECODE_CMD_SUB, exec_sub}, 120027458df8SWei Liu {X86_DECODE_CMD_NEG, exec_neg}, 120127458df8SWei Liu {X86_DECODE_CMD_XOR, exec_xor}, 120227458df8SWei Liu {X86_DECODE_CMD_CMP, exec_cmp}, 120327458df8SWei Liu {X86_DECODE_CMD_INC, exec_inc}, 120427458df8SWei Liu {X86_DECODE_CMD_DEC, exec_dec}, 120527458df8SWei Liu {X86_DECODE_CMD_TST, exec_tst}, 120627458df8SWei Liu {X86_DECODE_CMD_NOT, exec_not}, 120727458df8SWei Liu {X86_DECODE_CMD_MOVZX, exec_movzx}, 120827458df8SWei Liu {X86_DECODE_CMD_OUT, exec_out}, 120927458df8SWei Liu {X86_DECODE_CMD_IN, exec_in}, 121027458df8SWei Liu {X86_DECODE_CMD_INS, exec_ins}, 121127458df8SWei Liu {X86_DECODE_CMD_OUTS, exec_outs}, 121227458df8SWei Liu {X86_DECODE_CMD_RDMSR, exec_rdmsr}, 121327458df8SWei Liu {X86_DECODE_CMD_WRMSR, exec_wrmsr}, 121427458df8SWei Liu {X86_DECODE_CMD_BT, exec_bt}, 121527458df8SWei Liu {X86_DECODE_CMD_BTR, exec_btr}, 121627458df8SWei Liu {X86_DECODE_CMD_BTC, exec_btc}, 121727458df8SWei Liu {X86_DECODE_CMD_BTS, exec_bts}, 121827458df8SWei Liu {X86_DECODE_CMD_SHL, exec_shl}, 121927458df8SWei Liu {X86_DECODE_CMD_ROL, exec_rol}, 122027458df8SWei Liu {X86_DECODE_CMD_ROR, exec_ror}, 122127458df8SWei Liu {X86_DECODE_CMD_RCR, exec_rcr}, 122227458df8SWei Liu {X86_DECODE_CMD_RCL, exec_rcl}, 122327458df8SWei Liu /*{X86_DECODE_CMD_CPUID, exec_cpuid},*/ 122427458df8SWei Liu {X86_DECODE_CMD_MOVS, exec_movs}, 122527458df8SWei Liu {X86_DECODE_CMD_CMPS, exec_cmps}, 122627458df8SWei Liu {X86_DECODE_CMD_STOS, exec_stos}, 122727458df8SWei Liu {X86_DECODE_CMD_SCAS, exec_scas}, 122827458df8SWei Liu {X86_DECODE_CMD_LODS, exec_lods}, 122927458df8SWei Liu {X86_DECODE_CMD_MOVSX, exec_movsx}, 123027458df8SWei Liu {X86_DECODE_CMD_XCHG, exec_xchg}, 123127458df8SWei Liu {X86_DECODE_CMD_XADD, exec_xadd}, 123227458df8SWei Liu }; 123327458df8SWei Liu 123427458df8SWei Liu static struct cmd_handler _cmd_handler[X86_DECODE_CMD_LAST]; 123527458df8SWei Liu 123627458df8SWei Liu const struct x86_emul_ops *emul_ops; 123727458df8SWei Liu 123827458df8SWei Liu static void init_cmd_handler(void) 123927458df8SWei Liu { 124027458df8SWei Liu int i; 124127458df8SWei Liu for (i = 0; i < ARRAY_SIZE(handlers); i++) { 124227458df8SWei Liu _cmd_handler[handlers[i].cmd] = handlers[i]; 124327458df8SWei Liu } 124427458df8SWei Liu } 124527458df8SWei Liu 124627458df8SWei Liu bool exec_instruction(CPUX86State *env, struct x86_decode *ins) 124727458df8SWei Liu { 124827458df8SWei Liu if (!_cmd_handler[ins->cmd].handler) { 12497abf0d95SPaolo Bonzini printf("Unimplemented handler (" TARGET_FMT_lx ") for %d (%x %x) \n", env->eip, 125027458df8SWei Liu ins->cmd, ins->opcode[0], 125127458df8SWei Liu ins->opcode_len > 1 ? ins->opcode[1] : 0); 125227458df8SWei Liu env->eip += ins->len; 125327458df8SWei Liu return true; 125427458df8SWei Liu } 125527458df8SWei Liu 125627458df8SWei Liu _cmd_handler[ins->cmd].handler(env, ins); 125727458df8SWei Liu return true; 125827458df8SWei Liu } 125927458df8SWei Liu 126027458df8SWei Liu void init_emu(const struct x86_emul_ops *o) 126127458df8SWei Liu { 126227458df8SWei Liu emul_ops = o; 126327458df8SWei Liu init_cmd_handler(); 126427458df8SWei Liu } 1265