Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

riscv: Add the modesw.{cap,int} instructions #265

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion disas/riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,10 @@ typedef enum {
rv_op_cincoffsetimm,
rv_op_csetboundsimm,

// Zero operand
rv_op_modesw_cap,
rv_op_modesw_int,

// Two operand
rv_op_cgetperm,
rv_op_cgettype,
Expand Down Expand Up @@ -1303,7 +1307,9 @@ const rv_opcode_data opcode_data[] = {
[rv_op_csc] = { "csc", rv_codec_s, rv_fmt_cs2_offset_cs1, NULL, 0, 0, 0 },
[rv_op_cincoffsetimm] = { "cincoffset", rv_codec_i, rv_fmt_cd_cs1_imm, NULL, 0, 0, 0 },
[rv_op_csetboundsimm] = { "csetbounds", rv_codec_i, rv_fmt_cd_cs1_imm, NULL, 0, 0, 0 },

// Zero operand
[rv_op_modesw_cap] = { "modesw.cap", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
[rv_op_modesw_int] = { "modesw.int", rv_codec_none, rv_fmt_none, NULL, 0, 0, 0 },
// Two operand
[rv_op_cgetperm] = { "cgetperm", rv_codec_r, rv_fmt_rd_cs1, NULL, 0, 0, 0 },
[rv_op_cgettype] = { "cgettype", rv_codec_r, rv_fmt_rd_cs1, NULL, 0, 0, 0 },
Expand Down Expand Up @@ -2003,6 +2009,8 @@ static void decode_inst_opcode(rv_decode *dec, rv_isa isa, int flags)
case 45: op = rv_op_minu; break;
case 46: op = rv_op_max; break;
case 47: op = rv_op_maxu; break;
case 73: op = rv_op_modesw_cap; break;
case 81: op = rv_op_modesw_int; break;
case 130: op = rv_op_sh1add; break;
case 132: op = rv_op_sh2add; break;
case 134: op = rv_op_sh3add; break;
Expand Down
3 changes: 2 additions & 1 deletion target/cheri-common/cheri_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ typedef enum CheriPermissions {
} CheriPermissions;

typedef enum CheriFlags {
CHERI_FLAG_CAPMODE = (1 << 0),
CHERI_FLAG_INTMODE = 0,
CHERI_FLAG_CAPMODE = 1,
} CheriFlags;

typedef enum CheriTbFlags {
Expand Down
1 change: 1 addition & 0 deletions target/riscv/helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ DEF_HELPER_3(lr_c_cap, void, env, i32, i32)
DEF_HELPER_3(sc_c_modedep, tl, env, i32, i32)
DEF_HELPER_3(sc_c_ddc, tl, env, i32, i32)
DEF_HELPER_3(sc_c_cap, tl, env, i32, i32)
DEF_HELPER_2(modesw, void, env, int)
#endif

#ifdef CONFIG_TCG_LOG_INSTR
Expand Down
5 changes: 5 additions & 0 deletions target/riscv/insn32-cheri.decode
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,8 @@ sc_w_cap 1111100 ..... ..... 000 11010 1011011 @atom_st_cap_or_ddc
# 11101 is reserved
# 11110 is reserved
# 11111 is reserved

### Zero operands

modesw_cap 0001001 00000 00000 001 00000 0110011
modesw_int 0001010 00000 00000 001 00000 0110011
57 changes: 57 additions & 0 deletions target/riscv/insn_trans/trans_cheri.c.inc
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,63 @@ static inline bool trans_amoswap_c(DisasContext *ctx, arg_amoswap_c *a)
return true;
}

static inline bool do_trans_modesw(DisasContext *ctx, bool to_capmode)
{
if (ctx->capmode == to_capmode) {
qemu_log_mask_and_addr(CPU_LOG_INSTR, ctx->base.pc_first,
"Redundant modesw at " TARGET_FMT_lx " (%s)",
ctx->base.pc_first,
lookup_symbol(ctx->base.pc_first));
return true;
}
gen_helper_modesw(cpu_env, tcg_const_i32(to_capmode));

/*
* There's a number of RISC-V instructions whose behaviour depends on the
* mode. For some of them, the mode is checked at translation time (not at
* execution time).
* -> We have to process the mode update before any further translations.
*
* This comes down to ending the current translation block (tb). The tb is
* then cached and executed. After that, the status is updated by
* cheri_cpu_get_tb_cpu_state before the next tb is translated.
*
* We were wondering if the tb cache would cause issues in a scenario
* such as
* - tb with modesw is executed
* - mode update
* - next tb is to be translated - but it's already in the cache
* - cached tb is executed - but it was translated based on
* previous mode
*
* Note: The key for locating a cached tb in the hashtable includes the cpu
* status (part of which is the mode), so even if the next PC address has a
* cached TB, the lookup will not find the mismatched one.
*
* TODO: it should be possible to update the flag in DisasContext and
* continue translation after the modesw, but I am not confident this will
* be correct. Once we have some unit tests that we can run we should try
* to make this change since it will improve the performance of hybrid code.
* See Morello code which uses DISAS_UPDATE_EXIT.
*/
/* create tcg instruction to exit the tb */
gen_update_cpu_pc(ctx->pc_succ_insn);
tcg_gen_exit_tb(NULL, 0);
/* This indicates to riscv_tr_tb_stop that no cleanup is needed. */
ctx->base.is_jmp = DISAS_NORETURN;
return true;
}

static inline bool trans_modesw_cap(DisasContext *ctx, arg_modesw_cap *a)
{
return do_trans_modesw(ctx, /*to_capmode=*/true);
}

static inline bool trans_modesw_int(DisasContext *ctx, arg_modesw_int *a)
{
return do_trans_modesw(ctx, /*to_capmode=*/false);
}

// Explicit CAP/DDC atomic ops (no unsigned versions):
// Reuses gen_lr_impl, defined in trans_rva.c.inc
static inline bool gen_lr_impl(DisasContext *ctx, TCGv_cap_checked_ptr addr,
Expand Down
9 changes: 9 additions & 0 deletions target/riscv/op_helper_cheri.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,15 @@ void HELPER(cjal)(CPUArchState *env, uint32_t cd, target_ulong target_addr,
0, GETPC());
}

void HELPER(modesw)(CPUArchState *env, int to_capmode)
{
_Static_assert(CAP_FLAGS_ALL_BITS == 1, "Only one flag should exist");
assert(cheri_in_capmode(env) != to_capmode &&
"Should have skipped this call during translate");
CAP_cc(update_flags)(&env->pcc,
to_capmode ? CHERI_FLAG_CAPMODE : CHERI_FLAG_INTMODE);
}

void HELPER(amoswap_cap)(CPUArchState *env, uint32_t dest_reg,
uint32_t addr_reg, uint32_t val_reg)
{
Expand Down
Loading