STRUCT Error_Exit_Handler
{
 .error_buffer	DBB 260
 .use_count	DCD 0
 .ADFFS_alive	DCD 0
 .error_handler	DBB FSControl_Exit_handler - FSControl_Error_handler
 .exit_handler	DBB FSControl_Exit_handler_end - FSControl_Exit_handler
 .size
}


;setup_error_handler
;-------------------
;allocation space in RMA setup error handler for the JIT

;Entry:
; R12 - pointer to VARS

.setup_error_handler
 STMFD   R13!, {R1-R3, R14}
 MOV     R0, #Module_Claim
 MOV     R3, #Error_Exit_Handler.size
 SWI     XOS_Module
 LDMVSFD R13!, {R1-R3, PC}
 STR     R2, [R12, #Error_handler_buffer - VARS]
 MOV     R0, #0
 STR     R0, [R2, #Error_Exit_Handler.use_count]
 MOV     R0, #1
 STR     R0, [R2, #Error_Exit_Handler.ADFFS_alive]

 ADD     R1, R2, #Error_Exit_Handler.error_handler
 ADR     R0, FSControl_Error_handler
 MOV     R2, #Error_Exit_Handler.size - Error_Exit_Handler.error_handler
 BL      MemCopy
LDMFD   R13!, {R1-R3, PC}




.FSControl_Error_handler
 MOV     R6, R0
 MRS     R7, CPSR
 SWI     XOS_EnterOS
 MOV     R8, R14
 SWI     XADFFS_ShutdownThisTask	;shutdown task if being managed
 LDMIA   R6, {R1-R3, R4-R5}
 MOV     R0, #6
 SWI     XOS_ChangeEnvironment
 MOV     R0, #11			;release Exit handler
 MOV     R1, R4
 MOV     R2, R5
 SWI     XOS_ChangeEnvironment

 MOV     R0, #Module_Free
 MOV     R2, R6
 SWI     XOS_Module

 LDR     R0, FSControl_Error_handler - (Error_Exit_Handler.error_handler - Error_Exit_Handler.use_count)
 SUBS    R0, R0, #1			;decrease use count
 STR     R0, FSControl_Error_handler - (Error_Exit_Handler.error_handler - Error_Exit_Handler.use_count)
; LDREQ   R0, FSControl_Error_handler - (Error_Exit_Handler.error_handler - Error_Exit_Handler.ADFFS_alive)
; TEQEQ   R0, #0				;is ADFFS still loaded?
; MOVEQ   R0, #Module_Free
; ADREQ   R2, FSControl_Error_handler - (Error_Exit_Handler.error_handler - Error_Exit_Handler.error_buffer)
; SWIEQ   XOS_Module

 MOV     R14, R8
 MSR     CPSR_all, R7
 NOP
 ADR     R0, FSControl_Error_handler - (Error_Exit_Handler.error_handler - Error_Exit_Handler.error_buffer) + 4
SWI     OS_GenerateError


.FSControl_Exit_handler
 MRS     R7, CPSR
 SWI     XOS_EnterOS
 MOV     R8, R14
 SWI     XADFFS_ShutdownThisTask	;shutdown task if being managed
 LDMIA   R12, {R1-R3, R4-R5}
 MOV     R0, #6
 SWI     XOS_ChangeEnvironment
 MOV     R0, #11			;release Exit handler
 MOV     R1, R4
 MOV     R2, R5
 SWI     XOS_ChangeEnvironment

 MOV     R0, #Module_Free
 MOV     R2, R12
 SWI     XOS_Module

 LDR     R0, FSControl_Exit_handler - (Error_Exit_Handler.exit_handler - Error_Exit_Handler.use_count)
 SUBS    R0, R0, #1			;decrease use count
 STR     R0, FSControl_Exit_handler - (Error_Exit_Handler.exit_handler - Error_Exit_Handler.use_count)
 LDREQ   R0, FSControl_Exit_handler - (Error_Exit_Handler.exit_handler - Error_Exit_Handler.ADFFS_alive)
 TEQEQ   R0, #0				;is ADFFS still loaded?
 MOVEQ   R0, #Module_Free		;NO, free if last use
 ADREQ   R2, FSControl_Exit_handler - (Error_Exit_Handler.exit_handler - Error_Exit_Handler.error_buffer)
 SWIEQ   XOS_Module

 MOV     R14, R8
 MSR     CPSR_all, R7
 NOP
SWI     OS_Exit
.FSControl_Exit_handler_end




;claim_Error_handler
;------------------
;handle crashes returning to the desktop

.claim_Error_handler
 STMFD   R13!, {R0-R4, R11, R14}

 MOV     R0, #Module_Lookup		;find WIMP module
 ADR     R1, _WIMPModule
 SWI     XOS_Module			;PRM1-249
 LDMVSFD R13!, {R0-R4, R11, PC}		;WindowManager missing
 LDR     R4, [R3, #-4]			;R4=size, R3=module base
 ADD     R4, R4, R3			;R4=end of module

 MOV     R0, #11
 MOV     R1, #0
 MOV     R2, #0
 SWI     XOS_ChangeEnvironment
 CMP     R1, R3
 CMPHI   R4, R1				;is Exit handler in the Wimp?
 LDMLOFD R13!, {R0-R4, R11, PC}		;NO

 MOV     R0, #Module_Claim
 MOV     R3, #5*4
 SWI     XOS_Module
 LDMVSFD R13!, {R0-R4, R11, PC}		;@@@ needs to report failure
 MOV     R4, R2

 LDR     R11, Error_handler_buffer	;Error_Exit_Handler struct
 LDR     R0, [R11, #Error_Exit_Handler.use_count]
 ADD     R0, R0, #1			;increase use count
 STR     R0, [R11, #Error_Exit_Handler.use_count]

 MOV     R0, #6
 ADD     R1, R11, #Error_Exit_Handler.error_handler
 MOV     R3, R11
 SWI     XOS_ChangeEnvironment
 STMIA   R4!, {R1-R3}
 SUB     R2, R4, #3*4

 MOV     R0, #11
 ADD     R1, R11, #Error_Exit_Handler.exit_handler
 SWI     XOS_ChangeEnvironment
 STMIA   R4!, {R1-R2}
LDMFD   R13!, {R0-R4, R11, PC}

 ._WIMPModule	DCB "WindowManager", 0
		ALIGN




;vector_handler_29
;-----------------
;Takes over running a file if the JIT is running
;
;Reference PRM1-288 for actions to take depending on filetype
;          PRM1-197 for OS_UpCall 256 - new application starting
;          PRM1-266 for Service_NewApplication (not much use)
;          PRM2-85  for OS_FSControl 2 (*GO)
;          PRM2-87  for OS_FSControl 4
;
;Entry:
; R0 = reason code
; stack: {SWI stack}
; R12 = buffer for state

.vector_handler_29
 TEQ     R0, #FSControl_StartApplication	;PRM2-85 *GO?
 TEQNE   R0, #FSControl_Run			;PRM2-87 Run file?
 BNE     vector_handler_forward			;NO, hand to OS
 BL      check_JIT_and_taskID			;is the task supported?
 BEQ     _dont_claim_handlers			;YES
 BL      pre_SWI_veneer				;NO, 
 SWI     XADFFS_DoNothing
 BL      claim_Error_handler			;install Error/Exit handlers
 BL      dontexit_SWI_veneer
 B       vector_handler_forward

._dont_claim_handlers
 TEQ     R0, #FSControl_StartApplication	;PRM2-85 *GO?
 BEQ     _star_go				;YES

;FSControl 4
;
;Entry:
; R1 = pointer to command tail
;
;NOTE: Reference /RiscOs/Sources/FileSys/FileSwitch/s/FSControl RunEntry

 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XADFFS_DoNothing

 TEMP    R14
 STMFD   R13!, {R0-R11}			;preserve registers
 ADR     R10, fscontrol_filename	;R10=filename
 MOV     R2, #0
 ._copy_L1
   LDRB    R0, [R1, R2]
   STRB    R0, [R10, R2]
   TEQ     R0, #0
   TEQNE   R0, #13
   ADDNE   R2, R2, #1
   TEQNE   R2, #Max_File_Length		;ensure we dont overrun
 BNE     _copy_L1
 TEQ     R2, #Max_File_Length		;did we hit out limit
 ADREQ   R0, error_filename_too_long	;YES
 BEQ     _exit_with_error		; |+ exit with error

 ADD     R11, R10, R2			;R11=end of filename
 MOV     R0, #0
 STRB    R0, [R11, #0]			;terminate filename

 MOV     R0, #15			;R4 is path variable
 MOV     R1, R10
 ADR     R4, _run_path
 SWI     XOS_File			;PRM2-38 read file info
 BVS     _pass_to_RO			;pass to RISCOS on error
 TEQ     R0, #2				;directory?
 BLEQ     _directory			;Yes
 TEQ     R0, #1				;did we find the file?
 BNE     _pass_to_RO			;NO, hand to RISCOS

 MOV     R9, R3				;R9=execution address (if applicable)
 MOV     R6, R0				;object type
 MOV     R7, R2				;preserve load address
 MOV     R0, #FSControl_GetFileType	;get filetype
 SWI     XOS_FSControl			;PRM2-123
 BVS     _pass_to_RO			;pass to RISCOS on error

 CMN     R2, #1				;-1 no filetype?
 MOVEQ   R2, R7				;YES, use load address
 BEQ     _load_and_run			; |+  and load it

 TEQ     R2, #&FF8			;Absolute
 BEQ     _load_and_run_absolute

 TEQ     R2, #&FFA			;Module
 BEQ     _run_module

 TEQ     R2, #&FFC			;Utility
 BEQ     _utility

 LOCK    R14
 ._pass_to_RO
 LDMFD   R13!, {R0-R11}			;preserve registers
 BL      dontexit_SWI_veneer
B       vector_handler_forward		;hand to OS


 ._run_module
 MOV     R0, #Module_Run
 ADD     R13, R13, #4
 LDMFD   R13!, {R1-R11}			;preserve registers
 BL      dontexit_SWI_veneer
B       load_26bit_module		;run module


 ._run_path	DCB "Run$Path", 0
 ._plingrun	DCB ".!Run", 0
 		ALIGN

 ._directory				;check if !Run exists
 STR     R14, [R13, #-4]!
 ADR     R2, _plingrun

 ._directory_L1
   LDRB    R0, [R2], #1
   STRB    R0, [R11], #1
   TEQ     R0, #0
 BNE     _directory_L1

 MOV     R0, #15			;R4 is path variable
 ADR     R4, _run_path
 SWI     XOS_File			;PRM2-38 read file info
LDR     PC, [R13], #4


;Entry:
;R1 = filename
;R4 = filesize

._utility
 ADD     R4, R4, #8			;extra words for alignment
 MOV     R11, R1			;preserve R1
 MOV     R0, #Heap_Claim		;claim JIT RMA space for file
 MOV     R1, #jit_RMA_heap
 ADD     R3, R4, #&1100			;R3=file size + 1K stack
 SWI     XOS_Heap			;PRM1-379
 ADRVS   R0, Error_no_room_in_RMA	;the claim failed
 BVS     _exit_with_error		; |+ exit with error
 MOV     R1, R2
 ADD     R2, R2, #3			;ensure allocation is word aligned
 BIC     R2, R2, #%11			;R2=start of our temp stack
 STR     R1, [R2], #4			;store allocation start
 MOV     R1, R11			;preserve R1

 ADD     R3, R2, #&100			;R3=start of workspace for utility
 STR     R4, [R2], #4			;stack file size

 LDMFD   R13!, {R6-R11}			;pull R0-R5 from stack
 STMIA   R2!, {R6-R11}			;stack into buffer
 LDMFD   R13!, {R6-R11}			;pull R6-R11 from stack
 STMIA   R2!, {R6-R11}			;stack into buffer
 STMIA   R2, {R13-R14}^			;stack USER R13, R14 into buffer
 ADD     R2, R2, #8
 LDMIA   R12, {R6-R8}			;get SWI_veneer.*
 STMIA   R2!, {R6-R8}			;stack SWI_veneer.* into buffer
 STR     R2, [R13, #-4]!		;preserve R2 so we can free RMA later
					;stack: <Heap alloc>,{SWI stack},{SWI veneer}
 STR     R3, [R2, #2 * 4]		;stack new value for R12
 ADD     R3, R3, #&1000			;needs 1K workspace

 ADR     R14, _utility_return
 STR     R14, [R3, #-4]!		;stack return

 STR     R3, [R2, #3 * 4]		;stack R13
 ADD     R3, R3, #4
 ADD     R14, R3, #jit_code_start
 STR     R14, [R2, #4 * 4]		;stack PC

 STR     R1, [R13, #-4]!
 MOV     R0, #CAOPointer		;set CAO
 MOV     R1, R3				;to prevent memory shrinkage
 SWI     XOS_ChangeEnvironment		;PRM1-320
 LDR     R1, [R13], #4

 MOV     R0, #14			;R4 is path variable
 MOV     R2, R3				;load address
 MOV     R3, #0
 ADR     R4, _run_path
 SWI     XOS_File			;PRM2-43 load file hypervised
 LDR     R2, [R13]			;preserve R2

 STMFD   R13!, {R1-R2}
 SWI     XOS_GetEnv			;PRM1-301 get the environment string
 LDMFD   R13!, {R1-R2}
 STR     R0, [R2, #0 * 4]		;stack R0

 ._utility_L1
   LDRB    R14, [R1], #1		;copy command line
   STRB    R14, [R0], #1
   TEQ     R14, #0
   TEQNE   R14, #13
   TEQNE   R14, #32
 BNE     _utility_L1

 ._utility_L2				;copy any spaces
   TEQ     R14, #32
   STREQB  R14, [R0], #1
   LDREQB  R14, [R1], #1
 BEQ     _utility_L2

 SUB     R0, R0, #1			;R14=command tail
 STR     R0, [R2, #1 * 4]		;stack R1

 ._utility_L3				;copy arguments
   STRB    R14, [R0], #1
   LDRB    R14, [R1], #1
   TEQ     R14, #13
   TEQNE   R14, #0
 BNE     _utility_L3
 MOV     R14, #0
 STRB    R14, [R0]			;terminate string

 LDR     R0, [R12, #SWI_veneer.SPSR]
 AND     R0, R0, #%10000		;correct USER mode
 MSR     CPSR_all, R0			;switch to USER with flags cleared
 #if compile_IOMD == 1
   NOP
 #endif

 LDR     R14, jit_managed_ldr_pc_r13	;return in 26bit space
 LDMIA   R2!, {R0-R1, R12-R13}		;load USER registers
LDR     PC, [R2]			;call utility

 ._utility_return
 MRS     R1, CPSR			;need to track V status
 SWI     XOS_EnterOS

 LDR     R14, [R13], #4			;pull RMA allocation from SVC stack
 ADD     R12, R13, #SWI_stack.size	;buffer used by pre_swi_veneer
 LDMDB   R14!, {R6-R8}			;pull preserved SWI_veneer.*
 TST     R1, #1 << 28			;did it exit with V set?
 ORRNE   R6, R6, #1 << 28		;YES, set V in exit CPSR
 STMIA   R12, {R6-R8}			;preserve SWI_veneer.*
 LDMEQDB R14, {R0-R11, R13-R14}^	;preserve USER registers
 LDMNEDB R14, {R1-R11, R13-R14}^	;V set, preserve USER registers
 #if compile_IOMD == 1
   NOP					;fix for errata on ARM6/7 macrocells, StrongARM
 #endif
 SUB     R14, R14, #14 * 4		;drop registers we just restored
 STMFD   R13!, {R0-R4}			;preserve R0-R4
 LDR     R4, [R14, #-4]!		;R4=file size
					;R14=start of heap allocation
 ADD     R3, R14, #&1100		;R3=start of code (heap + 1K stack)

 MOV     R0, #Heap_Free			;release claimed JIT RMA space
 MOV     R1, #jit_RMA_heap
 LDR     R2, [R14, #-4]			;get address of allocation
 SWI     XOS_Heap			;PRM1-380

 MOV     R2, R3				;RMA block start
 BL      hv_reset_memory_block		;release block in JIT space
 LDMFD   R13!, {R0-R4}
B       exit_SWI_veneer




;Entry:
; R1,R10 - filename
; R9     - execution address

._load_and_run
 ;check R2 is within application space
 CMP     R2, #&8000			;valid load address?
 BLO     _pass_to_RO			;NO
 ADD     R5, R2, R4			;R5=start+size
 SUB     R14, R5, #1
 CMP     R3, R2				;is exec above load address?
 RSBGES  R14, R3, R14			;YES, is it below end address
 BLT     _pass_to_RO			;NO

 MOV     R3, #1				;use file load address
 B       _not_absolute


;Entry:
; R1,R10 - filename

._load_and_run_absolute
 MOV     R9, #&8000			;R9=execution address
 MOV     R3, #0				;use address in R2
 MOV     R2, #&8000

 ._not_absolute
 BL      _pre_application_starting	;may not return
 ADR     R4, _run_path
 MOV     R0, #14			;R4 is path variable
 SWI     XOS_File			;PRM2-43 load file hypervised
 BVS     _exit_with_error		;exit on error
 BL      _application_starting

 ._CAO_setup
 BL      dontexit_SWI_veneer
 BL      get_taskID
 LDR     R14, [R12, #SWI_veneer.SPSR]	;get entry SPSR
 BIC     R14, R14, #%1111 << 28		;clear flags (fixes Pipe Mania)
 BIC     R14, R14, #%11001111		;switch to USER, IRQ/FIQ enabled
 LDR     R13, SVC_stack_init		;collapse the SVC stack

 MSR     CPSR_all, R14			;now in USER
 #if compile_IOMD == 1
   NOP
 #endif
 LDR     R14, jit_managed_os_exit 	;return via an OS_Exit
 MOV     R13, #jit_allocate_memory	;put stack at end of user space
 MOV     R12, #jit_allocate_memory
ADD     PC, R9, #jit_code_start




;FSControl 2
;
;Entry:
; R1=command tail
; R2=address to *GO
; R3=command line
; R7=R2 if called from *GO, R7 is the address *GO uses
; stack: {SWI stack}
;
;Exit:
; R9  - address to call (in original appspace)
; R10 - command line
; NOTE: Dependent on /RiscOs/Sources/Kernel/s/SysComms GO_Code using R7
;       RO5 doesn't clear flags before calling code (causes Pipe Mania
;       to fail)

._star_go
 TEQ     R7, R2				;is it *GO?
 BNE     vector_handler_forward		;NO, pass on

 CMP     R2, #jit_appspace_end		;is it in appspace?
 BHI     vector_handler_forward		;NO

 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XADFFS_DoNothing

 STMFD   R13!, {R0-R11}
 MOV     R10, R3			;command line
 MOV     R9, R2				;address to call
 BL      _application_starting		;may not return
B       _CAO_setup



;Entry:
; R1  - command tail
; R9  - CAO
; R10 - command line

._application_starting
 STMFD   R13!, {R0-R4, R14}
 LDR     R4, pre_JIT_wimp_slot_size
 ADD     R4, R4, #&8000			;correct the value
 ADD     R4, R4, #jit_code_start

 MOV     R0, #11			;Exit handler
 MOV     R1, #0
 MOV     R2, #0
 MOV     R3, #0
 SWI     XOS_ChangeEnvironment
 CMP     R1, #jit_code_start
 CMPHI   R4, R1
 BHI     _shelling			;application shelling

 MOV     R0, #16
 MOV     R1, #0
 MOV     R2, #0
 MOV     R3, #0
 SWI     XOS_ChangeEnvironment
 CMP     R1, #jit_code_start
 CMPHI   R4, R1
 BHI     _shelling
 SWI     XOS_ReadDefaultHandler
 SWI     XOS_ChangeEnvironment
 ._shelling
 MOV     R0, #FSControl_StartApplication	;setup environment
 LDR     R1, [R13, #4]				;get R1 from stack
 MOV     R2, R9					;CAO
 MOV     R3, R10				;command line
 BL      pass_SWI_on
 SWI     XOS_FSControl				;PRM2-85
 BVS     _rejected

 SWI     XOS_GetEnv				;PRM1-301
 MOV     R1, R2					;R1=time
 MOV     R0, R10				;filename to become environment
 SWI     XOS_WriteEnv				;PRM1-322
 LDMFD   R13!, {R0-R4, PC}

 ._rejected
 ADD     R13, R13, #4				;drop R0
 LDMFD   R13!, {R1-R4, R14}
B       _exit_with_error			;exit on error


;Entry:
; R9  - CAO
;
;stack: {R0-R11}, {SWI stack}

._pre_application_starting
 STMFD   R13!, {R0-R3, R14}
 MOV     R0, #UpCall_NewApplication
 MOV     R2, R9					;CAO
 SWI     XOS_UpCall
 TEQ     R0, #0					;was it rejected
 MOVEQ   R1, #0					;YES
 MOVNE   R1, #Service_NewApplication		;NO
 SWINE   XOS_ServiceCall
 TEQ     R1, #0					;was it rejected
 LDMNEFD R13!, {R0-R3, PC}			;NO

 ADR     R0, error_unable_to_start
B       _rejected				;exit on error




._exit_with_error
 ADD     R13, R13, #4			;drop R0
 MOV     R1, #1<<31
 ADDS    R1, R1, R1			;set V
 LDMFD   R13!, {R1-R11}			;preserve registers
B      exit_SWI_veneer			;exit with error
;PULLSWI
;SWI OS_GenerateError
