From patchwork Sun Jul 24 17:10:55 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Max Filippov X-Patchwork-Id: 106556 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 1A648B6F82 for ; Mon, 25 Jul 2011 04:34:26 +1000 (EST) Received: from localhost ([::1]:49505 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ql2F0-0004yG-8C for incoming@patchwork.ozlabs.org; Sun, 24 Jul 2011 13:13:22 -0400 Received: from eggs.gnu.org ([140.186.70.92]:57584) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ql2Eg-00045V-Sf for qemu-devel@nongnu.org; Sun, 24 Jul 2011 13:13:04 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Ql2Ef-0005K9-8a for qemu-devel@nongnu.org; Sun, 24 Jul 2011 13:13:02 -0400 Received: from mail-fx0-f47.google.com ([209.85.161.47]:56785) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Ql2Ef-0004u6-15 for qemu-devel@nongnu.org; Sun, 24 Jul 2011 13:13:01 -0400 Received: by mail-fx0-f47.google.com with SMTP id 11so8353846fxg.34 for ; Sun, 24 Jul 2011 10:13:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=vbf9iTqXpqhNp/H+rHpKVnD/iRhCQNIBT/5v2k84lR0=; b=ouzb1vBY8MkVt+9mWMnlgAxK31AjXMlwGync7W1kwRkVfqJO0glkaAfG5/xSpnJf+o 70PiiaJcBKtBMnel4/ZFHWVI7JJuqL/WGxFfq7oujfA8oi4UqhUI+Yf+gYO+0B7ZwyyW DGhUFGoPEbLFz3AWlu0tDjxgl/6p969iI6+RA= Received: by 10.205.82.197 with SMTP id ad5mr977183bkc.238.1311527580624; Sun, 24 Jul 2011 10:13:00 -0700 (PDT) Received: from octofox.metropolis ([188.134.19.124]) by mx.google.com with ESMTPS id l27sm1071112bkt.50.2011.07.24.10.12.58 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 24 Jul 2011 10:12:59 -0700 (PDT) Received: by octofox.metropolis (sSMTP sendmail emulation); Sun, 24 Jul 2011 21:12:56 +0400 From: Max Filippov To: qemu-devel@nongnu.org Date: Sun, 24 Jul 2011 21:10:55 +0400 Message-Id: <1311527469-12963-18-git-send-email-jcmvbkbc@gmail.com> X-Mailer: git-send-email 1.7.3.4 In-Reply-To: <1311527469-12963-1-git-send-email-jcmvbkbc@gmail.com> References: <1311527469-12963-1-git-send-email-jcmvbkbc@gmail.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 209.85.161.47 Cc: jcmvbkbc@gmail.com Subject: [Qemu-devel] [PATCH v2 17/31] target-xtensa: implement exceptions X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org - mark privileged opcodes with ring check; - make debug exception on exception handler entry. Signed-off-by: Max Filippov --- 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 a5f62b2..6838df2 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 bc186af..43ff111 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 dfe9a75..214d294 100644 --- a/target-xtensa/op_helper.c +++ b/target-xtensa/op_helper.c @@ -58,6 +58,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 729002b..1fe212d 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);