diff mbox

sparc32 do_unassigned_access overhaul v2

Message ID 1263590936-17505-1-git-send-email-atar4qemu@google.com
State New
Headers show

Commit Message

Artyom Tarasenko Jan. 15, 2010, 9:28 p.m. UTC
According to pages 9-31 - 9-34 of "SuperSPARC & MultiCache Controller
User's Manual":

1. "A lower priority fault may not overwrite the
    MFSR status of a higher priority fault."
2. The MFAR is overwritten according to the policy defined for the MFSR
3. The overwrite bit is asserted if the fault status register (MFSR)
   has been written more than once by faults of the same class
4. SuperSPARC will never place instruction fault addresses in the MFAR.

Implementation of points 1-3 allows booting Solaris 2.6 and 2.5.1.

v2: CODING_STYLE fixes

Signed-off-by: Artyom Tarasenko <atar4qemu@gmail.com>
---

Comments

Blue Swirl Jan. 15, 2010, 9:34 p.m. UTC | #1
Thanks, applied.


On Fri, Jan 15, 2010 at 9:28 PM, Artyom Tarasenko
<atar4qemu@googlemail.com> wrote:
> According to pages 9-31 - 9-34 of "SuperSPARC & MultiCache Controller
> User's Manual":
>
> 1. "A lower priority fault may not overwrite the
>    MFSR status of a higher priority fault."
> 2. The MFAR is overwritten according to the policy defined for the MFSR
> 3. The overwrite bit is asserted if the fault status register (MFSR)
>   has been written more than once by faults of the same class
> 4. SuperSPARC will never place instruction fault addresses in the MFAR.
>
> Implementation of points 1-3 allows booting Solaris 2.6 and 2.5.1.
>
> v2: CODING_STYLE fixes
>
> Signed-off-by: Artyom Tarasenko <atar4qemu@gmail.com>
> ---
> diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
> index 381e6c4..3ff35d3 100644
> --- a/target-sparc/op_helper.c
> +++ b/target-sparc/op_helper.c
> @@ -3714,6 +3714,7 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
>                           int is_asi, int size)
>  {
>     CPUState *saved_env;
> +    int fault_type;
>
>     /* XXX: hack to restore env in all cases, even if not called from
>        generated code */
> @@ -3731,18 +3732,29 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
>                is_exec ? "exec" : is_write ? "write" : "read", size,
>                size == 1 ? "" : "s", addr, env->pc);
>  #endif
> -    if (env->mmuregs[3]) /* Fault status register */
> -        env->mmuregs[3] = 1; /* overflow (not read before another fault) */
> -    if (is_asi)
> -        env->mmuregs[3] |= 1 << 16;
> -    if (env->psrs)
> -        env->mmuregs[3] |= 1 << 5;
> -    if (is_exec)
> -        env->mmuregs[3] |= 1 << 6;
> -    if (is_write)
> -        env->mmuregs[3] |= 1 << 7;
> -    env->mmuregs[3] |= (5 << 2) | 2;
> -    env->mmuregs[4] = addr; /* Fault address register */
> +    /* Don't overwrite translation and access faults */
> +    fault_type = (env->mmuregs[3] & 0x1c) >> 2;
> +    if ((fault_type > 4) || (fault_type == 0)) {
> +        env->mmuregs[3] = 0; /* Fault status register */
> +        if (is_asi)
> +            env->mmuregs[3] |= 1 << 16;
> +        if (env->psrs)
> +            env->mmuregs[3] |= 1 << 5;
> +        if (is_exec)
> +            env->mmuregs[3] |= 1 << 6;
> +        if (is_write)
> +            env->mmuregs[3] |= 1 << 7;
> +        env->mmuregs[3] |= (5 << 2) | 2;
> +        /* SuperSPARC will never place instruction fault addresses in the FAR */
> +        if (!is_exec) {
> +            env->mmuregs[4] = addr; /* Fault address register */
> +        }
> +    }
> +    /* overflow (same type fault was not read before another fault) */
> +    if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) {
> +        env->mmuregs[3] |= 1;
> +    }
> +
>     if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
>         if (is_exec)
>             raise_exception(TT_CODE_ACCESS);
> @@ -3750,6 +3762,12 @@ void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
>             raise_exception(TT_DATA_ACCESS);
>     }
>     env = saved_env;
> +
> +    /* flush neverland mappings created during no-fault mode,
> +       so the sequential MMU faults report proper fault types */
> +    if (env->mmuregs[0] & MMU_NF) {
> +        tlb_flush(env, 1);
> +    }
>  }
>  #else
>  void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
>
Artyom Tarasenko Jan. 18, 2010, 4:17 p.m. UTC | #2
Btw, what is the following hack for in do_unassigned_access?


    saved_env = env;
    env = cpu_single_env;
//...
    env = saved_env;

I wonder whether I modify the correct env here:

   env = saved_env;

+    /* flush neverland mappings created during no-fault mode,
+       so the sequential MMU faults report proper fault types */
+    if (env->mmuregs[0] & MMU_NF) {
+        tlb_flush(env, 1);
+    }
Blue Swirl Jan. 18, 2010, 5:38 p.m. UTC | #3
On Mon, Jan 18, 2010 at 4:17 PM, Artyom Tarasenko
<atar4qemu@googlemail.com> wrote:
> Btw, what is the following hack for in do_unassigned_access?
>
>
>    saved_env = env;
>    env = cpu_single_env;
> //...
>    env = saved_env;

env is a host CPU register, see for example target-sparc/exec.h. Code
which is called directly from translated code (and cpu-exec.c) is
compiled this way.

I'm not sure if do_unassigned_access will ever be called from outside
of translated code, grep hits were from exec.c, cpu-exec.c and
op_helper.c.

> I wonder whether I modify the correct env here:
>
>   env = saved_env;
>
> +    /* flush neverland mappings created during no-fault mode,
> +       so the sequential MMU faults report proper fault types */
> +    if (env->mmuregs[0] & MMU_NF) {
> +        tlb_flush(env, 1);
> +    }

Right, if env was NULL when entering the function, it will crash.
diff mbox

Patch

diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 381e6c4..3ff35d3 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -3714,6 +3714,7 @@  void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
                           int is_asi, int size)
 {
     CPUState *saved_env;
+    int fault_type;
 
     /* XXX: hack to restore env in all cases, even if not called from
        generated code */
@@ -3731,18 +3732,29 @@  void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
                is_exec ? "exec" : is_write ? "write" : "read", size,
                size == 1 ? "" : "s", addr, env->pc);
 #endif
-    if (env->mmuregs[3]) /* Fault status register */
-        env->mmuregs[3] = 1; /* overflow (not read before another fault) */
-    if (is_asi)
-        env->mmuregs[3] |= 1 << 16;
-    if (env->psrs)
-        env->mmuregs[3] |= 1 << 5;
-    if (is_exec)
-        env->mmuregs[3] |= 1 << 6;
-    if (is_write)
-        env->mmuregs[3] |= 1 << 7;
-    env->mmuregs[3] |= (5 << 2) | 2;
-    env->mmuregs[4] = addr; /* Fault address register */
+    /* Don't overwrite translation and access faults */
+    fault_type = (env->mmuregs[3] & 0x1c) >> 2;
+    if ((fault_type > 4) || (fault_type == 0)) {
+        env->mmuregs[3] = 0; /* Fault status register */
+        if (is_asi)
+            env->mmuregs[3] |= 1 << 16;
+        if (env->psrs)
+            env->mmuregs[3] |= 1 << 5;
+        if (is_exec)
+            env->mmuregs[3] |= 1 << 6;
+        if (is_write)
+            env->mmuregs[3] |= 1 << 7;
+        env->mmuregs[3] |= (5 << 2) | 2;
+        /* SuperSPARC will never place instruction fault addresses in the FAR */
+        if (!is_exec) {
+            env->mmuregs[4] = addr; /* Fault address register */
+        }
+    }
+    /* overflow (same type fault was not read before another fault) */
+    if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) {
+        env->mmuregs[3] |= 1;
+    }
+
     if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
         if (is_exec)
             raise_exception(TT_CODE_ACCESS);
@@ -3750,6 +3762,12 @@  void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
             raise_exception(TT_DATA_ACCESS);
     }
     env = saved_env;
+
+    /* flush neverland mappings created during no-fault mode,
+       so the sequential MMU faults report proper fault types */
+    if (env->mmuregs[0] & MMU_NF) {
+        tlb_flush(env, 1);
+    }
 }
 #else
 void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,