diff options
author | Michael Pavone <pavone@retrodev.com> | 2016-04-27 23:11:24 -0700 |
---|---|---|
committer | Michael Pavone <pavone@retrodev.com> | 2016-04-27 23:11:24 -0700 |
commit | 3bdd7df1517185e8a9ea9841f0d999b90ee07960 (patch) | |
tree | 7267f4930df8f951e6ca9eb84430a1d2cb4033c1 | |
parent | 77a5b1309cb7a510cf4ec659ee8aa34d605f92b1 (diff) |
Implement privelege violation exceptions
-rw-r--r-- | m68k_core.c | 4 | ||||
-rw-r--r-- | m68k_core_x86.c | 30 | ||||
-rw-r--r-- | m68k_internal.h | 1 |
3 files changed, 29 insertions, 6 deletions
diff --git a/m68k_core.c b/m68k_core.c index 69cd94d..16614a7 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -350,6 +350,7 @@ void translate_m68k_illegal(m68k_options *opts, m68kinst *inst) void translate_m68k_move_usp(m68k_options *opts, m68kinst *inst) { + m68k_trap_if_not_supervisor(opts, inst); cycles(&opts->gen, BUS); int8_t reg; if (inst->src.addr_mode == MODE_UNUSED) { @@ -532,8 +533,9 @@ void translate_m68k_reset(m68k_options *opts, m68kinst *inst) void translate_m68k_rte(m68k_options *opts, m68kinst *inst) { + m68k_trap_if_not_supervisor(opts, inst); + code_info *code = &opts->gen.code; - //TODO: Trap if not in system mode //Read saved SR areg_to_native(opts, 7, opts->gen.scratch1); call(code, opts->read_16); diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 9c082e5..82cb954 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -1970,11 +1970,28 @@ void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos #define BIT_SUPERVISOR 5 +void m68k_trap_if_not_supervisor(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + //check supervisor bit in SR and trap if not in supervisor mode + bt_irdisp(code, BIT_SUPERVISOR, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + code_ptr in_sup_mode = code->cur + 1; + jcc(code, CC_C, code->cur + 2); + + ldi_native(opts, VECTOR_PRIV_VIOLATION, opts->gen.scratch2); + ldi_native(opts, inst->address, opts->gen.scratch1); + jmp(code, opts->trap); + + *in_sup_mode = code->cur - (in_sup_mode + 1); +} + void translate_m68k_andi_ori_ccr_sr(m68k_options *opts, m68kinst *inst) { code_info *code = &opts->gen.code; + if (inst->op == M68K_ANDI_SR || inst->op == M68K_ORI_SR) { + m68k_trap_if_not_supervisor(opts, inst); + } cycles(&opts->gen, 20); - //TODO: If ANDI to SR, trap if not in supervisor mode uint32_t flag_mask = 0; uint32_t base_flag = inst->op == M68K_ANDI_SR || inst->op == M68K_ANDI_CCR ? X0 : X1; for (int i = 0; i < 5; i++) @@ -2009,8 +2026,10 @@ void translate_m68k_andi_ori_ccr_sr(m68k_options *opts, m68kinst *inst) void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst) { code_info *code = &opts->gen.code; + if (inst->op == M68K_EORI_SR) { + m68k_trap_if_not_supervisor(opts, inst); + } cycles(&opts->gen, 20); - //TODO: If ANDI to SR, trap if not in supervisor mode if (inst->src.params.immed & 0x1) { xor_flag(opts, 1, FLAG_C); } @@ -2049,7 +2068,9 @@ void set_all_flags(m68k_options *opts, uint8_t flags) void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) { code_info *code = &opts->gen.code; - //TODO: Privilege check for MOVE to SR + if (inst->op == M68K_MOVE_SR) { + m68k_trap_if_not_supervisor(opts, inst); + } if (src_op->mode == MODE_IMMED) { set_all_flags(opts, src_op->disp); if (inst->op == M68K_MOVE_SR) { @@ -2085,7 +2106,7 @@ void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src void translate_m68k_stop(m68k_options *opts, m68kinst *inst) { - //TODO: Trap if not in system mode + m68k_trap_if_not_supervisor(opts, inst); //manual says 4 cycles, but it has to be at least 8 since it's a 2-word instruction //possibly even 12 since that's how long MOVE to SR takes //On further thought prefetch + the fact that this stops the CPU may make @@ -2189,7 +2210,6 @@ void translate_m68k_odd(m68k_options *opts, m68kinst *inst) void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) { code_info *code = &opts->gen.code; - //TODO: Trap if not in system mode call(code, opts->get_sr); if (dst_op->mode == MODE_REG_DIRECT) { mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_W); diff --git a/m68k_internal.h b/m68k_internal.h index 4b32e4a..4a3acf3 100644 --- a/m68k_internal.h +++ b/m68k_internal.h @@ -34,6 +34,7 @@ void nop_fill_or_jmp_next(code_info *code, code_ptr old_end, code_ptr next_inst) void check_user_mode_swap_ssp_usp(m68k_options *opts); void m68k_set_last_prefetch(m68k_options *opts, uint32_t address); void translate_m68k_odd(m68k_options *opts, m68kinst *inst); +void m68k_trap_if_not_supervisor(m68k_options *opts, m68kinst *inst); //functions implemented in m68k_core.c int8_t native_reg(m68k_op_info * op, m68k_options * opts); |