Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

/*
 * arm exception handlers
 */
#include "arm.s"

#undef B                                        /* B is for 'botch' */

/*
 *  exception vectors, copied by trapinit() to somewhere useful
 */
TEXT vectors(SB), 1, $-4
        MOVW    0x18(R15), R15          /* reset */
        MOVW    0x18(R15), R15          /* undefined instr. */
        MOVW    0x18(R15), R15          /* SWI & SMC */
        MOVW    0x18(R15), R15          /* prefetch abort */
        MOVW    0x18(R15), R15          /* data abort */
        MOVW    0x18(R15), R15          /* hypervisor call */
        MOVW    0x18(R15), R15          /* IRQ */
        MOVW    0x18(R15), R15          /* FIQ */

TEXT vtable(SB), 1, $-4
        WORD    $_vrst-KZERO(SB)        /* reset, in svc mode already */
        WORD    $_vund(SB)              /* undefined, switch to svc mode */
        WORD    $_vsvc(SB)              /* swi, in svc mode already */
        WORD    $_vpabt(SB)             /* prefetch abort, switch to svc mode */
        WORD    $_vdabt(SB)             /* data abort, switch to svc mode */
        WORD    $_vhype(SB)             /* hypervisor call */
        WORD    $_virq(SB)              /* IRQ, switch to svc mode */
        WORD    $_vfiq(SB)              /* FIQ, switch to svc mode */

/*
 * reset - start additional cpus
 */
TEXT _vrst(SB), 1, $-4
        /* running in the zero segment (pc is lower 256MB) */
        CPSMODE(PsrMsvc)                /* should be redundant */
        CPSID
        CPSAE
        SETEND(0)                       /* force little-endian */
        BARRIERS
        SETZSB
        MOVW    $PsrMsvc, SPSR
        MOVW    $0, R14

        /* invalidate i-cache and branch-target cache */
        MTCP    CpSC, 0, PC, C(CpCACHE), C(CpCACHEinvi), CpCACHEall
        BARRIERS

        BL      cpureset(SB)
spin:
        B       spin

/*
 * system call
 */
TEXT _vsvc(SB), 1, $-4                  /* SWI */
        CLREX
        BARRIERS
        /* stack is m->stack */
        MOVW.W  R14, -4(R13)            /* ureg->pc = interrupted PC */
        MOVW    SPSR, R14               /* ureg->psr = SPSR */
        MOVW.W  R14, -4(R13)            /* ... */
        MOVW    $PsrMsvc, R14           /* ureg->type = PsrMsvc */
        MOVW.W  R14, -4(R13)            /* ... */

        /* avoid the ambiguity described in notes/movm.w. */
        MOVM.DB.S [R0-R14], (R13)       /* save user level registers */
        SUB     $(NREGS*4), R13         /* r13 now points to ureg */

        MOVW    $setR12(SB), R12        /* Make sure we've got the kernel's SB loaded */

        /*
         * set up m and up registers since user registers could contain anything
         */
        CPUID(R1)
        SLL     $2, R1                  /* convert to word index */
        MOVW    $machaddr(SB), R2
        ADD     R1, R2
        MOVW    (R2), R(MACH)           /* m = machaddr[cpuid] */
        CMP     $0, R(MACH)
        MOVW.EQ $MACHADDR, R0           /* paranoia: use MACHADDR if 0 */
        MOVW    8(R(MACH)), R(USER)     /* up = m->proc */

        MOVW    ((NREGS+1)*4)(R13), R2  /* saved SPSR (user mode) */

        MOVW    R13, R0                 /* first arg is pointer to ureg */
        SUB     $8, R13                 /* space for argument+link */

        BL      syscall(SB)
        /*
         * caller saves on plan 9, so registers other than 9, 10, 13 & 14
         * may have been trashed when we get here.
         */

        MOVW    $setR12(SB), R12        /* reload kernel's SB */

        ADD     $(8+4*NREGS), R13       /* make r13 point to ureg->type */

        MOVW    8(R13), R14             /* restore link */
        MOVW    4(R13), R0              /* restore SPSR */
/*
 * return from user-mode exception.
 * expects new SPSR in R0.  R13 must point to ureg->type.
 */
_rfue:
TEXT rfue(SB), 1, $-4
        MOVW    R0, SPSR                /* ... */

        /*
         * order on stack is type, psr, pc, but RFEV7 needs pc, psr.
         * step on type and previous word to hold temporary values.
         * we could instead change the order in which psr & pc are pushed.
         */
        MOVW    4(R13), R1              /* psr */
        MOVW    8(R13), R2              /* pc */
        MOVW    R2, 4(R13)              /* pc */
        MOVW    R1, 8(R13)              /* psr */

        MOVM.DB.S (R13), [R0-R14]       /* restore user registers */
        ADD     $4, R13                 /* pop type, sp -> pc */
        RFEV7W(13)


TEXT _vund(SB), 1, $-4                  /* undefined */
        /* sp is m->sund */
        MOVM.IA [R0-R4], (R13)          /* free some working space */
        MOVW    $PsrMund, R0
        B       _vswitch

TEXT _vpabt(SB), 1, $-4                 /* prefetch abort */
        /* sp is m->sabt */
        MOVM.IA [R0-R4], (R13)          /* free some working space */
        MOVW    $PsrMabt, R0            /* r0 = type */
        B       _vswitch

TEXT _vdabt(SB), 1, $-4                 /* data abort */
        /* sp is m->sabt */
        MOVM.IA [R0-R4], (R13)          /* free some working space */
        MOVW    $(PsrMabt+1), R0        /* r0 = type */
        B       _vswitch

TEXT _virq(SB), 1, $-4                  /* IRQ */
        /* sp is m->sirq */
        MOVM.IA [R0-R4], (R13)          /* free some working space */
        MOVW    $PsrMirq, R0            /* r0 = type */
        B       _vswitch

        /*
         *  come here with type in R0 and R13 pointing above saved [r0-r4].
         *  we'll switch to SVC mode and then call trap.
         */
_vswitch:
// TEXT _vswtch(SB), 1, $-4             /* make symbol visible to debuggers */
        CLREX
        BARRIERS
        MOVW    SPSR, R1                /* save SPSR for ureg */
        /*
         * R12 needs to be set before using PsrMbz, so BIGENDCHECK code has
         * been moved below.
         */
        MOVW    R14, R2                 /* save interrupted pc for ureg */
        MOVW    R13, R3                 /* save pointer to where the original [R0-R4] are */

        /*
         * switch processor to svc mode.  this switches the banked registers
         * (r13 [sp] and r14 [link]) to those of svc mode (so we must be sure
         * to never get here already in svc mode).
         */
        CPSMODE(PsrMsvc)                /* switch! */
        CPSID

        AND.S   $0xf, R1, R4            /* interrupted code kernel or user? */
        BEQ     _userexcep

        /*
         * here for trap from SVC mode
         */

        /* push ureg->{type, psr, pc} onto Msvc stack.
         * r13 points to ureg->type after.
         */
        MOVM.DB.W [R0-R2], (R13)
        MOVM.IA   (R3), [R0-R4]         /* restore [R0-R4] from previous mode's stack */

        /*
         * avoid the ambiguity described in notes/movm.w.
         * In order to get a predictable value in R13 after the stores,
         * separate the store-multiple from the stack-pointer adjustment.
         * We'll assume that the old value of R13 should be stored on the stack.
         */
        /* save kernel level registers, at end r13 points to ureg */
        MOVM.DB [R0-R14], (R13)
        SUB     $(NREGS*4), R13         /* SP now points to saved R0 */

        MOVW    $setR12(SB), R12        /* Make sure we've got the kernel's SB loaded */
        /* previous mode was svc, so the saved spsr should be sane. */
        MOVW    ((NREGS+1)*4)(R13), R1

        MOVM.IA (R13), [R0-R8]          /* restore a few user registers */

        MOVW    R13, R0                 /* first arg is pointer to ureg */
        SUB     $(4*2), R13             /* space for argument+link (for debugger) */
        MOVW    $0xdeaddead, R11        /* marker */

        BL      trap(SB)                /* trap(ureg) */
        /*
         * caller saves on plan 9, so registers other than 9, 10, 13 & 14
         * may have been trashed when we get here.
         */

        MOVW    $setR12(SB), R12        /* reload kernel's SB */

        ADD     $(4*2+4*NREGS), R13     /* make r13 point to ureg->type */

        /*
         * if we interrupted a previous trap's handler and are now
         * returning to it, we need to propagate the current R(MACH) (R10)
         * by overriding the saved one on the stack, since we may have
         * been rescheduled and be on a different processor now than
         * at entry.
         */
        MOVW    R(MACH), (-(NREGS-MACH)*4)(R13) /* restore current cpu's MACH */

        MOVW    8(R13), R14             /* restore link */
        MOVW    4(R13), R0              /* restore SPSR */

        /* return from kernel-mode exception */
        MOVW    R0, SPSR                /* ... */

        /*
         * order on stack is type, psr, pc, but RFEV7 needs pc, psr.
         * step on type and previous word to hold temporary values.
         * we could instead change the order in which psr & pc are pushed.
         */
        MOVW    4(R13), R1              /* psr */
        MOVW    8(R13), R2              /* pc */
        MOVW    R2, 4(R13)              /* pc */
        MOVW    R1, 8(R13)              /* psr */

        /* restore kernel regs other than SP; we're using it */
        SUB     $(NREGS*4), R13
        MOVM.IA.W (R13), [R0-R12]
        ADD     $4, R13                 /* skip saved kernel SP */
        MOVM.IA.W (R13), [R14]
        ADD     $4, R13                 /* pop type, sp -> pc */
        BARRIERS
        RFEV7W(13)

        /*
         * here for trap from USER mode
         */
_userexcep:
        MOVM.DB.W [R0-R2], (R13)        /* set ureg->{type, psr, pc}; r13 points to ureg->type  */
        MOVM.IA   (R3), [R0-R4]         /* restore [R0-R4] from previous mode's stack */

        /* avoid the ambiguity described in notes/movm.w. */
        MOVM.DB.S [R0-R14], (R13)       /* save kernel level registers */
        SUB     $(NREGS*4), R13         /* r13 now points to ureg */

        MOVW    $setR12(SB), R12        /* Make sure we've got the kernel's SB loaded */

        /*
         * set up m and up registers since user registers could contain anything
         */
        CPUID(R1)
        SLL     $2, R1                  /* convert to word index */
        MOVW    $machaddr(SB), R2
        ADD     R1, R2
        MOVW    (R2), R(MACH)           /* m = machaddr[cpuid] */
        CMP     $0, R(MACH)
        MOVW.EQ $MACHADDR, R0           /* paranoia: use MACHADDR if 0 */
        MOVW    8(R(MACH)), R(USER)     /* up = m->proc */

        MOVW    ((NREGS+1)*4)(R13), R2  /* saved SPSR */

        MOVW    R13, R0                 /* first arg is pointer to ureg */
        SUB     $(4*2), R13             /* space for argument+link (for debugger) */

        BL      trap(SB)                /* trap(ureg) */
        /*
         * caller saves on plan 9, so registers other than 9, 10, 13 & 14
         * may have been trashed when we get here.
         */

        ADD     $(4*2+4*NREGS), R13     /* make r13 point to ureg->type */

        MOVW    8(R13), R14             /* restore link */
        MOVW    4(R13), R0              /* restore SPSR */

        MOVW    4(R13), R0              /* restore SPSR */
        B       _rfue


TEXT _vfiq(SB), 1, $-4                  /* FIQ */
        PUTC('?')
        PUTC('f')
        PUTC('i')
        PUTC('q')
        RFE                             /* FIQ is special, ignore it for now */

TEXT _vhype(SB), 1, $-4
        PUTC('?')
        PUTC('h')
        PUTC('y')
        PUTC('p')
        RFE

/*
 *  set the stack value for the mode passed in R0
 */
TEXT setr13(SB), 1, $-4
        MOVW    4(FP), R1

        MOVW    CPSR, R2
        BIC     $(PsrMask|PsrMbz), R2, R3
        ORR     $(PsrDirq|PsrDfiq), R3
        ORR     R0, R3

        MOVW    R3, CPSR                /* switch to new mode */

        MOVW    R13, R0                 /* return old sp */
        MOVW    R1, R13                 /* install new one */

        MOVW    R2, CPSR                /* switch back to old mode */
        RET

Generated by GNU Enscript 1.6.6.