diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h index e9699cfdc4..51cbd4c328 100644 --- a/target-sparc/cpu.h +++ b/target-sparc/cpu.h @@ -98,6 +98,8 @@ #define PS_AG (1<<0) #define FPRS_FEF (1<<2) + +#define HS_PRIV (1<<2) #endif /* Fcc */ @@ -166,7 +168,11 @@ typedef struct sparc_def_t sparc_def_t; +#if !defined(TARGET_SPARC64) #define NB_MMU_MODES 2 +#else +#define NB_MMU_MODES 3 +#endif typedef struct CPUSPARCState { target_ulong gregs[8]; /* general registers */ @@ -323,12 +329,37 @@ void cpu_check_irqs(CPUSPARCState *env); #define cpu_list sparc_cpu_list /* MMU modes definitions */ -#define MMU_MODE0_SUFFIX _kernel -#define MMU_MODE1_SUFFIX _user -#define MMU_USER_IDX 1 +#define MMU_MODE0_SUFFIX _user +#define MMU_MODE1_SUFFIX _kernel +#ifdef TARGET_SPARC64 +#define MMU_MODE2_SUFFIX _hypv +#endif +#define MMU_USER_IDX 0 static inline int cpu_mmu_index (CPUState *env) { - return env->psrs == 0 ? 1 : 0; +#if defined(CONFIG_USER_ONLY) + return 0; +#elif !defined(TARGET_SPARC64) + return env->psrs; +#else + if (!env->psrs) + return 0; + else if ((env->hpstate & HS_PRIV) == 0) + return 1; + else + return 2; +#endif +} + +static inline int cpu_fpu_enabled(CPUState *env) +{ +#if defined(CONFIG_USER_ONLY) + return 1; +#elif !defined(TARGET_SPARC64) + return env->psref; +#else + return ((env->pstate & PS_PEF) != 0) && ((env->fprs & FPRS_FEF) != 0); +#endif } #include "cpu-all.h" diff --git a/target-sparc/op.c b/target-sparc/op.c index e12347df1f..80864c3bb8 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1023,6 +1023,11 @@ void OPPROTO op_sra(void) #define MEMSUFFIX _kernel #include "op_mem.h" + +#ifdef TARGET_SPARC64 +#define MEMSUFFIX _hypv +#include "op_mem.h" +#endif #endif void OPPROTO op_ldfsr(void) diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index ac88b55d52..28c18b4036 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -789,7 +789,8 @@ void helper_ld_asi(int asi, int size, int sign) { uint64_t ret = 0; - if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) + if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) + || (asi >= 0x30 && asi < 0x80) && !(env->hpstate & HS_PRIV)) raise_exception(TT_PRIV_ACT); switch (asi) { @@ -800,20 +801,38 @@ void helper_ld_asi(int asi, int size, int sign) case 0x88: // Primary LE case 0x8a: // Primary no-fault LE if ((asi & 0x80) && (env->pstate & PS_PRIV)) { - switch(size) { - case 1: - ret = ldub_kernel(T0); - break; - case 2: - ret = lduw_kernel(T0 & ~1); - break; - case 4: - ret = ldl_kernel(T0 & ~3); - break; - default: - case 8: - ret = ldq_kernel(T0 & ~7); - break; + if (env->hpstate & HS_PRIV) { + switch(size) { + case 1: + ret = ldub_hypv(T0); + break; + case 2: + ret = lduw_hypv(T0 & ~1); + break; + case 4: + ret = ldl_hypv(T0 & ~3); + break; + default: + case 8: + ret = ldq_hypv(T0 & ~7); + break; + } + } else { + switch(size) { + case 1: + ret = ldub_kernel(T0); + break; + case 2: + ret = lduw_kernel(T0 & ~1); + break; + case 4: + ret = ldl_kernel(T0 & ~3); + break; + default: + case 8: + ret = ldq_kernel(T0 & ~7); + break; + } } } else { switch(size) { @@ -987,7 +1006,8 @@ void helper_ld_asi(int asi, int size, int sign) void helper_st_asi(int asi, int size) { - if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) + if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) + || (asi >= 0x30 && asi < 0x80) && !(env->hpstate & HS_PRIV)) raise_exception(TT_PRIV_ACT); /* Convert to little endian */ @@ -1022,20 +1042,38 @@ void helper_st_asi(int asi, int size) case 0x80: // Primary case 0x88: // Primary LE if ((asi & 0x80) && (env->pstate & PS_PRIV)) { - switch(size) { - case 1: - stb_kernel(T0, T1); - break; - case 2: - stw_kernel(T0 & ~1, T1); - break; - case 4: - stl_kernel(T0 & ~3, T1); - break; - case 8: - default: - stq_kernel(T0 & ~7, T1); - break; + if (env->hpstate & HS_PRIV) { + switch(size) { + case 1: + stb_hypv(T0, T1); + break; + case 2: + stw_hypv(T0 & ~1, T1); + break; + case 4: + stl_hypv(T0 & ~3, T1); + break; + case 8: + default: + stq_hypv(T0 & ~7, T1); + break; + } + } else { + switch(size) { + case 1: + stb_kernel(T0, T1); + break; + case 2: + stw_kernel(T0 & ~1, T1); + break; + case 4: + stl_kernel(T0 & ~3, T1); + break; + case 8: + default: + stq_kernel(T0 & ~7, T1); + break; + } } } else { switch(size) { diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 046dc0b2e1..d0dc511073 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -361,17 +361,24 @@ GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf); #endif #define gen_op_ldst(name) gen_op_##name##_raw() #else -#define supervisor(dc) (dc->mem_idx == 1) +#define supervisor(dc) (dc->mem_idx >= 1) #ifdef TARGET_SPARC64 #define hypervisor(dc) (dc->mem_idx == 2) -#endif -#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() +#define OP_LD_TABLE(width) \ + static GenOpFunc * const gen_op_##width[] = { \ + &gen_op_##width##_user, \ + &gen_op_##width##_kernel, \ + &gen_op_##width##_hypv, \ + }; +#else #define OP_LD_TABLE(width) \ static GenOpFunc * const gen_op_##width[] = { \ &gen_op_##width##_user, \ &gen_op_##width##_kernel, \ }; #endif +#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])() +#endif #ifndef CONFIG_USER_ONLY OP_LD_TABLE(ld); @@ -3378,17 +3385,8 @@ static inline int gen_intermediate_code_internal(TranslationBlock * tb, dc->pc = pc_start; last_pc = dc->pc; dc->npc = (target_ulong) tb->cs_base; -#if defined(CONFIG_USER_ONLY) - dc->mem_idx = 0; - dc->fpu_enabled = 1; -#else - dc->mem_idx = ((env->psrs) != 0); -#ifdef TARGET_SPARC64 - dc->fpu_enabled = (((env->pstate & PS_PEF) != 0) && ((env->fprs & FPRS_FEF) != 0)); -#else - dc->fpu_enabled = ((env->psref) != 0); -#endif -#endif + dc->mem_idx = cpu_mmu_index(env); + dc->fpu_enabled = cpu_fpu_enabled(env); gen_opc_ptr = gen_opc_buf; gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; gen_opparam_ptr = gen_opparam_buf; @@ -3522,6 +3520,7 @@ void cpu_reset(CPUSPARCState *env) env->psrps = 1; #ifdef TARGET_SPARC64 env->pstate = PS_PRIV; + env->hpstate = HS_PRIV; env->pc = 0x1fff0000000ULL; #else env->pc = 0;