4 ; Handling of application blocks
6 ; © 1994-1998 Straylight
9 ;----- Licensing note -------------------------------------------------------
11 ; This file is part of Straylight's Dynamic Linking System (SDLS)
13 ; SDLS 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 ; SDLS 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 SDLS. If not, write to the Free Software Foundation,
25 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 ;----- Standard header ------------------------------------------------------
34 ;----- External dependencies ------------------------------------------------
47 ;----- External routines ----------------------------------------------------
49 AREA |DLLM$$Code|,CODE,READONLY
62 STMFD R13!,{R1,R2,R14} ;Save some registers
64 ; --- Save workspace address ---
66 ; This is so that app__epilogue can find our workspace.
68 STR R12,app__pw ;Store data relocation
70 ; --- Now locate the OS's pid word ---
72 ; We do this using a table indexed by the OS version on the
73 ; grounds that it's easier to update if the address changes.
74 ; This is unlikely however, since DDEUtils uses this address
75 ; too, and it's right before the VDU driver workspace at
76 ; &1000, which seems to indicate it's there forever.
78 MOV R0,#&81 ;Read the OS version number
79 MOV R1,#0 ;Set up the odd arguments
80 MOV R2,#255 ;This is really very strange
81 SWI XOS_Byte ;Do the read operation
83 ADR R14,app__verTable ;Point to the table
84 00 LDMIA R14!,{R0,R2} ;Load version and address
85 CMP R0,R1 ;How do the versions compare?
86 BCC %b00 ;No match -- keep going
88 STR R2,app__pidAddr ;If matched, store address
89 LDMFD R13!,{R1,R2,PC}^ ;Restore caller's registers
90 BICS PC,R14,#V_flag ;And return to caller
92 app__verTable DCD -1,&FF8 ;All versions have PID here
96 app__pw DCD 0 ;Where to store private word
98 ; --- app_checkQuit ---
106 LDR R0,app__list ;Get list head pointer
107 CMP R0,#0 ;Are there any applications?
108 MOVEQS PC,R14 ;No -- that's OK then
109 ADRL R0,msg_errInUse ;Point to error
110 ORRS PC,R14,#V_flag ;Return an error
114 ; --- app_findDLL ---
116 ; On entry: R0 == pointer to name of DLL to find
117 ; R1 == version number to load
118 ; On exit: R0 == DLL handle loaded
123 STMFD R13!,{R11,R14} ;Stack registers nicely
124 BL app__sFindDLL ;Find the DLL etc.
125 BVC app__ok ;If it worked, make permanent
126 B app__dead ;Otherwise, tidy up
130 ; --- app_loseDLL ---
132 ; On entry: R0 == pointer to DLL to lose
138 STMFD R13!,{R1-R3,R11,R14} ;Look after some registers
139 MOV R11,R0 ;Keep hold of pointer
141 ; --- Find the application's handle ---
143 BL app_getHandle ;Find application's time
144 BLVC app__find ;Find the application block
145 LDMVSFD R13!,{R1-R3,R11,PC} ;Return an error if any
147 ; --- Find the link block ---
149 MOV R3,R0 ;Keep hold of app pointer
150 MOV R1,R11 ;Point to application
151 BL app__findLink ;Find the link block
152 LDMVSFD R13!,{R1-R3,R11,PC} ;Return an error if any
154 ; --- Remove the link block ---
156 MOV R1,R0 ;Point to the link block
157 MOV R0,R3 ;Point to the application
158 BL app__freeLink ;Free the link block up
160 ; --- Decrement the DLL count ---
162 ; This will release the DLL if it no longer has any clients
164 MOV R0,R11 ;Point to DLL
165 BL dll_dec ;Decrement its counter
167 ; --- Uncache the current link if we've removed it ---
169 LDR R0,[R3,#app_cachedll] ;Find which DLL we cached
170 CMP R0,R11 ;Have we just unlinked it?
171 MOVEQ R0,#0 ;Yes -- clear out the handle
172 STREQ R0,[R3,#app_cachedll] ;Won't match any more
173 STREQ R0,[R3,#app_cacheptr]
175 ; --- Return, deleting application if necessary ---
177 MOV R0,R3 ;Point to application
178 LDMFD R13!,{R1-R3,R11,R14} ;Unstack registers
179 B app__freeUnused ;Kill app block if no DLLs
183 ; --- app_setname ---
185 ; On entry: R0 == pointer to application's name
191 STMFD R13!,{R1,R14} ;Store registers and things
192 MOV R1,R0 ;Keep pointer to the name
193 BL app__add ;Make sure the app exists
195 ADDVC R0,R0,#app_name ;Point to the name
196 BLVC misc_strcpy ;Copy the string across
197 LDMFD R13!,{R1,PC} ;Return to caller
201 ; --- app_fromtable ---
203 ; On entry: R0 == pointer to start of external DLL block
204 ; R1 == pointer to limit of same
210 STMFD R13!,{R11,R14} ;Look after registers
211 BL app_sfromtbl ;Do primitive operation
212 BVC app__ok ;If it worked, to gadget
213 B app__dead ;If it failed,tidy up
217 ; --- app_sfromtbl ---
219 ; On entry: R0 == pointer to start of external DLL block
220 ; R1 == pointer to limit of same
226 STMFD R13!,{R1-R5,R10,R11,R14} ;Stack some registers
228 MOV R10,R0 ;Keep pointer to base
229 MOV R11,R1 ;Keep pointer to limit
231 00app_sfromtbl CMP R10,R11 ;Is there anything to do?
232 LDMEQFD R13!,{R1-R5,R10,R11,PC}^ ;No -- return to caller
234 ; --- Load an entry from the table ---
236 LDMIA R10!,{R0-R3} ;Load values from table
237 BL app__sFindDLL ;Try to find the DLL
238 LDMVSFD R13!,{R1-R5,R10,R11,PC} ;Return the error if any
240 ; --- Fill in the veneer table ---
242 MOV R1,R2 ;Point to first name to load
243 MOV R2,R0 ;Keep pointer to DLL base
244 LDR R5,[R2,#dl_entries] ;Load the entry count
245 BIC R4,R5,#&FF000000 ;Clear entry type bits
247 01app_sfromtbl LDR R0,[R3,#0] ;Load value from table
248 CMP R0,R4 ;Is it a valid ordinal?
249 BHS %05app_sfromtbl ;No -- look up the name then
251 LDR R14,[R2,#dl_eveneer] ;Yes -- load entry point base
252 TST R5,#dl_shortEntries ;Are the entries short?
253 ADDEQ R0,R14,R0,LSL #4 ;No -- find base of veneer
254 LDRNE R0,[R14,R0,LSL #2] ;Yes -- load address
255 B %10app_sfromtbl ;And skip past name lookup
257 05app_sfromtbl LDRB R0,[R1] ;Load first byte from string
258 CMP R0,#0 ;Is it a zero (end of list)?
259 BEQ %00app_sfromtbl ;Yes -- do next table entry
261 ; --- Find entry point address ---
263 MOV R0,R2 ;Point to DLL base
264 BL dll_findEntry ;Find the entry point
265 LDMVSFD R13!,{R1-R5,R10,R11,PC} ;Return the error if any
266 MOV R4,#0 ;Remember to bump name
268 ; --- Convert it into a branch ---
270 10app_sfromtbl SUB R0,R0,R3 ;Convert to offset from R3
271 SUB R0,R0,#8 ;Subtract 8 (pipeline)
272 MOV R0,R0,LSR #2 ;Shift right to word align
273 BIC R0,R0,#&FF000000 ;Clear top (opcode and cond)
274 ORR R0,R0,#&EA000000 ;Put in BAL (Branch always)
275 STR R0,[R3],#4 ;Store in veneer table
276 CMP R4,#0 ;Did we look up a name?
277 BNE %01app_sfromtbl ;No -- examine next entry pt
279 ; --- Find next entry point address ---
281 02app_sfromtbl LDRB R0,[R1],#1 ;Load a byte from the name
282 CMP R0,#0 ;Is it the string end?
283 BNE %02app_sfromtbl ;No -- get another
284 B %01app_sfromtbl ;Fill in another entry point
288 ; --- app_findNamed ---
290 ; On entry: R0 == name of an application
291 ; On exit: R0 == pointer to application block base
296 STMFD R13!,{R1-R3,R14} ;Preserve registers
297 MOV R1,R0 ;Keep pointer to string
298 LDR R3,app__list ;And load the pointer to list
300 00app_findNamed CMP R3,#0 ;Is this the end of the line?
301 BEQ %40app_findNamed ;Yes -- give an error
302 ADD R0,R3,#app_name ;Find the name string
303 MOV R2,#0 ;Caseless compare
304 BL misc_strcmp ;Compare the strings
305 LDRNE R3,[R3,#app_next] ;If no match, move on...
306 BNE %00app_findNamed ;... and try again
307 MOV R0,R3 ;Point to DLL (give handle)
308 LDMFD R13!,{R1-R3,PC}^ ;And return to caller
310 40app_findNamed ADRL R0,msg_errAppNotFound ;Couldn't find DLL name
311 BL misc_error ;... create an error message
312 LDMFD R13!,{R1-R3,R14} ;... restore registers
313 ORRS PC,R14,#V_flag ;... and return an error
317 ; --- app_setBtable ---
319 ; On entry: R0 == pointer to entry point table
320 ; R1 == pointer to name table
326 STMFD R13!,{R1,R2,R14} ;Stick 'em on the stack
327 MOV R2,R0 ;Keep this safe
328 BL app__add ;Create an entry for the app
329 STRVC R2,[R0,#app_btable] ;Store the entry table ptr
330 STRVC R1,[R0,#app_nametable] ;Store the name table ptr
331 LDMFD R13!,{R1,R2,PC} ;Return to caller
335 ; --- app_appEntry ---
337 ; On entry: R0 == pointer to name to find
338 ; On exit: R0 == pointer to entry point
343 STMFD R13!,{R1,R2,R14} ;Stack registers away
345 ; --- Find the application ---
347 MOV R2,R0 ;Point to name start
349 BLVC app__find ;Try to find the app block
350 LDMVSFD R13!,{R1,R2,PC} ;If not there, error
352 ; --- Get the entry table info out ---
354 LDR R1,[R0,#app_nametable] ;Find name table address
355 LDR R0,[R0,#app_btable] ;Find entry table address
356 CMP R0,#0 ;Is there no entry table?
357 BEQ %50app_appEntry ;No -- complain about it
359 ; --- Find the entry point ---
361 BL dll_appEntry ;Do the actual find
362 LDMFD R13!,{R1,R2,PC} ;Return to caller
364 ; --- Application has no entry points ---
366 50app_appEntry ADRL R0,msg_errAppNoEntry ;Point to error message
367 LDMFD R13!,{R1,R2,R14} ;Unstack registers
368 ORRS PC,R14,#V_flag ;Return the error to caller
374 ; --- app_fixExtension ---
376 ; On entry: R0 == pointer to name table
377 ; R1 == pointer to branch table to fill in
380 EXPORT app_fixExtension
383 STMFD R13!,{R14} ;Save return address
384 BL app_fix ;Do the real job
385 LDMVSFD R13!,{PC} ;If it failed, return now
386 MOV R0,#0 ;Otherwise do global resync
387 SWI XOS_SynchroniseCodeAreas ;Do that then
388 LDMFD R13!,{R14} ;Restore return address
389 BICS PC,R14,#V_flag ;And return with V clear
395 ; On entry: R0 == pointer to name table
396 ; R1 == pointer to branch table to fill in
402 STMFD R13!,{R1-R6,R14} ;Stack registers away
404 ; --- Find the application ---
406 MOV R2,R0 ;Point to name start
407 MOV R3,R1 ;Keep entry table safe
409 BLVC app__find ;Try to find the app block
410 LDMVSFD R13!,{R1-R6,PC} ;If not there, error
412 ; --- Get the entry table info out ---
414 LDR R4,[R0,#app_btable] ;Find entry table address
415 LDR R5,[R0,#app_nametable] ;Find name table address
416 MOV R6,#&1000 ;Guess number of entries
417 CMP R4,#0 ;Is there no entry table?
418 BEQ %50app_fix ;No -- complain about it
420 ; --- Set up for a nice loop ---
422 00app_fix LDR R0,[R3,#0] ;Load the word from btable
423 CMP R0,R6 ;Is it moderately sensible?
424 ADDLO R0,R4,R0,LSL #2 ;Yes -- find the entry
425 MOVLO R14,#1 ;Remember we done this
426 BLO %10app_fix ;And fill in the branch
427 LDRB R0,[R2] ;Get the first entry byte
428 CMP R0,#0 ;Is it the end of the table?
429 LDMEQFD R13!,{R1-R6,PC}^ ;Yes -- we did it OK
431 ; --- Find another entry point address ---
433 MOV R0,R4 ;Point to entry table
434 MOV R1,R5 ;Point to name table
435 BL dll_appEntry ;Find the actual entry name
436 LDMVSFD R13!,{R1-R6,PC} ;If not there, return error
437 MOV R6,#0 ;Move on to next string
439 ; --- Convert it to a branch instruction ---
441 10app_fix SUB R0,R0,R3 ;Convert to offset from R3
442 SUB R0,R0,#8 ;Subtract 8 (pipeline)
443 MOV R0,R0,LSR #2 ;Shift right to word align
444 BIC R0,R0,#&FF000000 ;Clear top (opcode and cond)
445 ORR R0,R0,#&EA000000 ;Put in BAL (Branch always)
446 STR R0,[R3],#4 ;Store in veneer table
448 ; --- Find next entry point address ---
450 CMP R6,#0 ;Do we need to move on?
451 BNE %00app_fix ;No -- just loop then
452 01app_fix LDRB R0,[R2],#1 ;Load a byte from the name
453 CMP R0,#0 ;Is it the string end?
454 BNE %01app_fix ;No -- get another
455 B %00app_fix ;Fill in another entry point
457 ; --- Application has no entry points to offer ---
459 50app_fix ADRL R0,msg_errAppNoEntry ;Point to error message
460 LDMFD R13!,{R1-R6,R14} ;Unstack registers
461 ORRS PC,R14,#V_flag ;Return the error to caller
465 ; --- app_listDLLs ---
467 ; On entry: R0 == pointer to name of an application
473 STMFD R13!,{R1,R14} ;Stack registers nicely
474 BL app_findNamed ;Find the application block
475 LDMVSFD R13!,{R1,PC} ;Return if not found
476 LDR R1,[R0,#app_dlls] ;Load head of DLL list
477 CMP R1,#0 ;This shouldn't be 0
478 BEQ %01app_listDLLs ;If it is, print a message
480 BL dll_writeTitle ;Display the line along top
482 ; --- Main loop thing ---
484 00app_listDLLs LDR R0,[R1,#lk_dll] ;Point to the DLL
485 BL dll_writeInfo ;Display information about it
486 LDR R1,[R1,#lk_next] ;Move onto the next one
487 CMP R1,#0 ;Is that all?
488 BNE %00app_listDLLs ;No -- continue round
490 LDMFD R13!,{R1,PC}^ ;Return to caller
492 ; --- No DLLs to list. Hmm... ---
494 01app_listDLLs ADRL R0,msg_noDLLsForApp ;Point to the message
495 SWI OS_Write0 ;And display it
496 LDMFD R13!,{R1,PC}^ ;Return to caller
500 ; --- app_listUsing ---
502 ; On entry: R0 == pointer to a DLL name
508 STMFD R13!,{R1,R2,R8-R11,R14} ;Stack registers
510 ; --- Check that the DLL exists ---
512 MOV R8,R0 ;Keep the name pointer safe
513 MOV R1,#0 ;Don't care which version
514 BL dll_find ;Try to find it
515 BVS %11app_listUsing ;If it's not there, error
517 ; --- Start a loop through the apps ---
519 LDR R11,app__list ;Find the list head pointer
520 MOV R10,#0 ;No matching DLLs found yet
521 CMP R11,#0 ;Are there any apps?
522 BEQ %10app_listUsing ;No -- print a message then
524 ; --- Start a loop through the DLLs with this app
526 00app_listUsing LDR R9,[R11,#app_dlls] ;Find the DLL list
527 CMP R9,#0 ;Are there any DLLs?
528 BEQ %03app_listUsing ;No -- move on to the next
530 ; --- Loop through DLLs on this app ---
532 01app_listUsing LDR R0,[R9,#lk_dll] ;Point to the DLL base
533 MOV R1,R8 ;Point to DLL name
534 MOV R2,#0 ;Don't care what version
535 BL dll_compare ;Compare with stuff given
536 CMP R0,#1 ;Is there a match?
537 BNE %02app_listUsing ;Move onto the next one
539 ; --- Print out info about this app ---
541 CMP R10,#1 ;Have we printed the title?
542 ADRNEL R0,msg_appHeader ;No -- point to header
543 SWINE XOS_Write0 ;And print it
544 MOV R10,#1 ;We've printed it now
545 ADD R0,R11,#app_name ;Point to application name
546 MOV R1,#12 ;Field width
547 BL dll_field ;Print it out
548 LDR R0,[R9,#lk_dll] ;Find DLL pointer again
549 LDR R0,[R0,#dl_version] ;Load version number
550 BL dll_convertVersion ;Convert it into a string
551 SWI XOS_Write0 ;Write it out as a string
552 SWI XOS_NewLine ;And move onto the next line
554 ; --- Finish off loop through app's DLLs ---
556 02app_listUsing LDR R9,[R9,#lk_next] ;Move on to next link block
557 CMP R9,#0 ;Anything to do here?
558 BNE %01app_listUsing ;Yes -- check that one too
560 ; --- Finish off loop through all apps ---
562 03app_listUsing LDR R11,[R11,#app_next] ;Move on to next application
563 CMP R11,#0 ;Is there any more to do?
564 BNE %00app_listUsing ;Yes -- do its DLLs
566 CMP R10,#0 ;Were any messages printed?
567 BEQ %10app_listUsing ;No -- print one
568 LDMFD R13!,{R1,R2,R8-R11,PC}^ ;Return to caller
570 ; --- No matching DLLs were found ---
572 10app_listUsing ADRL R0,msg_noAppsForDLL ;Point to message skeleton
573 MOV R1,R8 ;Point to the DLL name
574 BL misc_subst ;Do the substitution
575 SWI XOS_Write0 ;Display the string
576 LDMFD R13!,{R1,R2,R8-R11,PC}^
578 ; --- Print an error message about this ---
580 11app_listUsing MOV R1,R8 ;Point to DLL name
581 ADRL R0,msg_errDLLNotInMem ;Point to error block
582 BL misc_error ;Create error message fully
583 LDMFD R13!,{R1,R2,R8-R11,R14} ;Unstack all registers
584 ORRS PC,R14,#V_flag ;Return to caller with error
596 STMFD R13!,{R1,R14} ;Stack registers
598 ; --- Prepare for a loop ---
600 LDR R1,app__list ;Point to first entry
601 CMP R1,#0 ;Are there any entries?
602 BEQ %10app_list ;No -- give a message
604 ; --- Display entries in order ---
606 00app_list ADD R0,R1,#app_name ;Point to name in structure
607 SWI XOS_Write0 ;Display the app's name
608 SWI XOS_NewLine ;Display a new line char
609 LDR R1,[R1,#app_next] ;Get next entry in the list
610 CMP R1,#0 ;Is it the end yet?
611 BNE %00app_list ;No -- do the next one
612 LDMFD R13!,{R1,PC}^ ;Return to caller
614 ; --- Display message about no apps ---
616 10app_list ADRL R0,msg_noApps ;Point to the message
617 SWI XOS_Write0 ;Display it on the screen
618 LDMFD R13!,{R1,PC}^ ;Return to caller
630 STMFD R13!,{R14} ;Stack return address
631 BL app_getHandle ;Find application's time
632 BLVC app__find ;Find the application block
633 LDMFD R13!,{R14} ;Retrieve the return address
634 BVC app_kill ;If there's no error, kill it
635 ORRS PC,R14,#V_flag ;Return to caller with error
641 ; On entry: R0 == pointer to application base
647 STMFD R13!,{R1,R2,R14} ;Stack registers nicely
648 MOV R2,R0 ;Keep hold of this pointer
650 ; --- Free each DLL link ---
652 LDR R1,[R0,#app_dlls] ;Find head of link list
653 CMP R1,#0 ;Are there any DLLs?
654 BEQ %01app_kill ;No -- don't free them then
656 00app_kill LDR R0,[R1,#lk_dll] ;Find the DLL pointer
657 BL dll_dec ;Decrement its counter
658 MOV R0,R1 ;Point to old block
659 LDR R1,[R0,#lk_next] ;Point to next block
660 BL sub_free ;Free the old block
661 CMP R1,#0 ;Are there any more to do?
662 BNE %00app_kill ;Yes -- do the next one
664 ; --- Free the application block ---
666 01app_kill MOV R0,R2 ;Point to application block
667 LDMFD R13!,{R1,R2,R14} ;Restore registers
668 B app__free ;Free the application block
672 ; --- app_killAll ---
680 STMFD R13!,{R1,R2,R14}
682 ; --- Start up the main loop ---
684 LDR R2,app__list ;Point to application list
685 CMP R2,#0 ;Is there anything to do?
686 BEQ %01app_killAll ;No -- skip the loop
687 MOV R0,#7 ;Free memory reason code
689 00app_killAll LDR R1,[R2,#app_next] ;Find next block in the list
690 SWI XOS_Module ;Free the block
691 MOVS R2,R1 ;Point to the next one
692 BNE %00app_killAll ;Loop round for the next one
694 01app_killAll STR R2,app__list ;Clear out list head pointer
695 STR R2,app__cachePtr ;Clear out cached pointer
696 STR R2,app__cacheHnd ;Clear out cached handle
697 LDMFD R13!,{R1,R2,PC}^ ;Return to caller
701 ; --- app_instvars ---
703 ; On entry: R0 == anything for first call, or pointer to data block
704 ; R4 == 0 for first call, or pointer to link block
705 ; On exit: R0 == size of block required
706 ; R4 == pointer to next link block, or 0 to end
711 STMFD R13!,{R1,R14} ;Keep hold of link register
712 CMP R4,#0 ;Is this the first call?
713 BNE %00app_instvars ;No -- skip ahead quickly
715 ; --- Find start of application list ---
717 BL app_getHandle ;Get app's start time
718 BLVC app__find ;Locate the application
719 LDMVSFD R13!,{R1,PC}^ ;Return to caller on error
720 LDR R4,[R0,#app_dlls] ;Load list head pointer
721 B %01app_instvars ;Don't try registering vars
723 ; --- Register instance variables ---
725 00app_instvars CMP R0,#0 ;Check the allocator worked
726 BEQ %40app_instvars ;If not, give an error
727 MOV R1,R0 ;Point to the new block
728 LDR R0,[R4,#lk_dll] ;Point to the DLL block
729 BL dll_instvars ;Register the instance vars
730 LDR R0,[R4,#lk_dll] ;Point to the DLL block again
731 BL dll_convreloc ;Convert to a relocation
732 STR R0,[R4,#lk_work] ;Store relocation
734 ; --- Is this the end of the line? ---
736 02app_instvars LDR R4,[R4,#lk_next] ;Move to next block in list
737 01app_instvars CMP R4,#0 ;Is this the end?
738 LDMEQFD R13!,{R1,PC}^ ;Yes -- return to caller
739 LDR R0,[R4,#lk_work] ;Find workspace pointer
740 CMP R0,#0 ;Is there one yet?
741 BNE %02app_instvars ;Yes -- skip this one
742 LDR R0,[R4,#lk_dll] ;Point to DLL
743 BL dll_datasize ;Find how much space we need
744 CMP R0,#0 ;Is there any required?
745 BEQ %02app_instvars ;No -- skip to next block
746 LDMFD R13!,{R1,PC}^ ;Return -- that's done
748 40app_instvars ADRL R0,msg_errDLLNoMem ;Point to error message
749 LDMFD R13!,{R1,R14} ;Restore registers
750 ORRS PC,R14,#V_flag ;Return the error
754 ; --- app_giveclib ---
756 ; On entry: R0 == pointer to CLib data (__iob)
762 STMFD R13!,{R1,R14} ;Stack registers
763 MOV R1,R0 ;Keep pointer to data
764 BL app__add ;Make sure there's an app
765 STRVC R1,[R0,#app_clibdata] ;Store the pointer nicely
766 LDMFD R13!,{R1,PC} ;Return to caller nicely
770 ; --- app_appdata ---
772 ; On entry: R0 == application's stack limit
778 STMFD R13!,{R1,R14} ;Stack registers
779 LDR R1,[R0,#-536] ;Find application's reloc
780 BL app__add ;Ensure the app is present
781 STRVC R1,[R0,#app_owndata] ;Store the relocation nicely
782 LDMFD R13!,{R1,PC} ;Return to caller nicely
786 ; --- app_findclib ---
789 ; On exit: R0 == pointer to CLib data
794 STMFD R13!,{R14} ;Keep return address safe
795 BL app_getHandle ;Find app's start time
796 BLVC app__find ;Look up application's block
797 LDRVC R0,[R0,#app_clibdata] ;Find C Library data pointer
798 LDMFD R13!,{PC} ;Return to caller
802 ; --- app_readstackptr ---
805 ; On exit: R0 == `magic cookie' for the stack pointer
807 EXPORT app_readstkptr
810 STMFD R13!,{R14} ;Keep return address safe
811 BL app_getHandle ;Find app's start time
812 BLVC app__find ;Locate the app's data block
813 LDRVC R0,[R0,#app_stackPtr] ;Find the stack pointer
814 LDMFD R13!,{PC}^ ;Return to caller
818 ; --- app_setstkptr ---
820 ; On entry: R0 == `magic cookie' from app_readstkptr
821 ; R1 == app's current stack limit
826 STMFD R13!,{R11,R14} ;Keep return address safe
828 ; --- Find the application block ---
830 MOV R11,R0 ;Keep hold of new pointer
831 BL app_getHandle ;Find the app's start time
832 BLVC app__find ;Find the app's data block
833 LDMVSFD R13!,{R11,PC} ;If failed, return error
835 ; --- Find out what there is to do ---
837 LDR R14,[R0,#app_stackPtr] ;Load the old pointer
838 CMP R11,R14 ;How does it shape up?
839 LDMEQFD R13!,{R11,PC}^ ;Nothing doing here
841 ; --- Put back the new stack pointer and set relocation ---
843 STR R11,[R0,#app_stackPtr] ;Store new pointer
844 CMP R11,#0 ;Was the stack at top level?
845 ADDNE R0,R0,#app_stack ;Point to base of stack
846 SUBNE R11,R11,#8 ;Point to base of stack entry
847 LDRNE R0,[R0,R11] ;Find data relocation
848 LDREQ R0,[R0,#app_owndata] ;If toplevel, get client data
849 STR R0,[R1,#-536] ;Store in stack limit struct
850 LDMFD R13!,{R11,PC}^ ;Return to caller
854 ; --- app_prologue ---
856 ; On entry: R0 == return address for routine
857 ; R1 == pointer to stack limit structure
858 ; R2 == pointer to base of DLL code
859 ; On exit: R0 == new return address
861 ; Note -- I'm directly accessing the DLL data here, which may be considered
862 ; naughty by some. I don't care.
867 STMFD R13!,{R9-R11,R14} ;Stack some registers
869 ; --- Find application block ---
871 MOV R11,R0 ;Keep hold of this
872 BL app__add ;Make sure the app exists
873 LDMVSFD R13!,{R9-R11,PC} ;Return the error on fail
875 ; --- Stack current relocation and return address ---
877 LDR R14,[R0,#app_stackPtr] ;Find the stack pointer
878 CMP R14,#4096 ;Where is it currently?
879 BGE %00app_prologue ;Give error on overflow
880 ADD R10,R0,#app_stack ;Point to stack base
881 ADD R10,R10,R14 ;Add on stack pointer
882 LDR R9,[R1,#-536] ;Find the current reloc
883 STMIA R10,{R9,R11} ;Store registers on the stack
884 MOV R10,R1 ;Keep pointer to stack limit
885 ADD R14,R14,#8 ;Bump along stack pointer
886 STR R14,[R0,#app_stackPtr] ;Store stack pointer
888 ; --- Find workspace pointer ---
890 CMP R2,#0 ;What's the DLL pointer?
891 LDREQ R1,[R0,#app_owndata] ;0 -- find app workspace
892 BEQ %10app_prologue ;... and finish search
893 LDR R14,[R2,#dl_next-dl_extra] ;Find DLL's next ptr
894 CMP R14,#-1 ;Is it shared?
895 LDREQ R1,[R2,#dl_wspace-dl_extra] ;No -- find DLL workspace
896 BEQ %10app_prologue ;... and finish search
898 ; --- Get shared DLL workspace pointer ---
900 SUB R1,R2,#dl_extra ;Point to DLL handle
901 BL app__findLink ;Find the link block
902 LDMVSFD R13!,{R9-R11,PC} ;Return error if it failed
903 LDR R1,[R0,#lk_work] ;Find relocation offset
905 ; --- Round everything off ---
907 10app_prologue ADR R0,app__epilogue ;Point to tidy-up routine
908 STR R1,[R10,#-536] ;Store new data relocation
909 LDMFD R13!,{R9-R11,PC}^ ;Return to caller happy
911 ; --- Stack overflow error ---
913 00app_prologue ADRL R0,msg_errStackOvf ;Point to error
914 LDMFD R13!,{R9-R11,R14} ;Unstack registers
915 ORRS PC,R14,#V_flag ;Return the error
919 ; --- app_restoreHandle ---
921 ; On entry: R0 == an application handle to assume
924 EXPORT app_restoreHandle
925 app_restoreHandle ROUT
927 [ :LNOT::DEF:ddeutils_pid
929 STMFD R13!,{R0-R2,R14} ;Save some registers
930 SWI XOS_GetEnv ;Read current command string
931 MOV R1,R13 ;Point to new start time
932 SWI XOS_WriteEnv ;Set the start time back
933 LDMFD R13!,{R0-R2,PC}^ ;And return to caller
937 MOVS PC,R14 ;No need to do this
943 ; --- app_getHandle ---
946 ; On exit: R0 == application's start time
948 ; Since the application's start time is held in *five* bytes we use only the
949 ; least significant 4 (the four that change most).
954 [ :LNOT::DEF:ddeutils_pid
956 STMFD R13!,{R1,R2,R14} ;Save some registers
957 SWI XOS_GetEnv ;Get the session info
958 LDR R0,[R2,#0] ;Load the start time nicely
959 LDMFD R13!,{R1,R2,PC}^ ;And return to caller
963 LDR R0,app__pidAddr ;Load the PID address
964 LDR R0,[R0] ;And load the current PID
965 MOVS PC,R14 ;Return to caller when done
971 ;----- Private routines -----------------------------------------------------
973 ; --- app__epilogue ---
976 ; On exit: a1,a2 preserved. otherwise as APCS-R
978 ; I've used APCS register names throughout here.
982 STMFD sp!,{a1,a2} ;Keep two return values
983 LDR ip,app__pw ;Point to private word ptr
984 BL app_getHandle ;Find app's start time
985 BL app__find ;Find app block
986 LDR a2,[a1,#app_stackPtr] ;Find the stack pointer
987 ADD a3,a1,#app_stack ;Point to the stack base
988 ADD a3,a3,a2 ;Point to current stack pos
989 LDMDB a3!,{a4,lr} ;Find relocation and ret addr
990 SUB a2,a2,#8 ;Bump down the stack ptr
991 STR a2,[a1,#app_stackPtr] ;Store back in app block
992 STR a4,[sl,#-536] ;Store relocation offset
993 LDMFD sp!,{a1,a2} ;Restore return values
994 MOVS pc,lr ;Return to caller
1000 ; On entry: R0 == application handle (i.e. start time)
1001 ; On exit: R0 == pointer to application block, or error
1005 STMFD R13!,{R1,R2,R14} ;Preserve nice registers
1007 ; --- Try looking at the cached value ---
1009 LDR R1,app__cacheHnd ;Load the cached handle
1010 CMP R1,R0 ;Is it a match?
1011 LDREQ R0,app__cachePtr ;Yes -- load the pointer
1012 LDMEQFD R13!,{R1,R2,PC}^ ;And return!
1014 ; --- Otherwise, scan the list ---
1016 LDR R2,app__list ;Get list head pointer
1017 CMP R2,#0 ;Is there an entry here?
1018 BEQ %10app__find ;No -- return an error
1019 00app__find LDR R1,[R2,#app_handle] ;Get the app's handle
1020 CMP R1,R0 ;Is it a match?
1021 BEQ %01app__find ;Yes -- deal with it
1022 LDR R2,[R2,#app_next] ;No -- get the next pointer
1023 CMP R2,#0 ;Is this the end?
1024 BNE %00app__find ;No -- continue round
1026 ; --- Couldn't find the application ---
1028 10app__find ADRL R0,msg_errUnknownApp ;Point to error message
1029 LDMFD R13!,{R1,R2,R14} ;Pull back registers
1030 ORRS PC,R14,#V_flag ;And return with an error
1032 ; --- Found an application -- update the cache ---
1034 01app__find STR R0,app__cacheHnd ;Store the new handle
1035 STR R2,app__cachePtr ;And the new pointer
1036 MOV R0,R2 ;Return the pointer to caller
1037 LDMFD R13!,{R1,R2,PC}^ ;And live happily ever after
1044 ; On exit: Application handle
1048 STMFD R13!,{R1-R3,R14} ;Stack registers
1050 ; --- Find out whether the app is registered yet ---
1052 BL app_getHandle ;Find app's start time
1053 MOV R1,R0 ;Look after a copy
1054 BL app__find ;Call the find routine
1055 LDMVCFD R13!,{R1-R3,PC}^ ;If already there, return
1057 ; --- Allocate a block from the RMA ---
1059 MOV R0,#6 ;Code to allocate some store
1060 LDR R3,=app_strSize ;The size of an app block
1061 SWI XOS_Module ;Allocate the memory
1062 LDMVSFD R13!,{R1-R3,PC} ;If it failed, return error
1064 ; --- Link the block into the list ---
1066 LDR R0,app__list ;Find the list header
1067 STR R0,[R2,#app_next] ;Store in next pointer
1068 CMP R0,#0 ;Is there a next block?
1069 STRNE R2,[R0,#app_prev] ;Yes -- link in new block
1070 MOV R0,#0 ;Zero out the previous link
1071 STR R0,[R2,#app_prev] ;Store in previous entry
1072 STR R2,app__list ;Store this as new block
1074 ; --- Set this block up in the cache ---
1076 STR R1,app__cacheHnd ;Cache the app's start time
1077 STR R2,app__cachePtr ;Cache the app's pointer
1079 ; --- Set up the block's data ---
1081 MOV R0,#0 ;Zero some entries in block
1082 STR R0,[R2,#app_cachedll] ;No cached DLL yet
1083 STR R0,[R2,#app_cacheptr] ;No cached DLL yet
1084 STR R0,[R2,#app_dlls] ;No DLLs registered yet
1085 STR R0,[R2,#app_stackPtr] ;No entries on the stack
1086 STR R0,[R2,#app_btable] ;App has no entry table
1087 STR R1,[R2,#app_handle] ;Store the app's time info
1088 ADD R0,R2,#app_name ;Point to app's name field
1089 ADRL R1,msg_appName ;Point to default name
1090 BL misc_strcpy ;Copy the string across
1092 ; --- Return the app's handle ---
1094 MOV R0,R2 ;Return the app's pointer
1095 LDMFD R13!,{R1-R3,PC}^ ;Return to caller
1101 ; On entry: R0 == pointer to app to free
1106 STMFD R13!,{R1,R2,R14} ;Keep registers safe
1108 ; --- Remove the block from the list ---
1110 LDR R1,[R0,#app_next] ;Get next block in the list
1111 LDR R2,[R0,#app_prev] ;Get previous block too
1112 CMP R1,#0 ;Is there a next block?
1113 STRNE R2,[R1,#app_prev] ;Yes -- fix up its prev
1114 CMP R2,#0 ;Is there a previous block?
1115 ADREQ R2,app__list ;No -- point to list head
1116 STR R1,[R2,#app_next] ;Fix up next pointer
1118 ; --- Remove this app from the cache ---
1120 LDR R2,app__cachePtr ;Find which app was cached
1121 CMP R2,R0 ;Is it this one?
1122 MOVEQ R2,#0 ;Yes -- overwrite handle
1123 STREQ R2,app__cacheHnd ;Won't match this app now
1124 STREQ R2,app__cachePtr
1126 ; --- Free the block ---
1128 MOV R2,R0 ;Point to the block to free
1129 MOV R0,#7 ;Magic reason code
1130 SWI XOS_Module ;Free the block
1131 LDMFD R13!,{R1,R2,PC} ;Return to caller if failed
1135 ; --- app__freeUnused ---
1137 ; On entry: R0 == pointer to application
1140 app__freeUnused ROUT
1142 STMFD R13!,{R14} ;Keep link register
1143 LDR R14,[R0,#app_dlls] ;Find DLL link list
1144 CMP R14,#0 ;Are there any in the list?
1145 LDMFD R13!,{R14} ;Restore link register
1146 MOVNES PC,R14 ;Return is still attached
1147 B app__free ;Otherwise kill the app
1151 ; --- app__sFindDLL ---
1153 ; On entry: R0 == pointer to name of DLL to find
1154 ; R1 == version number to load
1155 ; On exit: R0 == DLL handle loaded
1159 STMFD R13!,{R1,R2,R9-R11,R14} ;Stack loads of registers
1161 MOV R11,R0 ;Keep pointer safe
1163 ; --- Ensure that the application structure is there ---
1165 BL app__add ;Add the application if reqd.
1166 LDMVSFD R13!,{R1,R2,R9-R11,PC} ;If it failed, return now
1167 MOV R10,R0 ;Keep pointer to app block
1169 ; --- Find out if there's anything to do ---
1171 MOV R2,R1 ;Put version number nicely
1172 MOV R1,R11 ;Point to required name
1173 BL app__findNamedLink ;Is there anything to do?
1174 LDMVCFD R13!,{R1,R2,R9-R11,PC}^ ;If found, return to caller
1175 MOV R1,R2 ;Put version number back
1177 ; --- Load the DLL if necessary ---
1179 MOV R0,R11 ;Move DLL pointer back
1180 BL dll_ensure ;Load the DLL into memory
1181 MOVVS R9,R0 ;If it failed, keep the error
1182 BVS %50app__sFindDLL ;And tidy up properly
1183 MOV R11,R0 ;Keep pointer to DLL
1184 BL dll_tentative ;Mark the DLL as tentative
1186 ; --- Add the link between the two ---
1188 MOV R0,R10 ;Point to application
1189 MOV R1,R11 ;Point to DLL block
1190 BL app__addLink ;Link them together
1191 MOVVS R9,R0 ;Keep error if any
1192 BVS %51app__sFindDLL ;And tidy things up
1194 ; --- Now we're done ---
1196 MOV R0,R11 ;Point to DLL structure
1197 LDMFD R13!,{R1,R2,R9-R11,PC}^ ;Restore registers
1199 ; --- Tidy up if link allocation failed ---
1202 50app__sFindDLL MOV R0,R10 ;Point to application block
1203 BL app__freeUnused ;If not being used, kill it
1205 ; --- Return the error to the caller ---
1207 MOV R0,R9 ;Point to the error message
1208 LDMFD R13!,{R1,R2,R9-R11,R14} ;Restore registers
1209 ORRS PC,R14,#V_flag ;Return to caller
1216 ; On exit: All registers preserved
1218 ; Expects a stacked R11 and R14
1222 MOV R11,R0 ;Look after error pointer
1223 BL dll_confirm ;Cancel tentative DLL blocks
1224 BL app_getHandle ;Find app time info
1225 BLVC app__find ;Find the application block
1226 BLVC app__confLink ;Cancel tentative links
1228 ; --- Resync code areas ---
1230 ; This seems as good a place as any to do this. I'm going
1231 ; to do a global resync, because I suspect that lots of
1232 ; local ones are going to be rather slower, actually.
1233 ; Besides, loading libraries isn't something which gets done
1236 MOV R0,#0 ;Resync everything
1237 SWI XOS_SynchroniseCodeAreas ;Do that then, please
1239 MOV R0,R11 ;Point to error again
1240 LDMFD R13!,{R11,R14} ;Restore registers
1241 BICS PC,R14,#V_flag ;Return to caller with V clr
1248 ; On exit: All registers preserved
1250 ; Expects a stacked R11 and R14
1254 MOV R11,R0 ;Look after error pointer
1255 CMP R0,R0 ;Clear the V flag
1256 BL dll_retrace ;Destroy tentative DLL blocks
1257 BL app_getHandle ;Find app time info
1258 BLVC app__find ;Find the application block
1259 BLVC app__cancel ;Destroy tentative links
1260 MOV R0,R11 ;Point to error again
1261 LDMFD R13!,{R11,R14} ;Restore registers
1262 ORRS PC,R14,#V_flag ;Return to caller with V set
1266 ; --- app__findNamedLk ---
1268 ; On entry: R0 == pointer to application
1269 ; R1 == pointer to DLL's name
1270 ; R2 == DLL's version number
1271 ; On exit: R0 == V set if couldn't be found, clear otherwise
1273 app__findNamedLink ROUT
1275 STMFD R13!,{R3,R4,R14} ;Stack registers safely
1276 LDR R3,[R0,#app_dlls] ;Point to first DLL block
1277 CMP R3,#0 ;Is there anything to do?
1278 BEQ %20app__findNamedLink ;No -- that's an error
1280 ; --- Now construct the proper DLL name ---
1282 MOV R0,R1 ;Point to the DLL name
1283 00 LDRB R14,[R0],#1 ;Load the next byte
1284 CMP R14,#'[' ;Is this a new-style DAN?
1285 BEQ %f05 ;Yes -- sort this out then
1286 CMP R14,#'.' ;Or is it a dot?
1287 MOVEQ R1,R0 ;Yes -- remember this place
1288 CMP R14,#&20 ;End of the string yet?
1289 BCS %b00 ;No -- keep going
1291 ADR R0,misc__sharedBuf ;Find the shared buffer
1292 00 LDRB R14,[R1],#1 ;Load a byte from the name
1293 CMP R14,#&20 ;Finished yet?
1294 MOVCC R14,#0 ;Yes -- zero-terminate
1295 STRB R14,[R0],#1 ;And store it out
1296 BCS %b00 ;No -- keep going
1297 B %10app__findNamedLink ;And skip to main matcher
1299 ; --- Handle a new-style DAN ---
1301 05 ADR R1,misc__sharedBuf ;Find the shared buffer
1302 00 LDRB R14,[R0],#1 ;Load a byte from the name
1303 CMP R14,#']' ;End of the name yet?
1304 MOVEQ R14,#0 ;Yes -- terminate here then
1305 CMP R14,#&20 ;Finished yet?
1306 MOVCC R14,#0 ;Yes -- zero-terminate
1307 STRB R14,[R1],#1 ;And store it out
1308 BCS %b00 ;No -- keep going
1310 10app__findNamedLink
1311 ADR R1,misc__sharedBuf ;Point to the DLL name
1313 00 LDR R0,[R3,#lk_dll] ;Find DLL pointer for block
1314 BL dll_compare ;Compare with passed values
1315 CMP R0,#1 ;Did it return TRUE?
1316 BEQ %30app__findNamedLink ;Yes -- be happy
1317 LDR R3,[R3,#lk_next] ;Find next pointer
1318 CMP R3,#0 ;Is there any more to do?
1319 BNE %b00 ;Yes -- loop round and do it
1321 20app__findNamedLink
1322 LDMFD R13!,{R3,R4,R14} ;Restore registers
1323 ORRS PC,R14,#V_flag ;Return with V set
1325 30app__findNamedLink
1326 LDR R0,[R3,#lk_dll] ;Load DLL pointer again
1327 LDMFD R13!,{R3,R4,R14} ;Restore registers
1328 BICS PC,R14,#V_flag ;Return with V clear
1332 ; --- app__findLink ---
1334 ; On entry: R0 == pointer to application
1335 ; R1 == pointer to DLL
1336 ; On exit: R0 == pointer to link structure
1340 STMFD R13!,{R1,R2,R14} ;Preserve nice registers
1342 ; --- Try looking at the cached value ---
1344 LDR R2,[R0,#app_cachedll] ;Load the cached handle
1345 CMP R2,R1 ;Is it a match?
1346 LDREQ R0,[R0,#app_cacheptr] ;Yes -- load the pointer
1347 LDMEQFD R13!,{R1,R2,PC}^ ;And return!
1349 ; --- Otherwise, scan the list ---
1351 LDR R2,[R0,#app_dlls] ;Get list head pointer
1352 CMP R2,#0 ;Is there an entry here?
1353 BEQ %10app__findLink ;No -- return an error
1354 00app__findLink LDR R14,[R2,#lk_dll] ;Get the DLL's pointer
1355 CMP R1,R14 ;Is it a match?
1356 BEQ %01app__findLink ;Yes -- deal with it
1357 LDR R2,[R2,#lk_next] ;No -- get the next pointer
1358 CMP R2,#0 ;Is this the end?
1359 BNE %00app__findLink ;No -- continue round
1361 ; --- Couldn't find the application ---
1363 10app__findLink ADRL R0,msg_errLinkNotFound ;Point to error message
1364 LDMFD R13!,{R1,R2,R14} ;Pull back registers
1365 ORRS PC,R14,#V_flag ;And return with an error
1367 ; --- Found an application -- update the cache ---
1369 01app__findLink STR R1,[R0,#app_cachedll] ;Store the new handle
1370 STR R2,[R0,#app_cacheptr] ;And the new pointer
1371 MOV R0,R2 ;Return the pointer to caller
1372 LDMFD R13!,{R1,R2,PC}^ ;And live happily ever after
1376 ; --- app__addLink ---
1378 ; On entry: R0 == pointer to application
1379 ; R1 == pointer to DLL
1384 STMFD R13!,{R1,R11,R14} ;Stack registers
1385 MOV R11,R0 ;Keep pointer to application
1387 ; --- Find out whether the link is registered yet ---
1389 BL app__findLink ;Call the find routine
1390 LDMVCFD R13!,{R1,R11,PC}^ ;If already there, return
1392 ; --- Allocate a block from the RMA ---
1394 CMP R0,R0 ;Clear V flag
1395 BL sub_alloc ;Allocate a link block
1396 LDMVSFD R13!,{R1,R11,PC} ;If it failed, return error
1398 ; --- Link the block into the list ---
1400 LDR R14,[R11,#app_dlls] ;Find the list header
1401 STR R14,[R0,#lk_next] ;Store in next pointer
1402 CMP R14,#0 ;Is there a next block?
1403 STRNE R0,[R14,#lk_prev] ;Yes -- link in new block
1404 MOV R14,#0 ;Zero out the previous link
1405 STR R14,[R0,#lk_prev] ;Store in previous entry
1406 STR R0,[R11,#app_dlls] ;Store this as new block
1408 ; --- Set this block up in the cache ---
1410 STR R1,[R11,#app_cachedll] ;Cache the DLL's pointer
1411 STR R0,[R11,#app_cacheptr] ;Cache the app's pointer
1413 ; --- Set up the block's data ---
1415 STR R1,[R0,#lk_dll] ;Store pointer to DLL
1416 MOV R1,#0 ;No workspace yet
1417 STR R1,[R0,#lk_work] ;So store in the block
1419 ; --- Mark as currently tentative ---
1421 MOV R1,#lk_tentative ;Tentative flag
1422 STR R1,[R0,#lk_flags] ;Store in block's flags area
1424 ; --- Return the app's handle ---
1426 LDMFD R13!,{R1,R11,PC}^ ;Return to caller
1430 ; --- app__freeLink ---
1432 ; On entry: R0 == pointer to application
1433 ; R1 == pointer to link structure
1438 STMFD R13!,{R1,R2,R14} ;Stack registers
1440 ; --- Fix up list ---
1442 LDR R2,[R1,#lk_next] ;Get next pointer
1443 LDR R14,[R1,#lk_prev] ;Get previous pointer
1444 CMP R2,#0 ;Is there a real next block?
1445 STRNE R14,[R2,#lk_prev] ;Yes -- fix backwards link
1446 CMP R14,#0 ;Is there a real prev block?
1447 ADDEQ R14,R0,#app_dlls ;No -- point to list head
1448 STR R2,[R14,#lk_next] ;Fix forwards link
1450 ; --- Free the link ---
1452 MOV R0,R1 ;Point to the link
1453 LDMFD R13!,{R1,R2,R14} ;Retreive registers
1454 B sub_free ;Free the link block
1458 ; --- app__confLk ---
1460 ; On entry: R0 == application to confirm
1465 STMFD R13!,{R1,R14} ;Stack registers
1466 LDR R0,[R0,#app_dlls] ;Find head of the link list
1467 CMP R0,#0 ;Is it empty?
1468 LDMEQFD R13!,{R1,PC}^ ;Yes -- return to caller
1469 00app__confLink LDR R1,[R0,#lk_next] ;Find the next entry
1470 LDR R14,[R0,#lk_flags] ;Load flags word
1471 BIC R14,R14,#lk_tentative ;Clear the magic flag
1472 STR R14,[R0,#lk_flags] ;Store the flags word back
1473 MOVS R0,R1 ;Move to next entry
1474 BNE %00app__confLink ;If more to do, do next one
1475 LDMFD R13!,{R1,PC}^ ;Return to caller, confirmed
1479 ; --- app__cancel ---
1481 ; On entry: R0 == app to cancel
1486 STMFD R13!,{R1,R2,R14} ;Stack registers
1487 MOV R2,R0 ;Keep pointer to app block
1488 LDR R0,[R0,#app_dlls] ;Find head of the link list
1489 CMP R0,#0 ;Is it empty?
1490 LDMEQFD R13!,{R1,R2,PC}^ ;Yes -- return to caller
1491 00app__cancel LDR R1,[R0,#lk_next] ;Find the next entry
1492 LDR R14,[R0,#lk_flags] ;Load flags word
1493 TST R14,#lk_tentative ;Is the flag set?
1494 BEQ %01app__cancel ;No -- move on to next one
1496 LDR R14,[R0,#lk_prev] ;Find pointer to previous
1497 CMP R1,#0 ;Is there a next block?
1498 STRNE R14,[R1,#lk_prev] ;Fix up previous pointer
1499 CMP R14,#0 ;Is there a previous block?
1500 ADDEQ R14,R2,#app_dlls ;No -- point to list base
1501 STR R1,[R14,#lk_next] ;Fix up next pointer
1502 BL sub_free ;Free the block
1504 01app__cancel MOVS R0,R1 ;Move to next entry
1505 BNE %00app__cancel ;If more to do, do next one
1507 MOV R0,R2 ;Point to application block
1508 BL app__freeUnused ;If nothing left, kill app
1509 LDMFD R13!,{R1,R2,PC}^ ;Return to caller, cancelled
1513 ;----- That's all folks -----------------------------------------------------