/* * pop_shack() * Pop next host eip from shadow stack. */ void pop_shack(TCGv_ptr cpu_env, TCGv next_eip) { // labels int label_end = gen_new_label(); // prepare registers TCGv_ptr temp_shack_start = tcg_temp_local_new_ptr(); // store shack start TCGv_ptr temp_shack_top = tcg_temp_local_new_ptr(); // store shack top TCGv eip_on_shack = tcg_temp_local_new(); TCGv_ptr host_slot_addr = tcg_temp_local_new(); TCGv_ptr host_addr = tcg_temp_new(); // load common values tcg_gen_ld_ptr(temp_shack_start, cpu_env, offsetof(CPUState, shack)); tcg_gen_ld_ptr(temp_shack_top, cpu_env, offsetof(CPUState, shack_top)); // check if stack empty? tcg_gen_brcond_ptr(TCG_COND_EQ,temp_shack_top,temp_shack_start,label_end); // stack not empty, pop one tcg_gen_subi_ptr(temp_shack_top, temp_shack_top, sizeof(uint64_t)); // decrease top tcg_gen_st_ptr(temp_shack_top, cpu_env, offsetof(CPUState, shack_top)); // store back top tcg_gen_ld_tl(eip_on_shack, temp_shack_top, 0); // get eip // check if the same? tcg_gen_brcond_ptr(TCG_COND_NE,tcg_const_tl(next_eip),eip_on_shack,label_end); // go to "end" if not the same tcg_gen_ld_tl(host_slot_addr, temp_shack_top, sizeof(unsigned long)); // get slot addr tcg_gen_ld_ptr(host_addr, host_slot_addr, 0) ; // get host addr tcg_gen_brcond_ptr(TCG_COND_EQ,tcg_const_tl(0),host_addr,label_end); // go to "end" if addr is zero // jump! *gen_opc_ptr++ = INDEX_op_jmp; *gen_opparam_ptr++ = GET_TCGV_I32(host_addr); // label: end gen_set_label(label_end); tcg_temp_free(eip_on_shack); tcg_temp_free_ptr(host_slot_addr); tcg_temp_free_ptr(host_addr); tcg_temp_free_ptr(temp_shack_top); tcg_temp_free_ptr(temp_shack_start); }
/* * push_shack() * Push next guest eip into shadow stack. */ void push_shack(CPUState *env, TCGv_ptr cpu_env, target_ulong next_eip) { // label int label_do_push = gen_new_label(); // prepare registers TCGv_ptr temp_shack_end = tcg_temp_local_new_ptr(); // store shack end TCGv_ptr temp_shack_top = tcg_temp_local_new_ptr(); // store shack top TCGv temp_next_eip = tcg_temp_local_new(); // store eip // load common values tcg_gen_ld_ptr(temp_shack_end, cpu_env, offsetof(CPUState, shack_end)); tcg_gen_ld_ptr(temp_shack_top, cpu_env, offsetof(CPUState, shack_top)); tcg_gen_mov_tl(temp_next_eip, tcg_const_tl(next_eip)); // check shack full? tcg_gen_brcond_ptr(TCG_COND_NE,temp_shack_top,temp_shack_end,label_do_push); // if not full // flush here TCGv_ptr temp_shack_start = tcg_temp_new_ptr(); // store shack start //tcg_en_st_tl(tcg_const_tl(0), cpu_env, offsetof(CPUState, shadow_ret_count)); // reset ret count tcg_gen_ld_ptr(temp_shack_start, cpu_env, offsetof(CPUState, shack)); tcg_gen_mov_tl(temp_shack_top, temp_shack_start); tcg_temp_free_ptr(temp_shack_start); // call helper: flush the hash gen_helper_shack_flush(cpu_env); // end of flush gen_set_label(label_do_push); // do push here // push guest eip tcg_gen_st_ptr(temp_next_eip, temp_shack_top, 0); // store guest eip tcg_gen_addi_ptr(temp_shack_top, temp_shack_top, sizeof(uint64_t)); // increase top // call helper: check if we can fill the ret directly, or need to add hash-pair gen_helper_shack_push(cpu_env, temp_next_eip); // store back top tcg_gen_st_ptr(temp_shack_top, cpu_env, offsetof(CPUState, shack_top)); // clean up tcg_temp_free(temp_next_eip); tcg_temp_free_ptr(temp_shack_top); tcg_temp_free_ptr(temp_shack_end); }
static unsigned int dec10_quick_imm(DisasContext *dc) { int32_t imm, simm; int op; /* sign extend. */ imm = dc->ir & ((1 << 6) - 1); simm = (int8_t) (imm << 2); simm >>= 2; switch (dc->opcode) { case CRISV10_QIMM_BDAP_R0: case CRISV10_QIMM_BDAP_R1: case CRISV10_QIMM_BDAP_R2: case CRISV10_QIMM_BDAP_R3: simm = (int8_t)dc->ir; LOG_DIS("bdap %d $r%d\n", simm, dc->dst); LOG_DIS("pc=%x mode=%x quickimm %d r%d r%d\n", dc->pc, dc->mode, dc->opcode, dc->src, dc->dst); cris_set_prefix(dc); if (dc->dst == 15) { tcg_gen_movi_tl(cpu_PR[PR_PREFIX], dc->pc + 2 + simm); } else { tcg_gen_addi_tl(cpu_PR[PR_PREFIX], cpu_R[dc->dst], simm); } break; case CRISV10_QIMM_MOVEQ: LOG_DIS("moveq %d, $r%d\n", simm, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, CC_OP_MOVE, cpu_R[dc->dst], cpu_R[dc->dst], tcg_const_tl(simm), 4); break; case CRISV10_QIMM_CMPQ: LOG_DIS("cmpq %d, $r%d\n", simm, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, CC_OP_CMP, cpu_R[dc->dst], cpu_R[dc->dst], tcg_const_tl(simm), 4); break; case CRISV10_QIMM_ADDQ: LOG_DIS("addq %d, $r%d\n", imm, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, CC_OP_ADD, cpu_R[dc->dst], cpu_R[dc->dst], tcg_const_tl(imm), 4); break; case CRISV10_QIMM_ANDQ: LOG_DIS("andq %d, $r%d\n", simm, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, CC_OP_AND, cpu_R[dc->dst], cpu_R[dc->dst], tcg_const_tl(simm), 4); break; case CRISV10_QIMM_ASHQ: LOG_DIS("ashq %d, $r%d\n", simm, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); op = imm & (1 << 5); imm &= 0x1f; if (op) { cris_alu(dc, CC_OP_ASR, cpu_R[dc->dst], cpu_R[dc->dst], tcg_const_tl(imm), 4); } else { /* BTST */ cris_update_cc_op(dc, CC_OP_FLAGS, 4); gen_helper_btst(cpu_PR[PR_CCS], cpu_R[dc->dst], tcg_const_tl(imm), cpu_PR[PR_CCS]); } break; case CRISV10_QIMM_LSHQ: LOG_DIS("lshq %d, $r%d\n", simm, dc->dst); op = CC_OP_LSL; if (imm & (1 << 5)) { op = CC_OP_LSR; } imm &= 0x1f; cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, op, cpu_R[dc->dst], cpu_R[dc->dst], tcg_const_tl(imm), 4); break; case CRISV10_QIMM_SUBQ: LOG_DIS("subq %d, $r%d\n", imm, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, CC_OP_SUB, cpu_R[dc->dst], cpu_R[dc->dst], tcg_const_tl(imm), 4); break; case CRISV10_QIMM_ORQ: LOG_DIS("andq %d, $r%d\n", simm, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); cris_alu(dc, CC_OP_OR, cpu_R[dc->dst], cpu_R[dc->dst], tcg_const_tl(simm), 4); break; case CRISV10_QIMM_BCC_R0: case CRISV10_QIMM_BCC_R1: case CRISV10_QIMM_BCC_R2: case CRISV10_QIMM_BCC_R3: imm = dc->ir & 0xff; /* bit 0 is a sign bit. */ if (imm & 1) { imm |= 0xffffff00; /* sign extend. */ imm &= ~1; /* get rid of the sign bit. */ } imm += 2; LOG_DIS("b%s %d\n", cc_name(dc->cond), imm); cris_cc_mask(dc, 0); cris_prepare_cc_branch(dc, imm, dc->cond); break; default: LOG_DIS("pc=%x mode=%x quickimm %d r%d r%d\n", dc->pc, dc->mode, dc->opcode, dc->src, dc->dst); cpu_abort(dc->env, "Unhandled quickimm\n"); break; } return 2; }
static unsigned int dec10_ind(DisasContext *dc) { unsigned int insn_len = 2; unsigned int size = dec10_size(dc->size); uint32_t imm; int32_t simm; TCGv t[2]; if (dc->size != 3) { switch (dc->opcode) { case CRISV10_IND_MOVE_M_R: return dec10_ind_move_m_r(dc, size); break; case CRISV10_IND_MOVE_R_M: return dec10_ind_move_r_m(dc, size); break; case CRISV10_IND_CMP: LOG_DIS("cmp size=%d op=%d %d\n", size, dc->src, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); insn_len += dec10_ind_alu(dc, CC_OP_CMP, size); break; case CRISV10_IND_TEST: LOG_DIS("test size=%d op=%d %d\n", size, dc->src, dc->dst); cris_evaluate_flags(dc); cris_cc_mask(dc, CC_MASK_NZVC); cris_alu_m_alloc_temps(t); insn_len += dec10_prep_move_m(dc, 0, size, t[0]); tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~3); cris_alu(dc, CC_OP_CMP, cpu_R[dc->dst], t[0], tcg_const_tl(0), size); cris_alu_m_free_temps(t); break; case CRISV10_IND_ADD: LOG_DIS("add size=%d op=%d %d\n", size, dc->src, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); insn_len += dec10_ind_alu(dc, CC_OP_ADD, size); break; case CRISV10_IND_SUB: LOG_DIS("sub size=%d op=%d %d\n", size, dc->src, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); insn_len += dec10_ind_alu(dc, CC_OP_SUB, size); break; case CRISV10_IND_BOUND: LOG_DIS("bound size=%d op=%d %d\n", size, dc->src, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); insn_len += dec10_ind_bound(dc, size); break; case CRISV10_IND_AND: LOG_DIS("and size=%d op=%d %d\n", size, dc->src, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); insn_len += dec10_ind_alu(dc, CC_OP_AND, size); break; case CRISV10_IND_OR: LOG_DIS("or size=%d op=%d %d\n", size, dc->src, dc->dst); cris_cc_mask(dc, CC_MASK_NZVC); insn_len += dec10_ind_alu(dc, CC_OP_OR, size); break; case CRISV10_IND_MOVX: insn_len = dec10_alux_m(dc, CC_OP_MOVE); break; case CRISV10_IND_ADDX: insn_len = dec10_alux_m(dc, CC_OP_ADD); break; case CRISV10_IND_SUBX: insn_len = dec10_alux_m(dc, CC_OP_SUB); break; case CRISV10_IND_CMPX: insn_len = dec10_alux_m(dc, CC_OP_CMP); break; case CRISV10_IND_MUL: /* This is a reg insn coded in the mem indir space. */ LOG_DIS("mul pc=%x opcode=%d\n", dc->pc, dc->opcode); cris_cc_mask(dc, CC_MASK_NZVC); dec10_reg_mul(dc, size, dc->ir & (1 << 10)); break; case CRISV10_IND_BDAP_M: insn_len = dec10_bdap_m(dc, size); break; default: LOG_DIS("pc=%x var-ind.%d %d r%d r%d\n", dc->pc, size, dc->opcode, dc->src, dc->dst); cpu_abort(dc->env, "Unhandled opcode"); break; } return insn_len; } switch (dc->opcode) { case CRISV10_IND_MOVE_M_SPR: insn_len = dec10_ind_move_m_pr(dc); break; case CRISV10_IND_MOVE_SPR_M: insn_len = dec10_ind_move_pr_m(dc); break; case CRISV10_IND_JUMP_M: if (dc->src == 15) { LOG_DIS("jump.%d %d r%d r%d direct\n", size, dc->opcode, dc->src, dc->dst); imm = ldl_code(dc->pc + 2); if (dc->mode == CRISV10_MODE_AUTOINC) insn_len += size; t_gen_mov_preg_TN(dc, dc->dst, tcg_const_tl(dc->pc + insn_len)); dc->jmp_pc = imm; cris_prepare_jmp(dc, JMP_DIRECT); dc->delayed_branch--; /* v10 has no dslot here. */ } else { if (dc->dst == 14) { LOG_DIS("break %d\n", dc->src); cris_evaluate_flags(dc); tcg_gen_movi_tl(env_pc, dc->pc + 2); t_gen_raise_exception(EXCP_BREAK); dc->is_jmp = DISAS_UPDATE; return insn_len; } LOG_DIS("%d: jump.%d %d r%d r%d\n", __LINE__, size, dc->opcode, dc->src, dc->dst); t[0] = tcg_temp_new(); t_gen_mov_preg_TN(dc, dc->dst, tcg_const_tl(dc->pc + insn_len)); crisv10_prepare_memaddr(dc, t[0], size); gen_load(dc, env_btarget, t[0], 4, 0); insn_len += crisv10_post_memaddr(dc, size); cris_prepare_jmp(dc, JMP_INDIRECT); dc->delayed_branch--; /* v10 has no dslot here. */ tcg_temp_free(t[0]); } break; case CRISV10_IND_MOVEM_R_M: LOG_DIS("movem_r_m pc=%x opcode=%d r%d r%d\n", dc->pc, dc->opcode, dc->dst, dc->src); dec10_movem_r_m(dc); break; case CRISV10_IND_MOVEM_M_R: LOG_DIS("movem_m_r pc=%x opcode=%d\n", dc->pc, dc->opcode); dec10_movem_m_r(dc); break; case CRISV10_IND_JUMP_R: LOG_DIS("jmp pc=%x opcode=%d r%d r%d\n", dc->pc, dc->opcode, dc->dst, dc->src); tcg_gen_mov_tl(env_btarget, cpu_R[dc->src]); t_gen_mov_preg_TN(dc, dc->dst, tcg_const_tl(dc->pc + insn_len)); cris_prepare_jmp(dc, JMP_INDIRECT); dc->delayed_branch--; /* v10 has no dslot here. */ break; case CRISV10_IND_MOVX: insn_len = dec10_alux_m(dc, CC_OP_MOVE); break; case CRISV10_IND_ADDX: insn_len = dec10_alux_m(dc, CC_OP_ADD); break; case CRISV10_IND_SUBX: insn_len = dec10_alux_m(dc, CC_OP_SUB); break; case CRISV10_IND_CMPX: insn_len = dec10_alux_m(dc, CC_OP_CMP); break; case CRISV10_IND_DIP: insn_len = dec10_dip(dc); break; case CRISV10_IND_BCC_M: cris_cc_mask(dc, 0); imm = ldsw_code(dc->pc + 2); simm = (int16_t)imm; simm += 4; LOG_DIS("bcc_m: b%s %x\n", cc_name(dc->cond), dc->pc + simm); cris_prepare_cc_branch(dc, simm, dc->cond); insn_len = 4; break; default: LOG_DIS("ERROR pc=%x opcode=%d\n", dc->pc, dc->opcode); cpu_abort(dc->env, "Unhandled opcode"); break; } return insn_len; }