diff --git a/target/arc/translate.c b/target/arc/translate.c index 2db7e5787dc..43d07a7c32e 100644 --- a/target/arc/translate.c +++ b/target/arc/translate.c @@ -456,6 +456,15 @@ static TCGv arc_decode_operand(const struct arc_opcode *opcode, ret = cpu_r[operand.value]; if (operand.value == 63) { tcg_gen_movi_tl(cpu_pcl, ctx->pcl); + } else if (operand.value == 29) { + /* ilink access in user mode raises a privilege violation */ + TCGv cond = tcg_temp_new(); + TCGLabel *cont = gen_new_label(); + tcg_gen_andi_tl(cond, cpu_pstate, STATUS32_U); + tcg_gen_brcondi_tl(TCG_COND_EQ, cond, 0, cont); + tcg_temp_free(cond); + arc_gen_excp(ctx, EXCP_PRIVILEGEV, 0, 0); + gen_set_label(cont); } } else { int64_t limm = operand.value; diff --git a/tests/tcg/arc/generic/check_ilink_usermode.S b/tests/tcg/arc/generic/check_ilink_usermode.S new file mode 100644 index 00000000000..aff0f54200c --- /dev/null +++ b/tests/tcg/arc/generic/check_ilink_usermode.S @@ -0,0 +1,57 @@ +.include "macros.inc" + +.data +.align 4 +return_addr: + .word @fail + +.text + .align 4 + .global EV_PrivilegeV + .type EV_PrivilegeV, @function +EV_PrivilegeV: + ld r0, [@return_addr] + sr r0, [eret] + rtie + +start + +; Test 1 +; ilink change in kernel mode (initial mode) is allowed +; CPU exception not triggered +mov r0, @fail +st r0, [@return_addr] + +mov ilink, 0x91 + + +; Test 2 +; ilink change in user mode not allowed +; CPU exception is triggered +mov r0, @success +st r0, [@return_addr] + +enter_user_mode @usermode + +j @fail + +usermode: + mov ilink, 0x91 + j @fail + +success: + mov r0, 0xdecaf + print "[PASS] " + b @1f + +; If a test fails, it jumps here. Although, for the sake of uniformity, +; the printed output does not say much about which test case failed, +; one can uncomment the print_number line below or set a breakpoint +; here to check the R0 register for the test case number. +fail: + mov r0, 0xbadc0ffe + print "[FAIL] " +1: + print " no ilink in usermode\n" + +end diff --git a/tests/tcg/arc64/check_ilink_usermode.S b/tests/tcg/arc64/check_ilink_usermode.S new file mode 100644 index 00000000000..19dcc829265 --- /dev/null +++ b/tests/tcg/arc64/check_ilink_usermode.S @@ -0,0 +1,57 @@ +.include "macros.inc" + +.data +.align 4 +return_addr: + .word @fail + +.text + .align 4 + .global EV_PrivilegeV + .type EV_PrivilegeV, @function +EV_PrivilegeV: + ld r0, [@return_addr] + sr r0, [eret] + rtie + +start + +; Test 1 +; ilink change in kernel mode (initial mode) is allowed +; CPU exception not triggered +mov r0, @fail +st r0, [@return_addr] + +mov ilink, 0x91 + + +; Test 2 +; ilink change in user mode not allowed +; CPU exception is triggered +mov r0, @success +st r0, [@return_addr] + +enter_user_mode @usermode + +j @fail + +usermode: + mov ilink, 0x91 + j @fail + +success: + mov r0, 0xdecaf + print "[PASS] " + b @1f + +; If a test fails, it jumps here. Although, for the sake of uniformity, +; the printed output does not say much about which test case failed, +; one can uncomment the print_number line below or set a breakpoint +; here to check the R0 register for the test case number. +fail: + mov r0, 0xbadc0ffe + print "[FAIL] " +1: + print " ilink in usermode\n" + +end