OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [armnommu/] [kernel/] [entry-armo.S] - Rev 1765

Compare with Previous | Blame | View Log

/*
 * linux/arch/arm/lib/traps.S
 *
 * Copyright (C) 1995, 1996 Russell King.
 *
 * Low-level vector interface routines
 *
 * Design issues:
 *  - We have several modes that each vector can be called from,
 *    each with its own set of registers.  On entry to any vector,
 *    we *must* save the registers used in *that* mode.
 *
 *  - This code must be as fast as possible.
 *
 * There are a few restrictions on the vectors:
 *  - the SWI vector cannot be called from *any* non-user mode
 *
 *  - the FP emulator is *never* called from *any* non-user mode undefined
 *    instruction.
 *
 * Ok, so this file may be a mess, but its as efficient as possible while
 * adhering to the above criteria.
 */

#include <asm/assembler.h>
#include <asm/errno.h>
#include <asm/hardware.h>

#if 0
/*
 * Uncomment these if you wish to get more debugging into about data aborts.
 */
#define FAULT_CODE_LDRSTRPOST   0x80
#define FAULT_CODE_LDRSTRPRE    0x40
#define FAULT_CODE_LDRSTRREG    0x20
#define FAULT_CODE_LDMSTM       0x10
#define FAULT_CODE_LDCSTC       0x08
#endif
#define FAULT_CODE_PREFETCH     0x04
#define FAULT_CODE_WRITE        0x02
#define FAULT_CODE_USER         0x01

                .text

/* Offsets into task structure
 * ---------------------------
 */
#define STATE           0
#define COUNTER         4
#define PRIORITY        8
#define SIGNAL          12
#define BLOCKED         16
#define FLAGS           20
#define ERRNO           24

#define PF_TRACESYS     0x20

/* Bad Abort numbers
 * -----------------
 */
#define BAD_PREFETCH    0
#define BAD_DATA        1
#define BAD_ADDREXCPTN  2
#define BAD_IRQ         3

/* OS version number used in SWIs
 *  RISC OS is 0
 *  RISC iX is 8
 */
#define OS_NUMBER       9

/* Stack format (ensured by USER_* and SVC_*)
 */
#define S_OLD_R0        64
#define S_PC            60
#define S_LR            56
#define S_SP            52
#define S_IP            48
#define S_FP            44
#define S_R10           40
#define S_R9            36
#define S_R8            32
#define S_R7            28
#define S_R6            24
#define S_R5            20
#define S_R4            16
#define S_R3            12
#define S_R2            8
#define S_R1            4
#define S_R0            0

#include "../lib/constants.h"

#define USER_SAVE_ALL                           \
                str     r0, [sp, #-4]!          ;\
                str     lr, [sp, #-4]!          ;\
                sub     sp, sp, #15*4           ;\
                stmia   sp, {r0 - lr}^          ;\
                mov     r0, r0                  ;\
                mov     fp, #0

#define SVC_SAVE_ALL                            \
                str     sp, [sp, #-16]!         ;\
                str     lr, [sp, #8]            ;\
                str     lr, [sp, #4]            ;\
                stmfd   sp!, {r0 - r12}         ;\
                mov     r0, #-1                 ;\
                str     r0, [sp, #S_OLD_R0]     ;\
                mov     fp, #0

#define SVC_IRQ_SAVE_ALL                        \
                str     sp, [sp, #-16]!         ;\
                str     lr, [sp, #4]            ;\
                ldr     lr, [pc, #LC4 - . - 8]  ;\
                ldr     lr, [lr]                ;\
                str     lr, [sp, #8]            ;\
                stmfd   sp!, {r0 - r12}         ;\
                mov     r0, #-1                 ;\
                str     r0, [sp, #S_OLD_R0]     ;\
                mov     fp, #0

#define USER_RESTORE_ALL                        \
                ldmia   sp, {r0 - lr}^          ;\
                mov     r0, r0                  ;\
                add     sp, sp, #15*4           ;\
                ldr     lr, [sp], #8            ;\
                movs    pc, lr

#define SVC_RESTORE_ALL                         \
                ldmfd   sp, {r0 - pc}^
                
                .global _ret_from_sys_call

/*
 * Interrupt table (incorporates priority).  First set is indexed using
 * IRQSTATB.
 */

Lirq_prio_h:    .byte    0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
                .byte   12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
                .byte   13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
                .byte   13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
                .byte   14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
                .byte   14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
                .byte   13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
                .byte   13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
                .byte   15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
                .byte   15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
                .byte   13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
                .byte   13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
                .byte   15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
                .byte   15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
                .byte   13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
                .byte   13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10

Lirq_prio_l:    .byte    0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
                .byte    4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
                .byte    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
                .byte    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
                .byte    6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
                .byte    6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
                .byte    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
                .byte    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
                .byte    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
                .byte    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
                .byte    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
                .byte    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
                .byte    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
                .byte    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
                .byte    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
                .byte    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7

/**************************************************************************
 * Interrupt (IRQ) handler (r13 points to irq temp save area)
 * Note: if in user mode, then *no* kernel routine is running, so dont have
 *       to save svc lr
 */

LC4:            .word   Lirq_temp
LC5:            .word   _irqjump

Lvector_IRQ:    ldr     r13, [pc, #LC4 - . - 8] @ Ill leave this one in just in case...
                sub     lr, lr, #4
                str     lr, [r13]
                tst     lr, #3
                bne     LIRQ_not_user
                teqp    pc, #0x08000003
                mov     r0, r0
                ldr     lr, [pc, #LC4 - . - 8]
                ldr     lr, [lr]
                USER_SAVE_ALL
                mov     r4, #IOC_BASE           @ point at IOC
                ldrb    r1, [r4, #0x24]         @ get high priority first
                adr     r2, Lirq_prio_h
                teq     r1, #0
                ldreqb  r1, [r4, #0x14]         @ get low priority
                adreq   r2, Lirq_prio_l
                teq     r1, #0
                beq     _ret_from_sys_call
                ldrb    r0, [r2, r1]            @ Get IRQ number
                ldr     r2, [pc, #LC5 - . - 8]
                mov     r1, sp
                mov     lr, pc
        /*
         * routine gets called with r0 = interrupt number, r1 = struct pt_regs *
         */
                ldr     pc, [r2, r0, lsl#2]
                mov     r2, #0
                teq     r0, #0                  @ Check to see if it is a fast IRQ
                beq     _ret_from_sys_call
                USER_RESTORE_ALL

LC65:
                .word   _intr_count             @ -8
                .word   _bh_mask                @ -4
                .word   _bh_active              @ -0

Lirq_illegal_mode:
                mov     r0, sp
                mov     r1, #BAD_IRQ
                b       _bad_mode

LIRQ_not_user:  teqp    pc, #0x08000003
                mov     r0, r0
                SVC_IRQ_SAVE_ALL
                and     r2, lr, #3
                teq     r2, #3
                bne     Lirq_illegal_mode
Lsrepeat:       mov     r4, #IOC_BASE           @ point at IOC
                ldrb    r1, [r4, #0x24]         @ get high priority first
                adr     r2, Lirq_prio_h
                teq     r1, #0
                ldreqb  r1, [r4, #0x14]         @ get low priority
                adreq   r2, Lirq_prio_l
                teq     r1, #0
                beq     Lno_irq2
                ldrb    r0, [r2, r1]            @ Get IRQ number
                ldr     r2, [pc, #LC5 - . - 8]
                mov     r1, sp
                mov     lr, pc
        /*
         * routine gets called with r0 = interrupt number, r1 = struct pt_regs *
         */
                ldr     pc, [r2, r0, lsl#2]
                mov     r2, #1
                teq     r0, #0                  @ Check to see if it is a fast IRQ
                bne     Lsrepeat
                ldr     r0, [pc, #LC65 - . - 8]
                ldr     r1, [r0]
                teq     r1, #0
                bne     Lsrepeat
                mov     r4, r0
                mov     r5, r1
                ldr     r6, [pc, #LC65 - . - 4]
                ldr     r7, [pc, #LC65 - . - 0]
Lrecheck_bh2:   ldr     r0, [r6]
                ldr     r1, [r7]
                tst     r0, r1
                beq     Lsrepeat
                add     r0, r5, #1
                str     r0, [r4]
                mov     r8, pc
                teqp    pc, #0x00000003
                bl      _do_bottom_half
                teqp    r8, #0
                str     r5, [r4]
                b       Lrecheck_bh2
Lno_irq2:       SVC_RESTORE_ALL

/**************************************************************************
 * Trap initialisation
 *
 * Note - FIQ code has changed.  The default is a couple of words in 0x1c,
 * 0x20 that call _unexp_fiq.  Nowever, we now copy the FIQ routine to
 * 0x1c (removes some excess cycles).
 */

Lswi_reset:     swi     SYS_ERROR0
                ldr     pc, . + 4
                .long   _unexp_fiq

Lfiqmsg:        .ascii  "*** Unexpeced FIQ\n\0"
                .align

_unexp_fiq:     mov     r12, #IOC_BASE
                strb    r12, [r12, #0x38]       @ Disable FIQ register
                teqp    pc, #0x0c000003
                mov     r0, r0
                stmfd   sp!, {r0 - r3, ip, lr}
                adr     r0, Lfiqmsg
                bl      _printk
                ldmfd   sp!, {r0 - r3, ip, lr}
                teqp    pc, #0x0c000001
                mov     r0, r0
                movs    pc, lr

Lvectors:       .long   Lvector_undefinstr - Lvectors - 12
                .long   Lvector_swi - Lvectors - 16
                .long   Lvector_prefetch - Lvectors - 20
                .long   Lvector_data - Lvectors - 24
                .long   Lvector_addrexcptn - Lvectors - 28
                .long   Lvector_IRQ - Lvectors - 32
                .long   0xea000000

                .global _trap_init
_trap_init:     stmfd   sp !,{r4 - r9,lr}       @ Save link register
                teqp    pc, #0x0c000003
                mov     r0, #IOC_BASE
                str     r0, [r0, #0x18]
                str     r0, [r0, #0x28]
                str     r0, [r0, #0x38]
                mov     r0, #0                  @ Lowest location
                adr     r1, Lvectors
                ldmia   r1, {r2, r3, r4, r5, r6, r7, ip}
                add     r1, ip, r1, asr #2
                add     r2, r1, r2, asr #2
                add     r3, r1, r3, asr #2
                add     r4, r1, r4, asr #2
                add     r5, r1, r5, asr #2
                add     r6, r1, r6, asr #2
                add     r7, r1, r7, asr #2
                adr     r1, Lswi_reset
                ldmia   r1, {r1, r8, r9}
                stmia   r0!, {r1 - r9}          @ Save all into page 0 ram
                ldmfd   sp!, {r4 - r9, pc}^

/**************************************************************************
 * Prefetch abort handler
 */

#ifdef DEBUG_UNDEF
t:              .ascii "*** undef ***\r\n\0"
                .align
#endif

Lvector_prefetch:
                sub     lr, lr, #4
                tst     lr, #3
                bne     Lprefetch_not_user
                USER_SAVE_ALL
                teqp    pc, #0x00000003         @ NOT a problem - doesnt change mode
                bic     r0, lr, #0xfc000003     @ Address of abort
                mov     r1, #FAULT_CODE_PREFETCH|FAULT_CODE_USER @ Error code
                mov     r2, sp                  @ Tasks registers
                bl      _do_PrefetchAbort
                teq     r0, #0                  @ If non-zero, we believe this abort..
                bne     _ret_from_sys_call
#ifdef DEBUG_UNDEF
                adr     r0,t                    @ Otherwise it was probably an undefined
                bl      _printk                 @ instruction.  (I do wish that I had a
#endif
                ldr     lr, [sp,#S_PC]          @ program to test this on.  I think its
                b       _undefinstr             @ broken at the moment though!)

Lprefetch_not_user:
                SVC_SAVE_ALL                    @ Prefetch aborts are definitely *not*
                mov     r0, sp                  @ allowed in non-user modes.  We cant
                mov     r1, #BAD_PREFETCH       @ recover from this problem.
                and     r2, lr, #3
                b       _bad_mode               @ Doesnt return

/**************************************************************************
 * Undefined instruction handler
 */
LC8:
                .word   _last_task_used_math
                .word   _current
LC9:
                .word   _fp_enter
                .word   _fp_save
                .word   _fp_restore

Lundef_not_user:
                SVC_SAVE_ALL                    @ Non-user mode
                bic     r0, lr, #0xfc000003
                and     r2, lr, #3
                sub     r0, r0, #4
                mov     r1, sp
                bl      _do_undefinstr
                SVC_RESTORE_ALL

                .global _fpreturn
                .global _fpundefinstr
Lvector_undefinstr:
                tst     lr,#3
                bne     Lundef_not_user
                USER_SAVE_ALL                   @ USER mode undefined instructions
                teqp    pc, #0x08000003         @ MUST disable interrupts.
_undefinstr:
@
@ before calling FP, must call math_state_restore!!!
@  something along the lines of:
@
                adr     r3, LC8
                ldmia   r3, {r1, r2, r3}
                ldr     r1, [r1]                @ last task used math
                ldr     r2, [r2]                @ current task
                teq     r1, r2
                stmnefd sp!, {ip, lr}
                blne    _math_state_restore
                ldmnefd sp!, {ip, lr}

                ldr     r3, [pc, #LC9 - . - 8]
                ldr     pc, [r3]                @ Call FP module (when loaded)
_fpundefinstr:  mov     r1,sp                   @ Called by FP module on undefined instr
                teqp    pc, #3                  @ Enable interrupts
                mov     r2,#0
                mov     lr, pc
@ Change!!
                add     lr, lr, #_ret_from_sys_call - . - 4
                b       _do_undefinstr

/**************************************************************************
 * Address exception handler
 *
 * These aren't too critical. (they're not supposed to happen).
 */

/*
 * In order to debug the reason for address exceptions in non-user modes,
 * we have to obtain all the registers so that we can see what's going on.
 */
Laddrexcptn_illegal_mode:
                mov     r0, sp
                str     lr, [sp, #-4]!
                orr     r1, r2, #0x0c000000
                teqp    r1, #0                  @ change into mode (wont be user mode)
                mov     r0, r0
                mov     r1, r8                  @ Any register from r8 - r14 can be banked
                mov     r2, r9
                mov     r3, r10
                mov     r4, r11
                mov     r5, r12
                mov     r6, r13
                mov     r7, r14
                teqp    pc, #0x04000003         @ back to svc
                mov     r0, r0
                stmfd   sp!, {r1-r7}
                ldmia   r0, {r0-r7}
                stmfd   sp!, {r0-r7}
                mov     r0, sp
                mov     r1, #BAD_ADDREXCPTN
                b       _bad_mode

Laddrexcptn_not_user:
                SVC_SAVE_ALL
                and     r2, lr, #3
                teq     r2, #3
                bne     Laddrexcptn_illegal_mode
                teqp    pc, #0x00000003         @ NOT a problem - doesnt change mode
                bic     r0, lr, #0xfc000003
                mov     r1, sp
                orr     r2, r2, #0x400
                bl      _do_excpt
                ldmia   sp, {r0 - lr}           @ I cant remember the reason I changed this...
                add     sp, sp, #15*4
                movs    pc, lr

Lvector_addrexcptn:
                sub     lr, lr, #8
                tst     lr, #3
                bne     Laddrexcptn_not_user
                USER_SAVE_ALL
                teq     pc, #0x00000003
                bic     r0, lr, #0xfc000003     @ Point to instruction
                mov     r1, sp                  @ Point to registers
                mov     r2, #0x400
                mov     lr, pc
@ Change!!
                add     lr, lr, #_ret_from_sys_call - . - 4
                b       _do_excpt

/**************************************************************************
 * Data abort handler code
 */

Lvector_data:   sub     lr, lr, #8              @ Correct lr
                tst     lr, #3
                bne     Ldata_not_user
                USER_SAVE_ALL
                teqp    pc, #0x00000003         @ NOT a problem - doesnt change mode
                bic     r0, lr, #0xfc000003
                mov     r2, #FAULT_CODE_USER
                mov     lr, pc
                add     lr, lr, #_ret_from_sys_call - . - 4
                b       Ldata_do

Ldata_not_user:
                SVC_SAVE_ALL
                and     r2, lr, #3
                teq     r2, #3
                bne     Ldata_illegal_mode
                tst     lr, #0x08000000
                teqeqp  pc, #0x00000003         @ NOT a problem - doesnt change mode
                bic     r0, lr, #0xfc000003
                mov     r2, #0
                bl      Ldata_do
                SVC_RESTORE_ALL

Ldata_illegal_mode:
                mov     r0, sp
                mov     r1, #BAD_DATA
                b       _bad_mode

/**************************************************************************
 *
 * All exits to user mode from the kernel go through this code.
 */

LC6:
                .word   _intr_count             @ -8
                .word   _bh_mask                @ -4
                .word   _bh_active              @ -0
                .word   _need_resched           @ +4
                .word   _current                @ +8
                .word   _init_task              @ +12

Lreschedule:    bl      _schedule
_fpreturn:
_ret_from_sys_call:
                adr     r4, LC6
                ldmia   r4, {r4, r6, r7, r9}
                ldr     r5, [r4]
                teq     r5, #0
                bne     Lret_no_check
Lrecheck_bh:    ldr     r0, [r6]
                ldr     r1, [r7]
                tst     r0, r1
                bne     Lhandle_bottom_half
                ldr     r0, [sp, #S_PC]         @ Get old PC
                tst     r0, #3
                bne     Lret_no_check
                ldr     r0, [r9]
                teq     r0, #0
                bne     Lreschedule

                ldr     r2, [pc, #LC6 - . + 8]
                ldr     r2, [r2]
                ldr     r1, [pc, #LC6 - . + 12]
                teq     r2, r1
                beq     Lret_no_check

                ldr     r1, [r2, #SIGNAL]
                ldr     r0, [r2, #BLOCKED]
                bics    r1, r1, r0
                movne   r1, sp
                blne    _do_signal
Lret_no_check:  USER_RESTORE_ALL

Lhandle_bottom_half:
                add     r0, r5, #1
                str     r0, [r4]
                mov     r8, pc
                teqp    pc, #0x00000003
                bl      _do_bottom_half
                teqp    r8, #0
                str     r5, [r4]
                b       Lrecheck_bh

/**************************************************************************
 * SWI handler
 *
 *
 * We now handle sys-call tracing, and the errno in the task structure.
 * Still have a problem with >4 arguments for functions.  Theres only
 * a couple of functions in the code that have 5 arguments, so Im not
 * too worried.
 */

#include "calls.S"

LC1:            .word   _current

Lvector_swi:    USER_SAVE_ALL
                bic     lr, lr, #0xfc000003     @ get pc value from link register
                ldr     r6, [lr, #-4]           @ get swi instruction
                teqp    pc, #0x00000003         @ enable irqs
                bic     r6, r6, #0xff000000     @ mask off swi op code
                eor     r6, r6, #OS_NUMBER << 20 @ check OS number
Lretry:         cmp     r6, #NR_SYSCALLS        @ check upper syscall limit
                bcs     Lswi_bad_call
                ldr     r5, [pc, #LC1 - . - 8]
                ldr     r5, [r5]
                mov     ip, #0                  @ zero errno
                str     ip, [r5, #ERRNO]

                ldr     ip, [r5, #FLAGS]        @ check for syscall tracing
                tst     ip, #PF_TRACESYS
                bne     Ltrace_this_syscall

                adr     ip, _sys_call_table
                mov     r9, sp                  @ hack for old routines needing '*regs'
                str     r4, [sp, #-4]!          @ new-style: (r0 = arg1, r4 = arg5)
                mov     lr, pc
                ldr     pc, [ip, r6, lsl #2]    @ call sys routine (r0, r1, r2, r3, r4)
                add     sp, sp, #4

                ldr     ip, [r5, #ERRNO]        @ check errno
                rsbs    ip, ip, #0
                movne   r0, ip
                str     r0, [sp, #0]            @ returned r0
                b       _ret_from_sys_call

Ltrace_this_syscall:
                ldr     r7, [sp, #S_IP]
                mov     r0, #0
                str     r0, [sp, #S_IP]
                bl      _syscall_trace          @ trace entry [IP must = 0]
                str     r7, [sp, #S_IP]
                ldmia   sp, {r0 - r3}           @ have to reload r0 - r3

                adr     ip, _sys_call_table
                mov     r9, sp                  @ hack for routines needing '*regs'
                str     r4, [sp, #-4]!
                mov     lr, pc
                ldr     pc, [ip, r6, lsl #2]    @ call sys routine (r0, r1, r2, r3, r4)
                add     sp, sp, #4

                ldr     ip, [r5, #ERRNO]
                rsbs    ip, ip, #0
                movne   r0, ip
                str     r0, [sp, #0]            @ returned r0

                mov     r0, #1
                str     r0, [sp, #S_IP]
                bl      _syscall_trace          @ trace exit [IP must != 0]
                str     r7, [sp, #S_IP]
                b       _ret_from_sys_call


Lswi_bad_call:  tst     r6, #0x00f00000
                bne     Lbad
                cmp     r6, #(KSWI_SYS_BASE - KSWI_BASE)@ check for arm private syscalls
                bcs     Larm_sys_call
                bl      _sys_ni_syscall
                str     r0, [sp, #0]            @ returned r0
                b       _ret_from_sys_call

Lbad:           eor     r0, r6, #OS_NUMBER << 20 @ check OS number
                bl      _deferred
                ldmfd   sp, {r0 - r3}
                b       Lretry

Larm_sys_call:  bic     r0, r6, #0x000f0000
                mov     r1, sp
                bl      _arm_syscall
                b       _ret_from_sys_call

@ r0 = syscall number
@ r1 = syscall r0
@ r5 = syscall r4
@ ip = syscall table
_sys_syscall:   mov     r6, r0
                eor     r6, r6, #OS_NUMBER << 20
                cmp     r6, #NR_SYSCALLS                @ check range
                movgt   r0, #-ENOSYS
                movgt   pc, lr
                add     sp, sp, #4                      @ take of the save of our r4
                ldmib   sp, {r0 - r4}                   @ get our args
                str     r4, [sp, #-4]!                  @ Put our arg on the stack
                ldr     pc, [ip, r6, lsl #2]

                .global _sys_call_table
_sys_call_table:
#include "calls.S"

/******************************************************************************
 *
 * Data abort handler code.  This handles both exceptions from user and SVC
 *   modes, computes the address range of the problem, and does any
 *   correction that is required.  It then calls the kernel data abort routine.
 *
 * This is where I wish that the ARM would tell you which address aborted.
 */

Ldata_do:       mov     r3, sp
                ldr     r4, [r0]                @ Get instruction
                tst     r4, #1 << 20            @ Check to see if it is a write instruction
                orreq   r2, r2, #FAULT_CODE_WRITE @ Indicate write instruction
                mov     r1, r4, lsr #22         @ Now branch to the relevent processing routine
                and     r1, r1, #15 << 2
                add     pc, pc, r1
                movs    pc, lr
                b       Ldata_unknown
                b       Ldata_unknown
                b       Ldata_unknown
                b       Ldata_unknown
                b       Ldata_ldrstr_post       @ ldr   rd, [rn], #m
                b       Ldata_ldrstr_numindex   @ ldr   rd, [rn, #m]    @ RegVal
                b       Ldata_ldrstr_post       @ ldr   rd, [rn], rm
                b       Ldata_ldrstr_regindex   @ ldr   rd, [rn, rm]
                b       Ldata_ldmstm            @ ldm*a rn, <rlist>
                b       Ldata_ldmstm            @ ldm*b rn, <rlist>
                b       Ldata_unknown
                b       Ldata_unknown
                b       Ldata_ldrstr_post       @ ldc   rd, [rn], #m    @ Same as ldr   rd, [rn], #m
                b       Ldata_ldcstc_pre        @ ldc   rd, [rn, #m]
                b       Ldata_unknown
Ldata_unknown:  @ Part of jumptable
                ldr     r3, [sp, #15 * 4]
                str     r3, [sp, #-4]!
                mov     r1, r1, lsr #2
                mov     r2, r0
                mov     r3, r4
                adr     r0, Ltt
                bl      _printk
Llpxx:          b       Llpxx

Ltt:            .ascii  "Unknown data abort code %d [pc=%p, *pc=%p]\nLR=%p\0"
                .align

Ldata_ldrstr_post:
                mov     r0, r4, lsr #14         @ Get Rn
                and     r0, r0, #15 << 2        @ Mask out reg.
                teq     r0, #15 << 2
                ldr     r0, [r3, r0]            @ Get register
                biceq   r0, r0, #0xfc000003
                mov     r1, r0
                tst     r4, #1 << 21
                orrne   r2, r2, #FAULT_CODE_USER
#ifdef FAULT_CODE_LDRSTRPOST
                orr     r2, r2, #FAULT_CODE_LDRSTRPOST
#endif
                b       _do_DataAbort

Ldata_ldrstr_numindex:
                mov     r0, r4, lsr #14         @ Get Rn
                and     r0, r0, #15 << 2        @ Mask out reg.
                teq     r0, #15 << 2
                ldr     r0, [r3, r0]            @ Get register
                biceq   r0, r0, #0xfc000003
                mov     r1, r4, lsl #20
                tst     r4, #1 << 23
                addne   r0, r0, r1, lsr #20
                subeq   r0, r0, r1, lsr #20
                mov     r1, r0
#ifdef FAULT_CODE_LDRSTRPRE
                orr     r2, r2, #FAULT_CODE_LDRSTRPRE
#endif
                b       _do_DataAbort

Ldata_ldrstr_regindex:
                mov     r0, r4, lsr #14         @ Get Rn
                and     r0, r0, #15 << 2        @ Mask out reg.
                teq     r0, #15 << 2
                ldr     r0, [r3, r0]            @ Get register
                biceq   r0, r0, #0xfc000003
                and     r7, r4, #15
                teq     r7, #15                 @ Check for PC
                ldr     r7, [r3, r7, lsl #2]    @ Get Rm
                biceq   r7, r7, #0xfc000003
                and     r8, r4, #0x60           @ Get shift types
                mov     r9, r4, lsr #7          @ Get shift amount
                and     r9, r9, #31
                teq     r8, #0
                moveq   r7, r7, lsl r9
                teq     r8, #0x20               @ LSR shift
                moveq   r7, r7, lsr r9
                teq     r8, #0x40               @ ASR shift
                moveq   r7, r7, asr r9
                teq     r8, #0x60               @ ROR shift
                moveq   r7, r7, ror r9
                tst     r4, #1 << 23
                addne   r0, r0, r7
                subeq   r0, r0, r7              @ Apply correction
                mov     r1, r0
#ifdef FAULT_CODE_LDRSTRREG
                orr     r2, r2, #FAULT_CODE_LDRSTRREG
#endif
                b       _do_DataAbort

Ldata_ldmstm:
                mov     r7, #0x11
                orr     r7, r7, r7, lsl #8
                and     r0, r4, r7
                and     r1, r4, r7, lsl #1
                add     r0, r0, r1, lsr #1
                and     r1, r4, r7, lsl #2
                add     r0, r0, r1, lsr #2
                and     r1, r4, r7, lsl #3
                add     r0, r0, r1, lsr #3
                add     r0, r0, r0, lsr #8
                add     r0, r0, r0, lsr #4
                and     r7, r0, #15             @ r7 = no. of registers to transfer.
                mov     r5, r4, lsr #14         @ Get Rn
                and     r5, r5, #15 << 2
                ldr     r0, [r3, r5]            @ Get reg
                eor     r6, r4, r4, lsl #2
                tst     r6, #1 << 23            @ Check inc/dec ^ writeback
                rsbeq   r7, r7, #0
                add     r7, r0, r7, lsl #2      @ Do correction (signed)
                subne   r1, r7, #1
                subeq   r1, r0, #1
                moveq   r0, r7
                tst     r4, #1 << 21            @ Check writeback
                strne   r7, [r3, r5]
                eor     r6, r4, r4, lsl #1
                tst     r6, #1 << 24            @ Check Pre/Post ^ inc/dec
                addeq   r0, r0, #4
                addeq   r1, r1, #4
                teq     r5, #15*4               @ CHECK FOR PC
                biceq   r1, r1, #0xfc000003
                biceq   r0, r0, #0xfc000003
#ifdef FAULT_CODE_LDMSTM
                orr     r2, r2, #FAULT_CODE_LDMSTM
#endif
                b       _do_DataAbort

Ldata_ldcstc_pre:
                mov     r0, r4, lsr #14         @ Get Rn
                and     r0, r0, #15 << 2        @ Mask out reg.
                teq     r0, #15 << 2
                ldr     r0, [r3, r0]            @ Get register
                biceq   r0, r0, #0xfc000003
                mov     r1, r4, lsl #24         @ Get offset
                tst     r4, #1 << 23
                addne   r0, r0, r1, lsr #24
                subeq   r0, r0, r1, lsr #24
                mov     r1, r0
#ifdef FAULT_CODE_LDCSTC
                orr     r2, r2, #FAULT_CODE_LDCSTC
#endif
                b       _do_DataAbort

                .global _fpe_save
_fpe_save:      ldr     r1, [pc, #LC9 - . - 4]
                ldr     pc, [r1]

                .global _fpe_restore
_fpe_restore:   ldr     r1, [pc, #LC9 - . - 0]
                ldr     pc, [r1]

_fpnull:        mov     pc, lr

                .data

                .global _fp_enter
                .global _fp_save
                .global _fp_restore
_fp_enter:      .word   _fpundefinstr
_fp_save:       .word   _fpnull
_fp_restore:    .word   _fpnull

Lirq_temp:      .word   0

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.