4 ; Sapphire exception handling (MDW)
6 ; © 1994-1998 Straylight
9 ;----- Licensing note -------------------------------------------------------
11 ; This file is part of Straylight's Sapphire library.
13 ; Sapphire is free software; you can redistribute it and/or modify
14 ; it under the terms of the GNU General Public License as published by
15 ; the Free Software Foundation; either version 2, or (at your option)
18 ; Sapphire is distributed in the hope that it will be useful,
19 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ; GNU General Public License for more details.
23 ; You should have received a copy of the GNU General Public License
24 ; along with Sapphire. If not, write to the Free Software Foundation,
25 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 ;----- Standard header ------------------------------------------------------
32 ;----- External dependencies ------------------------------------------------
37 ;----- Main code ------------------------------------------------------------
39 AREA |Sapphire$$Code|,CODE,READONLY
47 ; Use: Initialises the exception handler.
52 STMFD R13!,{R0,R12,R14} ;Stash registers away
53 WSPACE exc__wSpace ;Point to my workspace
55 ; --- Make sure I'm not already going ---
57 LDR R0,exc__flags ;Find the flags word
58 TST R0,#eFlag__inited ;Am I going yet?
59 LDMNEFD R13!,{R0,R12,PC}^ ;Yes -- return right now
61 ; --- Start up suballocation for exit list ---
63 BL sub_init ;Make sure suballoc's going
65 ; --- Fill in the flags and exit list ---
67 MOV R0,#eFlag__inited ;Set the initialised flag
68 STR R0,exc__flags ;Store it away nicely
71 STR R0,exc__exitList ;No atexit routines yet
72 STR R0,exc__query ;No error handler either
73 STR R11,exc__R11 ;Save R11 pointer
75 LDMFD R13!,{R0,R12,PC}^ ;Return to caller
85 ; Use: Sets up the OS handlers so we get called when strange things
90 STMFD R13!,{R0-R4,R14} ;Save registers
92 ; --- Make sure we need to do this ---
94 LDR R0,exc__flags ;Get my current flags
95 TST R0,#eFlag__handling ;Are we now handling errors?
96 LDMNEFD R13!,{R0-R4,PC}^ ;Yes -- return right now
98 ADR R4,exc__handlers ;Point to old handlers block
100 ; --- Set up the error handler ---
102 MOV R0,#6 ;Error handler number
103 ADR R1,exc__err ;Point to my handler routine
104 MOV R2,R12 ;I want my workspace pointer
105 MOV R3,R11 ;Use scratchpad for error
106 SWI XOS_ChangeEnvironment ;Set the handler up
107 STMIA R4!,{R1-R3} ;Save the old handler away
109 ; --- Set up the exit handler ---
111 MOV R0,#11 ;Exit handler number
112 ADR R1,exc__exit ;Point to my handler
113 MOV R2,R12 ;Give me my workspace
114 SWI XOS_ChangeEnvironment ;Set the handler up
115 STMIA R4!,{R1-R3} ;Save the old handler away
117 ; --- Set up the UpCall handler ---
119 MOV R0,#16 ;UpCall handler number
120 ADR R1,exc__upc ;Point to my handler
121 MOV R2,R12 ;Give me my workspace
122 SWI XOS_ChangeEnvironment ;Set the handler up
123 STMIA R4!,{R1-R3} ;Save the old handler away
127 LDR R0,exc__flags ;Get my current flags
128 ORR R0,R0,#eFlag__handling ;We are now handling errors
129 STR R0,exc__flags ;Store them away again
130 LDMFD R13!,{R0-R4,PC}^ ;Return to caller
134 ; --- exc__killHnd ---
140 ; Use: Releases any handlers we set up.
144 STMFD R13!,{R0-R4,R14} ;Save registers
146 ; --- Make sure we need to do this ---
148 LDR R0,exc__flags ;Get my current flags
149 TST R0,#eFlag__handling ;Are we now handling errors?
150 LDMEQFD R13!,{R0-R4,PC}^ ;No -- return right now
152 ADR R4,exc__handlers ;Point to old handlers block
154 ; --- Reset the error handler ---
156 MOV R0,#6 ;Error handler number
157 LDMIA R4!,{R1-R3} ;Get the old handler
158 SWI XOS_ChangeEnvironment ;Set the handler up
160 ; --- Reset the exit handler ---
162 MOV R0,#11 ;Exit handler number
163 LDMIA R4!,{R1-R3} ;Get the old handler
164 SWI XOS_ChangeEnvironment ;Set the handler up
166 ; --- Reset the UpCall handler ---
168 MOV R0,#16 ;UpCall handler number
169 LDMIA R4!,{R1-R3} ;Get the old handler
170 SWI XOS_ChangeEnvironment ;Set the handler up
174 LDR R0,exc__flags ;Get my current flags
175 BIC R0,R0,#eFlag__handling ;We are not handling errors
176 STR R0,exc__flags ;Store them away again
177 LDMFD R13!,{R0-R4,PC}^ ;Return to caller
183 ; On entry: R0 == pointer to workspace
185 ; On exit: Doesn't, really
187 ; Use: Handles an error, and dispatches it to the right place,
188 ; properly handling multiple exceptions (i.e. it falls over
193 MOV R12,R0 ;Because RISC OS is weird
194 LDR R11,exc__R11 ;Find the scratchpad pointer
196 ; --- Am I already handling an error? ---
198 LDR R0,exc__flags ;Find the flags word
199 TST R0,#eFlag__inError ;Check the flag bit
200 BNE %50exc__err ;Yes -- skip ahead
202 ; --- Remember that I'm handling an error ---
204 ORR R0,R0,#eFlag__inError ;Set the bit
205 STR R0,exc__flags ;And put my flags word away
207 ; --- Do I have an error handler? ---
209 LDR R2,exc__query ;Find the handler function
210 CMP R2,#0 ;Is it defined?
211 BEQ %20exc__err ;No -- skip ahead
213 ; --- Locate the error buffer and dispatch the error ---
215 ADD R0,R11,#4 ;Point to the error block
216 STMFD R13!,{R12} ;Save my workspace on stack
217 LDR R12,exc__qR12 ;Get the workspace they want
218 MOV R14,PC ;Get a return address
219 MOV PC,R2 ;Call the handler
221 ; --- We now have a resume routine to call ---
223 LDMFD R13!,{R12} ;Restore my workspace pointer
224 LDR R2,exc__flags ;Find the flags word
225 BIC R2,R2,#eFlag__inError ;We're leaving the handler
226 STR R2,exc__flags ;And put my flags word away
227 LDR R13,exc__stackPtr ;Get the stack pointer
228 MOV R12,R1 ;Get the resumer's wSpace
229 MOV PC,R0 ;And call the resumer.
231 ; --- No error handler registered ---
233 20exc__err LDR R13,sapph_stackBase ;We won't be coming back
234 BL exc__killHnd ;Reset all the handlers
235 BL exc__atexits ;Perform tidy-up operations
236 ADD R0,R11,#4 ;Point to the error block
237 SWI OS_GenerateError ;And report error to caller
239 ; --- Something went catastrophically wrong ---
241 50exc__err ADD R0,R11,#4 ;Point to the error block
242 B except_fatal ;And report the error
246 exc__wSpace DCD 0 ;Pointer to my workspace
248 ; --- except_fatal ---
250 ; On entry: R0 == pointer to an error block
254 ; Use: Reports an error to our /caller's/ error handler. We quit
255 ; and die at this point. Don't use unless you have absolutely
256 ; no choice in the matter.
261 WSPACE exc__wSpace ;Find my workspace address
262 LDR R13,sapph_stackBase ;Find a good piece of stack
263 BL exc__killHnd ;Get rid of our handlers
264 SWI OS_GenerateError ;And report the error
268 ; --- exc__atexits ---
274 ; Use: Calls all the registered atexit functions
278 STMFD R13!,{R1,R10-R12,R14} ;Save the registers I want
279 LDR R10,exc__exitList ;Get the list of handlers
281 01exc__atexits CMP R10,#0 ;Is the list empty
282 LDMEQFD R13!,{R1,R10-R12,PC}^ ;Return to call if so
283 LDR R12,[R10,#eExit__R12] ;Get the required R12
284 LDR R1,[R10,#eExit__handler] ;Get pointer to handler
285 MOV R14,PC ;Set up return address
286 MOV PC,R1 ;Call atexit routine
287 LDR R10,[R10,#eExit__next] ;Get next handler
294 ; On entry: R12 == pointer to my workspace
298 ; Use: Gets called by OS_Exit
302 ; --- Find a stack somewhere ---
304 LDR R11,exc__R11 ;Load scratchpad pointer
305 BL sapphire_resetStack ;Use initial stack
306 BL exc__killHnd ;Kill existing handlers
307 BL exc__atexits ;Call things on the exit list
308 SWI XOS_Exit ;Quit the application
314 ; On entry: R12 == pointer to my workspace
316 ; On exit: Handlers are restored
318 ; Use: Upcall handler
322 ; --- Are we interested in this UpCall? ---
324 CMP R0,#256 ;Is a new app starting?
325 MOVNES PC,R14 ;No -- return to caller
327 ; --- Stick everything on the SVC stack ---
329 STMFD R13!,{R14} ;Save the return address
330 TEQP PC,#0 ;Enter USR mode to keep the
331 ;atexit routines happy
332 MOV R0,R0 ;Keep ARM happy too
333 LDR R11,exc__R11 ;Load scratchpad pointer
334 BL sapphire_resetStack ;Use initial stack
335 BL exc__killHnd ;Restore the handlers
336 BL exc__atexits ;Close everything down now
337 SWI OS_EnterOS ;Go back to SVC mode
338 LDMFD R13!,{PC}^ ;Return and be killed :-)
342 ; --- except_atExit ---
344 ; On entry: R0 == pointer to routine to call on exit
345 ; R1 == R12 value to call with
349 ; Use: Registers a routine to get called when the application quits.
350 ; Later-registered routines are called earlier than earlier-
351 ; registered routines, so everything closes down in a nice
357 STMFD R13!,{R0-R3,R12,R14} ;Save everything on stack
358 WSPACE exc__wSpace ;Find my workspace
359 BL exc__setHnd ;Set up my handlers
361 ; --- Create the list item ---
363 MOV R0,#eExit__size ;Size of the block to get
364 BL sub_alloc ;Allocate the memory
365 SWIVS OS_GenerateError ;Barf if it failed
366 MOV R2,R0 ;Move to a nicer register
368 ; --- Fill it in and link it to the list ---
370 LDR R0,exc__exitList ;Get the current list head
371 STR R0,[R2,#eExit__next] ;Store this in the link
372 LDMIA R13!,{R0,R1} ;Get the stuff from the stack
373 STMIB R2,{R0,R1} ;Store them in the block
374 STR R2,exc__exitList ;This is the new list head
378 LDMFD R13!,{R2,R3,R12,PC}^ ;Return to caller
382 ; --- except_returnPt ---
384 ; On entry: R0 == pointer to exception handler routine
385 ; R1 == R12 value to enter routine with
386 ; R2 == R13 value to enter routine with
390 ; Use: Sets up a routine to be called whenever there's an error.
391 ; The idea is that it should ask the user whether to quit,
392 ; and if not, resume to some known (safe?) state.
394 ; The routine is called with R0 == pointer to error block, and
395 ; R12 and R13 being the values set up here(*). It should
396 ; return with R0 == pointer to a routine to resume at, and R1
397 ; being the value to pass to the resume routine in R12. If
398 ; you decide to quit, just call OS_Exit -- this should tidy
401 ; Note that the error is held in the scratchpad buffer, so
402 ; you can't use the first 256 bytes of that until you've
403 ; finished with the error message.
405 ; (*) Actually, R13 is 4 bytes lower because it's assumed that
406 ; it points to a full descending stack that we can use. This
407 ; shouldn't make any difference as long as you're using R13
408 ; as a full descending stack pointer.
410 EXPORT except_returnPt
413 STMFD R13!,{R12,R14} ;Save some registers
414 WSPACE exc__wSpace ;Get my workspace pointer
415 BL exc__setHnd ;Set up all the handlers
416 ADR R14,exc__query ;Point to my stack variable
417 STMIA R14,{R0-R2} ;Store the handler away
418 LDMFD R13!,{R12,PC}^ ;Return to caller
422 ;----- Workspace ------------------------------------------------------------
427 exc__flags # 4 ;Error handling flags
428 exc__handlers # 36 ;Old handlers information
429 exc__query # 4 ;Pointer to query routine
430 exc__qR12 # 4 ;R12 for query routine
431 exc__stackPtr # 4 ;Stack pointer for handling
432 exc__exitList # 4 ;The list of exit routines
433 exc__R11 # 4 ;Sapphire's R11 magic pointer
435 exc__wSize EQU {VAR}-exc__wStart ;My workspace size
437 eFlag__inited EQU (1<<0) ;Are we initialised?
438 eFlag__inError EQU (1<<1) ;Currently in error handler
439 eFlag__handling EQU (1<<2) ;We have handlers set up
441 ; --- Exit routine block format ---
444 eExit__next # 4 ;Address of next block
445 eExit__handler # 4 ;Address of routine to call
446 eExit__R12 # 4 ;R12 to call handler with
447 eExit__size # 0 ;Size of the block
449 AREA |Sapphire$$LibData|,CODE,READONLY
456 ;----- That's all, folks ----------------------------------------------------