NetBSD/sys/arch/arm/fpe-arm/armfpe_glue.S

476 lines
10 KiB
ArmAsm

/* $NetBSD: armfpe_glue.S,v 1.2 2001/11/24 03:39:18 thorpej Exp $ */
/*
* Copyright (c) 1996 Mark Brinicombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Mark Brinicombe.
* 4. The name of the company nor the name of the author may be used to
* endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* RiscBSD kernel project
*
* arm_fpe_glue.S
*
* Glue code for calling the ARM FPE core code
*
* Created : 21/12/95
*/
#define CHECK_BEFORE_USERRET
#include "assym.h"
#include <machine/asm.h>
#include <machine/cpu.h>
/*
* Glue for calling the core entry points
*/
ENTRY_NP(arm_fpe_core_disable)
stmfd sp!, {r0-r7, lr}
bl _C_LABEL(fpe_arm_core_disable)
ldmfd sp!, {r0-r7, pc}
ENTRY_NP(arm_fpe_core_enable)
stmfd sp!, {r0-r7, lr}
bl _C_LABEL(fpe_arm_core_enable)
ldmfd sp!, {r0-r7, pc}
ENTRY_NP(arm_fpe_core_initws)
stmfd sp!, {r10, lr}
mov r10, r0
bl _C_LABEL(fpe_arm_core_initws)
ldmfd sp!, {r10, pc}
ENTRY_NP(arm_fpe_core_abort)
stmfd sp!, {r1-r7, r10, lr}
mov r10, r0
mov r0, r1
mov r1, r2
bl _C_LABEL(fpe_arm_core_abort)
ldmfd sp!, {r1-r7, r10, pc}
/* Only needs to preserve r10 */
ENTRY_NP(arm_fpe_core_initcontext)
stmfd sp!, {r0-r7, r10, lr}
mov r10, r0
bl _C_LABEL(fpe_arm_core_initcontext)
ldmfd sp!, {r0-r7, r10, pc}
/* Only needs to preserve r10 */
ENTRY_NP(arm_fpe_core_changecontext)
stmfd sp!, {r1-r7, r10, lr}
mov r10, r0
bl _C_LABEL(fpe_arm_core_changecontext)
ldmfd sp!, {r1-r7, r10, pc}
/* All regs preserved */
ENTRY_NP(arm_fpe_core_shutdown)
stmfd sp!, {r0-r7, r10, lr}
bl _C_LABEL(fpe_arm_core_shutdown)
ldmfd sp!, {r0-r7, r10, pc}
/* Preserve r10 */
ENTRY_NP(arm_fpe_core_savecontext)
stmfd sp!, {r1-r7, r10, lr}
mov r10, r0
mov r0, r1
mov r1, r2
bl _C_LABEL(fpe_arm_core_savecontext)
ldmfd sp!, {r1-r7, r10, pc}
/* Preserve r10 */
ENTRY_NP(arm_fpe_core_loadcontext)
stmfd sp!, {r0-r7, r10, lr}
mov r10, r0
mov r0, r1
bl _C_LABEL(fpe_arm_core_loadcontext)
ldmfd sp!, {r0-r7, r10, pc}
/* Only needs to preserve r10 */
ENTRY_NP(arm_fpe_core_activatecontext)
stmfd sp!, {r0-r7, r10, lr}
mov r10, r0
bl _C_LABEL(fpe_arm_core_activatecontext)
ldmfd sp!, {r0-r7, r10, pc}
/* Only needs to preserve r10 */
ENTRY_NP(arm_fpe_core_deactivatecontext)
stmfd sp!, {r1-r7, r10, lr}
bl _C_LABEL(fpe_arm_core_deactivatecontext)
ldmfd sp!, {r1-r7, r10, pc}
/*
* Call back functions from the core
*/
ENTRY_NP(arm_fpe_newhandler)
stmfd sp!, {r0, lr}
ldr r0, Llocal_handler_addr
str r1, [r0]
ldmfd sp!, {r0, pc}
Llocal_handler_addr:
.word _C_LABEL(undefined_handler_address)
ENTRY_NP(arm_fpe_restorehandler)
stmfd sp!, {r0-r1, lr}
ldr r0, Llocal_handler_addr
ldr r1, Lold_handler_addr
ldr r1, [r1]
str r1, [r0]
ldmfd sp!, {r0-r1, pc}
Lold_handler_addr:
.word _C_LABEL(arm_fpe_old_handler_address)
ENTRY_NP(arm_fpe_handle_exception)
b _C_LABEL(arm_fpe_exception_glue)
ENTRY_NP(arm_fpe_get_ws)
sub sp, sp, #8
str r0, [sp]
ldr r0, Larm_fpe_core_workspace
ldr r0, [r0]
str r0, [sp, #4]
ldr r0, [sp], #4
mov pc, lr
Larm_fpe_core_workspace:
.word _C_LABEL(arm_fpe_core_workspace)
ENTRY_NP(arm_fpe_post_proc)
b _C_LABEL(arm_fpe_post_proc_glue)
/* Simple call back function that panics */
ENTRY_NP(arm_fpe_panic)
adr r0, Lfpe_panic_text
b _C_LABEL(panic)
Lfpe_panic_text:
.asciz "armfpe: we are panicing"
.align 0
/*
* Call back routine from FPE on completion of an instruction
*/
#ifdef CHECK_BEFORE_USERRET
.global _C_LABEL(userret_count0)
.global _C_LABEL(userret_count1)
.data
_C_LABEL(userret_count0):
.word 0
_C_LABEL(userret_count1):
.word 0
.text
Luserret_count0:
.word _C_LABEL(userret_count0)
Luserret_count1:
.word _C_LABEL(userret_count1)
Lwant_resched:
.word _C_LABEL(want_resched)
Lcurproc:
.word _C_LABEL(curproc)
Lcurpriority:
.word _C_LABEL(cpu_info_store)
#endif
ENTRY_NP(arm_fpe_post_proc_glue)
stmfd sp!, {r0-r3, lr}
#ifdef CHECK_BEFORE_USERRET
/* Call userret if we need a reschedule */
/* Debugging */
ldr r0, Luserret_count0
ldr r1, [r0]
add r1, r1, #1
str r1, [r0]
/* Do we need a reschedule */
ldr r0, Lwant_resched
ldr r0, [r0]
teq r0, #0x00000000
bne Lwe_need_userret
/* All other userret requirement conditions come from curproc */
ldr r0, Lcurproc
ldr r0, [r0]
/* Remember the flags field */
ldr r3, [r0, #(P_FLAG)]
/* Get the signal list */
ldr r1, [r0, #(P_SIGLIST)]
teq r1, #0x00000000
beq Lno_signals_pending
tst r3, #(P_TRACED)
bne Lwe_need_userret
ldr r1, [r0, #(P_SIGLIST)]
ldr r2, [r0, #(P_SIGMASK)]
bic r1, r1, r2
teq r1, #0x00000000
bne Lwe_need_userret
Lno_signals_pending:
/* Are we profiling ? */
tst r3, #(P_PROFIL)
bne Lwe_need_userret
/* Update the current priority */
ldrb r1, [r0, #(P_USRPRI)]
strb r1, [r0, #(P_PRIORITY)]
ldr r0, Lcurpriority
strb r1, [r0, #(CI_CURPRIORITY)]
/* Fast return */
ldmfd sp!, {r0-r3, pc}
Lwe_need_userret:
/* Ok we need to call userret() */
stmfd sp!, {r4-r6, r10-r12}
/* Debugging */
ldr r0, Luserret_count1
ldr r1, [r0]
add r1, r1, #1
str r1, [r0]
#endif
/* This could be optimised as we are going from UND32->SVC32 mode */
mrs r4, cpsr_all
bic r3, r4, #(PSR_MODE)
orr r3, r3, #(PSR_SVC32_MODE)
msr cpsr_all, r3
mov r0, r12
/* Reserve a trapframe on the SVC stack */
sub sp, sp, #(TRAPFRAMESIZE)
mov r1, sp
ldr r2, [r0, #-0x0008] /* Copy spsr */
str r2, [r1], #0x0004
ldmia r0!, {r2, r3, r5, r6} /* copy r0-r5 */
stmia r1!, {r2, r3, r5, r6}
ldmia r0!, {r2, r3, r5, r6} /* copy r6-r11 */
stmia r1!, {r2, r3, r5, r6}
ldmia r0!, {r2, r3, r5, r6} /* copy r6-r11 */
stmia r1!, {r2, r3, r5, r6}
ldmia r0!, {r2, r3, r5, r6} /* copy r12, r13, r14, r15 */
stmia r1!, {r2, r3, r5, r14}
str r6, [r1, #0x0000]
mov r0, r12
mov r1, sp
/*
* OK Question Time ...
*
* Do I need to save SVC r14 ?
* It only needs saving if this routine can interrupt something already
* running in SVC mode. Since FP is only valid from USR32 mode this
* should not happen.
*/
mov r5, r14
mov r6, r12
/* More optimisation ... Need to code an assembly version of userret() */
bl _C_LABEL(arm_fpe_postproc)
/* Release the trapframe on the SVC stack */
mov r14, r5
mov r0, sp
ldr r2, [r0], #0x0004 /* Copy spsr */
str r2, [r6, #-0x0008]
ldmia r0!, {r1, r2, r3, r5, r10, r11} /* copy r0-r5 */
stmia r6!, {r1, r2, r3, r5, r10, r11}
ldmia r0!, {r1, r2, r3, r5, r10, r11} /* copy r6-r11 */
stmia r6!, {r1, r2, r3, r5, r10, r11}
ldmia r0!, {r1, r2, r3} /* copy r12, r13, r14 */
stmia r6!, {r1, r2, r3}
ldr r1, [r0, #0x0004]
str r1, [r6]
add sp, sp, #(TRAPFRAMESIZE)
msr cpsr_all, r4
ldmfd sp!, {r4-r6, r10-r12}
ldmfd sp!, {r0-r3, pc}
/*
* Call back routine from FPE when the an exception occurs
*/
ENTRY_NP(arm_fpe_exception_glue)
stmfd sp!, {r0-r6, r10-r12, lr}
mov r10, r0
/* This could be optimised as we are going from UND32->SVC32 mode */
mrs r4, cpsr_all
bic r3, r4, #(PSR_MODE)
orr r3, r3, #(PSR_SVC32_MODE)
msr cpsr_all, r3
mov r0, r12
/* Reserve a trapframe on the SVC stack */
sub sp, sp, #(TRAPFRAMESIZE)
mov r1, sp
ldr r2, [r0, #-0x0008] /* Copy spsr */
str r2, [r1], #0x0004
ldmia r0!, {r2, r3, r5, r6} /* copy r0-r5 */
stmia r1!, {r2, r3, r5, r6}
ldmia r0!, {r2, r3, r5, r6} /* copy r6-r11 */
stmia r1!, {r2, r3, r5, r6}
ldmia r0!, {r2, r3, r5, r6} /* copy r6-r11 */
stmia r1!, {r2, r3, r5, r6}
ldmia r0!, {r2, r3, r5, r6} /* copy r12, r13, r14, r15 */
stmia r1!, {r2, r3, r5, r14}
str r6, [r1, #0x0000]
mov r0, r10 /* exception */
mov r1, r12 /* fpframe */
mov r2, sp /* trapframe */
/*
* OK Question Time ...
*
* Do I need to save SVC r14 ?
* It only needs saving if this routine can interrupt something already
* running in SVC mode. Since FP is only valid from USR32 mode this
* should not happen.
*/
mov r5, r14
mov r6, r12
/* More optimisation ... Need to code an assembly version of userret() */
bl _C_LABEL(arm_fpe_exception)
/* Release the trapframe on the SVC stack */
mov r14, r5
mov r0, sp
ldr r2, [r0], #0x0004 /* Copy spsr */
str r2, [r6, #-0x0008]
ldmia r0!, {r1, r2, r3, r5, r10, r11} /* copy r0-r5 */
stmia r6!, {r1, r2, r3, r5, r10, r11}
ldmia r0!, {r1, r2, r3, r5, r10, r11} /* copy r6-r11 */
stmia r6!, {r1, r2, r3, r5, r10, r11}
ldmia r0!, {r1, r2, r3} /* copy r12, r13, r14 */
stmia r6!, {r1, r2, r3}
ldr r1, [r0, #0x0004]
str r1, [r6]
add sp, sp, #(TRAPFRAMESIZE)
msr cpsr_all, r4
ldmfd sp!, {r0-r6, r10-r12, lr}
/* Now pull the original trapframe that the FPE pushed off the stack */
ldmdb r12, {r0, r1}
msr cpsr_all, r1
msr spsr_all, r0
mov sp, r12
ldmia sp, {r0-r14}^
mov r0, r0
add sp, sp, #15*4
ldmfd sp!, {pc}^
ENTRY_NP(arm_fpe_set_exception_mask)
rfs r1 /* Get FP status */
bic r1, r1, #0x001f0000 /* Zero exception mask */
and r0, r0, #0x0000001f /* Mask new bits */
orr r0, r1, r0, lsl #16 /* Merge */
wfs r0 /* Set status */
mov r0, r1, lsr #16 /* Return old mask */
mov pc, lr /* return */
.global _C_LABEL(fpe_nexthandler)
_C_LABEL(fpe_nexthandler):
.word _C_LABEL(undefinedinstruction_bounce)