qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Max Filippov <jcmvbkbc@gmail.com>
To: qemu-devel@nongnu.org
Cc: Max Filippov <jcmvbkbc@gmail.com>
Subject: [Qemu-devel] [RFC 18/28] target-xtensa: implement exceptions
Date: Wed,  4 May 2011 04:59:18 +0400	[thread overview]
Message-ID: <1304470768-16924-18-git-send-email-jcmvbkbc@gmail.com> (raw)
In-Reply-To: <1304470768-16924-1-git-send-email-jcmvbkbc@gmail.com>

- mark privileged opcodes with ring check;
- make debug exception on exception handler entry.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
 target-xtensa/cpu.h       |   91 +++++++++++++++++++++++++++++++++
 target-xtensa/helper.c    |   39 ++++++++++++++-
 target-xtensa/helpers.h   |    2 +
 target-xtensa/op_helper.c |   29 +++++++++++
 target-xtensa/translate.c |  124 +++++++++++++++++++++++++++++++++++++++++++--
 5 files changed, 279 insertions(+), 6 deletions(-)

diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index a12db8f..25041be 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -108,11 +108,86 @@ enum {
 enum {
     SAR = 3,
     SCOMPARE1 = 12,
+    EPC1 = 177,
+    DEPC = 192,
+    EXCSAVE1 = 209,
+    PS = 230,
+    EXCCAUSE = 232,
+    EXCVADDR = 238,
+};
+
+#define PS_INTLEVEL 0xf
+#define PS_INTLEVEL_SHIFT 0
+
+#define PS_EXCM 0x10
+#define PS_UM 0x20
+
+#define PS_RING 0xc0
+#define PS_RING_SHIFT 6
+
+#define PS_OWB 0xf00
+#define PS_OWB_SHIFT 8
+
+#define PS_CALLINC 0x30000
+#define PS_CALLINC_SHIFT 16
+#define PS_CALLINC_LEN 2
+
+#define PS_WOE 0x40000
+
+enum {
+    /* Static vectors */
+    EXC_RESET,
+    EXC_MEMORY_ERROR,
+
+    /* Dynamic vectors */
+    EXC_WINDOW_OVERFLOW4,
+    EXC_WINDOW_UNDERFLOW4,
+    EXC_WINDOW_OVERFLOW8,
+    EXC_WINDOW_UNDERFLOW8,
+    EXC_WINDOW_OVERFLOW12,
+    EXC_WINDOW_UNDERFLOW12,
+    EXC_IRQ,
+    EXC_KERNEL,
+    EXC_USER,
+    EXC_DOUBLE,
+    EXC_MAX
+};
+
+enum {
+    ILLEGAL_INSTRUCTION_CAUSE = 0,
+    SYSCALL_CAUSE,
+    INSTRUCTION_FETCH_ERROR_CAUSE,
+    LOAD_STORE_ERROR_CAUSE,
+    LEVEL1_INTERRUPT_CAUSE,
+    ALLOCA_CAUSE,
+    INTEGER_DIVIE_BY_ZERO_CAUSE,
+    PRIVILEGED_CAUSE = 8,
+    LOAD_STORE_ALIGNMENT_CAUSE,
+
+    INSTR_PIF_DATA_ERROR_CAUSE = 12,
+    LOAD_STORE_PIF_DATA_ERROR_CAUSE,
+    INSTR_PIF_ADDR_ERROR_CAUSE,
+    LOAD_STORE_PIF_ADDR_ERROR_CAUSE,
+
+    INST_TLB_MISS_CAUSE,
+    INST_TLB_MULTI_HIT_CAUSE,
+    INST_FETCH_PRIVILEGE_CAUSE,
+    INST_FETCH_PROHIBITED_CAUSE = 20,
+    LOAD_STORE_TLB_MISS_CAUSE = 24,
+    LOAD_STORE_TLB_MULTI_HIT_CAUSE,
+    LOAD_STORE_PRIVILEGE_CAUSE,
+    LOAD_PROHIBITED_CAUSE = 28,
+    STORE_PROHIBITED_CAUSE,
+
+    COPROCESSOR0_DISABLED = 32,
 };
 
 typedef struct XtensaConfig {
     const char *name;
     uint64_t options;
+    int excm_level;
+    int ndepc;
+    uint32_t exception_vector[EXC_MAX];
 } XtensaConfig;
 
 typedef struct CPUXtensaState {
@@ -122,6 +197,8 @@ typedef struct CPUXtensaState {
     uint32_t sregs[256];
     uint32_t uregs[256];
 
+    int exception_taken;
+
     CPU_COMMON
 } CPUXtensaState;
 
@@ -151,6 +228,20 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
     *flags = 0;
 }
 
+static inline int xtensa_option_enabled(const XtensaConfig *config, int opt)
+{
+    return (config->options & (((uint64_t)1) << (opt))) != 0;
+}
+
+static inline int xtensa_get_cintlevel(CPUState *env)
+{
+    int level = (env->sregs[PS] & PS_INTLEVEL) >> PS_INTLEVEL_SHIFT;
+    if ((env->sregs[PS] & PS_EXCM) && env->config->excm_level > level) {
+        level = env->config->excm_level;
+    }
+    return level;
+}
+
 #include "cpu-all.h"
 
 #endif
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index 6f374d3..e641360 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -36,13 +36,29 @@
 
 void cpu_reset(CPUXtensaState *env)
 {
-    env->pc = 0;
+    env->exception_taken = 0;
+    env->pc = env->config->exception_vector[EXC_RESET];
+    env->sregs[PS] = 0x1f;
 }
 
 static const XtensaConfig core_config[] = {
     {
         .name = "sample-xtensa-core",
         .options = -1,
+        .ndepc = 1,
+        .excm_level = 16,
+        .exception_vector = {
+            [EXC_RESET] = 0x5fff8000,
+            [EXC_WINDOW_OVERFLOW4] = 0x5fff8400,
+            [EXC_WINDOW_UNDERFLOW4] = 0x5fff8440,
+            [EXC_WINDOW_OVERFLOW8] = 0x5fff8480,
+            [EXC_WINDOW_UNDERFLOW8] = 0x5fff84c0,
+            [EXC_WINDOW_OVERFLOW12] = 0x5fff8500,
+            [EXC_WINDOW_UNDERFLOW12] = 0x5fff8540,
+            [EXC_KERNEL] = 0x5fff861c,
+            [EXC_USER] = 0x5fff863c,
+            [EXC_DOUBLE] = 0x5fff865c,
+        },
     },
 };
 
@@ -94,4 +110,25 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 
 void do_interrupt(CPUState *env)
 {
+    switch (env->exception_index) {
+    case EXC_WINDOW_OVERFLOW4:
+    case EXC_WINDOW_UNDERFLOW4:
+    case EXC_WINDOW_OVERFLOW8:
+    case EXC_WINDOW_UNDERFLOW8:
+    case EXC_WINDOW_OVERFLOW12:
+    case EXC_WINDOW_UNDERFLOW12:
+    case EXC_KERNEL:
+    case EXC_USER:
+    case EXC_DOUBLE:
+        if (env->config->exception_vector[env->exception_index]) {
+            env->pc = env->config->exception_vector[env->exception_index];
+            env->exception_taken = 1;
+        } else {
+            printf("%s(pc = %08x) bad exception_index: %d\n",
+                    __func__, env->pc, env->exception_index);
+        }
+        break;
+
+    }
+    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
 }
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
index c298d74..f13e005 100644
--- a/target-xtensa/helpers.h
+++ b/target-xtensa/helpers.h
@@ -1,5 +1,7 @@
 #include "def-helper.h"
 
 DEF_HELPER_1(exception, void, i32)
+DEF_HELPER_2(exception_cause, void, i32, i32)
+DEF_HELPER_3(exception_cause_vaddr, void, i32, i32, i32)
 
 #include "def-helper.h"
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index d1e620c..9bfe493 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -56,3 +56,32 @@ void HELPER(exception)(uint32_t excp)
     env->exception_index = excp;
     cpu_loop_exit();
 }
+
+void HELPER(exception_cause)(uint32_t pc, uint32_t cause)
+{
+    uint32_t vector;
+
+    env->pc = pc;
+    if (env->sregs[PS] & PS_EXCM) {
+        if (env->config->ndepc) {
+            env->sregs[DEPC] = pc;
+        } else {
+            env->sregs[EPC1] = pc;
+        }
+        vector = EXC_DOUBLE;
+    } else {
+        env->sregs[EPC1] = pc;
+        vector = (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL;
+    }
+
+    env->sregs[EXCCAUSE] = cause;
+    env->sregs[PS] |= PS_EXCM;
+
+    HELPER(exception)(vector);
+}
+
+void HELPER(exception_cause_vaddr)(uint32_t pc, uint32_t cause, uint32_t vaddr)
+{
+    env->sregs[EXCVADDR] = vaddr;
+    HELPER(exception_cause)(pc, cause);
+}
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 4b5edc3..faf1adc 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -59,6 +59,12 @@ static TCGv_i32 cpu_UR[256];
 static const char * const sregnames[256] = {
     [SAR] = "SAR",
     [SCOMPARE1] = "SCOMPARE1",
+    [EPC1] = "EPC1",
+    [DEPC] = "DEPC",
+    [EXCSAVE1] = "EXCSAVE1",
+    [PS] = "PS",
+    [EXCCAUSE] = "EXCCAUSE",
+    [EXCVADDR] = "EXCVADDR",
 };
 
 static const char * const uregnames[256] = {
@@ -104,6 +110,11 @@ void xtensa_translate_init(void)
     }
 }
 
+static inline int option_enabled(DisasContext *dc, int opt)
+{
+    return xtensa_option_enabled(dc->config, opt);
+}
+
 static void gen_rsr(TCGv_i32 d, int sr)
 {
     if (sregnames[sr]) {
@@ -137,6 +148,33 @@ static void gen_exception(int excp)
     tcg_temp_free(tmp);
 }
 
+static void gen_exception_cause(DisasContext *dc, uint32_t cause)
+{
+    TCGv_i32 _pc = tcg_const_i32(dc->pc);
+    TCGv_i32 _cause = tcg_const_i32(cause);
+    gen_helper_exception_cause(_pc, _cause);
+    tcg_temp_free(_pc);
+    tcg_temp_free(_cause);
+}
+
+static void gen_check_privilege(DisasContext *dc)
+{
+    if (option_enabled(dc, XTENSA_OPTION_MMU)) {
+        TCGv_i32 tmp = tcg_temp_new_i32();
+        int label = gen_new_label();
+
+        tcg_gen_andi_i32(tmp, cpu_SR[PS], PS_EXCM);
+        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, PS_EXCM, label);
+        tcg_gen_andi_i32(tmp, cpu_SR[PS], PS_RING);
+        tcg_gen_brcondi_i32(TCG_COND_GEU, tmp, 0, label);
+
+        gen_exception_cause(dc, PRIVILEGED_CAUSE);
+
+        gen_set_label(label);
+        tcg_temp_free(tmp);
+    }
+}
+
 static void gen_jump(DisasContext *dc, TCGv dest)
 {
     tcg_gen_mov_i32(cpu_pc, dest);
@@ -263,7 +301,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 case 0: /*SNM0*/
                     switch (CALLX_M) {
                     case 0: /*ILL*/
-                        TBD();
+                        gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
                         break;
 
                     case 1: /*reserved*/
@@ -350,7 +388,52 @@ static void disas_xtensa_insn(DisasContext *dc)
                     break;
 
                 case 3: /*RFEIx*/
-                    TBD();
+                    switch (RRR_T) {
+                    case 0: /*RFETx*/
+                        HAS_OPTION(XTENSA_OPTION_EXCEPTION);
+                        switch (RRR_S) {
+                        case 0: /*RFEx*/
+                            gen_check_privilege(dc);
+                            tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_EXCM);
+                            gen_jump(dc, cpu_SR[EPC1]);
+                            break;
+
+                        case 1: /*RFUEx*/
+                            RESERVED();
+                            break;
+
+                        case 2: /*RFDEx*/
+                            gen_check_privilege(dc);
+                            gen_jump(dc, cpu_SR[
+                                    dc->config->ndepc ? DEPC : EPC1]);
+                            break;
+
+                        case 4: /*RFWOw*/
+                        case 5: /*RFWUw*/
+                            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER);
+                            TBD();
+                            break;
+
+                        default: /*reserved*/
+                            RESERVED();
+                            break;
+                        }
+                        break;
+
+                    case 1: /*RFIx*/
+                        HAS_OPTION(XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT);
+                        TBD();
+                        break;
+
+                    case 2: /*RFME*/
+                        TBD();
+                        break;
+
+                    default: /*reserved*/
+                        RESERVED();
+                        break;
+
+                    }
                     break;
 
                 case 4: /*BREAKx*/
@@ -360,12 +443,28 @@ static void disas_xtensa_insn(DisasContext *dc)
 
                 case 5: /*SYSCALLx*/
                     HAS_OPTION(XTENSA_OPTION_EXCEPTION);
-                    TBD();
+                    switch (RRR_S) {
+                    case 0: /*SYSCALLx*/
+                        gen_exception_cause(dc, SYSCALL_CAUSE);
+                        break;
+
+                    case 1: /*SIMCALL*/
+                        TBD();
+                        break;
+
+                    default:
+                        RESERVED();
+                        break;
+                    }
                     break;
 
                 case 6: /*RSILx*/
                     HAS_OPTION(XTENSA_OPTION_INTERRUPT);
-                    TBD();
+                    gen_check_privilege(dc);
+                    tcg_gen_mov_i32(cpu_R[RRR_T], cpu_SR[PS]);
+                    tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], RRR_S);
+                    tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS],
+                            RRR_S | ~PS_INTLEVEL);
                     break;
 
                 case 7: /*WAITIx*/
@@ -599,6 +698,9 @@ static void disas_xtensa_insn(DisasContext *dc)
             case 6: /*XSR*/
                 {
                     TCGv_i32 tmp = tcg_temp_new_i32();
+                    if (RSR_SR >= 64) {
+                        gen_check_privilege(dc);
+                    }
                     tcg_gen_mov_i32(tmp, cpu_R[RRR_T]);
                     gen_rsr(cpu_R[RRR_T], RSR_SR);
                     gen_wsr(dc, RSR_SR, tmp);
@@ -697,6 +799,9 @@ static void disas_xtensa_insn(DisasContext *dc)
         case 3: /*RST3*/
             switch (_OP2) {
             case 0: /*RSR*/
+                if (RSR_SR >= 64) {
+                    gen_check_privilege(dc);
+                }
                 gen_rsr(cpu_R[RRR_T], RSR_SR);
                 if (!sregnames[RSR_SR]) {
                     TBD();
@@ -704,6 +809,9 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 1: /*WSR*/
+                if (RSR_SR >= 64) {
+                    gen_check_privilege(dc);
+                }
                 gen_wsr(dc, RSR_SR, cpu_R[RRR_T]);
                 if (!sregnames[RSR_SR]) {
                     TBD();
@@ -1344,7 +1452,7 @@ static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 6: /*ILL.Nn*/
-                TBD();
+                gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
                 break;
 
             default: /*reserved*/
@@ -1414,6 +1522,12 @@ static void gen_intermediate_code_internal(
 
     gen_icount_start();
 
+    if (env->singlestep_enabled && env->exception_taken) {
+        env->exception_taken = 0;
+        tcg_gen_movi_i32(cpu_pc, dc.pc);
+        gen_exception(EXCP_DEBUG);
+    }
+
     do {
         check_breakpoint(env, &dc);
 
-- 
1.7.3.4

  parent reply	other threads:[~2011-05-04  1:00 UTC|newest]

Thread overview: 49+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-05-04  0:59 [Qemu-devel] [RFC 01/28] target-xtensa: add target stubs Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 02/28] target-xtensa: add target to the configure script Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 03/28] target-xtensa: implement disas_xtensa_insn Max Filippov
2011-05-04 15:39   ` Richard Henderson
2011-05-04  0:59 ` [Qemu-devel] [RFC 04/28] target-xtensa: implement narrow instructions Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 05/28] target-xtensa: implement RT0 group Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 06/28] target-xtensa: add sample board Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 07/28] target-xtensa: add gdb support Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 08/28] target-xtensa: implement conditional jumps Max Filippov
2011-05-04 15:45   ` Richard Henderson
2011-05-04  0:59 ` [Qemu-devel] [RFC 09/28] target-xtensa: implement JX/RET0/CALLX Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 10/28] target-xtensa: add special and user registers Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 11/28] target-xtensa: implement RST3 group Max Filippov
2011-05-04 15:51   ` Richard Henderson
2011-05-04  0:59 ` [Qemu-devel] [RFC 12/28] target-xtensa: implement shifts (ST1 and RST1 groups) Max Filippov
2011-05-04 16:16   ` Richard Henderson
2011-05-04 16:39     ` Max Filippov
2011-05-04 19:07       ` Richard Henderson
2011-05-05  8:40         ` Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 13/28] target-xtensa: implement LSAI group Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 14/28] target-xtensa: mark reserved and TBD opcodes Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 15/28] target-xtensa: big endian support Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 16/28] target-xtensa: implement SYNC group Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 17/28] target-xtensa: implement CACHE group Max Filippov
2011-05-04  0:59 ` Max Filippov [this message]
2011-05-04 16:33   ` [Qemu-devel] [RFC 18/28] target-xtensa: implement exceptions Richard Henderson
2011-05-04 17:00     ` Richard Henderson
2011-05-09 19:38       ` Max Filippov
2011-05-09 20:32         ` Richard Henderson
2011-05-04  0:59 ` [Qemu-devel] [RFC 19/28] target-xtensa: implement RST2 group (32 bit mul/div/rem) Max Filippov
2011-05-04 19:36   ` Blue Swirl
2011-05-05  8:27     ` Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 20/28] target-xtensa: implement windowed registers Max Filippov
2011-05-04 19:35   ` Blue Swirl
2011-05-04 20:07     ` Richard Henderson
2011-05-04 20:13       ` Blue Swirl
2011-05-04 20:30         ` Richard Henderson
2011-05-04  0:59 ` [Qemu-devel] [RFC 21/28] target-xtensa: implement loop option Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 22/28] target-xtensa: implement extended L32R Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 23/28] target-xtensa: implement unaligned exception option Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 24/28] target-xtensa: implement SIMCALL Max Filippov
2011-05-04 19:48   ` Blue Swirl
2011-05-04 20:31     ` Peter Maydell
2011-05-04  0:59 ` [Qemu-devel] [RFC 25/28] target-xtensa: implement interrupt option Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 26/28] target-xtensa: implement accurate window check Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 27/28] target-xtensa: implement CPENABLE and PRID SRs Max Filippov
2011-05-04  0:59 ` [Qemu-devel] [RFC 28/28] target-xtensa: implement relocatable vectors Max Filippov
2011-05-04  6:04 ` [Qemu-devel] [RFC 01/28] target-xtensa: add target stubs Max Filippov
2011-05-04 19:51 ` Blue Swirl

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1304470768-16924-18-git-send-email-jcmvbkbc@gmail.com \
    --to=jcmvbkbc@gmail.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).