;===========================================================================
;
;FILE: swihandler.s
;
;SERVICES: Software Interrupt Handler for BRIDLE
;
;DESCRIPTION
;  This file contains the implementation of the software interrupt handler
;  and other functions required for BREW memory protection
;
;
;PUBLIC CLASSES:  
;   N/A
;
;INITIALIZATION AND SEQUENCING REQUIREMENTS:  N/A
;
;
;        Copyright © 1999-2003 QUALCOMM Incorporated.
;               All Rights Reserved.
;            QUALCOMM Proprietary/GTDR
;==========================================================================
   EXPORT SWI_Handler
   EXPORT bridle_SwitchToUser
   EXPORT bridle_SwitchToSystem
   IMPORT g_bridle_SubSystems

; SWI No. used by BRIDLE. If OEMs are already using this for something
; else, this number may be changed 
BRIDLE_SWI_NO EQU 0x10

MAX_SWI_NEST EQU 8
MAX_SWI_NO EQU 125
PART_MASK  EQU 0xFFF

;-------------------------------------------------------------------------
; array of pointers to saved spots on the SVC stack, for nested SVC-USR->SVC
; max nest of 8, TODO: make these per-rex task
;-------------------------------------------------------------------------
   AREA BRIDLESCVSTACK, DATA, READWRITE

g_bridle_SVCStack      SPACE   32 ; array of stack pointers 8 deep
g_bridle_SWINestLevel  DCD     0  ; index into SVCStack


   AREA BRIDLESAFECALL, CODE, READONLY
   CODE32

bridle_SwitchToSystem
      LDR    r12,  [r13]
      STMFD  r13!, {r11, r14}
      SWI    BRIDLE_SWI_NO
      LDMFD  r13!, {r11, r14}
      BX     r14
     
bridle_switch_to_user
;below msr not only changes mode, but lose previous state of cpsr
;this is not a risk because we know we are in arm etc..
      MOV   r12,   r14
      MSR   cpsr_cxsf, #0x10
      MOV   r14,   pc
      BX    r12 
      MOV   r12,   #0x01
      SWI   BRIDLE_SWI_NO
           
   AREA BRIDLESWI, CODE, READONLY
   CODE32
;-------------------------------------------------------------------------
; bridle_SwitchToUser
;-------------------------------------------------------------------------

bridle_SwitchToUser
      LDR   r12,  [r13]
      STMFD r13!, {r14}
      STMFD r13!, {r1, r3}
      LDR   r1,   =g_bridle_SVCStack      ;Start of the SVC stack array.
                                          ;The array maintains the SVC
                                          ;stack for each nest level
      LDR   r3,   =g_bridle_SWINestLevel  ;SWI nest level
      LDR   r3,   [r3]
      MOV   r3,   r3, LSL #2 
      MOV   r14,  r12
      ADD   r12,  r3, r1
      LDMFD r13!, {r1, r3}
      STR   r13,  [r12]
      LDR   r12,  =g_bridle_SWINestLevel  ;SWI nest level
      LDR   r12,  [r12]
      ADD   r12,  r12, #1                 ;Increment the SWI nest level
      STMFD r13!, {r1}
      LDR   r1,   =g_bridle_SWINestLevel
      STR   r12,  [r1]
      LDMFD r13!, {r1}
      LDR   r12,  =bridle_switch_to_user
      BX    r12

;-------------------------------------------------------------------------
; SWI_Handler
;-------------------------------------------------------------------------
SWI_Handler    ; will always be in arm mode
      ;IRQs are disabled when we get here. 
      ;First thing we do is restore the SVC mode stack
      LDR     r13,  =g_bridle_SVCStack
      LDR     r11,  =g_bridle_SWINestLevel
      LDR     r11,  [r11]
      SUB     r11,  r11, #1
      LDR     r13,  [r13, r11, LSL #2]

      STMFD   r13!, {r4, r11, r14}   ; Save registers
      MRS     r11,  spsr              ; Get spsr
      STMFD   r13!, {r11}
      MOV     r11,  #0xF
      MOV     r11,  r11, LSL #28
      BIC     r12,  r12, r11          ; because we came from User mode
      MRS     r11,  cpsr
      BIC     r11,  r11, #0xc0        ; clear the IRQ disable bit
      MSR     cpsr_cxsf, r11
      MOV     r4,   r12, LSL #0x0C
      MOV     r4,   r4, LSR #0x0C
      CMP     r4,   #1
      BEQ     special_swi            ; This gets called from bridle_switch_to_user
                                     ; If called mischeviously by the user, it will
                                     ; cause the UI task to abort handling of the
                                     ; BREW signal and continue, but that is not dangerous
                                     ; since we were going to continue anyway after
                                     ; the BREW signals wer taken care of. The code
                                     ; has no danger of jumping to any other location
                                     ; since the return register is restored from the
                                     ; stack that was saved when we switched to user.
      CMP     r4,   #MAX_SWI_NO
      BGT     No_Handler
      LDR     r11,  =g_bridle_SubSystems
      LDR     r11,  [r11, r4, LSL #2]
      MOV     r4,   r12
;***********************************************
      STMFD   r13!, {r3}
      MOV     r3,   r2
      MOV     r2,   r1
      MOV     r1,   r0
      MOV     r0,   r4
;*************************************************
      MOV     r14,  pc
      BX      r11
;************************************************
      LDMFD  r13!, {r3}
;************************************************
      MRS     r12,  cpsr
      ORR     r12,  r12, #0xC0
      MSR     cpsr_cxsf, r12
      LDMFD   r13!, {r11}         
      MSR     spsr_cxsf, r11
      LDMFD   r13!, {r4, r11, pc}^         ; Restore registers and return

special_swi 
      LDR     r11,  =g_bridle_SWINestLevel
      LDR     r4,   [r11]
      SUB     r4,   r4, #1
      STR     r4,   [r11]
      LDMFD   r13!, {r11}         
      LDMFD   r13!, {r4, r11, r14}        ; Restore registers and return
      LDMFD   r13!, {r14}
      BX      r14

No_Handler
      MRS     r12,  cpsr
      ORR     r12,  r12, #0xC0
      MSR     cpsr_cxsf, r12
      LDMFD   r13!, {r11}         
      MSR     spsr_cxsf, r11
      LDMFD   r13!, {r4, r11, pc}^         ; Restore registers and return    

      END
