From 623a930ec30a75e6d6482ca8208d7bf1ca8d359b Mon Sep 17 00:00:00 2001 From: ths Date: Sun, 28 Oct 2007 19:45:05 +0000 Subject: Implement missing MIPS supervisor mode bits. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3472 c046a42c-6fe2-441c-8c8c-71466251a162 --- cpu-defs.h | 2 +- linux-user/elfload.c | 2 +- target-mips/cpu.h | 26 ++++++++++++++++---------- target-mips/exec.h | 12 ++++-------- target-mips/helper.c | 6 +++--- target-mips/op.c | 10 +++++++--- target-mips/op_helper.c | 18 ++++++++++++------ target-mips/translate.c | 12 +++++++----- 8 files changed, 51 insertions(+), 37 deletions(-) diff --git a/cpu-defs.h b/cpu-defs.h index 86557e442b..8414aca221 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -122,7 +122,7 @@ typedef struct CPUTLBEntry { written */ \ target_ulong mem_write_vaddr; /* target virtual addr at which the \ memory was written */ \ - /* 0 = kernel, 1 = user */ \ + /* The meaning of the MMU modes is defined in the target code. */ \ CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \ struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \ \ diff --git a/linux-user/elfload.c b/linux-user/elfload.c index ab5a74e49a..2d758de204 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -374,7 +374,7 @@ static inline void init_thread(struct target_pt_regs *_regs, struct image_info * static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) { - regs->cp0_status = CP0St_UM; + regs->cp0_status = 2 << CP0St_KSU; regs->cp0_epc = infop->entry; regs->regs[29] = infop->start_stack; } diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 363fcd866c..5fbb90e672 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -107,7 +107,7 @@ struct CPUMIPSFPUContext { #define FP_UNIMPLEMENTED 32 }; -#define NB_MMU_MODES 2 +#define NB_MMU_MODES 3 typedef struct CPUMIPSMVPContext CPUMIPSMVPContext; struct CPUMIPSMVPContext { @@ -285,8 +285,7 @@ struct CPUMIPSState { #define CP0St_KX 7 #define CP0St_SX 6 #define CP0St_UX 5 -#define CP0St_UM 4 -#define CP0St_R0 3 +#define CP0St_KSU 3 #define CP0St_ERL 2 #define CP0St_EXL 1 #define CP0St_IE 0 @@ -418,9 +417,14 @@ struct CPUMIPSState { /* TMASK defines different execution modes */ #define MIPS_HFLAG_TMASK 0x00FF #define MIPS_HFLAG_MODE 0x0007 /* execution modes */ -#define MIPS_HFLAG_UM 0x0001 /* user mode */ -#define MIPS_HFLAG_DM 0x0002 /* Debug mode */ -#define MIPS_HFLAG_SM 0x0004 /* Supervisor mode */ + /* The KSU flags must be the lowest bits in hflags. The flag order + must be the same as defined for CP0 Status. This allows to use + the bits as the value of mmu_idx. */ +#define MIPS_HFLAG_KSU 0x0003 /* kernel/supervisor/user mode mask */ +#define MIPS_HFLAG_UM 0x0002 /* user mode flag */ +#define MIPS_HFLAG_SM 0x0001 /* supervisor mode flag */ +#define MIPS_HFLAG_KM 0x0000 /* kernel mode flag */ +#define MIPS_HFLAG_DM 0x0004 /* Debug mode */ #define MIPS_HFLAG_64 0x0008 /* 64-bit instructions enabled */ #define MIPS_HFLAG_CP0 0x0010 /* CP0 enabled */ #define MIPS_HFLAG_FPU 0x0020 /* FPU enabled */ @@ -489,13 +493,15 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, #define cpu_signal_handler cpu_mips_signal_handler #define cpu_list mips_cpu_list -/* MMU modes definitions */ +/* MMU modes definitions. We carefully match the indices with our + hflags layout. */ #define MMU_MODE0_SUFFIX _kernel -#define MMU_MODE1_SUFFIX _user -#define MMU_USER_IDX 1 +#define MMU_MODE1_SUFFIX _super +#define MMU_MODE2_SUFFIX _user +#define MMU_USER_IDX 2 static inline int cpu_mmu_index (CPUState *env) { - return (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM ? 1 : 0; + return env->hflags & MIPS_HFLAG_KSU; } #include "cpu-all.h" diff --git a/target-mips/exec.h b/target-mips/exec.h index 61c09acb66..529306f3b2 100644 --- a/target-mips/exec.h +++ b/target-mips/exec.h @@ -230,24 +230,20 @@ static always_inline int cpu_halted(CPUState *env) static always_inline void compute_hflags(CPUState *env) { env->hflags &= ~(MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 | - MIPS_HFLAG_FPU | MIPS_HFLAG_UM); + MIPS_HFLAG_FPU | MIPS_HFLAG_KSU); if (!(env->CP0_Status & (1 << CP0St_EXL)) && !(env->CP0_Status & (1 << CP0St_ERL)) && !(env->hflags & MIPS_HFLAG_DM)) { - if (env->CP0_Status & (1 << CP0St_UM)) - env->hflags |= MIPS_HFLAG_UM; - if (env->CP0_Status & (1 << CP0St_R0)) - env->hflags |= MIPS_HFLAG_SM; + env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU; } #if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) - if (!(env->hflags & MIPS_HFLAG_UM) || + if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || (env->CP0_Status & (1 << CP0St_PX)) || (env->CP0_Status & (1 << CP0St_UX))) env->hflags |= MIPS_HFLAG_64; #endif if ((env->CP0_Status & (1 << CP0St_CU0)) || - (!(env->hflags & MIPS_HFLAG_UM) && - !(env->hflags & MIPS_HFLAG_SM))) + !(env->hflags & MIPS_HFLAG_KSU)) env->hflags |= MIPS_HFLAG_CP0; if (env->CP0_Status & (1 << CP0St_CU1)) env->hflags |= MIPS_HFLAG_FPU; diff --git a/target-mips/helper.c b/target-mips/helper.c index 45874d4462..708641c42f 100644 --- a/target-mips/helper.c +++ b/target-mips/helper.c @@ -373,7 +373,7 @@ void do_interrupt (CPUState *env) } enter_debug_mode: env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0; - env->hflags &= ~(MIPS_HFLAG_SM | MIPS_HFLAG_UM); + env->hflags &= ~(MIPS_HFLAG_KSU); /* EJTAG probe trap enable is not implemented... */ if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); @@ -399,7 +399,7 @@ void do_interrupt (CPUState *env) } env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV); env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; - env->hflags &= ~(MIPS_HFLAG_SM | MIPS_HFLAG_UM); + env->hflags &= ~(MIPS_HFLAG_KSU); if (!(env->CP0_Status & (1 << CP0St_EXL))) env->CP0_Cause &= ~(1 << CP0Ca_BD); env->PC[env->current_tc] = (int32_t)0xBFC00000; @@ -501,7 +501,7 @@ void do_interrupt (CPUState *env) } env->CP0_Status |= (1 << CP0St_EXL); env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; - env->hflags &= ~(MIPS_HFLAG_SM | MIPS_HFLAG_UM); + env->hflags &= ~(MIPS_HFLAG_KSU); } env->hflags &= ~MIPS_HFLAG_BMASK; if (env->CP0_Status & (1 << CP0St_BEV)) { diff --git a/target-mips/op.c b/target-mips/op.c index 9e8324d49b..f29134567c 100644 --- a/target-mips/op.c +++ b/target-mips/op.c @@ -286,6 +286,10 @@ void op_store_LO (void) #include "op_mem.c" #undef MEMSUFFIX +#define MEMSUFFIX _super +#include "op_mem.c" +#undef MEMSUFFIX + #define MEMSUFFIX _kernel #include "op_mem.c" #undef MEMSUFFIX @@ -298,7 +302,7 @@ void op_addr_add (void) with Status_UX = 0 should be casted to 32-bit and sign extended. See the MIPS64 PRA manual, section 4.10. */ #if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) - if ((env->hflags & MIPS_HFLAG_UM) && + if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) && !(env->CP0_Status & (1 << CP0St_UX))) T0 = (int64_t)(int32_t)(T0 + T1); else @@ -1269,7 +1273,7 @@ void op_mftc0_status(void) T0 = env->CP0_Status & ~0xf1000018; T0 |= tcstatus & (0xf << CP0TCSt_TCU0); T0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX); - T0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_R0); + T0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU); RETURN(); } @@ -1833,7 +1837,7 @@ void op_mttc0_status(void) env->CP0_Status = T0 & ~0xf1000018; tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (T0 & (0xf << CP0St_CU0)); tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((T0 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX)); - tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((T0 & (0x3 << CP0St_R0)) << (CP0TCSt_TKSU - CP0St_R0)); + tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((T0 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU)); env->CP0_TCStatus[other_tc] = tcstatus; RETURN(); } diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index ff26ab5afa..3c04c55d83 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -315,8 +315,12 @@ void do_mtc0_status_debug(uint32_t old, uint32_t val) old, old & env->CP0_Cause & CP0Ca_IP_mask, val, val & env->CP0_Cause & CP0Ca_IP_mask, env->CP0_Cause); - (env->hflags & MIPS_HFLAG_UM) ? fputs(", UM\n", logfile) - : fputs("\n", logfile); + switch (env->hflags & MIPS_HFLAG_KSU) { + case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break; + case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break; + case MIPS_HFLAG_KM: fputs("\n", logfile); break; + default: cpu_abort(env, "Invalid MMU mode!\n"); break; + } } void do_mtc0_status_irqraise_debug(void) @@ -518,10 +522,12 @@ void debug_post_eret (void) fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC); if (env->hflags & MIPS_HFLAG_DM) fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC); - if (env->hflags & MIPS_HFLAG_UM) - fputs(", UM\n", logfile); - else - fputs("\n", logfile); + switch (env->hflags & MIPS_HFLAG_KSU) { + case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break; + case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break; + case MIPS_HFLAG_KM: fputs("\n", logfile); break; + default: cpu_abort(env, "Invalid MMU mode!\n"); break; + } } void do_pmon (int function) diff --git a/target-mips/translate.c b/target-mips/translate.c index 89fe5fe231..ce0b4dcfe8 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -790,13 +790,15 @@ static always_inline void check_mips_64(DisasContext *ctx) #define op_ldst(name) (*gen_op_##name[ctx->mem_idx])() #define OP_LD_TABLE(width) \ static GenOpFunc *gen_op_l##width[] = { \ - &gen_op_l##width##_user, \ &gen_op_l##width##_kernel, \ + &gen_op_l##width##_super, \ + &gen_op_l##width##_user, \ } #define OP_ST_TABLE(width) \ static GenOpFunc *gen_op_s##width[] = { \ - &gen_op_s##width##_user, \ &gen_op_s##width##_kernel, \ + &gen_op_s##width##_super, \ + &gen_op_s##width##_user, \ } #endif @@ -6494,9 +6496,9 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */ restore_cpu_state(env, &ctx); #if defined(CONFIG_USER_ONLY) - ctx.mem_idx = 0; + ctx.mem_idx = MIPS_HFLAG_UM; #else - ctx.mem_idx = !((ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM); + ctx.mem_idx = ctx.hflags & MIPS_HFLAG_KSU; #endif #ifdef DEBUG_DISAS if (loglevel & CPU_LOG_TB_CPU) { @@ -6507,7 +6509,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, #endif #ifdef MIPS_DEBUG_DISAS if (loglevel & CPU_LOG_TB_IN_ASM) - fprintf(logfile, "\ntb %p super %d cond %04x\n", + fprintf(logfile, "\ntb %p idx %d hflags %04x\n", tb, ctx.mem_idx, ctx.hflags); #endif while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { -- cgit v1.2.1