Patchwork [v4,17/32] target-xtensa: implement exceptions

login
register
mail settings
Submitter Max Filippov
Date Sept. 1, 2011, 8:45 p.m.
Message ID <1314909960-31738-18-git-send-email-jcmvbkbc@gmail.com>
Download mbox | patch
Permalink /patch/112991/
State New
Headers show

Comments

Max Filippov - Sept. 1, 2011, 8:45 p.m.
- mark privileged opcodes with ring check;
- make debug exception on exception handler entry.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
---
 cpu-exec.c                |    6 +++
 target-xtensa/cpu.h       |   67 ++++++++++++++++++++++++++++
 target-xtensa/helper.c    |   37 +++++++++++++++-
 target-xtensa/helpers.h   |    2 +
 target-xtensa/op_helper.c |   29 ++++++++++++
 target-xtensa/translate.c |  107 ++++++++++++++++++++++++++++++++++++++++++--
 6 files changed, 242 insertions(+), 6 deletions(-)
Blue Swirl - Sept. 4, 2011, 6:22 p.m.
On Thu, Sep 1, 2011 at 8:45 PM, Max Filippov <jcmvbkbc@gmail.com> wrote:
> - mark privileged opcodes with ring check;
> - make debug exception on exception handler entry.
>
> Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
> ---
>  cpu-exec.c                |    6 +++
>  target-xtensa/cpu.h       |   67 ++++++++++++++++++++++++++++
>  target-xtensa/helper.c    |   37 +++++++++++++++-
>  target-xtensa/helpers.h   |    2 +
>  target-xtensa/op_helper.c |   29 ++++++++++++
>  target-xtensa/translate.c |  107 ++++++++++++++++++++++++++++++++++++++++++--
>  6 files changed, 242 insertions(+), 6 deletions(-)
>
> diff --git a/cpu-exec.c b/cpu-exec.c
> index 3fce033..2fc37d8 100644
> --- a/cpu-exec.c
> +++ b/cpu-exec.c
> @@ -488,6 +488,12 @@ int cpu_exec(CPUState *env)
>                         do_interrupt(env);
>                         next_tb = 0;
>                     }
> +#elif defined(TARGET_XTENSA)
> +                    if (interrupt_request & CPU_INTERRUPT_HARD) {
> +                        env->exception_index = EXC_IRQ;
> +                        do_interrupt(env);
> +                        next_tb = 0;
> +                    }
>  #endif
>                    /* Don't use the cached interrupt_request value,
>                       do_interrupt may have updated the EXITTB flag. */
> diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
> index 939222c..cae6637 100644
> --- a/target-xtensa/cpu.h
> +++ b/target-xtensa/cpu.h
> @@ -108,7 +108,12 @@ enum {
>  enum {
>     SAR = 3,
>     SCOMPARE1 = 12,
> +    EPC1 = 177,
> +    DEPC = 192,
> +    EXCSAVE1 = 209,
>     PS = 230,
> +    EXCCAUSE = 232,
> +    EXCVADDR = 238,
>  };
>
>  #define PS_INTLEVEL 0xf
> @@ -129,9 +134,60 @@ enum {
>
>  #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_DIVIDE_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 {
> @@ -141,6 +197,8 @@ typedef struct CPUXtensaState {
>     uint32_t sregs[256];
>     uint32_t uregs[256];
>
> +    int exception_taken;
> +
>     CPU_COMMON
>  } CPUXtensaState;
>
> @@ -164,6 +222,15 @@ static inline bool xtensa_option_enabled(const XtensaConfig *config, int opt)
>     return (config->options & XTENSA_OPTION_BIT(opt)) != 0;
>  }
>
> +static inline int xtensa_get_cintlevel(const 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;
> +}
> +
>  static inline int xtensa_get_ring(const CPUState *env)
>  {
>     if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
> diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
> index 83b8a04..44ebb9f 100644
> --- a/target-xtensa/helper.c
> +++ b/target-xtensa/helper.c
> @@ -36,7 +36,8 @@
>
>  void cpu_reset(CPUXtensaState *env)
>  {
> -    env->pc = 0;
> +    env->exception_taken = 0;
> +    env->pc = env->config->exception_vector[EXC_RESET];
>     env->sregs[PS] = 0x1f;
>  }
>
> @@ -44,6 +45,20 @@ 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 +109,24 @@ 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 {
> +            qemu_log("%s(pc = %08x) bad exception_index: %d\n",
> +                    __func__, env->pc, env->exception_index);
> +        }
> +        break;
> +
> +    }
>  }
> diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
> index 976c8d8..6329c43 100644
> --- a/target-xtensa/helpers.h
> +++ b/target-xtensa/helpers.h
> @@ -1,6 +1,8 @@
>  #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)
>  DEF_HELPER_1(nsa, i32, i32)
>  DEF_HELPER_1(nsau, i32, i32)
>
> diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
> index c1cfd2e..794a834 100644
> --- a/target-xtensa/op_helper.c
> +++ b/target-xtensa/op_helper.c
> @@ -59,6 +59,35 @@ void HELPER(exception)(uint32_t excp)
>     cpu_loop_exit(env);
>  }
>
> +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);
> +}
> +
>  uint32_t HELPER(nsa)(uint32_t v)
>  {
>     if (v & 0x80000000) {
> diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
> index b6d0210..4c9db9e 100644
> --- a/target-xtensa/translate.c
> +++ b/target-xtensa/translate.c
> @@ -67,7 +67,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] = {
> @@ -165,6 +170,22 @@ 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);

Please don't use identifiers starting with underscore.

> +    gen_helper_exception_cause(_pc, _cause);
> +    tcg_temp_free(_pc);
> +    tcg_temp_free(_cause);
> +}
> +
> +static void gen_check_privilege(DisasContext *dc)
> +{
> +    if (dc->cring) {
> +        gen_exception_cause(dc, PRIVILEGED_CAUSE);
> +    }
> +}
> +
>  static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot)
>  {
>     tcg_gen_mov_i32(cpu_pc, dest);
> @@ -392,7 +413,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*/
> @@ -479,7 +500,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*/
> @@ -489,12 +555,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*/
> @@ -691,6 +773,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(dc, cpu_R[RRR_T], RSR_SR);
>                     gen_wsr(dc, RSR_SR, tmp);
> @@ -799,6 +884,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(dc, cpu_R[RRR_T], RSR_SR);
>                 if (!sregnames[RSR_SR]) {
>                     TBD();
> @@ -806,6 +894,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();
> @@ -1421,7 +1512,7 @@ static void disas_xtensa_insn(DisasContext *dc)
>                 break;
>
>             case 6: /*ILL.Nn*/
> -                TBD();
> +                gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
>                 break;
>
>             default: /*reserved*/
> @@ -1493,6 +1584,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.6
>
>
>

Patch

diff --git a/cpu-exec.c b/cpu-exec.c
index 3fce033..2fc37d8 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -488,6 +488,12 @@  int cpu_exec(CPUState *env)
                         do_interrupt(env);
                         next_tb = 0;
                     }
+#elif defined(TARGET_XTENSA)
+                    if (interrupt_request & CPU_INTERRUPT_HARD) {
+                        env->exception_index = EXC_IRQ;
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
 #endif
                    /* Don't use the cached interrupt_request value,
                       do_interrupt may have updated the EXITTB flag. */
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 939222c..cae6637 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -108,7 +108,12 @@  enum {
 enum {
     SAR = 3,
     SCOMPARE1 = 12,
+    EPC1 = 177,
+    DEPC = 192,
+    EXCSAVE1 = 209,
     PS = 230,
+    EXCCAUSE = 232,
+    EXCVADDR = 238,
 };
 
 #define PS_INTLEVEL 0xf
@@ -129,9 +134,60 @@  enum {
 
 #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_DIVIDE_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 {
@@ -141,6 +197,8 @@  typedef struct CPUXtensaState {
     uint32_t sregs[256];
     uint32_t uregs[256];
 
+    int exception_taken;
+
     CPU_COMMON
 } CPUXtensaState;
 
@@ -164,6 +222,15 @@  static inline bool xtensa_option_enabled(const XtensaConfig *config, int opt)
     return (config->options & XTENSA_OPTION_BIT(opt)) != 0;
 }
 
+static inline int xtensa_get_cintlevel(const 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;
+}
+
 static inline int xtensa_get_ring(const CPUState *env)
 {
     if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) {
diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c
index 83b8a04..44ebb9f 100644
--- a/target-xtensa/helper.c
+++ b/target-xtensa/helper.c
@@ -36,7 +36,8 @@ 
 
 void cpu_reset(CPUXtensaState *env)
 {
-    env->pc = 0;
+    env->exception_taken = 0;
+    env->pc = env->config->exception_vector[EXC_RESET];
     env->sregs[PS] = 0x1f;
 }
 
@@ -44,6 +45,20 @@  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 +109,24 @@  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 {
+            qemu_log("%s(pc = %08x) bad exception_index: %d\n",
+                    __func__, env->pc, env->exception_index);
+        }
+        break;
+
+    }
 }
diff --git a/target-xtensa/helpers.h b/target-xtensa/helpers.h
index 976c8d8..6329c43 100644
--- a/target-xtensa/helpers.h
+++ b/target-xtensa/helpers.h
@@ -1,6 +1,8 @@ 
 #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)
 DEF_HELPER_1(nsa, i32, i32)
 DEF_HELPER_1(nsau, i32, i32)
 
diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c
index c1cfd2e..794a834 100644
--- a/target-xtensa/op_helper.c
+++ b/target-xtensa/op_helper.c
@@ -59,6 +59,35 @@  void HELPER(exception)(uint32_t excp)
     cpu_loop_exit(env);
 }
 
+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);
+}
+
 uint32_t HELPER(nsa)(uint32_t v)
 {
     if (v & 0x80000000) {
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index b6d0210..4c9db9e 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -67,7 +67,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] = {
@@ -165,6 +170,22 @@  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 (dc->cring) {
+        gen_exception_cause(dc, PRIVILEGED_CAUSE);
+    }
+}
+
 static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot)
 {
     tcg_gen_mov_i32(cpu_pc, dest);
@@ -392,7 +413,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*/
@@ -479,7 +500,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*/
@@ -489,12 +555,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*/
@@ -691,6 +773,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(dc, cpu_R[RRR_T], RSR_SR);
                     gen_wsr(dc, RSR_SR, tmp);
@@ -799,6 +884,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(dc, cpu_R[RRR_T], RSR_SR);
                 if (!sregnames[RSR_SR]) {
                     TBD();
@@ -806,6 +894,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();
@@ -1421,7 +1512,7 @@  static void disas_xtensa_insn(DisasContext *dc)
                 break;
 
             case 6: /*ILL.Nn*/
-                TBD();
+                gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE);
                 break;
 
             default: /*reserved*/
@@ -1493,6 +1584,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);