All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Igor V. Kovalenko" <igor.v.kovalenko@gmail.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH 3/3] sparc64: handle asi referencing nucleus and secondary MMU contexts
Date: Mon, 03 May 2010 11:29:44 +0400	[thread overview]
Message-ID: <20100503072944.367.50356.stgit@skyserv> (raw)
In-Reply-To: <20100503072448.367.7010.stgit@skyserv>

From: Igor V. Kovalenko <igor.v.kovalenko@gmail.com>

- increase max supported MMU modes to 6
- handle nucleus context asi
- handle secondary context asi
- handle non-faulting loads from secondary context

Signed-off-by: Igor V. Kovalenko <igor.v.kovalenko@gmail.com>
---
 softmmu_exec.h           |   25 ++++-
 target-sparc/cpu.h       |   13 ++-
 target-sparc/exec.h      |    4 +
 target-sparc/helper.c    |   42 ++++++--
 target-sparc/op_helper.c |  235 ++++++++++++++++++++++++++++++++++------------
 5 files changed, 241 insertions(+), 78 deletions(-)

diff --git a/softmmu_exec.h b/softmmu_exec.h
index a43e621..28d1d53 100644
--- a/softmmu_exec.h
+++ b/softmmu_exec.h
@@ -100,9 +100,28 @@
 #undef MEMSUFFIX
 #endif /* (NB_MMU_MODES >= 5) */
 
-#if (NB_MMU_MODES > 5)
-#error "NB_MMU_MODES > 5 is not supported for now"
-#endif /* (NB_MMU_MODES > 5) */
+#if (NB_MMU_MODES >= 6)
+
+#define ACCESS_TYPE 5
+#define MEMSUFFIX MMU_MODE5_SUFFIX
+#define DATA_SIZE 1
+#include "softmmu_header.h"
+
+#define DATA_SIZE 2
+#include "softmmu_header.h"
+
+#define DATA_SIZE 4
+#include "softmmu_header.h"
+
+#define DATA_SIZE 8
+#include "softmmu_header.h"
+#undef ACCESS_TYPE
+#undef MEMSUFFIX
+#endif /* (NB_MMU_MODES >= 6) */
+
+#if (NB_MMU_MODES > 6)
+#error "NB_MMU_MODES > 6 is not supported for now"
+#endif /* (NB_MMU_MODES > 6) */
 
 /* these access are slower, they must be as rare as possible */
 #define ACCESS_TYPE (NB_MMU_MODES)
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index b705728..b679333 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -224,7 +224,7 @@ enum {
 #if !defined(TARGET_SPARC64)
 #define NB_MMU_MODES 2
 #else
-#define NB_MMU_MODES 3
+#define NB_MMU_MODES 6
 typedef struct trap_state {
     uint64_t tpc;
     uint64_t tnpc;
@@ -571,6 +571,9 @@ static inline void PUT_CWP64(CPUSPARCState *env1, int cwp)
 #if !defined(CONFIG_USER_ONLY)
 void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
                           int is_asi, int size);
+target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
+                                           int mmu_idx);
+
 #endif
 int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
 
@@ -587,10 +590,18 @@ int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
 #define MMU_MODE1_SUFFIX _kernel
 #ifdef TARGET_SPARC64
 #define MMU_MODE2_SUFFIX _hypv
+#define MMU_MODE3_SUFFIX _nucleus
+#define MMU_MODE4_SUFFIX _user_secondary
+#define MMU_MODE5_SUFFIX _kernel_secondary
 #endif
 #define MMU_USER_IDX   0
 #define MMU_KERNEL_IDX 1
 #define MMU_HYPV_IDX   2
+#ifdef TARGET_SPARC64
+#define MMU_NUCLEUS_IDX 3
+#define MMU_USER_SECONDARY_IDX   4
+#define MMU_KERNEL_SECONDARY_IDX 5
+#endif
 
 static inline int cpu_mmu_index(CPUState *env1)
 {
diff --git a/target-sparc/exec.h b/target-sparc/exec.h
index 70df828..1e9de82 100644
--- a/target-sparc/exec.h
+++ b/target-sparc/exec.h
@@ -13,6 +13,10 @@ register struct CPUSPARCState *env asm(AREG0);
 #include "cpu.h"
 #include "exec-all.h"
 
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif /* !defined(CONFIG_USER_ONLY) */
+
 /* op_helper.c */
 void do_interrupt(CPUState *env);
 
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 4ece01b..cac6cad 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -420,21 +420,32 @@ static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
 
 static int get_physical_address_data(CPUState *env,
                                      target_phys_addr_t *physical, int *prot,
-                                     target_ulong address, int rw, int is_user)
+                                     target_ulong address, int rw, int mmu_idx)
 {
     unsigned int i;
     uint64_t context;
 
+    int is_user = (mmu_idx == MMU_USER_IDX ||
+                   mmu_idx == MMU_USER_SECONDARY_IDX);
+
     if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
         *physical = ultrasparc_truncate_physical(address);
         *prot = PAGE_READ | PAGE_WRITE;
         return 0;
     }
 
-    if (env->tl == 0) {
+    switch(mmu_idx) {
+    case MMU_USER_IDX:
+    case MMU_KERNEL_IDX:
         context = env->dmmu.mmu_primary_context & 0x1fff;
-    } else {
+        break;
+    case MMU_USER_SECONDARY_IDX:
+    case MMU_KERNEL_SECONDARY_IDX:
+        context = env->dmmu.mmu_secondary_context & 0x1fff;
+        break;
+    case MMU_NUCLEUS_IDX:
         context = 0;
+        break;
     }
 
     for (i = 0; i < 64; i++) {
@@ -482,11 +493,14 @@ static int get_physical_address_data(CPUState *env,
 
 static int get_physical_address_code(CPUState *env,
                                      target_phys_addr_t *physical, int *prot,
-                                     target_ulong address, int is_user)
+                                     target_ulong address, int mmu_idx)
 {
     unsigned int i;
     uint64_t context;
 
+    int is_user = (mmu_idx == MMU_USER_IDX ||
+                   mmu_idx == MMU_USER_SECONDARY_IDX);
+
     if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
         /* IMMU disabled */
         *physical = ultrasparc_truncate_physical(address);
@@ -495,8 +509,10 @@ static int get_physical_address_code(CPUState *env,
     }
 
     if (env->tl == 0) {
+        /* PRIMARY context */
         context = env->dmmu.mmu_primary_context & 0x1fff;
     } else {
+        /* NUCLEUS context */
         context = 0;
     }
 
@@ -535,17 +551,15 @@ static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
                                 target_ulong address, int rw, int mmu_idx,
                                 target_ulong *page_size)
 {
-    int is_user = mmu_idx == MMU_USER_IDX;
-
     /* ??? We treat everything as a small page, then explicitly flush
        everything when an entry is evicted.  */
     *page_size = TARGET_PAGE_SIZE;
     if (rw == 2)
         return get_physical_address_code(env, physical, prot, address,
-                                         is_user);
+                                         mmu_idx);
     else
         return get_physical_address_data(env, physical, prot, address, rw,
-                                         is_user);
+                                         mmu_idx);
 }
 
 /* Perform address translation */
@@ -659,21 +673,27 @@ void dump_mmu(CPUState *env)
 
 
 #if !defined(CONFIG_USER_ONLY)
-target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
+                                           int mmu_idx)
 {
     target_phys_addr_t phys_addr;
     target_ulong page_size;
     int prot, access_index;
 
     if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2,
-                             MMU_KERNEL_IDX, &page_size) != 0)
+                             mmu_idx, &page_size) != 0)
         if (get_physical_address(env, &phys_addr, &prot, &access_index, addr,
-                                 0, MMU_KERNEL_IDX, &page_size) != 0)
+                                 0, mmu_idx, &page_size) != 0)
             return -1;
     if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED)
         return -1;
     return phys_addr;
 }
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    return cpu_get_phys_page_nofault(env, addr, MMU_KERNEL_IDX);
+}
 #endif
 
 void cpu_reset(CPUSPARCState *env)
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index e048845..0388646 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -1,9 +1,6 @@
 #include "exec.h"
 #include "host-utils.h"
 #include "helper.h"
-#if !defined(CONFIG_USER_ONLY)
-#include "softmmu_exec.h"
-#endif /* !defined(CONFIG_USER_ONLY) */
 
 //#define DEBUG_MMU
 //#define DEBUG_MXCC
@@ -2141,17 +2138,29 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
     switch (asi) {
     case 0x82: // Primary no-fault
     case 0x8a: // Primary no-fault LE
-        if (cpu_get_phys_page_debug(env, addr) == -1ULL) {
+    case 0x83: // Secondary no-fault
+    case 0x8b: // Secondary no-fault LE
+        {
+            /* secondary space access has lowest asi bit equal to 1 */
+            int access_mmu_idx = ( asi & 1 ) ? MMU_KERNEL_IDX
+                                             : MMU_KERNEL_SECONDARY_IDX;
+
+            if (cpu_get_phys_page_nofault(env, addr, access_mmu_idx) == -1ULL) {
 #ifdef DEBUG_ASI
-            dump_asi("read ", last_addr, asi, size, ret);
+                dump_asi("read ", last_addr, asi, size, ret);
 #endif
-            return 0;
+                return 0;
+            }
         }
         // Fall through
     case 0x10: // As if user primary
+    case 0x11: // As if user secondary
     case 0x18: // As if user primary LE
+    case 0x19: // As if user secondary LE
     case 0x80: // Primary
+    case 0x81: // Secondary
     case 0x88: // Primary LE
+    case 0x89: // Secondary LE
     case 0xe2: // UA2007 Primary block init
     case 0xe3: // UA2007 Secondary block init
         if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
@@ -2173,37 +2182,75 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
                     break;
                 }
             } else {
+                /* secondary space access has lowest asi bit equal to 1 */
+                if (asi & 1) {
+                    switch(size) {
+                    case 1:
+                        ret = ldub_kernel_secondary(addr);
+                        break;
+                    case 2:
+                        ret = lduw_kernel_secondary(addr);
+                        break;
+                    case 4:
+                        ret = ldl_kernel_secondary(addr);
+                        break;
+                    default:
+                    case 8:
+                        ret = ldq_kernel_secondary(addr);
+                        break;
+                    }
+                } else {
+                    switch(size) {
+                    case 1:
+                        ret = ldub_kernel(addr);
+                        break;
+                    case 2:
+                        ret = lduw_kernel(addr);
+                        break;
+                    case 4:
+                        ret = ldl_kernel(addr);
+                        break;
+                    default:
+                    case 8:
+                        ret = ldq_kernel(addr);
+                        break;
+                    }
+                }
+            }
+        } else {
+            /* secondary space access has lowest asi bit equal to 1 */
+            if (asi & 1) {
                 switch(size) {
                 case 1:
-                    ret = ldub_kernel(addr);
+                    ret = ldub_user_secondary(addr);
                     break;
                 case 2:
-                    ret = lduw_kernel(addr);
+                    ret = lduw_user_secondary(addr);
                     break;
                 case 4:
-                    ret = ldl_kernel(addr);
+                    ret = ldl_user_secondary(addr);
                     break;
                 default:
                 case 8:
-                    ret = ldq_kernel(addr);
+                    ret = ldq_user_secondary(addr);
+                    break;
+                }
+            } else {
+                switch(size) {
+                case 1:
+                    ret = ldub_user(addr);
+                    break;
+                case 2:
+                    ret = lduw_user(addr);
+                    break;
+                case 4:
+                    ret = ldl_user(addr);
+                    break;
+                default:
+                case 8:
+                    ret = ldq_user(addr);
                     break;
                 }
-            }
-        } else {
-            switch(size) {
-            case 1:
-                ret = ldub_user(addr);
-                break;
-            case 2:
-                ret = lduw_user(addr);
-                break;
-            case 4:
-                ret = ldl_user(addr);
-                break;
-            default:
-            case 8:
-                ret = ldq_user(addr);
-                break;
             }
         }
         break;
@@ -2234,22 +2281,27 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
         //  Only ldda allowed
         raise_exception(TT_ILL_INSN);
         return 0;
-    case 0x83: // Secondary no-fault
-    case 0x8b: // Secondary no-fault LE
-        if (cpu_get_phys_page_debug(env, addr) == -1ULL) {
-#ifdef DEBUG_ASI
-            dump_asi("read ", last_addr, asi, size, ret);
-#endif
-            return 0;
-        }
-        // Fall through
     case 0x04: // Nucleus
     case 0x0c: // Nucleus Little Endian (LE)
-    case 0x11: // As if user secondary
-    case 0x19: // As if user secondary LE
+    {
+        switch(size) {
+        case 1:
+            ret = ldub_nucleus(addr);
+            break;
+        case 2:
+            ret = lduw_nucleus(addr);
+            break;
+        case 4:
+            ret = ldl_nucleus(addr);
+            break;
+        default:
+        case 8:
+            ret = ldq_nucleus(addr);
+            break;
+        }
+        break;
+    }
     case 0x4a: // UPA config
-    case 0x81: // Secondary
-    case 0x89: // Secondary LE
         // XXX
         break;
     case 0x45: // LSU
@@ -2463,9 +2515,13 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
 
     switch(asi) {
     case 0x10: // As if user primary
+    case 0x11: // As if user secondary
     case 0x18: // As if user primary LE
+    case 0x19: // As if user secondary LE
     case 0x80: // Primary
+    case 0x81: // Secondary
     case 0x88: // Primary LE
+    case 0x89: // Secondary LE
     case 0xe2: // UA2007 Primary block init
     case 0xe3: // UA2007 Secondary block init
         if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
@@ -2487,37 +2543,75 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
                     break;
                 }
             } else {
+                /* secondary space access has lowest asi bit equal to 1 */
+                if (asi & 1) {
+                    switch(size) {
+                    case 1:
+                        stb_kernel_secondary(addr, val);
+                        break;
+                    case 2:
+                        stw_kernel_secondary(addr, val);
+                        break;
+                    case 4:
+                        stl_kernel_secondary(addr, val);
+                        break;
+                    case 8:
+                    default:
+                        stq_kernel_secondary(addr, val);
+                        break;
+                    }
+                } else {
+                    switch(size) {
+                    case 1:
+                        stb_kernel(addr, val);
+                        break;
+                    case 2:
+                        stw_kernel(addr, val);
+                        break;
+                    case 4:
+                        stl_kernel(addr, val);
+                        break;
+                    case 8:
+                    default:
+                        stq_kernel(addr, val);
+                        break;
+                    }
+                }
+            }
+        } else {
+            /* secondary space access has lowest asi bit equal to 1 */
+            if (asi & 1) {
                 switch(size) {
                 case 1:
-                    stb_kernel(addr, val);
+                    stb_user_secondary(addr, val);
                     break;
                 case 2:
-                    stw_kernel(addr, val);
+                    stw_user_secondary(addr, val);
                     break;
                 case 4:
-                    stl_kernel(addr, val);
+                    stl_user_secondary(addr, val);
                     break;
                 case 8:
                 default:
-                    stq_kernel(addr, val);
+                    stq_user_secondary(addr, val);
+                    break;
+                }
+            } else {
+                switch(size) {
+                case 1:
+                    stb_user(addr, val);
+                    break;
+                case 2:
+                    stw_user(addr, val);
+                    break;
+                case 4:
+                    stl_user(addr, val);
+                    break;
+                case 8:
+                default:
+                    stq_user(addr, val);
                     break;
                 }
-            }
-        } else {
-            switch(size) {
-            case 1:
-                stb_user(addr, val);
-                break;
-            case 2:
-                stw_user(addr, val);
-                break;
-            case 4:
-                stl_user(addr, val);
-                break;
-            case 8:
-            default:
-                stq_user(addr, val);
-                break;
             }
         }
         break;
@@ -2550,11 +2644,26 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
         return;
     case 0x04: // Nucleus
     case 0x0c: // Nucleus Little Endian (LE)
-    case 0x11: // As if user secondary
-    case 0x19: // As if user secondary LE
+    {
+        switch(size) {
+        case 1:
+            stb_nucleus(addr, val);
+            break;
+        case 2:
+            stw_nucleus(addr, val);
+            break;
+        case 4:
+            stl_nucleus(addr, val);
+            break;
+        default:
+        case 8:
+            stq_nucleus(addr, val);
+            break;
+        }
+        break;
+    }
+
     case 0x4a: // UPA config
-    case 0x81: // Secondary
-    case 0x89: // Secondary LE
         // XXX
         return;
     case 0x45: // LSU

      parent reply	other threads:[~2010-05-03  7:30 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-05-03  7:29 [Qemu-devel] [PATCH 0/3] sparc64: improve mmu context handling Igor V. Kovalenko
2010-05-03  7:29 ` [Qemu-devel] [PATCH 1/3] sparc64: more ultrasparc asi extensions for disassembler Igor V. Kovalenko
2010-05-03  7:29 ` [Qemu-devel] [PATCH 2/3] sparc64: implement global translation table entries Igor V. Kovalenko
2010-05-03 20:06   ` Blue Swirl
2010-05-03 20:21     ` Igor Kovalenko
2010-05-03 20:29       ` Blue Swirl
2010-05-04 19:12         ` Igor Kovalenko
2010-05-03  7:29 ` Igor V. Kovalenko [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20100503072944.367.50356.stgit@skyserv \
    --to=igor.v.kovalenko@gmail.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.