vxKernel/kernel/src/drivers/mpu/sh/sh7305/intc/inth_callback.S

102 lines
2.6 KiB
ArmAsm

#define ASM_SOURCE
#include <vhex/hardware.h>
#include "boards/fxcg50/include/hardware.h"
.text
.global _sh7305_inth_callback
/* CALLBACK HELPER
This function implements the callback with context saving. It is a general
function and does not need to reside in VBR space which is block-structured.
This function saves registers r0_bank...r7_bank, enables interrupts,
switches back to user bank and executes the callback. It does not save other
registers (pr/mach/macl/gbr) which are managed by the handler entry. */
/* sh7305_inth_callback: Indirect call from kernel space to userland
@r4 Address of callback function
-> Returns the return value of the callback (int). */
_sh7305_inth_callback:
stc.l r0_bank, @-r15
stc.l r1_bank, @-r15
stc.l r2_bank, @-r15
stc.l r3_bank, @-r15
stc.l r4_bank, @-r15
stc.l r5_bank, @-r15
stc.l r6_bank, @-r15
stc.l r7_bank, @-r15
stc.l spc, @-r15
stc.l ssr, @-r15
stc.l sr, @-r15
/* Save some values to user bank; once we enable interrupts, the kernel
bank might be overwritten at any moment. */
ldc r4, r0_bank
/* Enable interrupts and go back to user bank. On SH4, SR.IMASK is set
to the level of the current interrupt, which makes sure we can only
be re-interrupted by something with a higher priority. */
stc sr, r1
mov.l .SR_clear_RB_BL, r0
and r0, r1
/* On the fx-CG emulator, it is outright ignored. In these situations,
set IMASK to 15 to block interrupts while allowing TLB misses to be
handled. */
mov.l .vhex, r2
mov.l @(4*HWDEVICE,r2), r0
cmp/eq #HWDEVICE_FXCG_MANAGER, r0
bt .set_imask
bra .load_sr
nop
.set_imask:
mov.l .SR_set_IMASK, r0
or r0, r1
.load_sr:
ldc r1, sr
/* We are now in the user bank with r0 set. Perform the call. We want
to forward the return value to kernel bank, but this bank can be
changed at any moment since interrupts are enabled. */
sts.l pr, @-r15
mov.l @(4, r0), r4
mov.l @(8, r0), r5
mov.l @(12, r0), r6
mov.l @(16, r0), r7
mov.l @r0, r0
jsr @r0
nop
lds.l @r15+, pr
/* Restore the previous status register and the registers of the
interrupted procedure. Restoring sr gets us back to system bank with
interrupts disabled. */
ldc.l @r15+, sr
/* We can now pull the return value since interrupts are disabled */
stc r0_bank, r0
ldc.l @r15+, ssr
ldc.l @r15+, spc
ldc.l @r15+, r7_bank
ldc.l @r15+, r6_bank
ldc.l @r15+, r5_bank
ldc.l @r15+, r4_bank
ldc.l @r15+, r3_bank
ldc.l @r15+, r2_bank
ldc.l @r15+, r1_bank
rts
ldc.l @r15+, r0_bank
.align 4
.SR_clear_RB_BL:
.long ~((1 << 29) | (1 << 28))
.SR_set_IMASK:
.long (0xf << 4)
.vhex:
.long _vhex