;
;    DivaPC ARM Assembler source
;
;    SYS.S.SYSS - Assembly-language system functions
;
;
;    15-04-92 INH  Original
;    07-12-93      Service ID removed
;    19-05-95 DAF  Corrected SYSs_CallViaR12 - had bug due to me giving
;                  INH the wrong version of code.
;

    GET SYS.S.STDDEFS



    AREA |C$$Code|, CODE, READONLY

    EXPORT  SYSs_CallViaR12



; CallViaR12 ---------------------------------

; This is Borris' CPU.S.R12SUPP, moved here 16/5/95

; Assembler support routine for performing 'far' call into a module.
; Used in contexts such as transfer and notify functions of DMA
; handler when R12_value is not zero.
;
; uint SYSs_CallViaR12(_kernel_swi_regs *inout, int fnaddr, uint R12_value)
;
; Can be called from USR, SVC or IRQ mode.
; Must not be called from FIQ mode.
;
; Not truly APCS, but you shouldn't be doing an APCS stack trace through
; this point anyway!
;
; Interrupt mode preserved across call.
; USR mode (probably) calls with IRQs enabled.
; SVC mode preserves entry IRQ state.
; IRQ mode disables IRQs for entry to user's routine
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


USR_mode	*	2_00
IRQ_mode	*	2_10
SVC_mode	*	2_11
I_bit		*	1 :SHL: 27


SYSs_CallViaR12  ROUT

            STMFD   SP!, {R4, LR}    ; onto whichever stack is current

            MOV     R3, PC
            ANDS    R3, R3, #3
            ASSERT  USR_mode = 0
            BEQ     %f10            ; call from USR mode

            TEQ     R3, #SVC_mode   ; aLReady in SVC mode?
            BNE     %f20            ; must be IRQ mode (FIQ not allowed)

            MOV     R4, R1          ; fnptr
            MOV     R12, R2         ; R12_value
            LDMFD   R0, {R0-R3}     ; inout
            MOV     LR, PC          ; return straight after
            MOV     PC, R4          ; fnptr

            LDMFD   SP!, {R4, PC}^  ; return (maybe to wrapper)

; Handle USR => SVC call - fairly basic wrapper

10
            EnterSVCmode
            BL      SYSs_CallViaR12
            ExitSVCmode
            LDMFD   SP!, {R4, PC}^  ; exit through USR stack

; Handle IRQ => SVC call - little more complicated

20          MOV     R3, PC
            ORR     R3, R3, # SVC_mode + I_bit
            TEQP    R3, # 0
            MOV     R0, R0          ; SVC mode, IRQs disabled

            STMFD   SP!, {LR}       ; preserve SVC's R14
            BL      SYSs_CallViaR12 ; Call now in SVC mode
            LDMFD   SP!, {LR}       ; restore SVC's R14

            TEQ     PC, # IRQ_mode + I_bit
            MOV     R0, R0          ; snore

            LDMFD   SP!, {R4, PC}^  ; restores IRQ entry state


    END


