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) { \ 5527458df8SWei Liu write_val_ext(env, decode->op[0].ptr, 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) { \ 6627458df8SWei Liu write_val_ext(env, decode->op[0].ptr, 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) { \ 7727458df8SWei Liu write_val_ext(env, decode->op[0].ptr, 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 12427458df8SWei Liu target_ulong read_val_from_reg(target_ulong 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 14727458df8SWei Liu void write_val_to_reg(target_ulong 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 16727458df8SWei Liu static bool is_host_reg(CPUX86State *env, target_ulong ptr) 16827458df8SWei Liu { 16927458df8SWei Liu return (ptr - (target_ulong)&env->regs[0]) < sizeof(env->regs); 17027458df8SWei Liu } 17127458df8SWei Liu 17227458df8SWei Liu void write_val_ext(CPUX86State *env, target_ulong ptr, target_ulong val, int size) 17327458df8SWei Liu { 17427458df8SWei Liu if (is_host_reg(env, ptr)) { 17527458df8SWei Liu write_val_to_reg(ptr, val, size); 17627458df8SWei Liu return; 17727458df8SWei Liu } 17827458df8SWei Liu emul_ops->write_mem(env_cpu(env), &val, ptr, size); 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 18827458df8SWei Liu target_ulong read_val_ext(CPUX86State *env, target_ulong ptr, int size) 18927458df8SWei Liu { 19027458df8SWei Liu target_ulong val; 19127458df8SWei Liu uint8_t *mmio_ptr; 19227458df8SWei Liu 19327458df8SWei Liu if (is_host_reg(env, ptr)) { 19427458df8SWei Liu return read_val_from_reg(ptr, size); 19527458df8SWei Liu } 19627458df8SWei Liu 19727458df8SWei Liu mmio_ptr = read_mmio(env, ptr, size); 19827458df8SWei Liu switch (size) { 19927458df8SWei Liu case 1: 20027458df8SWei Liu val = *(uint8_t *)mmio_ptr; 20127458df8SWei Liu break; 20227458df8SWei Liu case 2: 20327458df8SWei Liu val = *(uint16_t *)mmio_ptr; 20427458df8SWei Liu break; 20527458df8SWei Liu case 4: 20627458df8SWei Liu val = *(uint32_t *)mmio_ptr; 20727458df8SWei Liu break; 20827458df8SWei Liu case 8: 20927458df8SWei Liu val = *(uint64_t *)mmio_ptr; 21027458df8SWei Liu break; 21127458df8SWei Liu default: 21227458df8SWei Liu VM_PANIC("bad size\n"); 21327458df8SWei Liu break; 21427458df8SWei Liu } 21527458df8SWei Liu return val; 21627458df8SWei Liu } 21727458df8SWei Liu 21827458df8SWei Liu static void fetch_operands(CPUX86State *env, struct x86_decode *decode, 21927458df8SWei Liu int n, bool val_op0, bool val_op1, bool val_op2) 22027458df8SWei Liu { 22127458df8SWei Liu int i; 22227458df8SWei Liu bool calc_val[3] = {val_op0, val_op1, val_op2}; 22327458df8SWei Liu 22427458df8SWei Liu for (i = 0; i < n; i++) { 22527458df8SWei Liu switch (decode->op[i].type) { 22627458df8SWei Liu case X86_VAR_IMMEDIATE: 22727458df8SWei Liu break; 22827458df8SWei Liu case X86_VAR_REG: 22927458df8SWei Liu VM_PANIC_ON(!decode->op[i].ptr); 23027458df8SWei Liu if (calc_val[i]) { 23127458df8SWei Liu decode->op[i].val = read_val_from_reg(decode->op[i].ptr, 23227458df8SWei Liu decode->operand_size); 23327458df8SWei Liu } 23427458df8SWei Liu break; 23527458df8SWei Liu case X86_VAR_RM: 23627458df8SWei Liu calc_modrm_operand(env, decode, &decode->op[i]); 23727458df8SWei Liu if (calc_val[i]) { 23827458df8SWei Liu decode->op[i].val = read_val_ext(env, decode->op[i].ptr, 23927458df8SWei Liu decode->operand_size); 24027458df8SWei Liu } 24127458df8SWei Liu break; 24227458df8SWei Liu case X86_VAR_OFFSET: 24327458df8SWei Liu decode->op[i].ptr = decode_linear_addr(env, decode, 24427458df8SWei Liu decode->op[i].ptr, 24527458df8SWei Liu R_DS); 24627458df8SWei Liu if (calc_val[i]) { 24727458df8SWei Liu decode->op[i].val = read_val_ext(env, decode->op[i].ptr, 24827458df8SWei Liu decode->operand_size); 24927458df8SWei Liu } 25027458df8SWei Liu break; 25127458df8SWei Liu default: 25227458df8SWei Liu break; 25327458df8SWei Liu } 25427458df8SWei Liu } 25527458df8SWei Liu } 25627458df8SWei Liu 25727458df8SWei Liu static void exec_mov(CPUX86State *env, struct x86_decode *decode) 25827458df8SWei Liu { 25927458df8SWei Liu fetch_operands(env, decode, 2, false, true, false); 26027458df8SWei Liu write_val_ext(env, decode->op[0].ptr, decode->op[1].val, 26127458df8SWei Liu decode->operand_size); 26227458df8SWei Liu 26327458df8SWei Liu env->eip += decode->len; 26427458df8SWei Liu } 26527458df8SWei Liu 26627458df8SWei Liu static void exec_add(CPUX86State *env, struct x86_decode *decode) 26727458df8SWei Liu { 26827458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, +, SET_FLAGS_OSZAPC_ADD, true); 26927458df8SWei Liu env->eip += decode->len; 27027458df8SWei Liu } 27127458df8SWei Liu 27227458df8SWei Liu static void exec_or(CPUX86State *env, struct x86_decode *decode) 27327458df8SWei Liu { 27427458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, |, SET_FLAGS_OSZAPC_LOGIC, true); 27527458df8SWei Liu env->eip += decode->len; 27627458df8SWei Liu } 27727458df8SWei Liu 27827458df8SWei Liu static void exec_adc(CPUX86State *env, struct x86_decode *decode) 27927458df8SWei Liu { 28027458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, +get_CF(env)+, SET_FLAGS_OSZAPC_ADD, true); 28127458df8SWei Liu env->eip += decode->len; 28227458df8SWei Liu } 28327458df8SWei Liu 28427458df8SWei Liu static void exec_sbb(CPUX86State *env, struct x86_decode *decode) 28527458df8SWei Liu { 28627458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, -get_CF(env)-, SET_FLAGS_OSZAPC_SUB, true); 28727458df8SWei Liu env->eip += decode->len; 28827458df8SWei Liu } 28927458df8SWei Liu 29027458df8SWei Liu static void exec_and(CPUX86State *env, struct x86_decode *decode) 29127458df8SWei Liu { 29227458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, &, SET_FLAGS_OSZAPC_LOGIC, true); 29327458df8SWei Liu env->eip += decode->len; 29427458df8SWei Liu } 29527458df8SWei Liu 29627458df8SWei Liu static void exec_sub(CPUX86State *env, struct x86_decode *decode) 29727458df8SWei Liu { 29827458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, true); 29927458df8SWei Liu env->eip += decode->len; 30027458df8SWei Liu } 30127458df8SWei Liu 30227458df8SWei Liu static void exec_xor(CPUX86State *env, struct x86_decode *decode) 30327458df8SWei Liu { 30427458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, ^, SET_FLAGS_OSZAPC_LOGIC, true); 30527458df8SWei Liu env->eip += decode->len; 30627458df8SWei Liu } 30727458df8SWei Liu 30827458df8SWei Liu static void exec_neg(CPUX86State *env, struct x86_decode *decode) 30927458df8SWei Liu { 31027458df8SWei Liu /*EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false);*/ 31127458df8SWei Liu int32_t val; 31227458df8SWei Liu fetch_operands(env, decode, 2, true, true, false); 31327458df8SWei Liu 31427458df8SWei Liu val = 0 - sign(decode->op[1].val, decode->operand_size); 31527458df8SWei Liu write_val_ext(env, decode->op[1].ptr, val, decode->operand_size); 31627458df8SWei Liu 31727458df8SWei Liu if (4 == decode->operand_size) { 31827458df8SWei Liu SET_FLAGS_OSZAPC_SUB32(env, 0, 0 - val, val); 31927458df8SWei Liu } else if (2 == decode->operand_size) { 32027458df8SWei Liu SET_FLAGS_OSZAPC_SUB16(env, 0, 0 - val, val); 32127458df8SWei Liu } else if (1 == decode->operand_size) { 32227458df8SWei Liu SET_FLAGS_OSZAPC_SUB8(env, 0, 0 - val, val); 32327458df8SWei Liu } else { 32427458df8SWei Liu VM_PANIC("bad op size\n"); 32527458df8SWei Liu } 32627458df8SWei Liu 32727458df8SWei Liu /*lflags_to_rflags(env);*/ 32827458df8SWei Liu env->eip += decode->len; 32927458df8SWei Liu } 33027458df8SWei Liu 33127458df8SWei Liu static void exec_cmp(CPUX86State *env, struct x86_decode *decode) 33227458df8SWei Liu { 33327458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); 33427458df8SWei Liu env->eip += decode->len; 33527458df8SWei Liu } 33627458df8SWei Liu 33727458df8SWei Liu static void exec_inc(CPUX86State *env, struct x86_decode *decode) 33827458df8SWei Liu { 33927458df8SWei Liu decode->op[1].type = X86_VAR_IMMEDIATE; 34027458df8SWei Liu decode->op[1].val = 0; 34127458df8SWei Liu 34227458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, +1+, SET_FLAGS_OSZAP_ADD, true); 34327458df8SWei Liu 34427458df8SWei Liu env->eip += decode->len; 34527458df8SWei Liu } 34627458df8SWei Liu 34727458df8SWei Liu static void exec_dec(CPUX86State *env, struct x86_decode *decode) 34827458df8SWei Liu { 34927458df8SWei Liu decode->op[1].type = X86_VAR_IMMEDIATE; 35027458df8SWei Liu decode->op[1].val = 0; 35127458df8SWei Liu 35227458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, -1-, SET_FLAGS_OSZAP_SUB, true); 35327458df8SWei Liu env->eip += decode->len; 35427458df8SWei Liu } 35527458df8SWei Liu 35627458df8SWei Liu static void exec_tst(CPUX86State *env, struct x86_decode *decode) 35727458df8SWei Liu { 35827458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, &, SET_FLAGS_OSZAPC_LOGIC, false); 35927458df8SWei Liu env->eip += decode->len; 36027458df8SWei Liu } 36127458df8SWei Liu 36227458df8SWei Liu static void exec_not(CPUX86State *env, struct x86_decode *decode) 36327458df8SWei Liu { 36427458df8SWei Liu fetch_operands(env, decode, 1, true, false, false); 36527458df8SWei Liu 36627458df8SWei Liu write_val_ext(env, decode->op[0].ptr, ~decode->op[0].val, 36727458df8SWei Liu decode->operand_size); 36827458df8SWei Liu env->eip += decode->len; 36927458df8SWei Liu } 37027458df8SWei Liu 37127458df8SWei Liu void exec_movzx(CPUX86State *env, struct x86_decode *decode) 37227458df8SWei Liu { 37327458df8SWei Liu int src_op_size; 37427458df8SWei Liu int op_size = decode->operand_size; 37527458df8SWei Liu 37627458df8SWei Liu fetch_operands(env, decode, 1, false, false, false); 37727458df8SWei Liu 37827458df8SWei Liu if (0xb6 == decode->opcode[1]) { 37927458df8SWei Liu src_op_size = 1; 38027458df8SWei Liu } else { 38127458df8SWei Liu src_op_size = 2; 38227458df8SWei Liu } 38327458df8SWei Liu decode->operand_size = src_op_size; 38427458df8SWei Liu calc_modrm_operand(env, decode, &decode->op[1]); 38527458df8SWei Liu decode->op[1].val = read_val_ext(env, decode->op[1].ptr, src_op_size); 38627458df8SWei Liu write_val_ext(env, decode->op[0].ptr, decode->op[1].val, op_size); 38727458df8SWei Liu 38827458df8SWei Liu env->eip += decode->len; 38927458df8SWei Liu } 39027458df8SWei Liu 39127458df8SWei Liu static void exec_out(CPUX86State *env, struct x86_decode *decode) 39227458df8SWei Liu { 39327458df8SWei Liu switch (decode->opcode[0]) { 39427458df8SWei Liu case 0xe6: 39527458df8SWei Liu emul_ops->handle_io(env_cpu(env), decode->op[0].val, &AL(env), 1, 1, 1); 39627458df8SWei Liu break; 39727458df8SWei Liu case 0xe7: 39827458df8SWei Liu emul_ops->handle_io(env_cpu(env), decode->op[0].val, &RAX(env), 1, 39927458df8SWei Liu decode->operand_size, 1); 40027458df8SWei Liu break; 40127458df8SWei Liu case 0xee: 40227458df8SWei Liu emul_ops->handle_io(env_cpu(env), DX(env), &AL(env), 1, 1, 1); 40327458df8SWei Liu break; 40427458df8SWei Liu case 0xef: 40527458df8SWei Liu emul_ops->handle_io(env_cpu(env), DX(env), &RAX(env), 1, 40627458df8SWei Liu decode->operand_size, 1); 40727458df8SWei Liu break; 40827458df8SWei Liu default: 40927458df8SWei Liu VM_PANIC("Bad out opcode\n"); 41027458df8SWei Liu break; 41127458df8SWei Liu } 41227458df8SWei Liu env->eip += decode->len; 41327458df8SWei Liu } 41427458df8SWei Liu 41527458df8SWei Liu static void exec_in(CPUX86State *env, struct x86_decode *decode) 41627458df8SWei Liu { 41727458df8SWei Liu target_ulong val = 0; 41827458df8SWei Liu switch (decode->opcode[0]) { 41927458df8SWei Liu case 0xe4: 42027458df8SWei Liu emul_ops->handle_io(env_cpu(env), decode->op[0].val, &AL(env), 0, 1, 1); 42127458df8SWei Liu break; 42227458df8SWei Liu case 0xe5: 42327458df8SWei Liu emul_ops->handle_io(env_cpu(env), decode->op[0].val, &val, 0, 42427458df8SWei Liu decode->operand_size, 1); 42527458df8SWei Liu if (decode->operand_size == 2) { 42627458df8SWei Liu AX(env) = val; 42727458df8SWei Liu } else { 42827458df8SWei Liu RAX(env) = (uint32_t)val; 42927458df8SWei Liu } 43027458df8SWei Liu break; 43127458df8SWei Liu case 0xec: 43227458df8SWei Liu emul_ops->handle_io(env_cpu(env), DX(env), &AL(env), 0, 1, 1); 43327458df8SWei Liu break; 43427458df8SWei Liu case 0xed: 43527458df8SWei Liu emul_ops->handle_io(env_cpu(env), DX(env), &val, 0, 43627458df8SWei Liu decode->operand_size, 1); 43727458df8SWei Liu if (decode->operand_size == 2) { 43827458df8SWei Liu AX(env) = val; 43927458df8SWei Liu } else { 44027458df8SWei Liu RAX(env) = (uint32_t)val; 44127458df8SWei Liu } 44227458df8SWei Liu 44327458df8SWei Liu break; 44427458df8SWei Liu default: 44527458df8SWei Liu VM_PANIC("Bad in opcode\n"); 44627458df8SWei Liu break; 44727458df8SWei Liu } 44827458df8SWei Liu 44927458df8SWei Liu env->eip += decode->len; 45027458df8SWei Liu } 45127458df8SWei Liu 45227458df8SWei Liu static inline void string_increment_reg(CPUX86State *env, int reg, 45327458df8SWei Liu struct x86_decode *decode) 45427458df8SWei Liu { 45527458df8SWei Liu target_ulong val = read_reg(env, reg, decode->addressing_size); 45627458df8SWei Liu if (env->eflags & DF_MASK) { 45727458df8SWei Liu val -= decode->operand_size; 45827458df8SWei Liu } else { 45927458df8SWei Liu val += decode->operand_size; 46027458df8SWei Liu } 46127458df8SWei Liu write_reg(env, reg, val, decode->addressing_size); 46227458df8SWei Liu } 46327458df8SWei Liu 46427458df8SWei Liu static inline void string_rep(CPUX86State *env, struct x86_decode *decode, 46527458df8SWei Liu void (*func)(CPUX86State *env, 46627458df8SWei Liu struct x86_decode *ins), int rep) 46727458df8SWei Liu { 46827458df8SWei Liu target_ulong rcx = read_reg(env, R_ECX, decode->addressing_size); 46927458df8SWei Liu while (rcx--) { 47027458df8SWei Liu func(env, decode); 47127458df8SWei Liu write_reg(env, R_ECX, rcx, decode->addressing_size); 47227458df8SWei Liu if ((PREFIX_REP == rep) && !get_ZF(env)) { 47327458df8SWei Liu break; 47427458df8SWei Liu } 47527458df8SWei Liu if ((PREFIX_REPN == rep) && get_ZF(env)) { 47627458df8SWei Liu break; 47727458df8SWei Liu } 47827458df8SWei Liu } 47927458df8SWei Liu } 48027458df8SWei Liu 48127458df8SWei Liu static void exec_ins_single(CPUX86State *env, struct x86_decode *decode) 48227458df8SWei Liu { 48327458df8SWei Liu target_ulong addr = linear_addr_size(env_cpu(env), RDI(env), 48427458df8SWei Liu decode->addressing_size, R_ES); 48527458df8SWei Liu 48627458df8SWei Liu emul_ops->handle_io(env_cpu(env), DX(env), env->emu_mmio_buf, 0, 48727458df8SWei Liu decode->operand_size, 1); 48827458df8SWei Liu emul_ops->write_mem(env_cpu(env), env->emu_mmio_buf, addr, 48927458df8SWei Liu decode->operand_size); 49027458df8SWei Liu 49127458df8SWei Liu string_increment_reg(env, R_EDI, decode); 49227458df8SWei Liu } 49327458df8SWei Liu 49427458df8SWei Liu static void exec_ins(CPUX86State *env, struct x86_decode *decode) 49527458df8SWei Liu { 49627458df8SWei Liu if (decode->rep) { 49727458df8SWei Liu string_rep(env, decode, exec_ins_single, 0); 49827458df8SWei Liu } else { 49927458df8SWei Liu exec_ins_single(env, decode); 50027458df8SWei Liu } 50127458df8SWei Liu 50227458df8SWei Liu env->eip += decode->len; 50327458df8SWei Liu } 50427458df8SWei Liu 50527458df8SWei Liu static void exec_outs_single(CPUX86State *env, struct x86_decode *decode) 50627458df8SWei Liu { 50727458df8SWei Liu target_ulong addr = decode_linear_addr(env, decode, RSI(env), R_DS); 50827458df8SWei Liu 50927458df8SWei Liu emul_ops->read_mem(env_cpu(env), env->emu_mmio_buf, addr, 51027458df8SWei Liu decode->operand_size); 51127458df8SWei Liu emul_ops->handle_io(env_cpu(env), DX(env), env->emu_mmio_buf, 1, 51227458df8SWei Liu decode->operand_size, 1); 51327458df8SWei Liu 51427458df8SWei Liu string_increment_reg(env, R_ESI, decode); 51527458df8SWei Liu } 51627458df8SWei Liu 51727458df8SWei Liu static void exec_outs(CPUX86State *env, struct x86_decode *decode) 51827458df8SWei Liu { 51927458df8SWei Liu if (decode->rep) { 52027458df8SWei Liu string_rep(env, decode, exec_outs_single, 0); 52127458df8SWei Liu } else { 52227458df8SWei Liu exec_outs_single(env, decode); 52327458df8SWei Liu } 52427458df8SWei Liu 52527458df8SWei Liu env->eip += decode->len; 52627458df8SWei Liu } 52727458df8SWei Liu 52827458df8SWei Liu static void exec_movs_single(CPUX86State *env, struct x86_decode *decode) 52927458df8SWei Liu { 53027458df8SWei Liu target_ulong src_addr; 53127458df8SWei Liu target_ulong dst_addr; 53227458df8SWei Liu target_ulong val; 53327458df8SWei Liu 53427458df8SWei Liu src_addr = decode_linear_addr(env, decode, RSI(env), R_DS); 53527458df8SWei Liu dst_addr = linear_addr_size(env_cpu(env), RDI(env), 53627458df8SWei Liu decode->addressing_size, R_ES); 53727458df8SWei Liu 53827458df8SWei Liu val = read_val_ext(env, src_addr, decode->operand_size); 53927458df8SWei Liu write_val_ext(env, dst_addr, val, decode->operand_size); 54027458df8SWei Liu 54127458df8SWei Liu string_increment_reg(env, R_ESI, decode); 54227458df8SWei Liu string_increment_reg(env, R_EDI, decode); 54327458df8SWei Liu } 54427458df8SWei Liu 54527458df8SWei Liu static void exec_movs(CPUX86State *env, struct x86_decode *decode) 54627458df8SWei Liu { 54727458df8SWei Liu if (decode->rep) { 54827458df8SWei Liu string_rep(env, decode, exec_movs_single, 0); 54927458df8SWei Liu } else { 55027458df8SWei Liu exec_movs_single(env, decode); 55127458df8SWei Liu } 55227458df8SWei Liu 55327458df8SWei Liu env->eip += decode->len; 55427458df8SWei Liu } 55527458df8SWei Liu 55627458df8SWei Liu static void exec_cmps_single(CPUX86State *env, struct x86_decode *decode) 55727458df8SWei Liu { 55827458df8SWei Liu target_ulong src_addr; 55927458df8SWei Liu target_ulong dst_addr; 56027458df8SWei Liu 56127458df8SWei Liu src_addr = decode_linear_addr(env, decode, RSI(env), R_DS); 56227458df8SWei Liu dst_addr = linear_addr_size(env_cpu(env), RDI(env), 56327458df8SWei Liu decode->addressing_size, R_ES); 56427458df8SWei Liu 56527458df8SWei Liu decode->op[0].type = X86_VAR_IMMEDIATE; 56627458df8SWei Liu decode->op[0].val = read_val_ext(env, src_addr, decode->operand_size); 56727458df8SWei Liu decode->op[1].type = X86_VAR_IMMEDIATE; 56827458df8SWei Liu decode->op[1].val = read_val_ext(env, dst_addr, decode->operand_size); 56927458df8SWei Liu 57027458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); 57127458df8SWei Liu 57227458df8SWei Liu string_increment_reg(env, R_ESI, decode); 57327458df8SWei Liu string_increment_reg(env, R_EDI, decode); 57427458df8SWei Liu } 57527458df8SWei Liu 57627458df8SWei Liu static void exec_cmps(CPUX86State *env, struct x86_decode *decode) 57727458df8SWei Liu { 57827458df8SWei Liu if (decode->rep) { 57927458df8SWei Liu string_rep(env, decode, exec_cmps_single, decode->rep); 58027458df8SWei Liu } else { 58127458df8SWei Liu exec_cmps_single(env, decode); 58227458df8SWei Liu } 58327458df8SWei Liu env->eip += decode->len; 58427458df8SWei Liu } 58527458df8SWei Liu 58627458df8SWei Liu 58727458df8SWei Liu static void exec_stos_single(CPUX86State *env, struct x86_decode *decode) 58827458df8SWei Liu { 58927458df8SWei Liu target_ulong addr; 59027458df8SWei Liu target_ulong val; 59127458df8SWei Liu 59227458df8SWei Liu addr = linear_addr_size(env_cpu(env), RDI(env), 59327458df8SWei Liu decode->addressing_size, R_ES); 59427458df8SWei Liu val = read_reg(env, R_EAX, decode->operand_size); 59527458df8SWei Liu emul_ops->write_mem(env_cpu(env), &val, addr, decode->operand_size); 59627458df8SWei Liu 59727458df8SWei Liu string_increment_reg(env, R_EDI, decode); 59827458df8SWei Liu } 59927458df8SWei Liu 60027458df8SWei Liu 60127458df8SWei Liu static void exec_stos(CPUX86State *env, struct x86_decode *decode) 60227458df8SWei Liu { 60327458df8SWei Liu if (decode->rep) { 60427458df8SWei Liu string_rep(env, decode, exec_stos_single, 0); 60527458df8SWei Liu } else { 60627458df8SWei Liu exec_stos_single(env, decode); 60727458df8SWei Liu } 60827458df8SWei Liu 60927458df8SWei Liu env->eip += decode->len; 61027458df8SWei Liu } 61127458df8SWei Liu 61227458df8SWei Liu static void exec_scas_single(CPUX86State *env, struct x86_decode *decode) 61327458df8SWei Liu { 61427458df8SWei Liu target_ulong addr; 61527458df8SWei Liu 61627458df8SWei Liu addr = linear_addr_size(env_cpu(env), RDI(env), 61727458df8SWei Liu decode->addressing_size, R_ES); 61827458df8SWei Liu decode->op[1].type = X86_VAR_IMMEDIATE; 61927458df8SWei Liu emul_ops->read_mem(env_cpu(env), &decode->op[1].val, addr, decode->operand_size); 62027458df8SWei Liu 62127458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); 62227458df8SWei Liu string_increment_reg(env, R_EDI, decode); 62327458df8SWei Liu } 62427458df8SWei Liu 62527458df8SWei Liu static void exec_scas(CPUX86State *env, struct x86_decode *decode) 62627458df8SWei Liu { 62727458df8SWei Liu decode->op[0].type = X86_VAR_REG; 62827458df8SWei Liu decode->op[0].reg = R_EAX; 62927458df8SWei Liu if (decode->rep) { 63027458df8SWei Liu string_rep(env, decode, exec_scas_single, decode->rep); 63127458df8SWei Liu } else { 63227458df8SWei Liu exec_scas_single(env, decode); 63327458df8SWei Liu } 63427458df8SWei Liu 63527458df8SWei Liu env->eip += decode->len; 63627458df8SWei Liu } 63727458df8SWei Liu 63827458df8SWei Liu static void exec_lods_single(CPUX86State *env, struct x86_decode *decode) 63927458df8SWei Liu { 64027458df8SWei Liu target_ulong addr; 64127458df8SWei Liu target_ulong val = 0; 64227458df8SWei Liu 64327458df8SWei Liu addr = decode_linear_addr(env, decode, RSI(env), R_DS); 64427458df8SWei Liu emul_ops->read_mem(env_cpu(env), &val, addr, decode->operand_size); 64527458df8SWei Liu write_reg(env, R_EAX, val, decode->operand_size); 64627458df8SWei Liu 64727458df8SWei Liu string_increment_reg(env, R_ESI, decode); 64827458df8SWei Liu } 64927458df8SWei Liu 65027458df8SWei Liu static void exec_lods(CPUX86State *env, struct x86_decode *decode) 65127458df8SWei Liu { 65227458df8SWei Liu if (decode->rep) { 65327458df8SWei Liu string_rep(env, decode, exec_lods_single, 0); 65427458df8SWei Liu } else { 65527458df8SWei Liu exec_lods_single(env, decode); 65627458df8SWei Liu } 65727458df8SWei Liu 65827458df8SWei Liu env->eip += decode->len; 65927458df8SWei Liu } 66027458df8SWei Liu 66127458df8SWei Liu void x86_emul_raise_exception(CPUX86State *env, int exception_index, int error_code) 66227458df8SWei Liu { 66327458df8SWei Liu env->exception_nr = exception_index; 66427458df8SWei Liu env->error_code = error_code; 66527458df8SWei Liu env->has_error_code = true; 66627458df8SWei Liu env->exception_injected = 1; 66727458df8SWei Liu } 66827458df8SWei Liu 66927458df8SWei Liu static void exec_rdmsr(CPUX86State *env, struct x86_decode *decode) 67027458df8SWei Liu { 67127458df8SWei Liu emul_ops->simulate_rdmsr(env_cpu(env)); 67227458df8SWei Liu env->eip += decode->len; 67327458df8SWei Liu } 67427458df8SWei Liu 67527458df8SWei Liu static void exec_wrmsr(CPUX86State *env, struct x86_decode *decode) 67627458df8SWei Liu { 67727458df8SWei Liu emul_ops->simulate_wrmsr(env_cpu(env)); 67827458df8SWei Liu env->eip += decode->len; 67927458df8SWei Liu } 68027458df8SWei Liu 68127458df8SWei Liu /* 68227458df8SWei Liu * flag: 68327458df8SWei Liu * 0 - bt, 1 - btc, 2 - bts, 3 - btr 68427458df8SWei Liu */ 68527458df8SWei Liu static void do_bt(CPUX86State *env, struct x86_decode *decode, int flag) 68627458df8SWei Liu { 68727458df8SWei Liu int32_t displacement; 68827458df8SWei Liu uint8_t index; 68927458df8SWei Liu bool cf; 69027458df8SWei Liu int mask = (4 == decode->operand_size) ? 0x1f : 0xf; 69127458df8SWei Liu 69227458df8SWei Liu VM_PANIC_ON(decode->rex.rex); 69327458df8SWei Liu 69427458df8SWei Liu fetch_operands(env, decode, 2, false, true, false); 69527458df8SWei Liu index = decode->op[1].val & mask; 69627458df8SWei Liu 69727458df8SWei Liu if (decode->op[0].type != X86_VAR_REG) { 69827458df8SWei Liu if (4 == decode->operand_size) { 69927458df8SWei Liu displacement = ((int32_t) (decode->op[1].val & 0xffffffe0)) / 32; 70027458df8SWei Liu decode->op[0].ptr += 4 * displacement; 70127458df8SWei Liu } else if (2 == decode->operand_size) { 70227458df8SWei Liu displacement = ((int16_t) (decode->op[1].val & 0xfff0)) / 16; 70327458df8SWei Liu decode->op[0].ptr += 2 * displacement; 70427458df8SWei Liu } else { 70527458df8SWei Liu VM_PANIC("bt 64bit\n"); 70627458df8SWei Liu } 70727458df8SWei Liu } 70827458df8SWei Liu decode->op[0].val = read_val_ext(env, decode->op[0].ptr, 70927458df8SWei Liu decode->operand_size); 71027458df8SWei Liu cf = (decode->op[0].val >> index) & 0x01; 71127458df8SWei Liu 71227458df8SWei Liu switch (flag) { 71327458df8SWei Liu case 0: 71427458df8SWei Liu set_CF(env, cf); 71527458df8SWei Liu return; 71627458df8SWei Liu case 1: 71727458df8SWei Liu decode->op[0].val ^= (1u << index); 71827458df8SWei Liu break; 71927458df8SWei Liu case 2: 72027458df8SWei Liu decode->op[0].val |= (1u << index); 72127458df8SWei Liu break; 72227458df8SWei Liu case 3: 72327458df8SWei Liu decode->op[0].val &= ~(1u << index); 72427458df8SWei Liu break; 72527458df8SWei Liu } 72627458df8SWei Liu write_val_ext(env, decode->op[0].ptr, decode->op[0].val, 72727458df8SWei Liu decode->operand_size); 72827458df8SWei Liu set_CF(env, cf); 72927458df8SWei Liu } 73027458df8SWei Liu 73127458df8SWei Liu static void exec_bt(CPUX86State *env, struct x86_decode *decode) 73227458df8SWei Liu { 73327458df8SWei Liu do_bt(env, decode, 0); 73427458df8SWei Liu env->eip += decode->len; 73527458df8SWei Liu } 73627458df8SWei Liu 73727458df8SWei Liu static void exec_btc(CPUX86State *env, struct x86_decode *decode) 73827458df8SWei Liu { 73927458df8SWei Liu do_bt(env, decode, 1); 74027458df8SWei Liu env->eip += decode->len; 74127458df8SWei Liu } 74227458df8SWei Liu 74327458df8SWei Liu static void exec_btr(CPUX86State *env, struct x86_decode *decode) 74427458df8SWei Liu { 74527458df8SWei Liu do_bt(env, decode, 3); 74627458df8SWei Liu env->eip += decode->len; 74727458df8SWei Liu } 74827458df8SWei Liu 74927458df8SWei Liu static void exec_bts(CPUX86State *env, struct x86_decode *decode) 75027458df8SWei Liu { 75127458df8SWei Liu do_bt(env, decode, 2); 75227458df8SWei Liu env->eip += decode->len; 75327458df8SWei Liu } 75427458df8SWei Liu 75527458df8SWei Liu void exec_shl(CPUX86State *env, struct x86_decode *decode) 75627458df8SWei Liu { 75727458df8SWei Liu uint8_t count; 75827458df8SWei Liu int of = 0, cf = 0; 75927458df8SWei Liu 76027458df8SWei Liu fetch_operands(env, decode, 2, true, true, false); 76127458df8SWei Liu 76227458df8SWei Liu count = decode->op[1].val; 76327458df8SWei Liu count &= 0x1f; /* count is masked to 5 bits*/ 76427458df8SWei Liu if (!count) { 76527458df8SWei Liu goto exit; 76627458df8SWei Liu } 76727458df8SWei Liu 76827458df8SWei Liu switch (decode->operand_size) { 76927458df8SWei Liu case 1: 77027458df8SWei Liu { 77127458df8SWei Liu uint8_t res = 0; 77227458df8SWei Liu if (count <= 8) { 77327458df8SWei Liu res = (decode->op[0].val << count); 77427458df8SWei Liu cf = (decode->op[0].val >> (8 - count)) & 0x1; 77527458df8SWei Liu of = cf ^ (res >> 7); 77627458df8SWei Liu } 77727458df8SWei Liu 77827458df8SWei Liu write_val_ext(env, decode->op[0].ptr, res, 1); 77927458df8SWei Liu SET_FLAGS_OSZAPC_LOGIC8(env, 0, 0, res); 78027458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 78127458df8SWei Liu break; 78227458df8SWei Liu } 78327458df8SWei Liu case 2: 78427458df8SWei Liu { 78527458df8SWei Liu uint16_t res = 0; 78627458df8SWei Liu 78727458df8SWei Liu /* from bochs */ 78827458df8SWei Liu if (count <= 16) { 78927458df8SWei Liu res = (decode->op[0].val << count); 79027458df8SWei Liu cf = (decode->op[0].val >> (16 - count)) & 0x1; 79127458df8SWei Liu of = cf ^ (res >> 15); /* of = cf ^ result15 */ 79227458df8SWei Liu } 79327458df8SWei Liu 79427458df8SWei Liu write_val_ext(env, decode->op[0].ptr, res, 2); 79527458df8SWei Liu SET_FLAGS_OSZAPC_LOGIC16(env, 0, 0, res); 79627458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 79727458df8SWei Liu break; 79827458df8SWei Liu } 79927458df8SWei Liu case 4: 80027458df8SWei Liu { 80127458df8SWei Liu uint32_t res = decode->op[0].val << count; 80227458df8SWei Liu 80327458df8SWei Liu write_val_ext(env, decode->op[0].ptr, res, 4); 80427458df8SWei Liu SET_FLAGS_OSZAPC_LOGIC32(env, 0, 0, res); 80527458df8SWei Liu cf = (decode->op[0].val >> (32 - count)) & 0x1; 80627458df8SWei Liu of = cf ^ (res >> 31); /* of = cf ^ result31 */ 80727458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 80827458df8SWei Liu break; 80927458df8SWei Liu } 81027458df8SWei Liu default: 81127458df8SWei Liu abort(); 81227458df8SWei Liu } 81327458df8SWei Liu 81427458df8SWei Liu exit: 81527458df8SWei Liu /* lflags_to_rflags(env); */ 81627458df8SWei Liu env->eip += decode->len; 81727458df8SWei Liu } 81827458df8SWei Liu 81927458df8SWei Liu void exec_movsx(CPUX86State *env, struct x86_decode *decode) 82027458df8SWei Liu { 82127458df8SWei Liu int src_op_size; 82227458df8SWei Liu int op_size = decode->operand_size; 82327458df8SWei Liu 82427458df8SWei Liu fetch_operands(env, decode, 2, false, false, false); 82527458df8SWei Liu 82627458df8SWei Liu if (0xbe == decode->opcode[1]) { 82727458df8SWei Liu src_op_size = 1; 82827458df8SWei Liu } else { 82927458df8SWei Liu src_op_size = 2; 83027458df8SWei Liu } 83127458df8SWei Liu 83227458df8SWei Liu decode->operand_size = src_op_size; 83327458df8SWei Liu calc_modrm_operand(env, decode, &decode->op[1]); 83427458df8SWei Liu decode->op[1].val = sign(read_val_ext(env, decode->op[1].ptr, src_op_size), 83527458df8SWei Liu src_op_size); 83627458df8SWei Liu 83727458df8SWei Liu write_val_ext(env, decode->op[0].ptr, decode->op[1].val, op_size); 83827458df8SWei Liu 83927458df8SWei Liu env->eip += decode->len; 84027458df8SWei Liu } 84127458df8SWei Liu 84227458df8SWei Liu void exec_ror(CPUX86State *env, struct x86_decode *decode) 84327458df8SWei Liu { 84427458df8SWei Liu uint8_t count; 84527458df8SWei Liu 84627458df8SWei Liu fetch_operands(env, decode, 2, true, true, false); 84727458df8SWei Liu count = decode->op[1].val; 84827458df8SWei Liu 84927458df8SWei Liu switch (decode->operand_size) { 85027458df8SWei Liu case 1: 85127458df8SWei Liu { 85227458df8SWei Liu uint32_t bit6, bit7; 85327458df8SWei Liu uint8_t res; 85427458df8SWei Liu 85527458df8SWei Liu if ((count & 0x07) == 0) { 85627458df8SWei Liu if (count & 0x18) { 85727458df8SWei Liu bit6 = ((uint8_t)decode->op[0].val >> 6) & 1; 85827458df8SWei Liu bit7 = ((uint8_t)decode->op[0].val >> 7) & 1; 85927458df8SWei Liu SET_FLAGS_OxxxxC(env, bit6 ^ bit7, bit7); 86027458df8SWei Liu } 86127458df8SWei Liu } else { 86227458df8SWei Liu count &= 0x7; /* use only bottom 3 bits */ 86327458df8SWei Liu res = ((uint8_t)decode->op[0].val >> count) | 86427458df8SWei Liu ((uint8_t)decode->op[0].val << (8 - count)); 86527458df8SWei Liu write_val_ext(env, decode->op[0].ptr, res, 1); 86627458df8SWei Liu bit6 = (res >> 6) & 1; 86727458df8SWei Liu bit7 = (res >> 7) & 1; 86827458df8SWei Liu /* set eflags: ROR count affects the following flags: C, O */ 86927458df8SWei Liu SET_FLAGS_OxxxxC(env, bit6 ^ bit7, bit7); 87027458df8SWei Liu } 87127458df8SWei Liu break; 87227458df8SWei Liu } 87327458df8SWei Liu case 2: 87427458df8SWei Liu { 87527458df8SWei Liu uint32_t bit14, bit15; 87627458df8SWei Liu uint16_t res; 87727458df8SWei Liu 87827458df8SWei Liu if ((count & 0x0f) == 0) { 87927458df8SWei Liu if (count & 0x10) { 88027458df8SWei Liu bit14 = ((uint16_t)decode->op[0].val >> 14) & 1; 88127458df8SWei Liu bit15 = ((uint16_t)decode->op[0].val >> 15) & 1; 88227458df8SWei Liu /* of = result14 ^ result15 */ 88327458df8SWei Liu SET_FLAGS_OxxxxC(env, bit14 ^ bit15, bit15); 88427458df8SWei Liu } 88527458df8SWei Liu } else { 88627458df8SWei Liu count &= 0x0f; /* use only 4 LSB's */ 88727458df8SWei Liu res = ((uint16_t)decode->op[0].val >> count) | 88827458df8SWei Liu ((uint16_t)decode->op[0].val << (16 - count)); 88927458df8SWei Liu write_val_ext(env, decode->op[0].ptr, res, 2); 89027458df8SWei Liu 89127458df8SWei Liu bit14 = (res >> 14) & 1; 89227458df8SWei Liu bit15 = (res >> 15) & 1; 89327458df8SWei Liu /* of = result14 ^ result15 */ 89427458df8SWei Liu SET_FLAGS_OxxxxC(env, bit14 ^ bit15, bit15); 89527458df8SWei Liu } 89627458df8SWei Liu break; 89727458df8SWei Liu } 89827458df8SWei Liu case 4: 89927458df8SWei Liu { 90027458df8SWei Liu uint32_t bit31, bit30; 90127458df8SWei Liu uint32_t res; 90227458df8SWei Liu 90327458df8SWei Liu count &= 0x1f; 90427458df8SWei Liu if (count) { 90527458df8SWei Liu res = ((uint32_t)decode->op[0].val >> count) | 90627458df8SWei Liu ((uint32_t)decode->op[0].val << (32 - count)); 90727458df8SWei Liu write_val_ext(env, decode->op[0].ptr, res, 4); 90827458df8SWei Liu 90927458df8SWei Liu bit31 = (res >> 31) & 1; 91027458df8SWei Liu bit30 = (res >> 30) & 1; 91127458df8SWei Liu /* of = result30 ^ result31 */ 91227458df8SWei Liu SET_FLAGS_OxxxxC(env, bit30 ^ bit31, bit31); 91327458df8SWei Liu } 91427458df8SWei Liu break; 91527458df8SWei Liu } 91627458df8SWei Liu } 91727458df8SWei Liu env->eip += decode->len; 91827458df8SWei Liu } 91927458df8SWei Liu 92027458df8SWei Liu void exec_rol(CPUX86State *env, struct x86_decode *decode) 92127458df8SWei Liu { 92227458df8SWei Liu uint8_t count; 92327458df8SWei Liu 92427458df8SWei Liu fetch_operands(env, decode, 2, true, true, false); 92527458df8SWei Liu count = decode->op[1].val; 92627458df8SWei Liu 92727458df8SWei Liu switch (decode->operand_size) { 92827458df8SWei Liu case 1: 92927458df8SWei Liu { 93027458df8SWei Liu uint32_t bit0, bit7; 93127458df8SWei Liu uint8_t res; 93227458df8SWei Liu 93327458df8SWei Liu if ((count & 0x07) == 0) { 93427458df8SWei Liu if (count & 0x18) { 93527458df8SWei Liu bit0 = ((uint8_t)decode->op[0].val & 1); 93627458df8SWei Liu bit7 = ((uint8_t)decode->op[0].val >> 7); 93727458df8SWei Liu SET_FLAGS_OxxxxC(env, bit0 ^ bit7, bit0); 93827458df8SWei Liu } 93927458df8SWei Liu } else { 94027458df8SWei Liu count &= 0x7; /* use only lowest 3 bits */ 94127458df8SWei Liu res = ((uint8_t)decode->op[0].val << count) | 94227458df8SWei Liu ((uint8_t)decode->op[0].val >> (8 - count)); 94327458df8SWei Liu 94427458df8SWei Liu write_val_ext(env, decode->op[0].ptr, res, 1); 94527458df8SWei Liu /* set eflags: 94627458df8SWei Liu * ROL count affects the following flags: C, O 94727458df8SWei Liu */ 94827458df8SWei Liu bit0 = (res & 1); 94927458df8SWei Liu bit7 = (res >> 7); 95027458df8SWei Liu SET_FLAGS_OxxxxC(env, bit0 ^ bit7, bit0); 95127458df8SWei Liu } 95227458df8SWei Liu break; 95327458df8SWei Liu } 95427458df8SWei Liu case 2: 95527458df8SWei Liu { 95627458df8SWei Liu uint32_t bit0, bit15; 95727458df8SWei Liu uint16_t res; 95827458df8SWei Liu 95927458df8SWei Liu if ((count & 0x0f) == 0) { 96027458df8SWei Liu if (count & 0x10) { 96127458df8SWei Liu bit0 = ((uint16_t)decode->op[0].val & 0x1); 96227458df8SWei Liu bit15 = ((uint16_t)decode->op[0].val >> 15); 96327458df8SWei Liu /* of = cf ^ result15 */ 96427458df8SWei Liu SET_FLAGS_OxxxxC(env, bit0 ^ bit15, bit0); 96527458df8SWei Liu } 96627458df8SWei Liu } else { 96727458df8SWei Liu count &= 0x0f; /* only use bottom 4 bits */ 96827458df8SWei Liu res = ((uint16_t)decode->op[0].val << count) | 96927458df8SWei Liu ((uint16_t)decode->op[0].val >> (16 - count)); 97027458df8SWei Liu 97127458df8SWei Liu write_val_ext(env, decode->op[0].ptr, res, 2); 97227458df8SWei Liu bit0 = (res & 0x1); 97327458df8SWei Liu bit15 = (res >> 15); 97427458df8SWei Liu /* of = cf ^ result15 */ 97527458df8SWei Liu SET_FLAGS_OxxxxC(env, bit0 ^ bit15, bit0); 97627458df8SWei Liu } 97727458df8SWei Liu break; 97827458df8SWei Liu } 97927458df8SWei Liu case 4: 98027458df8SWei Liu { 98127458df8SWei Liu uint32_t bit0, bit31; 98227458df8SWei Liu uint32_t res; 98327458df8SWei Liu 98427458df8SWei Liu count &= 0x1f; 98527458df8SWei Liu if (count) { 98627458df8SWei Liu res = ((uint32_t)decode->op[0].val << count) | 98727458df8SWei Liu ((uint32_t)decode->op[0].val >> (32 - count)); 98827458df8SWei Liu 98927458df8SWei Liu write_val_ext(env, decode->op[0].ptr, res, 4); 99027458df8SWei Liu bit0 = (res & 0x1); 99127458df8SWei Liu bit31 = (res >> 31); 99227458df8SWei Liu /* of = cf ^ result31 */ 99327458df8SWei Liu SET_FLAGS_OxxxxC(env, bit0 ^ bit31, bit0); 99427458df8SWei Liu } 99527458df8SWei Liu break; 99627458df8SWei Liu } 99727458df8SWei Liu } 99827458df8SWei Liu env->eip += decode->len; 99927458df8SWei Liu } 100027458df8SWei Liu 100127458df8SWei Liu 100227458df8SWei Liu void exec_rcl(CPUX86State *env, struct x86_decode *decode) 100327458df8SWei Liu { 100427458df8SWei Liu uint8_t count; 100527458df8SWei Liu int of = 0, cf = 0; 100627458df8SWei Liu 100727458df8SWei Liu fetch_operands(env, decode, 2, true, true, false); 100827458df8SWei Liu count = decode->op[1].val & 0x1f; 100927458df8SWei Liu 101027458df8SWei Liu switch (decode->operand_size) { 101127458df8SWei Liu case 1: 101227458df8SWei Liu { 101327458df8SWei Liu uint8_t op1_8 = decode->op[0].val; 101427458df8SWei Liu uint8_t res; 101527458df8SWei Liu count %= 9; 101627458df8SWei Liu if (!count) { 101727458df8SWei Liu break; 101827458df8SWei Liu } 101927458df8SWei Liu 102027458df8SWei Liu if (1 == count) { 102127458df8SWei Liu res = (op1_8 << 1) | get_CF(env); 102227458df8SWei Liu } else { 102327458df8SWei Liu res = (op1_8 << count) | (get_CF(env) << (count - 1)) | 102427458df8SWei Liu (op1_8 >> (9 - count)); 102527458df8SWei Liu } 102627458df8SWei Liu 102727458df8SWei Liu write_val_ext(env, decode->op[0].ptr, res, 1); 102827458df8SWei Liu 102927458df8SWei Liu cf = (op1_8 >> (8 - count)) & 0x01; 103027458df8SWei Liu of = cf ^ (res >> 7); /* of = cf ^ result7 */ 103127458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 103227458df8SWei Liu break; 103327458df8SWei Liu } 103427458df8SWei Liu case 2: 103527458df8SWei Liu { 103627458df8SWei Liu uint16_t res; 103727458df8SWei Liu uint16_t op1_16 = decode->op[0].val; 103827458df8SWei Liu 103927458df8SWei Liu count %= 17; 104027458df8SWei Liu if (!count) { 104127458df8SWei Liu break; 104227458df8SWei Liu } 104327458df8SWei Liu 104427458df8SWei Liu if (1 == count) { 104527458df8SWei Liu res = (op1_16 << 1) | get_CF(env); 104627458df8SWei Liu } else if (count == 16) { 104727458df8SWei Liu res = (get_CF(env) << 15) | (op1_16 >> 1); 104827458df8SWei Liu } else { /* 2..15 */ 104927458df8SWei Liu res = (op1_16 << count) | (get_CF(env) << (count - 1)) | 105027458df8SWei Liu (op1_16 >> (17 - count)); 105127458df8SWei Liu } 105227458df8SWei Liu 105327458df8SWei Liu write_val_ext(env, decode->op[0].ptr, res, 2); 105427458df8SWei Liu 105527458df8SWei Liu cf = (op1_16 >> (16 - count)) & 0x1; 105627458df8SWei Liu of = cf ^ (res >> 15); /* of = cf ^ result15 */ 105727458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 105827458df8SWei Liu break; 105927458df8SWei Liu } 106027458df8SWei Liu case 4: 106127458df8SWei Liu { 106227458df8SWei Liu uint32_t res; 106327458df8SWei Liu uint32_t op1_32 = decode->op[0].val; 106427458df8SWei Liu 106527458df8SWei Liu if (!count) { 106627458df8SWei Liu break; 106727458df8SWei Liu } 106827458df8SWei Liu 106927458df8SWei Liu if (1 == count) { 107027458df8SWei Liu res = (op1_32 << 1) | get_CF(env); 107127458df8SWei Liu } else { 107227458df8SWei Liu res = (op1_32 << count) | (get_CF(env) << (count - 1)) | 107327458df8SWei Liu (op1_32 >> (33 - count)); 107427458df8SWei Liu } 107527458df8SWei Liu 107627458df8SWei Liu write_val_ext(env, decode->op[0].ptr, res, 4); 107727458df8SWei Liu 107827458df8SWei Liu cf = (op1_32 >> (32 - count)) & 0x1; 107927458df8SWei Liu of = cf ^ (res >> 31); /* of = cf ^ result31 */ 108027458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 108127458df8SWei Liu break; 108227458df8SWei Liu } 108327458df8SWei Liu } 108427458df8SWei Liu env->eip += decode->len; 108527458df8SWei Liu } 108627458df8SWei Liu 108727458df8SWei Liu void exec_rcr(CPUX86State *env, struct x86_decode *decode) 108827458df8SWei Liu { 108927458df8SWei Liu uint8_t count; 109027458df8SWei Liu int of = 0, cf = 0; 109127458df8SWei Liu 109227458df8SWei Liu fetch_operands(env, decode, 2, true, true, false); 109327458df8SWei Liu count = decode->op[1].val & 0x1f; 109427458df8SWei Liu 109527458df8SWei Liu switch (decode->operand_size) { 109627458df8SWei Liu case 1: 109727458df8SWei Liu { 109827458df8SWei Liu uint8_t op1_8 = decode->op[0].val; 109927458df8SWei Liu uint8_t res; 110027458df8SWei Liu 110127458df8SWei Liu count %= 9; 110227458df8SWei Liu if (!count) { 110327458df8SWei Liu break; 110427458df8SWei Liu } 110527458df8SWei Liu res = (op1_8 >> count) | (get_CF(env) << (8 - count)) | 110627458df8SWei Liu (op1_8 << (9 - count)); 110727458df8SWei Liu 110827458df8SWei Liu write_val_ext(env, decode->op[0].ptr, res, 1); 110927458df8SWei Liu 111027458df8SWei Liu cf = (op1_8 >> (count - 1)) & 0x1; 111127458df8SWei Liu of = (((res << 1) ^ res) >> 7) & 0x1; /* of = result6 ^ result7 */ 111227458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 111327458df8SWei Liu break; 111427458df8SWei Liu } 111527458df8SWei Liu case 2: 111627458df8SWei Liu { 111727458df8SWei Liu uint16_t op1_16 = decode->op[0].val; 111827458df8SWei Liu uint16_t res; 111927458df8SWei Liu 112027458df8SWei Liu count %= 17; 112127458df8SWei Liu if (!count) { 112227458df8SWei Liu break; 112327458df8SWei Liu } 112427458df8SWei Liu res = (op1_16 >> count) | (get_CF(env) << (16 - count)) | 112527458df8SWei Liu (op1_16 << (17 - count)); 112627458df8SWei Liu 112727458df8SWei Liu write_val_ext(env, decode->op[0].ptr, res, 2); 112827458df8SWei Liu 112927458df8SWei Liu cf = (op1_16 >> (count - 1)) & 0x1; 113027458df8SWei Liu of = ((uint16_t)((res << 1) ^ res) >> 15) & 0x1; /* of = result15 ^ 113127458df8SWei Liu result14 */ 113227458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 113327458df8SWei Liu break; 113427458df8SWei Liu } 113527458df8SWei Liu case 4: 113627458df8SWei Liu { 113727458df8SWei Liu uint32_t res; 113827458df8SWei Liu uint32_t op1_32 = decode->op[0].val; 113927458df8SWei Liu 114027458df8SWei Liu if (!count) { 114127458df8SWei Liu break; 114227458df8SWei Liu } 114327458df8SWei Liu 114427458df8SWei Liu if (1 == count) { 114527458df8SWei Liu res = (op1_32 >> 1) | (get_CF(env) << 31); 114627458df8SWei Liu } else { 114727458df8SWei Liu res = (op1_32 >> count) | (get_CF(env) << (32 - count)) | 114827458df8SWei Liu (op1_32 << (33 - count)); 114927458df8SWei Liu } 115027458df8SWei Liu 115127458df8SWei Liu write_val_ext(env, decode->op[0].ptr, res, 4); 115227458df8SWei Liu 115327458df8SWei Liu cf = (op1_32 >> (count - 1)) & 0x1; 115427458df8SWei Liu of = ((res << 1) ^ res) >> 31; /* of = result30 ^ result31 */ 115527458df8SWei Liu SET_FLAGS_OxxxxC(env, of, cf); 115627458df8SWei Liu break; 115727458df8SWei Liu } 115827458df8SWei Liu } 115927458df8SWei Liu env->eip += decode->len; 116027458df8SWei Liu } 116127458df8SWei Liu 116227458df8SWei Liu static void exec_xchg(CPUX86State *env, struct x86_decode *decode) 116327458df8SWei Liu { 116427458df8SWei Liu fetch_operands(env, decode, 2, true, true, false); 116527458df8SWei Liu 116627458df8SWei Liu write_val_ext(env, decode->op[0].ptr, decode->op[1].val, 116727458df8SWei Liu decode->operand_size); 116827458df8SWei Liu write_val_ext(env, decode->op[1].ptr, decode->op[0].val, 116927458df8SWei Liu decode->operand_size); 117027458df8SWei Liu 117127458df8SWei Liu env->eip += decode->len; 117227458df8SWei Liu } 117327458df8SWei Liu 117427458df8SWei Liu static void exec_xadd(CPUX86State *env, struct x86_decode *decode) 117527458df8SWei Liu { 117627458df8SWei Liu EXEC_2OP_FLAGS_CMD(env, decode, +, SET_FLAGS_OSZAPC_ADD, true); 117727458df8SWei Liu write_val_ext(env, decode->op[1].ptr, decode->op[0].val, 117827458df8SWei Liu decode->operand_size); 117927458df8SWei Liu 118027458df8SWei Liu env->eip += decode->len; 118127458df8SWei Liu } 118227458df8SWei Liu 118327458df8SWei Liu static struct cmd_handler { 118427458df8SWei Liu enum x86_decode_cmd cmd; 118527458df8SWei Liu void (*handler)(CPUX86State *env, struct x86_decode *ins); 118627458df8SWei Liu } handlers[] = { 118727458df8SWei Liu {X86_DECODE_CMD_INVL, NULL,}, 118827458df8SWei Liu {X86_DECODE_CMD_MOV, exec_mov}, 118927458df8SWei Liu {X86_DECODE_CMD_ADD, exec_add}, 119027458df8SWei Liu {X86_DECODE_CMD_OR, exec_or}, 119127458df8SWei Liu {X86_DECODE_CMD_ADC, exec_adc}, 119227458df8SWei Liu {X86_DECODE_CMD_SBB, exec_sbb}, 119327458df8SWei Liu {X86_DECODE_CMD_AND, exec_and}, 119427458df8SWei Liu {X86_DECODE_CMD_SUB, exec_sub}, 119527458df8SWei Liu {X86_DECODE_CMD_NEG, exec_neg}, 119627458df8SWei Liu {X86_DECODE_CMD_XOR, exec_xor}, 119727458df8SWei Liu {X86_DECODE_CMD_CMP, exec_cmp}, 119827458df8SWei Liu {X86_DECODE_CMD_INC, exec_inc}, 119927458df8SWei Liu {X86_DECODE_CMD_DEC, exec_dec}, 120027458df8SWei Liu {X86_DECODE_CMD_TST, exec_tst}, 120127458df8SWei Liu {X86_DECODE_CMD_NOT, exec_not}, 120227458df8SWei Liu {X86_DECODE_CMD_MOVZX, exec_movzx}, 120327458df8SWei Liu {X86_DECODE_CMD_OUT, exec_out}, 120427458df8SWei Liu {X86_DECODE_CMD_IN, exec_in}, 120527458df8SWei Liu {X86_DECODE_CMD_INS, exec_ins}, 120627458df8SWei Liu {X86_DECODE_CMD_OUTS, exec_outs}, 120727458df8SWei Liu {X86_DECODE_CMD_RDMSR, exec_rdmsr}, 120827458df8SWei Liu {X86_DECODE_CMD_WRMSR, exec_wrmsr}, 120927458df8SWei Liu {X86_DECODE_CMD_BT, exec_bt}, 121027458df8SWei Liu {X86_DECODE_CMD_BTR, exec_btr}, 121127458df8SWei Liu {X86_DECODE_CMD_BTC, exec_btc}, 121227458df8SWei Liu {X86_DECODE_CMD_BTS, exec_bts}, 121327458df8SWei Liu {X86_DECODE_CMD_SHL, exec_shl}, 121427458df8SWei Liu {X86_DECODE_CMD_ROL, exec_rol}, 121527458df8SWei Liu {X86_DECODE_CMD_ROR, exec_ror}, 121627458df8SWei Liu {X86_DECODE_CMD_RCR, exec_rcr}, 121727458df8SWei Liu {X86_DECODE_CMD_RCL, exec_rcl}, 121827458df8SWei Liu /*{X86_DECODE_CMD_CPUID, exec_cpuid},*/ 121927458df8SWei Liu {X86_DECODE_CMD_MOVS, exec_movs}, 122027458df8SWei Liu {X86_DECODE_CMD_CMPS, exec_cmps}, 122127458df8SWei Liu {X86_DECODE_CMD_STOS, exec_stos}, 122227458df8SWei Liu {X86_DECODE_CMD_SCAS, exec_scas}, 122327458df8SWei Liu {X86_DECODE_CMD_LODS, exec_lods}, 122427458df8SWei Liu {X86_DECODE_CMD_MOVSX, exec_movsx}, 122527458df8SWei Liu {X86_DECODE_CMD_XCHG, exec_xchg}, 122627458df8SWei Liu {X86_DECODE_CMD_XADD, exec_xadd}, 122727458df8SWei Liu }; 122827458df8SWei Liu 122927458df8SWei Liu static struct cmd_handler _cmd_handler[X86_DECODE_CMD_LAST]; 123027458df8SWei Liu 123127458df8SWei Liu const struct x86_emul_ops *emul_ops; 123227458df8SWei Liu 123327458df8SWei Liu static void init_cmd_handler(void) 123427458df8SWei Liu { 123527458df8SWei Liu int i; 123627458df8SWei Liu for (i = 0; i < ARRAY_SIZE(handlers); i++) { 123727458df8SWei Liu _cmd_handler[handlers[i].cmd] = handlers[i]; 123827458df8SWei Liu } 123927458df8SWei Liu } 124027458df8SWei Liu 124127458df8SWei Liu bool exec_instruction(CPUX86State *env, struct x86_decode *ins) 124227458df8SWei Liu { 124327458df8SWei Liu if (!_cmd_handler[ins->cmd].handler) { 1244*7abf0d95SPaolo Bonzini printf("Unimplemented handler (" TARGET_FMT_lx ") for %d (%x %x) \n", env->eip, 124527458df8SWei Liu ins->cmd, ins->opcode[0], 124627458df8SWei Liu ins->opcode_len > 1 ? ins->opcode[1] : 0); 124727458df8SWei Liu env->eip += ins->len; 124827458df8SWei Liu return true; 124927458df8SWei Liu } 125027458df8SWei Liu 125127458df8SWei Liu _cmd_handler[ins->cmd].handler(env, ins); 125227458df8SWei Liu return true; 125327458df8SWei Liu } 125427458df8SWei Liu 125527458df8SWei Liu void init_emu(const struct x86_emul_ops *o) 125627458df8SWei Liu { 125727458df8SWei Liu emul_ops = o; 125827458df8SWei Liu init_cmd_handler(); 125927458df8SWei Liu } 1260