Sparc64 hypervisor mode
authorblueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 14 Oct 2007 17:07:21 +0000 (17:07 +0000)
committerblueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 14 Oct 2007 17:07:21 +0000 (17:07 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3398 c046a42c-6fe2-441c-8c8c-71466251a162

target-sparc/cpu.h
target-sparc/op.c
target-sparc/op_helper.c
target-sparc/translate.c

index e9699cf..51cbd4c 100644 (file)
@@ -98,6 +98,8 @@
 #define PS_AG    (1<<0)
 
 #define FPRS_FEF (1<<2)
+
+#define HS_PRIV  (1<<2)
 #endif
 
 /* Fcc */
 
 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"
index e12347d..80864c3 100644 (file)
@@ -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)
index ac88b55..28c18b4 100644 (file)
@@ -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) {
index 046dc0b..d0dc511 100644 (file)
@@ -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;