Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/mips/mips Implement true LL/SC emulation. Mostly f...



details:   https://anonhg.NetBSD.org/src/rev/564e922283e4
branches:  trunk
changeset: 534304:564e922283e4
user:      gmcgarry <gmcgarry%NetBSD.org@localhost>
date:      Sun Jul 21 05:47:51 2002 +0000

description:
Implement true LL/SC emulation.  Mostly from Jason Thorpe in PR17548.

diffstat:

 sys/arch/mips/mips/mips_emul.c |  141 ++++++++++++++--------------------------
 1 files changed, 50 insertions(+), 91 deletions(-)

diffs (228 lines):

diff -r cde93eb37dcf -r 564e922283e4 sys/arch/mips/mips/mips_emul.c
--- a/sys/arch/mips/mips/mips_emul.c    Sun Jul 21 02:56:35 2002 +0000
+++ b/sys/arch/mips/mips/mips_emul.c    Sun Jul 21 05:47:51 2002 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: mips_emul.c,v 1.1 2002/07/06 23:59:21 gmcgarry Exp $ */
+/*     $NetBSD: mips_emul.c,v 1.2 2002/07/21 05:47:51 gmcgarry Exp $ */
 
 /*
  * Copyright (c) 1999 Shuichiro URATA.  All rights reserved.
@@ -71,6 +71,15 @@
 void   bcemul_swr(u_int32_t inst, struct frame *f, u_int32_t);
 
 /*
+ * MIPS2 LL instruction emulation state
+ */
+struct {
+       struct proc *proc;
+       vaddr_t addr;
+       u_int32_t value;
+} llstate;
+
+/*
  * Analyse 'next' PC address taking account of branch/jump instructions
  */
 vaddr_t
@@ -210,7 +219,6 @@
                inst = fuword((u_int32_t *)opc);
 
        switch (((InstFmt)inst).FRType.op) {
-#if defined(MIPS1)
        case OP_LWC0:
                MachEmulateLWC0(inst, frame, cause);
                break;
@@ -220,7 +228,6 @@
        case OP_SPECIAL:
                MachEmulateSpecial(inst, frame, cause);
                break;
-#endif
        case OP_COP1:
                MachEmulateFP(inst, frame, cause);
                break;
@@ -268,12 +275,8 @@
                frame->f_regs[PC] += 4;
 }
 
-#if defined(MIPS1)
-
-#define LWLWC0_MAXLOOP 12
-
 /*
- * XXX only on uniprocessor machines
+ * MIPS2 LL instruction
  */
 void
 MachEmulateLWC0(u_int32_t inst, struct frame *frame, u_int32_t cause)
@@ -281,15 +284,15 @@
        u_int32_t       vaddr;
        int16_t         offset;
        void            *t;
-       mips_reg_t      pc;
-       int             i;
 
        offset = inst & 0xFFFF;
        vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
 
        /* segment and alignment check */
        if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
-               send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
+               frame->f_regs[CAUSE] = cause;
+               frame->f_regs[BADVADDR] = vaddr;
+               trapsignal(curproc, SIGBUS, vaddr);
                return;
        }
 
@@ -300,107 +303,66 @@
                return;
        }
 
-       pc = frame->f_regs[PC];
-       update_pc(frame, cause);
-
-       if (cause & MIPS_CR_BR_DELAY)
-               return;
-
-       for (i = 1; i < LWLWC0_MAXLOOP; i++) {
-               if (mips_btop(frame->f_regs[PC]) != mips_btop(pc))
-                       return;
-
-               vaddr = frame->f_regs[PC];      /* XXX truncates to 32 bits */
-               inst = fuiword((u_int32_t *)vaddr);
-               if (((InstFmt)inst).FRType.op != OP_LWC0)
-                       return;
+       llstate.proc = curproc;
+       llstate.addr = vaddr;
+       llstate.value = *((u_int32_t *)t);
 
-               offset = inst & 0xFFFF;
-               vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
-
-               /* segment and alignment check */
-               if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
-                       send_sigsegv(vaddr, T_ADDR_ERR_LD, frame, cause);
-                       return;
-               }
-
-               t = &(frame->f_regs[(inst>>16)&0x1F]);
-
-               if (copyin((void *)vaddr, t, 4) != 0) {
-                       send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
-                       return;
-               }
-
-               pc = frame->f_regs[PC];
-               update_pc(frame, cause);
-       }
+       update_pc(frame, cause);
 }
 
-#define LWSWC0_MAXLOOP 12
-
 /*
- * XXX only on uniprocessor machines
+ * MIPS2 SC instruction
  */
 void
 MachEmulateSWC0(u_int32_t inst, struct frame *frame, u_int32_t cause)
 {
-
-       u_int32_t       vaddr;
+       u_int32_t       vaddr, value;
        int16_t         offset;
-       void            *t;
-       mips_reg_t      pc;
-       int             i;
+       mips_reg_t      *t;
 
        offset = inst & 0xFFFF;
        vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
 
        /* segment and alignment check */
        if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
-               send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
-               return;
-       }
-
-       t = &(frame->f_regs[(inst>>16)&0x1F]);
-
-       if (copyout(t, (void *)vaddr, 4) != 0) {
-               send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
+               frame->f_regs[CAUSE] = cause;
+               frame->f_regs[BADVADDR] = vaddr;
+               trapsignal(curproc, SIGBUS, vaddr);
                return;
        }
 
-       pc = frame->f_regs[PC];
-       update_pc(frame, cause);
-
-       if (cause & MIPS_CR_BR_DELAY)
-               return;
-
-       for (i = 1; i < LWSWC0_MAXLOOP; i++) {
-               if (mips_btop(frame->f_regs[PC]) != mips_btop(pc))
-                       return;
+       t = (mips_reg_t *)&(frame->f_regs[(inst>>16)&0x1F]);
 
-               vaddr = frame->f_regs[PC];      /* XXX truncates to 32 bits */
-               inst = fuiword((u_int32_t *)vaddr);
-               if (((InstFmt)inst).FRType.op != OP_SWC0)
-                       return;
-
-               offset = inst & 0xFFFF;
-               vaddr = frame->f_regs[(inst>>21)&0x1F] + offset;
-
-               /* segment and alignment check */
-               if (vaddr > VM_MAX_ADDRESS || vaddr & 0x3) {
-                       send_sigsegv(vaddr, T_ADDR_ERR_ST, frame, cause);
+       /*
+        * Check that the process and address match the last
+        * LL instruction.
+        */
+       if (curproc == llstate.proc && vaddr == llstate.addr) {
+               llstate.proc = NULL;
+               /*
+                * Check that the data at the address hasn't changed
+                * since the LL instruction.
+                */
+               if (copyin((void *)vaddr, &value, 4) != 0) {
+                       send_sigsegv(vaddr, T_TLB_LD_MISS, frame, cause);
                        return;
                }
-
-               t = &(frame->f_regs[(inst>>16)&0x1F]);
-
-               if (copyout(t, (void *)vaddr, 4) != 0) {
-                       send_sigsegv(vaddr, T_TLB_ST_MISS, frame, cause);
+               if (value == llstate.value) {
+                       /* SC successful */
+                       if (copyout(t, (void *)vaddr, 4) != 0) {
+                               send_sigsegv(vaddr, T_TLB_ST_MISS,
+                                   frame, cause);
+                               return;
+                       }
+                       *t = 1;
+                       update_pc(frame, cause);
                        return;
                }
+       }
 
-               pc = frame->f_regs[PC];
-               update_pc(frame, cause);
-       }
+       /* SC failed */
+       *t = 0;
+       update_pc(frame, cause);
 }
 
 void
@@ -419,9 +381,6 @@
        update_pc(frame, cause);
 }
 
-#endif /* defined(MIPS1) */
-
-
 #if defined(SOFTFLOAT)
 
 #define LWSWC1_MAXLOOP 12



Home | Main Index | Thread Index | Old Index