Home | History | Annotate | Line # | Download | only in arm32
exception.S revision 1.2
      1  1.2  thorpej /*	$NetBSD: exception.S,v 1.2 2001/11/28 01:06:19 thorpej Exp $	*/
      2  1.1    chris 
      3  1.1    chris /*
      4  1.1    chris  * Copyright (c) 1994-1997 Mark Brinicombe.
      5  1.1    chris  * Copyright (c) 1994 Brini.
      6  1.1    chris  * All rights reserved.
      7  1.1    chris  *
      8  1.1    chris  * This code is derived from software written for Brini by Mark Brinicombe
      9  1.1    chris  *
     10  1.1    chris  * Redistribution and use in source and binary forms, with or without
     11  1.1    chris  * modification, are permitted provided that the following conditions
     12  1.1    chris  * are met:
     13  1.1    chris  * 1. Redistributions of source code must retain the above copyright
     14  1.1    chris  *    notice, this list of conditions and the following disclaimer.
     15  1.1    chris  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1    chris  *    notice, this list of conditions and the following disclaimer in the
     17  1.1    chris  *    documentation and/or other materials provided with the distribution.
     18  1.1    chris  * 3. All advertising materials mentioning features or use of this software
     19  1.1    chris  *    must display the following acknowledgement:
     20  1.1    chris  *	This product includes software developed by Brini.
     21  1.1    chris  * 4. The name of the company nor the name of the author may be used to
     22  1.1    chris  *    endorse or promote products derived from this software without specific
     23  1.1    chris  *    prior written permission.
     24  1.1    chris  *
     25  1.1    chris  * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
     26  1.1    chris  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     27  1.1    chris  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     28  1.1    chris  * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     29  1.1    chris  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     30  1.1    chris  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     31  1.1    chris  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     32  1.1    chris  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     33  1.1    chris  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     34  1.1    chris  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     35  1.1    chris  * SUCH DAMAGE.
     36  1.1    chris  *
     37  1.1    chris  * RiscBSD kernel project
     38  1.1    chris  *
     39  1.1    chris  * exception.S
     40  1.1    chris  *
     41  1.1    chris  * Low level handlers for exception vectors
     42  1.1    chris  *
     43  1.1    chris  * Created      : 24/09/94
     44  1.1    chris  *
     45  1.1    chris  * Based on kate/display/abort.s
     46  1.1    chris  */
     47  1.1    chris 
     48  1.1    chris #include "opt_ipkdb.h"
     49  1.1    chris #include <machine/asm.h>
     50  1.1    chris #include <machine/cpu.h>
     51  1.1    chris #include <machine/frame.h>
     52  1.1    chris #include "assym.h"
     53  1.1    chris 
     54  1.1    chris 	.text
     55  1.1    chris 	.align	0
     56  1.1    chris 
     57  1.1    chris Lastpending:
     58  1.1    chris         .word   _C_LABEL(astpending)
     59  1.1    chris 
     60  1.1    chris /*
     61  1.1    chris  * General exception exit handler
     62  1.1    chris  *
     63  1.1    chris  * It exits straight away if not returning to USR mode.
     64  1.1    chris  * This loops around delivering any pending ASTs.
     65  1.1    chris  * Interrupts are disabled at suitable points to avoid ASTs
     66  1.1    chris  * being posted between testing and exit to user mode.
     67  1.1    chris  *
     68  1.1    chris  * This function uses PULLFRAMEFROMSVCANDEXIT thus should
     69  1.1    chris  * only be called if the exception handler used PUSHFRAMEINSVC
     70  1.1    chris  */
     71  1.1    chris 
     72  1.1    chris exception_exit:
     73  1.1    chris 	mrs     r4, cpsr_all		/* Get CPSR */
     74  1.1    chris 
     75  1.1    chris 	ldr	r0, [sp]		/* Get the SPSR from stack */
     76  1.1    chris 	and	r0, r0, #(PSR_MODE)	/* Test for USR32 mode before the AST */
     77  1.1    chris 	teq	r0, #(PSR_USR32_MODE)
     78  1.1    chris 	bne	do_exit			/* Not USR mode so no AST delivery */
     79  1.1    chris 
     80  1.1    chris 	ldr	r5, Lastpending		/* Get address of astpending */
     81  1.1    chris 
     82  1.1    chris Lexception_exit_loop:
     83  1.1    chris 	orr     r0, r4, #(I32_bit)	/* Block IRQs */
     84  1.1    chris 	msr     cpsr_all, r0
     85  1.1    chris 
     86  1.1    chris 	ldr	r1, [r5]		/* Do we have an AST pending */
     87  1.1    chris 	teq	r1, #0x00000000
     88  1.1    chris 	bne	do_ast
     89  1.1    chris 
     90  1.1    chris 	PULLFRAMEFROMSVCANDEXIT		/* No AST so exit */
     91  1.1    chris 
     92  1.1    chris do_ast:
     93  1.1    chris 	mov	r1, #0x00000000		/* Clear ast pending */
     94  1.1    chris 	str	r1, [r5]
     95  1.1    chris 
     96  1.2  thorpej 	msr     cpsr_all, r4		/* Restore interrupts */
     97  1.2  thorpej 
     98  1.1    chris 	mov	r0, sp			/* arg 0 = trap frame */
     99  1.1    chris 	bl	_C_LABEL(ast)		/* call the AST handler */
    100  1.1    chris 	b	Lexception_exit_loop	/* Try and exit again */
    101  1.1    chris 
    102  1.1    chris do_exit:
    103  1.1    chris 	orr     r0, r4, #(I32_bit)	/* Disable interupts */
    104  1.1    chris 	msr     cpsr_all, r0
    105  1.1    chris 
    106  1.1    chris 	PULLFRAMEFROMSVCANDEXIT		/* Restore the trap frame and exit */
    107  1.1    chris 
    108  1.1    chris 
    109  1.1    chris /* entry point for CPU data abort */
    110  1.1    chris 
    111  1.1    chris ASENTRY_NP(data_abort_entry)
    112  1.1    chris         sub     lr, lr, #0x00000008     /* Adjust the lr */
    113  1.1    chris 
    114  1.1    chris 	PUSHFRAMEINSVC			/* Push trap frame and switch */
    115  1.1    chris 					/* to SVC32 mode */
    116  1.1    chris 
    117  1.1    chris 	mov	r0, sp			/* pass the stack pointer as r0 */
    118  1.1    chris 
    119  1.1    chris 	add	lr, pc, #exception_exit - . - 8
    120  1.1    chris 	ldr	r1, Ldata_abort_handler_address
    121  1.1    chris 	ldr	pc, [r1]
    122  1.1    chris 
    123  1.1    chris Ldata_abort_handler_address:
    124  1.1    chris 	.word	_C_LABEL(data_abort_handler_address)
    125  1.1    chris 
    126  1.1    chris 	.data
    127  1.1    chris 	.global	_C_LABEL(data_abort_handler_address)
    128  1.1    chris _C_LABEL(data_abort_handler_address):
    129  1.1    chris 	.word	abortdata
    130  1.1    chris 
    131  1.1    chris 	.text
    132  1.1    chris abortdata:
    133  1.1    chris         add     r0, pc, #abortdatamsg - . - 8
    134  1.1    chris 	b	_C_LABEL(panic)
    135  1.1    chris 
    136  1.1    chris abortdatamsg:
    137  1.1    chris         .asciz  "abortdata"
    138  1.1    chris         .align  0
    139  1.1    chris 
    140  1.1    chris 
    141  1.1    chris ASENTRY_NP(prefetch_abort_entry)
    142  1.1    chris         sub     lr, lr, #0x00000004     /* Adjust the lr */
    143  1.1    chris 
    144  1.1    chris 	PUSHFRAMEINSVC
    145  1.1    chris 
    146  1.1    chris  	mov	r0, sp			/* pass the stack pointer as r0 */
    147  1.1    chris 
    148  1.1    chris 	add	lr, pc, #exception_exit - . - 8
    149  1.1    chris 	ldr	r1, Lprefetch_abort_handler_address
    150  1.1    chris 	ldr	pc, [r1]
    151  1.1    chris 
    152  1.1    chris Lprefetch_abort_handler_address:
    153  1.1    chris 	.word	_C_LABEL(prefetch_abort_handler_address)
    154  1.1    chris 
    155  1.1    chris 	.data
    156  1.1    chris 	.global	_C_LABEL(prefetch_abort_handler_address)
    157  1.1    chris 
    158  1.1    chris _C_LABEL(prefetch_abort_handler_address):
    159  1.1    chris 	.word	abortprefetch
    160  1.1    chris 
    161  1.1    chris 	.text
    162  1.1    chris abortprefetch:
    163  1.1    chris         add     r0, pc, #abortprefetchmsg - . - 8
    164  1.1    chris 	b	_C_LABEL(panic)
    165  1.1    chris 
    166  1.1    chris abortprefetchmsg:
    167  1.1    chris         .asciz  "abortprefetch"
    168  1.1    chris         .align  0
    169  1.1    chris 
    170  1.1    chris 
    171  1.1    chris /*
    172  1.1    chris  * swi_entry
    173  1.1    chris  *
    174  1.1    chris  * Main entry point for the SWI vector
    175  1.1    chris  */
    176  1.1    chris 
    177  1.1    chris ASENTRY_NP(swi_entry)
    178  1.1    chris 	PUSHFRAME
    179  1.1    chris 
    180  1.1    chris  	sub	r0, lr, #0x00000004	/* Get the address of the SWI */
    181  1.1    chris 	ldr	r4, [r0]		/* Get the instruction */
    182  1.1    chris 
    183  1.1    chris 	bic	r1, r4, #0xff000000	/* Extract the comment field */
    184  1.1    chris 
    185  1.1    chris 	mov	r0, sp			/* Pass the frame to any function */
    186  1.1    chris 
    187  1.1    chris 	bl	_C_LABEL(syscall)	/* It's a syscall ! */
    188  1.1    chris 
    189  1.1    chris 	ldr	r5, Lastpending		/* Get address of astpending */
    190  1.1    chris 	mrs     r4, cpsr_all		/* Get CPSR */
    191  1.1    chris 
    192  1.1    chris swi_exit_loop:
    193  1.1    chris 	orr     r0, r4, #(I32_bit)	/* Disable IRQs */
    194  1.1    chris 	msr     cpsr_all, r0
    195  1.1    chris 
    196  1.1    chris 	ldr	r1, [r5]		/* Do we have an AST pending */
    197  1.1    chris 	teq	r1, #0x00000000
    198  1.1    chris 	bne	do_swi_ast
    199  1.1    chris 
    200  1.1    chris 	PULLFRAME
    201  1.1    chris 	movs	pc, lr			/* Exit */
    202  1.1    chris 
    203  1.1    chris do_swi_ast:
    204  1.1    chris 	mov	r1, #0x00000000		/* Clear ast pending */
    205  1.1    chris 	str	r1, [r5]
    206  1.2  thorpej 
    207  1.2  thorpej 	msr     cpsr_all, r4		/* Restore interrupts */
    208  1.1    chris 
    209  1.1    chris 	mov	r0, sp			/* arg 0 = trap frame */
    210  1.1    chris 	bl	_C_LABEL(ast)		/* call the AST handler */
    211  1.1    chris 	b	swi_exit_loop		/* Try and exit again */
    212  1.1    chris 
    213  1.1    chris 
    214  1.1    chris /*
    215  1.1    chris  * We indirect the undefined vector via the handler address
    216  1.1    chris  * in the data area.
    217  1.1    chris  * Entry to the undefined handler must look like direct
    218  1.1    chris  * entry from the vector.
    219  1.1    chris  */
    220  1.1    chris 
    221  1.1    chris ASENTRY_NP(undefined_entry)
    222  1.1    chris #ifdef IPKDB
    223  1.1    chris /*
    224  1.1    chris  * IPKDB must be hooked in at the earliest possible entry point.
    225  1.1    chris  *
    226  1.1    chris  */
    227  1.1    chris /*
    228  1.1    chris  * Make room for all registers saving real r0-r7 and r15.
    229  1.1    chris  * The remaining registers are updated later.
    230  1.1    chris  */
    231  1.1    chris 	stmfd	sp!, {r0,r1}		/* psr & spsr */
    232  1.1    chris 	stmfd	sp!, {lr}		/* pc */
    233  1.1    chris 	stmfd	sp!, {r0-r14}		/* r0-r7, r8-r14 */
    234  1.1    chris /*
    235  1.1    chris  * Get previous psr.
    236  1.1    chris  */
    237  1.1    chris 	mrs	r7, cpsr_all
    238  1.1    chris 	mrs	r0, spsr_all
    239  1.1    chris 	str	r0, [sp, #(16*4)]
    240  1.1    chris /*
    241  1.1    chris  * Test for user mode.
    242  1.1    chris  */
    243  1.1    chris 	tst	r0, #0xf
    244  1.1    chris 	bne	Lprenotuser_push
    245  1.1    chris 	add	r1, sp, #(8*4)
    246  1.1    chris 	stmia	r1,{r8-r14}^		/* store user mode r8-r14*/
    247  1.1    chris 	b	Lgoipkdb
    248  1.1    chris /*
    249  1.1    chris  * Switch to previous mode to get r8-r13.
    250  1.1    chris  */
    251  1.1    chris Lprenotuser_push:
    252  1.1    chris 	orr	r0, r0, #(I32_bit) /* disable interrupts */
    253  1.1    chris 	msr	cpsr_all, r0
    254  1.1    chris 	mov	r1, r8
    255  1.1    chris 	mov	r2, r9
    256  1.1    chris 	mov	r3, r10
    257  1.1    chris 	mov	r4, r11
    258  1.1    chris 	mov	r5, r12
    259  1.1    chris 	mov	r6, r13
    260  1.1    chris 	msr	cpsr_all, r7		/* back to undefined mode */
    261  1.1    chris 	add	r8, sp, #(8*4)
    262  1.1    chris 	stmia	r8, {r1-r6}		/* r8-r13 */
    263  1.1    chris /*
    264  1.1    chris  * Now back to previous mode to get r14 and spsr.
    265  1.1    chris  */
    266  1.1    chris 	msr	cpsr_all, r0
    267  1.1    chris 	mov	r1, r14
    268  1.1    chris 	mrs	r2, spsr
    269  1.1    chris 	msr	cpsr_all, r7		/* back to undefined mode */
    270  1.1    chris 	str	r1, [sp, #(14*4)]	/* r14 */
    271  1.1    chris 	str	r2, [sp, #(17*4)]	/* spsr */
    272  1.1    chris /*
    273  1.1    chris  * Now to IPKDB.
    274  1.1    chris  */
    275  1.1    chris Lgoipkdb:
    276  1.1    chris 	mov	r0, sp
    277  1.1    chris 	bl	_C_LABEL(ipkdb_trap_glue)
    278  1.1    chris 	ldr	r1, Lipkdb_trap_return
    279  1.1    chris 	str	r0,[r1]
    280  1.1    chris /*
    281  1.1    chris  * Have to load all registers from the stack.
    282  1.1    chris  *
    283  1.1    chris  * Start with spsr and pc.
    284  1.1    chris  */
    285  1.1    chris 	ldr	r0, [sp, #(16*4)]	/* spsr */
    286  1.1    chris 	ldr	r1, [sp, #(15*4)]	/* r15 */
    287  1.1    chris 	msr	spsr_all, r0
    288  1.1    chris 	mov	r14, r1
    289  1.1    chris /*
    290  1.1    chris  * Test for user mode.
    291  1.1    chris  */
    292  1.1    chris 	tst	r0, #0xf
    293  1.1    chris 	bne	Lprenotuser_pull
    294  1.1    chris 	add	r1, sp, #(8*4)
    295  1.1    chris 	ldmia	r1, {r8-r14}^		/* load user mode r8-r14 */
    296  1.1    chris 	b	Lpull_r0r7
    297  1.1    chris Lprenotuser_pull:
    298  1.1    chris /*
    299  1.1    chris  * Now previous mode spsr and r14.
    300  1.1    chris  */
    301  1.1    chris 	ldr	r1, [sp, #(17*4)]		/* spsr */
    302  1.1    chris 	ldr	r2, [sp, #(14*4)]		/* r14 */
    303  1.1    chris 	orr	r0, r0, #(I32_bit)
    304  1.1    chris 	msr	cpsr_all, r0			/* switch to previous mode */
    305  1.1    chris 	msr	spsr_all, r1
    306  1.1    chris 	mov	r14, r2
    307  1.1    chris 	msr	cpsr_all, r7			/* back to undefined mode */
    308  1.1    chris /*
    309  1.1    chris  * Now r8-r13.
    310  1.1    chris  */
    311  1.1    chris 	add	r8, sp, #(8*4)
    312  1.1    chris 	ldmia	r8, {r1-r6}		/* r8-r13 */
    313  1.1    chris 	msr	cpsr_all, r0
    314  1.1    chris 	mov	r8, r1
    315  1.1    chris 	mov	r9, r2
    316  1.1    chris 	mov	r10, r3
    317  1.1    chris 	mov	r11, r4
    318  1.1    chris 	mov	r12, r5
    319  1.1    chris 	mov	r13, r6
    320  1.1    chris 	msr	cpsr_all, r7
    321  1.1    chris Lpull_r0r7:
    322  1.1    chris /*
    323  1.1    chris  * Now the rest of the registers.
    324  1.1    chris  */
    325  1.1    chris 	ldr	r1,Lipkdb_trap_return
    326  1.1    chris 	ldr	r0,[r1]
    327  1.1    chris 	tst	r0,r0
    328  1.1    chris 	ldmfd	sp!, {r0-r7}		/* r0-r7 */
    329  1.1    chris 	add	sp, sp, #(10*4)		/* adjust sp */
    330  1.1    chris 
    331  1.1    chris /*
    332  1.1    chris  * Did IPKDB handle it?
    333  1.1    chris  */
    334  1.1    chris 	movnes	pc, lr			/* return */
    335  1.1    chris 
    336  1.1    chris #endif
    337  1.1    chris 	stmfd	sp!, {r0, r1}
    338  1.1    chris 	ldr	r0, Lundefined_handler_indirection
    339  1.1    chris 	ldr	r1, [sp], #0x0004
    340  1.1    chris 	str	r1, [r0, #0x0000]
    341  1.1    chris 	ldr	r1, [sp], #0x0004
    342  1.1    chris 	str	r1, [r0, #0x0004]
    343  1.1    chris 	ldmia	r0, {r0, r1, pc}
    344  1.1    chris 
    345  1.1    chris #ifdef IPKDB
    346  1.1    chris Lipkdb_trap_return:
    347  1.1    chris 	.word	Lipkdb_trap_return_data
    348  1.1    chris #endif
    349  1.1    chris 
    350  1.1    chris Lundefined_handler_indirection:
    351  1.1    chris 	.word	Lundefined_handler_indirection_data
    352  1.1    chris 
    353  1.1    chris /*
    354  1.1    chris  * assembly bounce code for calling the kernel
    355  1.1    chris  * undefined instruction handler. This uses
    356  1.1    chris  * a standard trap frame and is called in SVC mode.
    357  1.1    chris  */
    358  1.1    chris 
    359  1.1    chris ENTRY_NP(undefinedinstruction_bounce)
    360  1.1    chris 	PUSHFRAMEINSVC
    361  1.1    chris 	mov	r0, sp
    362  1.1    chris 	bl	_C_LABEL(undefinedinstruction)
    363  1.1    chris 
    364  1.1    chris 	b	exception_exit
    365  1.1    chris 
    366  1.1    chris 	.data
    367  1.1    chris 	.align	0
    368  1.1    chris 
    369  1.1    chris #ifdef IPKDB
    370  1.1    chris Lipkdb_trap_return_data:
    371  1.1    chris 	.word	0
    372  1.1    chris #endif
    373  1.1    chris 
    374  1.1    chris /*
    375  1.1    chris  * Indirection data
    376  1.1    chris  * 2 words use for preserving r0 and r1
    377  1.1    chris  * 3rd word contains the undefined handler address.
    378  1.1    chris  */
    379  1.1    chris 
    380  1.1    chris Lundefined_handler_indirection_data:
    381  1.1    chris 	.word	0
    382  1.1    chris 	.word	0
    383  1.1    chris 
    384  1.1    chris 	.global	_C_LABEL(undefined_handler_address)
    385  1.1    chris _C_LABEL(undefined_handler_address):
    386  1.1    chris 	.word	_C_LABEL(undefinedinstruction_bounce)
    387  1.1    chris 
    388  1.1    chris /* End of exception.S */
    389