Implement missing MIPS supervisor mode bits.

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3472 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
ths 2007-10-28 19:45:05 +00:00
parent 8e129e0748
commit 623a930ec3
8 changed files with 51 additions and 37 deletions

View File

@ -122,7 +122,7 @@ typedef struct CPUTLBEntry {
written */ \ written */ \
target_ulong mem_write_vaddr; /* target virtual addr at which the \ target_ulong mem_write_vaddr; /* target virtual addr at which the \
memory was written */ \ 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]; \ CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \
struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \ struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \
\ \

View File

@ -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) 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->cp0_epc = infop->entry;
regs->regs[29] = infop->start_stack; regs->regs[29] = infop->start_stack;
} }

View File

@ -107,7 +107,7 @@ struct CPUMIPSFPUContext {
#define FP_UNIMPLEMENTED 32 #define FP_UNIMPLEMENTED 32
}; };
#define NB_MMU_MODES 2 #define NB_MMU_MODES 3
typedef struct CPUMIPSMVPContext CPUMIPSMVPContext; typedef struct CPUMIPSMVPContext CPUMIPSMVPContext;
struct CPUMIPSMVPContext { struct CPUMIPSMVPContext {
@ -285,8 +285,7 @@ struct CPUMIPSState {
#define CP0St_KX 7 #define CP0St_KX 7
#define CP0St_SX 6 #define CP0St_SX 6
#define CP0St_UX 5 #define CP0St_UX 5
#define CP0St_UM 4 #define CP0St_KSU 3
#define CP0St_R0 3
#define CP0St_ERL 2 #define CP0St_ERL 2
#define CP0St_EXL 1 #define CP0St_EXL 1
#define CP0St_IE 0 #define CP0St_IE 0
@ -418,9 +417,14 @@ struct CPUMIPSState {
/* TMASK defines different execution modes */ /* TMASK defines different execution modes */
#define MIPS_HFLAG_TMASK 0x00FF #define MIPS_HFLAG_TMASK 0x00FF
#define MIPS_HFLAG_MODE 0x0007 /* execution modes */ #define MIPS_HFLAG_MODE 0x0007 /* execution modes */
#define MIPS_HFLAG_UM 0x0001 /* user mode */ /* The KSU flags must be the lowest bits in hflags. The flag order
#define MIPS_HFLAG_DM 0x0002 /* Debug mode */ must be the same as defined for CP0 Status. This allows to use
#define MIPS_HFLAG_SM 0x0004 /* Supervisor mode */ 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_64 0x0008 /* 64-bit instructions enabled */
#define MIPS_HFLAG_CP0 0x0010 /* CP0 enabled */ #define MIPS_HFLAG_CP0 0x0010 /* CP0 enabled */
#define MIPS_HFLAG_FPU 0x0020 /* FPU 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_signal_handler cpu_mips_signal_handler
#define cpu_list mips_cpu_list #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_MODE0_SUFFIX _kernel
#define MMU_MODE1_SUFFIX _user #define MMU_MODE1_SUFFIX _super
#define MMU_USER_IDX 1 #define MMU_MODE2_SUFFIX _user
#define MMU_USER_IDX 2
static inline int cpu_mmu_index (CPUState *env) 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" #include "cpu-all.h"

View File

@ -230,24 +230,20 @@ static always_inline int cpu_halted(CPUState *env)
static always_inline void compute_hflags(CPUState *env) static always_inline void compute_hflags(CPUState *env)
{ {
env->hflags &= ~(MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 | 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)) && if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
!(env->CP0_Status & (1 << CP0St_ERL)) && !(env->CP0_Status & (1 << CP0St_ERL)) &&
!(env->hflags & MIPS_HFLAG_DM)) { !(env->hflags & MIPS_HFLAG_DM)) {
if (env->CP0_Status & (1 << CP0St_UM)) env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU;
env->hflags |= MIPS_HFLAG_UM;
if (env->CP0_Status & (1 << CP0St_R0))
env->hflags |= MIPS_HFLAG_SM;
} }
#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) #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_PX)) ||
(env->CP0_Status & (1 << CP0St_UX))) (env->CP0_Status & (1 << CP0St_UX)))
env->hflags |= MIPS_HFLAG_64; env->hflags |= MIPS_HFLAG_64;
#endif #endif
if ((env->CP0_Status & (1 << CP0St_CU0)) || if ((env->CP0_Status & (1 << CP0St_CU0)) ||
(!(env->hflags & MIPS_HFLAG_UM) && !(env->hflags & MIPS_HFLAG_KSU))
!(env->hflags & MIPS_HFLAG_SM)))
env->hflags |= MIPS_HFLAG_CP0; env->hflags |= MIPS_HFLAG_CP0;
if (env->CP0_Status & (1 << CP0St_CU1)) if (env->CP0_Status & (1 << CP0St_CU1))
env->hflags |= MIPS_HFLAG_FPU; env->hflags |= MIPS_HFLAG_FPU;

View File

@ -373,7 +373,7 @@ void do_interrupt (CPUState *env)
} }
enter_debug_mode: enter_debug_mode:
env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0; 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... */ /* EJTAG probe trap enable is not implemented... */
if (!(env->CP0_Status & (1 << CP0St_EXL))) if (!(env->CP0_Status & (1 << CP0St_EXL)))
env->CP0_Cause &= ~(1 << CP0Ca_BD); 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->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; 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))) if (!(env->CP0_Status & (1 << CP0St_EXL)))
env->CP0_Cause &= ~(1 << CP0Ca_BD); env->CP0_Cause &= ~(1 << CP0Ca_BD);
env->PC[env->current_tc] = (int32_t)0xBFC00000; env->PC[env->current_tc] = (int32_t)0xBFC00000;
@ -501,7 +501,7 @@ void do_interrupt (CPUState *env)
} }
env->CP0_Status |= (1 << CP0St_EXL); env->CP0_Status |= (1 << CP0St_EXL);
env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0; 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; env->hflags &= ~MIPS_HFLAG_BMASK;
if (env->CP0_Status & (1 << CP0St_BEV)) { if (env->CP0_Status & (1 << CP0St_BEV)) {

View File

@ -286,6 +286,10 @@ void op_store_LO (void)
#include "op_mem.c" #include "op_mem.c"
#undef MEMSUFFIX #undef MEMSUFFIX
#define MEMSUFFIX _super
#include "op_mem.c"
#undef MEMSUFFIX
#define MEMSUFFIX _kernel #define MEMSUFFIX _kernel
#include "op_mem.c" #include "op_mem.c"
#undef MEMSUFFIX #undef MEMSUFFIX
@ -298,7 +302,7 @@ void op_addr_add (void)
with Status_UX = 0 should be casted to 32-bit and sign extended. with Status_UX = 0 should be casted to 32-bit and sign extended.
See the MIPS64 PRA manual, section 4.10. */ See the MIPS64 PRA manual, section 4.10. */
#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64) #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))) !(env->CP0_Status & (1 << CP0St_UX)))
T0 = (int64_t)(int32_t)(T0 + T1); T0 = (int64_t)(int32_t)(T0 + T1);
else else
@ -1269,7 +1273,7 @@ void op_mftc0_status(void)
T0 = env->CP0_Status & ~0xf1000018; T0 = env->CP0_Status & ~0xf1000018;
T0 |= tcstatus & (0xf << CP0TCSt_TCU0); T0 |= tcstatus & (0xf << CP0TCSt_TCU0);
T0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX); 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(); RETURN();
} }
@ -1833,7 +1837,7 @@ void op_mttc0_status(void)
env->CP0_Status = T0 & ~0xf1000018; env->CP0_Status = T0 & ~0xf1000018;
tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (T0 & (0xf << CP0St_CU0)); tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (T0 & (0xf << CP0St_CU0));
tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((T0 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX)); 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; env->CP0_TCStatus[other_tc] = tcstatus;
RETURN(); RETURN();
} }

View File

@ -315,8 +315,12 @@ void do_mtc0_status_debug(uint32_t old, uint32_t val)
old, old & env->CP0_Cause & CP0Ca_IP_mask, old, old & env->CP0_Cause & CP0Ca_IP_mask,
val, val & env->CP0_Cause & CP0Ca_IP_mask, val, val & env->CP0_Cause & CP0Ca_IP_mask,
env->CP0_Cause); env->CP0_Cause);
(env->hflags & MIPS_HFLAG_UM) ? fputs(", UM\n", logfile) switch (env->hflags & MIPS_HFLAG_KSU) {
: fputs("\n", logfile); 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) 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); fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
if (env->hflags & MIPS_HFLAG_DM) if (env->hflags & MIPS_HFLAG_DM)
fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC); fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
if (env->hflags & MIPS_HFLAG_UM) switch (env->hflags & MIPS_HFLAG_KSU) {
fputs(", UM\n", logfile); case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break;
else case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break;
fputs("\n", logfile); case MIPS_HFLAG_KM: fputs("\n", logfile); break;
default: cpu_abort(env, "Invalid MMU mode!\n"); break;
}
} }
void do_pmon (int function) void do_pmon (int function)

View File

@ -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_ldst(name) (*gen_op_##name[ctx->mem_idx])()
#define OP_LD_TABLE(width) \ #define OP_LD_TABLE(width) \
static GenOpFunc *gen_op_l##width[] = { \ static GenOpFunc *gen_op_l##width[] = { \
&gen_op_l##width##_user, \
&gen_op_l##width##_kernel, \ &gen_op_l##width##_kernel, \
&gen_op_l##width##_super, \
&gen_op_l##width##_user, \
} }
#define OP_ST_TABLE(width) \ #define OP_ST_TABLE(width) \
static GenOpFunc *gen_op_s##width[] = { \ static GenOpFunc *gen_op_s##width[] = { \
&gen_op_s##width##_user, \
&gen_op_s##width##_kernel, \ &gen_op_s##width##_kernel, \
&gen_op_s##width##_super, \
&gen_op_s##width##_user, \
} }
#endif #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? */ ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */
restore_cpu_state(env, &ctx); restore_cpu_state(env, &ctx);
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
ctx.mem_idx = 0; ctx.mem_idx = MIPS_HFLAG_UM;
#else #else
ctx.mem_idx = !((ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM); ctx.mem_idx = ctx.hflags & MIPS_HFLAG_KSU;
#endif #endif
#ifdef DEBUG_DISAS #ifdef DEBUG_DISAS
if (loglevel & CPU_LOG_TB_CPU) { if (loglevel & CPU_LOG_TB_CPU) {
@ -6507,7 +6509,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
#endif #endif
#ifdef MIPS_DEBUG_DISAS #ifdef MIPS_DEBUG_DISAS
if (loglevel & CPU_LOG_TB_IN_ASM) 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); tb, ctx.mem_idx, ctx.hflags);
#endif #endif
while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) { while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {