STRUCT EnvHandler
{
  .entry		DCD 0
  .r12_value		DCD 0
  .buffer		DCD 0
  .user_entry		DCD 0
  .user_r12_value	DCD 0
  .user_buffer		DCD 0
  .size
}




;claim_ChangeEnvironmentV
;------------------------
;claims handlers the JIT needs to Hypervise and tracks changes by other
;software

.claim_ChangeEnvironmentV
 STMFD   R13!, {R0-R4, R14}
 LDR     R4, environment_handlers
 ADD     R4, R4, #EnvHandler.user_entry
 MOV     R0, #0
 ._L1
   MOV     R1, #0
   MOV     R2, #0
   MOV     R3, #0
   STMIA   R4, {R1-R3}
   SWI     XOS_ChangeEnvironment
   STMDB   R4, {R1-R3}
   ADD     R4, R4, #EnvHandler.size
   ADD     R0, R0, #1
   TEQ     R0, #17
 BNE     _L1
LDMFD   R13!, {R0-R4, PC}



 
;release_all_ChangeEnvironmentV
;------------------------------
;releases all environment handlers

.release_all_ChangeEnvironmentV
 STMFD   R13!, {R0-R4, R14}
 LDR     R4, environment_handlers
 ADD     R4, R4, #EnvHandler.size * 6 + EnvHandler.user_entry
 MOV     R0, #6
 ._L1
   LDMDB   R4, {R1-R3}
   SWI     XOS_ChangeEnvironment
   STMDB   R4, {R1-R3}
   MOV     R1, #0
   MOV     R2, #0
   MOV     R3, #0
   STMIA   R4, {R1-R3}
   ADD     R4, R4, #EnvHandler.size
   ADD     R0, R0, #1
   TEQ     R0, #12
   MOVEQ   R0, #16
   TEQ     R0, #17
 BNE     _L1
LDMFD   R13!, {R0-R4, PC}




;change_environment_handler
;--------------------------
;tracks user environment handlers
;
;Entry:
; R0 - handler #
; R1 - handler address
; R2 - value of R12
; R3 - buffer address (optional)

.change_environment_handler
 STR     R14, [R13, #-4]!

 CMP     R0, #17
 ADDLO   PC, PC, R0, LSL #2
 B       _report_handler
 B       _env_handler0			;0 - Memory limit
 B       _read_only			;1 - Undefined instruction (used in Overload Paradise)
 B       _read_only			;2 - Prefetch abort
 B       _read_only			;3 - Data abort
 B       _read_only			;4 - Address exception
 B       _read_only			;5 - Other exceptions
#if JIT_prevent_Exit_Handlers == 0 AND JIT_prevent_Error_Handler == 0 AND compile_RO > 311
 B       _ok				;6 - Error (used in Chequered Flag)
#endif
#if (JIT_prevent_Exit_Handlers <> 0 OR JIT_prevent_Error_Handler <> 0) AND compile_RO > 311
 B       _read_only			;6 - Error
#endif
 B       _ok				;7 - CallBack (used in Chequered Flag)
 B       _read_only			;8 - BreakPoint
 B       _ok				;9 - Escape
 B       _ok				;10 - Event (used in Ballarena)
#if JIT_prevent_Exit_Handlers == 0 AND compile_RO > 311
 B       _ok				;11 - Exit (used in Gribblys Day Out)
#endif
#if JIT_prevent_Exit_Handlers <> 0 AND compile_RO > 311
 B       _read_only			;11 - Exit
#endif
 B       _ok				;12 - Unused SWI (used in Overload Paradise)
 B       _read_only			;13 - Exception registers (used in Overload Paradise)
 B       _env_handler14			;14 - Application space
 B       _read_only			;15 - Currently active object
 B       _ok				;16 - Upcall (used by MiG-29 Fulcrum)


 ._report_handler
 ADD     R13, R13, #4			;clear stack
 MOV     R12, #&F			;ADFF500F
B       hv_report_unimplemented		;report


 ._ok
 STMFD   R13!, {R4}
 LDR     R4, environment_handlers
 MOV     R14, #EnvHandler.size
 MLA     R14, R0, R14, R4
 ADD     R14, R14, #EnvHandler.user_entry
 STMIA   R14, {R1-R3}			;store values for error reporting
 LDMFD   R13!, {R4}

 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XADFFS_DoNothing
 BL      ChangeEnvironmentV_handler
 BL      dontexit_SWI_veneer
LDR     PC, [R13], #4

 ._read_only
 MOV     R1, #0				;read the handler, dont change it
 TEQ     R0, #6
 TEQNE   R0, #7
 TEQNE   R0, #8
 MOVEQ   R3, #0				;6..8 need R3 to be read only
 TEQNE   R0, #11
 MOVEQ   R2, #0				;6..12 / 16 need R2 read only

 BL      pre_SWI_veneer			;call SWI that follows
 SWI     XOS_ChangeEnvironment
 BL      dontexit_SWI_veneer
LDR     PC, [R13], #4


 ._env_handler0
 TEMP    R0
 TEQ     R1, #0				;read or set?
 SUBNE   R1, R1, #&8000			;set, correct the value
 STRNE   R1, pre_JIT_wimp_slot_size	; |+  update slot size
 LOCK    R0
 MOV     R0, #0
 ._env_handler14
 LDR     R1, pre_JIT_wimp_slot_size
 ADD     R1, R1, #&8000			;correct the value
LDR     PC, [R13], #4




;Entry:
; R11 - entry SWI stack ptr for error reporting

.ChangeEnvironmentV_handler
 STMFD   R13!, {R4-R6, R14}
 TEQ     R1, #0				;read?
 BEQ     _read

 CMP     R1, #jit_appspace_end		;is it within appspace?
 BLO     _needs_pre_veneer		;YES
 CMP     R1, #jit_code_start		;is it a codelet?
 BLO     _remove_handler		;YES

._pass_on
 SWI     XOS_ChangeEnvironment
 LDMFD   R13!, {R4-R6, PC}


._read
 SWI     XOS_ChangeEnvironment
 CMP     R1, #jit_appspace_end		;is it within appspace?
 LDMLOFD R13!, {R4-R6, PC}		;YES
 CMP     R1, #jit_code_start		;is it a codelet?
 LDMHIFD R13!, {R4-R6, PC}		;NO

 LDR     R5, [R1, #_verify - _pre_veneer]
 LDR     R4, _verify
 TEQ     R5, R4				;is R1 pointing at a veneer?
 LDREQ   R1, [R1, #_entry - _pre_veneer]	;YES,
 SUBEQ   R1, R1, #jit_code_start	; |+ return the correct address
 LDMFD   R13!, {R4-R6, PC}


._remove_handler
 LDR     R5, [R1, #_verify - _previous]
 LDR     R4, _verify
 TEQ     R5, R4				;is R1 pointing at _previous?
 BNE     _pass_on			;NO, pass on

 STMFD   R13!, {R2}
 LDR     R2, environment_handlers
 MOV     R14, #EnvHandler.size
 MLA     R14, R0, R14, R2
; MOV     R2, #0
; STR     R2, [R14, #EnvHandler.user_entry]	;mark as cleared

 LDR     R1, [R1, #_previous_handler - _previous]	;get previous handler address
 LDMFD   R13!, {R2}
 B       _pass_on			;pass on


._needs_pre_veneer
 STMFD   R13!, {R0-R3, R7}
 MOV     R7, R1				;use entry address as instruction
 MOV     R1, #0				;can't be reused
 MOV     R6, #(codelet_struct.codelet + _handler_end - _pre_veneer + (codelet_alignment - 1)) AND -codelet_alignment
 ADR     R0, _pre_veneer
 ._copy_codelet
 BL      allocate_codelet
 MOV     R1, R6
 MOV     R2, #_handler_end - _pre_veneer
 BL      MemCopy			;copy handler into codelet

 LDR     R0, [R13], #4
 MOV     R1, #0
 MOV     R2, #0
 MOV     R3, #0
 SWI     XOS_ChangeEnvironment		;get previous handler address
 STR     R1, [R6, #_previous_handler - _pre_veneer]
 LDMFD   R13!, {R1-R3, R7}

 ADD     R1, R1, #jit_code_start
 STR     R1, [R6, #_entry - _pre_veneer]

 ADR     R1, free_codelet
 STR     R1, [R6, #_free_codelet - _pre_veneer]
 #if compile_RO > 400
   STR     R0, [R6, #_handler_no - _pre_veneer]	;handler no for later
   TEQ     R0, #7				;callback?
   STREQ   R3, [R6, #_regdump_original - _pre_veneer]
   ADDEQ   R3, R6, #_regdump - _pre_veneer	;point regdump at veneer
 #endif
 MOV     R1, R6
 SWI     XOS_ChangeEnvironment		;claim
 ADD     R1, R6, #_previous - _pre_veneer
LDMFD   R13!, {R4-R6, PC}


._pre_veneer
 STR     R14, _return
 STR     R10, _tmp
#if compile_RO > 400
 LDR     R14, _handler_no
 TEQ     R14, #7		;callback?
 BNE     _pre_veneer_ok
 STR     R0, _tmp2
 STR     R1, _tmp3
 LDR     R1, _regdump_original
 ADR     R0, _regdump
 CMP     R1, #&8000
 BLO     _invalid_regdump
 MOV     R10, #15
 ._pre_veneer_L1
   LDR     R14, [R0], #4
   STR     R14, [R1], #4
   SUBS    R10, R10, #1
 BNE     _pre_veneer_L1
 LDR     R0, _tmp2
 ._invalid_regdump
 LDR     R14, _regdump + 16*4		;get PSR
 AND     R10, R14, #%11 << 6
 AND     R14, R14, #&F0000003
 ORR     R14, R14, R10, LSL #20
 LDR     R10, _regdump + 15*4		;get PC
 STR     R10, _return
 ADR     R10, _our_return
 ORR     R14, R10, R14
 ADR     R10, _regdump
 TEQ     R0, R10
 STRNE   R14, [R1]
 LDREQ   R0, _tmp2
 STREQ   R14, _regdump + 15*4
 LDR     R1, _tmp3
 LDR     R10, _tmp
LDR     PC, _entry

 ._pre_veneer_ok
#endif
 MRS     R14, CPSR
 AND     R10, R14, #%11 << 6
 AND     R14, R14, #&F0000003
 ORR     R14, R14, R10, LSL #20
 ADR     R10, _our_return
 ORR     R14, R14, R10
 LDR     R10, _tmp
LDR     PC, _entry

 ._entry	DCD 0
 ._tmp		DCD 0
#if compile_RO > 400
 ._tmp2		DCD 0
 ._tmp3		DCD 0
 ._handler_no	DCD 0
 ._regdump	DBD 17		;R0-R15, PSR
 ._regdump_original	DCD 0
#endif

 ._our_return
LDR     PC, _return
 ._return	DCD 0

 ._previous
 STR     R2, _tmp
 MRS     R2, CPSR
 SWI     XOS_EnterOS
 STMFD   R13!, {R2, R14}
 ADR     R2, _pre_veneer - 8
 MOV     R14, PC
 LDR     PC, _free_codelet	;free codelet
 LDMFD   R13!, {R2, R14}
 MSR     CPSR_all, R2
 NOP
 LDR     R2, _tmp
LDR     PC, _previous_handler
 ._previous_handler	DCD 0
 ._free_codelet		DCD 0
 ._verify		DCD &ADFF5888

 ._post_handler
 LDR     PC, _previous_handler
 ._handler_end
