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_ChangeEnvironmentV
;--------------------------
;releases all environment handlers

.release_ChangeEnvironmentV
 STMFD   R13!, {R0-R4, R14}
 LDR     R4, environment_handlers
 ADD     R4, R4, #EnvHandler.size * 7 + EnvHandler.user_entry
 MOV     R0, #7
 ._L1
   TEQ     R0, #13
   TEQNE   R0, #14
   TEQNE   R0, #15
   TEQNE   R0, #11			;Obey Module alters Error/Exit handler
   BEQ     _skip
   LDMDB   R4, {R1-R3}
   SWI     XOS_ChangeEnvironment
   MOV     R1, #0
   MOV     R2, #0
   MOV     R3, #0
   STMIA   R4, {R1-R3}
   ._skip
   ADD     R4, R4, #EnvHandler.size
   ADD     R0, R0, #1
   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




.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
 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

 SUB     R2, R1, #(_previous - _pre_veneer) + 8	;R2=base of codelet - 8
 LDR     R1, [R1, #_previous_handler - _previous]	;get previous handler address
; BL      free_codelet			;causes Elite to crash when exiting to desktop
 LDMFD   R13!, {R2}
 B       _pass_on			;pass on


._needs_pre_veneer
 STMFD   R13!, {R0-R2, R7}
 MOV     R7, #-1 ;make immortal ;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 (&FFFFF-codelet_alignment+1)
 BL      allocate_codelet
 ADR     R0, _pre_veneer
 MOV     R1, R6
 MOV     R2, #_handler_end - _pre_veneer
 BL      MemCopy			;copy handler into codelet
 LDMFD   R13!, {R0-R2, R7}

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

 MOV     R1, R6
 SWI     XOS_ChangeEnvironment		;claim and get previous handler address
 STR     R1, [R6, #_previous_handler - _pre_veneer]
 ADD     R1, R6, #_previous - _pre_veneer
LDMFD   R13!, {R4-R6, PC}


._pre_veneer
 STR     R14, _return
 STR     R10, _tmp
 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

 ._our_return
 LDR     PC, _return
 ._return	DCD 0

 ._previous
 LDR     PC, _previous_handler
 ._previous_handler	DCD 0
 ._verify	DCD &ADFF5888

 ._post_handler
 LDR     PC, _previous_handler
 ._handler_end
