+/*
+ * Indirect calls
+ * - jalr x1, rs where rs != x5;
+ * - jalr x5, rs where rs != x1;
+ * - c.jalr rs1 where rs1 != x5;
+ *
+ * Indirect jumps
+ * - jalr x0, rs where rs != x1 and rs != x5;
+ * - c.jr rs1 where rs1 != x1 and rs1 != x5.
+ *
+ * Returns
+ * - jalr rd, rs where (rs == x1 or rs == x5) and rd != x1 and rd != x5;
+ * - c.jr rs1 where rs1 == x1 or rs1 == x5.
+ *
+ * Co-routine swap
+ * - jalr x1, x5;
+ * - jalr x5, x1;
+ * - c.jalr x5.
+ *
+ * Other indirect jumps
+ * - jalr rd, rs where rs != x1, rs != x5, rd != x0, rd != x1 and rd != x5.
+ */
+void helper_ctr_jalr(CPURISCVState *env, target_ulong src, target_ulong dest,
+ target_ulong rd, target_ulong rs1)
+{
+ target_ulong curr_priv = env->priv;
+ bool curr_virt = env->virt_enabled;
+
+ if ((rd == 1 && rs1 != 5) || (rd == 5 && rs1 != 1)) {
+ riscv_ctr_add_entry(env, src, dest, CTRDATA_TYPE_INDIRECT_CALL,
+ curr_priv, curr_virt);
+ } else if (rd == 0 && rs1 != 1 && rs1 != 5) {
+ riscv_ctr_add_entry(env, src, dest, CTRDATA_TYPE_INDIRECT_JUMP,
+ curr_priv, curr_virt);
+ } else if ((rs1 == 1 || rs1 == 5) && (rd != 1 && rd != 5)) {
+ riscv_ctr_add_entry(env, src, dest, CTRDATA_TYPE_RETURN,
+ curr_priv, curr_virt);
+ } else if ((rs1 == 1 && rd == 5) || (rs1 == 5 && rd == 1)) {
+ riscv_ctr_add_entry(env, src, dest, CTRDATA_TYPE_CO_ROUTINE_SWAP,
+ curr_priv, curr_virt);
+ } else {
+ riscv_ctr_add_entry(env, src, dest,
+ CTRDATA_TYPE_OTHER_INDIRECT_JUMP, curr_priv,
+ curr_virt);
+ }
+}
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -569,6 +569,16 @@ static void gen_jal(DisasContext *ctx, int rd,
target_ulong imm)
}
}
+#ifndef CONFIG_USER_ONLY
+ if (ctx->cfg_ptr->ext_smctr || ctx->cfg_ptr->ext_ssctr) {
+ TCGv dest = tcg_constant_tl(ctx->base.pc_next + imm);
+ TCGv src = tcg_constant_tl(ctx->base.pc_next);
+ TCGv tcg_rd = tcg_constant_tl((target_ulong)rd);
+
+ gen_helper_ctr_jal(tcg_env, src, dest, tcg_rd);
+ }
+#endif
+void helper_ctr_popret(CPURISCVState *env, target_ulong src, target_ulong dest)
+{
+ riscv_ctr_add_entry(env, src, dest, CTRDATA_TYPE_RETURN,
+ env->priv, env->virt_enabled);
+}
+
+void helper_ctr_branch(CPURISCVState *env, target_ulong src, target_ulong dest,
+ target_ulong branch_taken)
+{
+ target_ulong curr_priv = env->priv;
+ bool curr_virt = env->virt_enabled;
+
+ if (branch_taken) {
+ riscv_ctr_add_entry(env, src, dest, CTRDATA_TYPE_TAKEN_BRANCH,
+ curr_priv, curr_virt);
+ } else {
+ riscv_ctr_add_entry(env, src, dest, CTRDATA_TYPE_NONTAKEN_BRANCH,
+ curr_priv, curr_virt);
+ }
+}