chiark / gitweb /
JPEG support and other fixes from Nick Clark
[ssr] / StraySrc / Libraries / Sapphire / s / except
1 ;
2 ; except.s
3 ;
4 ; Sapphire exception handling (MDW)
5 ;
6 ; © 1994-1998 Straylight
7 ;
8
9 ;----- Licensing note -------------------------------------------------------
10 ;
11 ; This file is part of Straylight's Sapphire library.
12 ;
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)
16 ; any later version.
17 ;
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.
22 ;
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.
26
27 ;----- Standard header ------------------------------------------------------
28
29                 GET     libs:header
30                 GET     libs:swis
31
32 ;----- External dependencies ------------------------------------------------
33
34                 GET     sapphire:sapphire
35                 GET     sapphire:suballoc
36
37 ;----- Main code ------------------------------------------------------------
38
39                 AREA    |Sapphire$$Code|,CODE,READONLY
40
41 ; --- except_init ---
42 ;
43 ; On entry:     --
44 ;
45 ; On exit:      --
46 ;
47 ; Use:          Initialises the exception handler.
48
49                 EXPORT  except_init
50 except_init     ROUT
51
52                 STMFD   R13!,{R0,R12,R14}       ;Stash registers away
53                 WSPACE  exc__wSpace             ;Point to my workspace
54
55                 ; --- Make sure I'm not already going ---
56
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
60
61                 ; --- Start up suballocation for exit list ---
62
63                 BL      sub_init                ;Make sure suballoc's going
64
65                 ; --- Fill in the flags and exit list ---
66
67                 MOV     R0,#eFlag__inited       ;Set the initialised flag
68                 STR     R0,exc__flags           ;Store it away nicely
69
70                 MOV     R0,#0
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
74
75                 LDMFD   R13!,{R0,R12,PC}^       ;Return to caller
76
77                 LTORG
78
79 ; --- exc__setHnd ---
80 ;
81 ; On entry:     --
82 ;
83 ; On exit:      --
84 ;
85 ; Use:          Sets up the OS handlers so we get called when strange things
86 ;               happen.
87
88 exc__setHnd     ROUT
89
90                 STMFD   R13!,{R0-R4,R14}        ;Save registers
91
92                 ; --- Make sure we need to do this ---
93
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
97
98                 ADR     R4,exc__handlers        ;Point to old handlers block
99
100                 ; --- Set up the error handler ---
101
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
108
109                 ; --- Set up the exit handler ---
110
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
116
117                 ; --- Set up the UpCall handler ---
118
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
124
125                 ; --- Done ---
126
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
131
132                 LTORG
133
134 ; --- exc__killHnd ---
135 ;
136 ; On entry:     --
137 ;
138 ; On exit:      --
139 ;
140 ; Use:          Releases any handlers we set up.
141
142 exc__killHnd    ROUT
143
144                 STMFD   R13!,{R0-R4,R14}        ;Save registers
145
146                 ; --- Make sure we need to do this ---
147
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
151
152                 ADR     R4,exc__handlers        ;Point to old handlers block
153
154                 ; --- Reset the error handler ---
155
156                 MOV     R0,#6                   ;Error handler number
157                 LDMIA   R4!,{R1-R3}             ;Get the old handler
158                 SWI     XOS_ChangeEnvironment   ;Set the handler up
159
160                 ; --- Reset the exit handler ---
161
162                 MOV     R0,#11                  ;Exit handler number
163                 LDMIA   R4!,{R1-R3}             ;Get the old handler
164                 SWI     XOS_ChangeEnvironment   ;Set the handler up
165
166                 ; --- Reset the UpCall handler ---
167
168                 MOV     R0,#16                  ;UpCall handler number
169                 LDMIA   R4!,{R1-R3}             ;Get the old handler
170                 SWI     XOS_ChangeEnvironment   ;Set the handler up
171
172                 ; --- Done ---
173
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
178
179                 LTORG
180
181 ; --- exc__error ---
182 ;
183 ; On entry:     R0 == pointer to workspace
184 ;
185 ; On exit:      Doesn't, really
186 ;
187 ; Use:          Handles an error, and dispatches it to the right place,
188 ;               properly handling multiple exceptions (i.e. it falls over
189 ;               and dies).
190
191 exc__err        ROUT
192
193                 MOV     R12,R0                  ;Because RISC OS is weird
194                 LDR     R11,exc__R11            ;Find the scratchpad pointer
195
196                 ; --- Am I already handling an error? ---
197
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
201
202                 ; --- Remember that I'm handling an error ---
203
204                 ORR     R0,R0,#eFlag__inError   ;Set the bit
205                 STR     R0,exc__flags           ;And put my flags word away
206
207                 ; --- Do I have an error handler? ---
208
209                 LDR     R2,exc__query           ;Find the handler function
210                 CMP     R2,#0                   ;Is it defined?
211                 BEQ     %20exc__err             ;No -- skip ahead
212
213                 ; --- Locate the error buffer and dispatch the error ---
214
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
220
221                 ; --- We now have a resume routine to call ---
222
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.
230
231                 ; --- No error handler registered ---
232
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
238
239                 ; --- Something went catastrophically wrong ---
240
241 50exc__err      ADD     R0,R11,#4               ;Point to the error block
242                 B       except_fatal            ;And report the error
243
244                 LTORG
245
246 exc__wSpace     DCD     0                       ;Pointer to my workspace
247
248 ; --- except_fatal ---
249 ;
250 ; On entry:     R0 == pointer to an error block
251 ;
252 ; On exit:      Doesn't
253 ;
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.
257
258                 EXPORT  except_fatal
259 except_fatal    ROUT
260
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
265
266                 LTORG
267
268 ; --- exc__atexits ---
269 ;
270 ; On entry:     --
271 ;
272 ; On exit:      --
273 ;
274 ; Use:          Calls all the registered atexit functions
275
276 exc__atexits    ROUT
277
278                 STMFD   R13!,{R1,R10-R12,R14}   ;Save the registers I want
279                 LDR     R10,exc__exitList       ;Get the list of handlers
280
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
288                 B       %01exc__atexits
289
290                 LTORG
291
292 ; --- exc__exit ---
293 ;
294 ; On entry:     R12 == pointer to my workspace
295 ;
296 ; On exit:      Doesn't
297 ;
298 ; Use:          Gets called by OS_Exit
299
300 exc__exit       ROUT
301
302                 ; --- Find a stack somewhere ---
303
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
309
310                 LTORG
311
312 ; --- exc__upc ---
313 ;
314 ; On entry:     R12 == pointer to my workspace
315 ;
316 ; On exit:      Handlers are restored
317 ;
318 ; Use:          Upcall handler
319
320 exc__upc        ROUT
321
322                 ; --- Are we interested in this UpCall? ---
323
324                 CMP     R0,#256                 ;Is a new app starting?
325                 MOVNES  PC,R14                  ;No -- return to caller
326
327                 ; --- Stick everything on the SVC stack ---
328
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 :-)
339
340                 LTORG
341
342 ; --- except_atExit ---
343 ;
344 ; On entry:     R0 == pointer to routine to call on exit
345 ;               R1 == R12 value to call with
346 ;
347 ; On exit:      --
348 ;
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
352 ;               manner.
353
354                 EXPORT  except_atExit
355 except_atExit   ROUT
356
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
360
361                 ; --- Create the list item ---
362
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
367
368                 ; --- Fill it in and link it to the list ---
369
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
375
376                 ; --- Done ---
377
378                 LDMFD   R13!,{R2,R3,R12,PC}^    ;Return to caller
379
380                 LTORG
381
382 ; --- except_returnPt ---
383 ;
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
387 ;
388 ; On exit:      --
389 ;
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.
393 ;
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
399 ;               everything up.
400 ;
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.
404 ;
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.
409
410                 EXPORT  except_returnPt
411 except_returnPt ROUT
412
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
419
420                 LTORG
421
422 ;----- Workspace ------------------------------------------------------------
423
424                 ^       0,R12
425 exc__wStart     #       0
426
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
434
435 exc__wSize      EQU     {VAR}-exc__wStart       ;My workspace size
436
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
440
441 ; --- Exit routine block format ---
442
443                 ^       0
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
448
449                 AREA    |Sapphire$$LibData|,CODE,READONLY
450
451                 DCD     exc__wSize
452                 DCD     exc__wSpace
453                 DCD     256
454                 DCD     except_init
455
456 ;----- That's all, folks ----------------------------------------------------
457
458                 END