; ; app.s ; ; Handling of application blocks ; ; © 1994-1998 Straylight ; ;----- Licensing note ------------------------------------------------------- ; ; This file is part of Straylight's Dynamic Linking System (SDLS) ; ; SDLS is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2, or (at your option) ; any later version. ; ; SDLS is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with SDLS. If not, write to the Free Software Foundation, ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ;----- Standard header ------------------------------------------------------ GET libs:header GET libs:swis GET libs:stream ;----- External dependencies ------------------------------------------------ GET sh.wSpace GET sh.appblock GET sh.linkblock GET sh.dllblock GET sh.misc GET sh.suballoc GET sh.dll GET sh.messages ;----- External routines ---------------------------------------------------- AREA |DLLM$$Code|,CODE,READONLY GBLL debug debug SETL {FALSE} ; --- app_init --- ; ; On entry: -- ; On exit: -- EXPORT app_init app_init ROUT STMFD R13!,{R1,R2,R14} ;Save some registers ; --- Save workspace address --- ; ; This is so that app__epilogue can find our workspace. STR R12,app__pw ;Store data relocation ; --- Now locate the OS's pid word --- ; ; We do this using a table indexed by the OS version on the ; grounds that it's easier to update if the address changes. ; This is unlikely however, since DDEUtils uses this address ; too, and it's right before the VDU driver workspace at ; &1000, which seems to indicate it's there forever. MOV R0,#&81 ;Read the OS version number MOV R1,#0 ;Set up the odd arguments MOV R2,#255 ;This is really very strange SWI XOS_Byte ;Do the read operation ADR R14,app__verTable ;Point to the table 00 LDMIA R14!,{R0,R2} ;Load version and address CMP R0,R1 ;How do the versions compare? BCC %b00 ;No match -- keep going STR R2,app__pidAddr ;If matched, store address LDMFD R13!,{R1,R2,PC}^ ;Restore caller's registers BICS PC,R14,#V_flag ;And return to caller app__verTable DCD -1,&FF8 ;All versions have PID here LTORG app__pw DCD 0 ;Where to store private word ; --- app_checkQuit --- ; ; On entry: -- ; On exit: -- EXPORT app_checkQuit app_checkQuit ROUT LDR R0,app__list ;Get list head pointer CMP R0,#0 ;Are there any applications? MOVEQS PC,R14 ;No -- that's OK then ADRL R0,msg_errInUse ;Point to error ORRS PC,R14,#V_flag ;Return an error LTORG ; --- app_findDLL --- ; ; On entry: R0 == pointer to name of DLL to find ; R1 == version number to load ; On exit: R0 == DLL handle loaded EXPORT app_findDLL app_findDLL ROUT STMFD R13!,{R11,R14} ;Stack registers nicely BL app__sFindDLL ;Find the DLL etc. BVC app__ok ;If it worked, make permanent B app__dead ;Otherwise, tidy up LTORG ; --- app_loseDLL --- ; ; On entry: R0 == pointer to DLL to lose ; On exit: -- EXPORT app_loseDLL app_loseDLL ROUT STMFD R13!,{R1-R3,R11,R14} ;Look after some registers MOV R11,R0 ;Keep hold of pointer ; --- Find the application's handle --- BL app_getHandle ;Find application's time BLVC app__find ;Find the application block LDMVSFD R13!,{R1-R3,R11,PC} ;Return an error if any ; --- Find the link block --- MOV R3,R0 ;Keep hold of app pointer MOV R1,R11 ;Point to application BL app__findLink ;Find the link block LDMVSFD R13!,{R1-R3,R11,PC} ;Return an error if any ; --- Remove the link block --- MOV R1,R0 ;Point to the link block MOV R0,R3 ;Point to the application BL app__freeLink ;Free the link block up ; --- Decrement the DLL count --- ; ; This will release the DLL if it no longer has any clients MOV R0,R11 ;Point to DLL BL dll_dec ;Decrement its counter ; --- Uncache the current link if we've removed it --- LDR R0,[R3,#app_cachedll] ;Find which DLL we cached CMP R0,R11 ;Have we just unlinked it? MOVEQ R0,#0 ;Yes -- clear out the handle STREQ R0,[R3,#app_cachedll] ;Won't match any more STREQ R0,[R3,#app_cacheptr] ; --- Return, deleting application if necessary --- MOV R0,R3 ;Point to application LDMFD R13!,{R1-R3,R11,R14} ;Unstack registers B app__freeUnused ;Kill app block if no DLLs LTORG ; --- app_setname --- ; ; On entry: R0 == pointer to application's name ; On exit: -- EXPORT app_setname app_setname ROUT STMFD R13!,{R1,R14} ;Store registers and things MOV R1,R0 ;Keep pointer to the name BL app__add ;Make sure the app exists ADDVC R0,R0,#app_name ;Point to the name BLVC misc_strcpy ;Copy the string across LDMFD R13!,{R1,PC} ;Return to caller LTORG ; --- app_fromtable --- ; ; On entry: R0 == pointer to start of external DLL block ; R1 == pointer to limit of same ; On exit: -- EXPORT app_fromtable app_fromtable ROUT STMFD R13!,{R11,R14} ;Look after registers BL app_sfromtbl ;Do primitive operation BVC app__ok ;If it worked, to gadget B app__dead ;If it failed,tidy up LTORG ; --- app_sfromtbl --- ; ; On entry: R0 == pointer to start of external DLL block ; R1 == pointer to limit of same ; On exit: -- EXPORT app_sfromtbl app_sfromtbl ROUT STMFD R13!,{R1-R5,R10,R11,R14} ;Stack some registers MOV R10,R0 ;Keep pointer to base MOV R11,R1 ;Keep pointer to limit 00app_sfromtbl CMP R10,R11 ;Is there anything to do? LDMEQFD R13!,{R1-R5,R10,R11,PC}^ ;No -- return to caller ; --- Load an entry from the table --- LDMIA R10!,{R0-R3} ;Load values from table BL app__sFindDLL ;Try to find the DLL LDMVSFD R13!,{R1-R5,R10,R11,PC} ;Return the error if any ; --- Fill in the veneer table --- MOV R1,R2 ;Point to first name to load MOV R2,R0 ;Keep pointer to DLL base LDR R5,[R2,#dl_entries] ;Load the entry count BIC R4,R5,#&FF000000 ;Clear entry type bits 01app_sfromtbl LDR R0,[R3,#0] ;Load value from table CMP R0,R4 ;Is it a valid ordinal? BHS %05app_sfromtbl ;No -- look up the name then LDR R14,[R2,#dl_eveneer] ;Yes -- load entry point base TST R5,#dl_shortEntries ;Are the entries short? ADDEQ R0,R14,R0,LSL #4 ;No -- find base of veneer LDRNE R0,[R14,R0,LSL #2] ;Yes -- load address B %10app_sfromtbl ;And skip past name lookup 05app_sfromtbl LDRB R0,[R1] ;Load first byte from string CMP R0,#0 ;Is it a zero (end of list)? BEQ %00app_sfromtbl ;Yes -- do next table entry ; --- Find entry point address --- MOV R0,R2 ;Point to DLL base BL dll_findEntry ;Find the entry point LDMVSFD R13!,{R1-R5,R10,R11,PC} ;Return the error if any MOV R4,#0 ;Remember to bump name ; --- Convert it into a branch --- 10app_sfromtbl SUB R0,R0,R3 ;Convert to offset from R3 SUB R0,R0,#8 ;Subtract 8 (pipeline) MOV R0,R0,LSR #2 ;Shift right to word align BIC R0,R0,#&FF000000 ;Clear top (opcode and cond) ORR R0,R0,#&EA000000 ;Put in BAL (Branch always) STR R0,[R3],#4 ;Store in veneer table CMP R4,#0 ;Did we look up a name? BNE %01app_sfromtbl ;No -- examine next entry pt ; --- Find next entry point address --- 02app_sfromtbl LDRB R0,[R1],#1 ;Load a byte from the name CMP R0,#0 ;Is it the string end? BNE %02app_sfromtbl ;No -- get another B %01app_sfromtbl ;Fill in another entry point LTORG ; --- app_findNamed --- ; ; On entry: R0 == name of an application ; On exit: R0 == pointer to application block base EXPORT app_findNamed app_findNamed ROUT STMFD R13!,{R1-R3,R14} ;Preserve registers MOV R1,R0 ;Keep pointer to string LDR R3,app__list ;And load the pointer to list 00app_findNamed CMP R3,#0 ;Is this the end of the line? BEQ %40app_findNamed ;Yes -- give an error ADD R0,R3,#app_name ;Find the name string MOV R2,#0 ;Caseless compare BL misc_strcmp ;Compare the strings LDRNE R3,[R3,#app_next] ;If no match, move on... BNE %00app_findNamed ;... and try again MOV R0,R3 ;Point to DLL (give handle) LDMFD R13!,{R1-R3,PC}^ ;And return to caller 40app_findNamed ADRL R0,msg_errAppNotFound ;Couldn't find DLL name BL misc_error ;... create an error message LDMFD R13!,{R1-R3,R14} ;... restore registers ORRS PC,R14,#V_flag ;... and return an error LTORG ; --- app_setBtable --- ; ; On entry: R0 == pointer to entry point table ; R1 == pointer to name table ; On exit: -- EXPORT app_setBtable app_setBtable ROUT STMFD R13!,{R1,R2,R14} ;Stick 'em on the stack MOV R2,R0 ;Keep this safe BL app__add ;Create an entry for the app STRVC R2,[R0,#app_btable] ;Store the entry table ptr STRVC R1,[R0,#app_nametable] ;Store the name table ptr LDMFD R13!,{R1,R2,PC} ;Return to caller LTORG ; --- app_appEntry --- ; ; On entry: R0 == pointer to name to find ; On exit: R0 == pointer to entry point EXPORT app_appEntry app_appEntry ROUT STMFD R13!,{R1,R2,R14} ;Stack registers away ; --- Find the application --- MOV R2,R0 ;Point to name start BL app_getHandle BLVC app__find ;Try to find the app block LDMVSFD R13!,{R1,R2,PC} ;If not there, error ; --- Get the entry table info out --- LDR R1,[R0,#app_nametable] ;Find name table address LDR R0,[R0,#app_btable] ;Find entry table address CMP R0,#0 ;Is there no entry table? BEQ %50app_appEntry ;No -- complain about it ; --- Find the entry point --- BL dll_appEntry ;Do the actual find LDMFD R13!,{R1,R2,PC} ;Return to caller ; --- Application has no entry points --- 50app_appEntry ADRL R0,msg_errAppNoEntry ;Point to error message LDMFD R13!,{R1,R2,R14} ;Unstack registers ORRS PC,R14,#V_flag ;Return the error to caller LTORG ALIGN ; --- app_fixExtension --- ; ; On entry: R0 == pointer to name table ; R1 == pointer to branch table to fill in ; On exit: -- EXPORT app_fixExtension app_fixExtension STMFD R13!,{R14} ;Save return address BL app_fix ;Do the real job LDMVSFD R13!,{PC} ;If it failed, return now MOV R0,#0 ;Otherwise do global resync SWI XOS_SynchroniseCodeAreas ;Do that then LDMFD R13!,{R14} ;Restore return address BICS PC,R14,#V_flag ;And return with V clear LTORG ; --- app_fix --- ; ; On entry: R0 == pointer to name table ; R1 == pointer to branch table to fill in ; On exit: -- EXPORT app_fix app_fix ROUT STMFD R13!,{R1-R6,R14} ;Stack registers away ; --- Find the application --- MOV R2,R0 ;Point to name start MOV R3,R1 ;Keep entry table safe BL app_getHandle BLVC app__find ;Try to find the app block LDMVSFD R13!,{R1-R6,PC} ;If not there, error ; --- Get the entry table info out --- LDR R4,[R0,#app_btable] ;Find entry table address LDR R5,[R0,#app_nametable] ;Find name table address MOV R6,#&1000 ;Guess number of entries CMP R4,#0 ;Is there no entry table? BEQ %50app_fix ;No -- complain about it ; --- Set up for a nice loop --- 00app_fix LDR R0,[R3,#0] ;Load the word from btable CMP R0,R6 ;Is it moderately sensible? ADDLO R0,R4,R0,LSL #2 ;Yes -- find the entry MOVLO R14,#1 ;Remember we done this BLO %10app_fix ;And fill in the branch LDRB R0,[R2] ;Get the first entry byte CMP R0,#0 ;Is it the end of the table? LDMEQFD R13!,{R1-R6,PC}^ ;Yes -- we did it OK ; --- Find another entry point address --- MOV R0,R4 ;Point to entry table MOV R1,R5 ;Point to name table BL dll_appEntry ;Find the actual entry name LDMVSFD R13!,{R1-R6,PC} ;If not there, return error MOV R6,#0 ;Move on to next string ; --- Convert it to a branch instruction --- 10app_fix SUB R0,R0,R3 ;Convert to offset from R3 SUB R0,R0,#8 ;Subtract 8 (pipeline) MOV R0,R0,LSR #2 ;Shift right to word align BIC R0,R0,#&FF000000 ;Clear top (opcode and cond) ORR R0,R0,#&EA000000 ;Put in BAL (Branch always) STR R0,[R3],#4 ;Store in veneer table ; --- Find next entry point address --- CMP R6,#0 ;Do we need to move on? BNE %00app_fix ;No -- just loop then 01app_fix LDRB R0,[R2],#1 ;Load a byte from the name CMP R0,#0 ;Is it the string end? BNE %01app_fix ;No -- get another B %00app_fix ;Fill in another entry point ; --- Application has no entry points to offer --- 50app_fix ADRL R0,msg_errAppNoEntry ;Point to error message LDMFD R13!,{R1-R6,R14} ;Unstack registers ORRS PC,R14,#V_flag ;Return the error to caller LTORG ; --- app_listDLLs --- ; ; On entry: R0 == pointer to name of an application ; On exit: -- EXPORT app_listDLLs app_listDLLs ROUT STMFD R13!,{R1,R14} ;Stack registers nicely BL app_findNamed ;Find the application block LDMVSFD R13!,{R1,PC} ;Return if not found LDR R1,[R0,#app_dlls] ;Load head of DLL list CMP R1,#0 ;This shouldn't be 0 BEQ %01app_listDLLs ;If it is, print a message BL dll_writeTitle ;Display the line along top ; --- Main loop thing --- 00app_listDLLs LDR R0,[R1,#lk_dll] ;Point to the DLL BL dll_writeInfo ;Display information about it LDR R1,[R1,#lk_next] ;Move onto the next one CMP R1,#0 ;Is that all? BNE %00app_listDLLs ;No -- continue round LDMFD R13!,{R1,PC}^ ;Return to caller ; --- No DLLs to list. Hmm... --- 01app_listDLLs ADRL R0,msg_noDLLsForApp ;Point to the message SWI OS_Write0 ;And display it LDMFD R13!,{R1,PC}^ ;Return to caller LTORG ; --- app_listUsing --- ; ; On entry: R0 == pointer to a DLL name ; On exit: -- EXPORT app_listUsing app_listUsing ROUT STMFD R13!,{R1,R2,R8-R11,R14} ;Stack registers ; --- Check that the DLL exists --- MOV R8,R0 ;Keep the name pointer safe MOV R1,#0 ;Don't care which version BL dll_find ;Try to find it BVS %11app_listUsing ;If it's not there, error ; --- Start a loop through the apps --- LDR R11,app__list ;Find the list head pointer MOV R10,#0 ;No matching DLLs found yet CMP R11,#0 ;Are there any apps? BEQ %10app_listUsing ;No -- print a message then ; --- Start a loop through the DLLs with this app 00app_listUsing LDR R9,[R11,#app_dlls] ;Find the DLL list CMP R9,#0 ;Are there any DLLs? BEQ %03app_listUsing ;No -- move on to the next ; --- Loop through DLLs on this app --- 01app_listUsing LDR R0,[R9,#lk_dll] ;Point to the DLL base MOV R1,R8 ;Point to DLL name MOV R2,#0 ;Don't care what version BL dll_compare ;Compare with stuff given CMP R0,#1 ;Is there a match? BNE %02app_listUsing ;Move onto the next one ; --- Print out info about this app --- CMP R10,#1 ;Have we printed the title? ADRNEL R0,msg_appHeader ;No -- point to header SWINE XOS_Write0 ;And print it MOV R10,#1 ;We've printed it now ADD R0,R11,#app_name ;Point to application name MOV R1,#12 ;Field width BL dll_field ;Print it out LDR R0,[R9,#lk_dll] ;Find DLL pointer again LDR R0,[R0,#dl_version] ;Load version number BL dll_convertVersion ;Convert it into a string SWI XOS_Write0 ;Write it out as a string SWI XOS_NewLine ;And move onto the next line ; --- Finish off loop through app's DLLs --- 02app_listUsing LDR R9,[R9,#lk_next] ;Move on to next link block CMP R9,#0 ;Anything to do here? BNE %01app_listUsing ;Yes -- check that one too ; --- Finish off loop through all apps --- 03app_listUsing LDR R11,[R11,#app_next] ;Move on to next application CMP R11,#0 ;Is there any more to do? BNE %00app_listUsing ;Yes -- do its DLLs CMP R10,#0 ;Were any messages printed? BEQ %10app_listUsing ;No -- print one LDMFD R13!,{R1,R2,R8-R11,PC}^ ;Return to caller ; --- No matching DLLs were found --- 10app_listUsing ADRL R0,msg_noAppsForDLL ;Point to message skeleton MOV R1,R8 ;Point to the DLL name BL misc_subst ;Do the substitution SWI XOS_Write0 ;Display the string LDMFD R13!,{R1,R2,R8-R11,PC}^ ; --- Print an error message about this --- 11app_listUsing MOV R1,R8 ;Point to DLL name ADRL R0,msg_errDLLNotInMem ;Point to error block BL misc_error ;Create error message fully LDMFD R13!,{R1,R2,R8-R11,R14} ;Unstack all registers ORRS PC,R14,#V_flag ;Return to caller with error LTORG ; --- app_list --- ; ; On entry: -- ; On exit: -- EXPORT app_list app_list ROUT STMFD R13!,{R1,R14} ;Stack registers ; --- Prepare for a loop --- LDR R1,app__list ;Point to first entry CMP R1,#0 ;Are there any entries? BEQ %10app_list ;No -- give a message ; --- Display entries in order --- 00app_list ADD R0,R1,#app_name ;Point to name in structure SWI XOS_Write0 ;Display the app's name SWI XOS_NewLine ;Display a new line char LDR R1,[R1,#app_next] ;Get next entry in the list CMP R1,#0 ;Is it the end yet? BNE %00app_list ;No -- do the next one LDMFD R13!,{R1,PC}^ ;Return to caller ; --- Display message about no apps --- 10app_list ADRL R0,msg_noApps ;Point to the message SWI XOS_Write0 ;Display it on the screen LDMFD R13!,{R1,PC}^ ;Return to caller LTORG ; --- app_dying --- ; ; On entry: -- ; On exit: -- EXPORT app_dying app_dying ROUT STMFD R13!,{R14} ;Stack return address BL app_getHandle ;Find application's time BLVC app__find ;Find the application block LDMFD R13!,{R14} ;Retrieve the return address BVC app_kill ;If there's no error, kill it ORRS PC,R14,#V_flag ;Return to caller with error LTORG ; --- app_kill -- ; ; On entry: R0 == pointer to application base ; On exit: -- EXPORT app_kill app_kill ROUT STMFD R13!,{R1,R2,R14} ;Stack registers nicely MOV R2,R0 ;Keep hold of this pointer ; --- Free each DLL link --- LDR R1,[R0,#app_dlls] ;Find head of link list CMP R1,#0 ;Are there any DLLs? BEQ %01app_kill ;No -- don't free them then 00app_kill LDR R0,[R1,#lk_dll] ;Find the DLL pointer BL dll_dec ;Decrement its counter MOV R0,R1 ;Point to old block LDR R1,[R0,#lk_next] ;Point to next block BL sub_free ;Free the old block CMP R1,#0 ;Are there any more to do? BNE %00app_kill ;Yes -- do the next one ; --- Free the application block --- 01app_kill MOV R0,R2 ;Point to application block LDMFD R13!,{R1,R2,R14} ;Restore registers B app__free ;Free the application block LTORG ; --- app_killAll --- ; ; On entry: -- ; On exit: -- EXPORT app_killAll app_killAll ROUT STMFD R13!,{R1,R2,R14} ; --- Start up the main loop --- LDR R2,app__list ;Point to application list CMP R2,#0 ;Is there anything to do? BEQ %01app_killAll ;No -- skip the loop MOV R0,#7 ;Free memory reason code 00app_killAll LDR R1,[R2,#app_next] ;Find next block in the list SWI XOS_Module ;Free the block MOVS R2,R1 ;Point to the next one BNE %00app_killAll ;Loop round for the next one 01app_killAll STR R2,app__list ;Clear out list head pointer STR R2,app__cachePtr ;Clear out cached pointer STR R2,app__cacheHnd ;Clear out cached handle LDMFD R13!,{R1,R2,PC}^ ;Return to caller LTORG ; --- app_instvars --- ; ; On entry: R0 == anything for first call, or pointer to data block ; R4 == 0 for first call, or pointer to link block ; On exit: R0 == size of block required ; R4 == pointer to next link block, or 0 to end EXPORT app_instvars app_instvars ROUT STMFD R13!,{R1,R14} ;Keep hold of link register CMP R4,#0 ;Is this the first call? BNE %00app_instvars ;No -- skip ahead quickly ; --- Find start of application list --- BL app_getHandle ;Get app's start time BLVC app__find ;Locate the application LDMVSFD R13!,{R1,PC}^ ;Return to caller on error LDR R4,[R0,#app_dlls] ;Load list head pointer B %01app_instvars ;Don't try registering vars ; --- Register instance variables --- 00app_instvars CMP R0,#0 ;Check the allocator worked BEQ %40app_instvars ;If not, give an error MOV R1,R0 ;Point to the new block LDR R0,[R4,#lk_dll] ;Point to the DLL block BL dll_instvars ;Register the instance vars LDR R0,[R4,#lk_dll] ;Point to the DLL block again BL dll_convreloc ;Convert to a relocation STR R0,[R4,#lk_work] ;Store relocation ; --- Is this the end of the line? --- 02app_instvars LDR R4,[R4,#lk_next] ;Move to next block in list 01app_instvars CMP R4,#0 ;Is this the end? LDMEQFD R13!,{R1,PC}^ ;Yes -- return to caller LDR R0,[R4,#lk_work] ;Find workspace pointer CMP R0,#0 ;Is there one yet? BNE %02app_instvars ;Yes -- skip this one LDR R0,[R4,#lk_dll] ;Point to DLL BL dll_datasize ;Find how much space we need CMP R0,#0 ;Is there any required? BEQ %02app_instvars ;No -- skip to next block LDMFD R13!,{R1,PC}^ ;Return -- that's done 40app_instvars ADRL R0,msg_errDLLNoMem ;Point to error message LDMFD R13!,{R1,R14} ;Restore registers ORRS PC,R14,#V_flag ;Return the error LTORG ; --- app_giveclib --- ; ; On entry: R0 == pointer to CLib data (__iob) ; On exit: -- EXPORT app_giveclib app_giveclib ROUT STMFD R13!,{R1,R14} ;Stack registers MOV R1,R0 ;Keep pointer to data BL app__add ;Make sure there's an app STRVC R1,[R0,#app_clibdata] ;Store the pointer nicely LDMFD R13!,{R1,PC} ;Return to caller nicely LTORG ; --- app_appdata --- ; ; On entry: R0 == application's stack limit ; On exit: -- EXPORT app_appdata app_appdata ROUT STMFD R13!,{R1,R14} ;Stack registers LDR R1,[R0,#-536] ;Find application's reloc BL app__add ;Ensure the app is present STRVC R1,[R0,#app_owndata] ;Store the relocation nicely LDMFD R13!,{R1,PC} ;Return to caller nicely LTORG ; --- app_findclib --- ; ; On entry: -- ; On exit: R0 == pointer to CLib data EXPORT app_findclib app_findclib ROUT STMFD R13!,{R14} ;Keep return address safe BL app_getHandle ;Find app's start time BLVC app__find ;Look up application's block LDRVC R0,[R0,#app_clibdata] ;Find C Library data pointer LDMFD R13!,{PC} ;Return to caller LTORG ; --- app_readstackptr --- ; ; On entry: -- ; On exit: R0 == `magic cookie' for the stack pointer EXPORT app_readstkptr app_readstkptr ROUT STMFD R13!,{R14} ;Keep return address safe BL app_getHandle ;Find app's start time BLVC app__find ;Locate the app's data block LDRVC R0,[R0,#app_stackPtr] ;Find the stack pointer LDMFD R13!,{PC}^ ;Return to caller LTORG ; --- app_setstkptr --- ; ; On entry: R0 == `magic cookie' from app_readstkptr ; R1 == app's current stack limit EXPORT app_setstkptr app_setstkptr ROUT STMFD R13!,{R11,R14} ;Keep return address safe ; --- Find the application block --- MOV R11,R0 ;Keep hold of new pointer BL app_getHandle ;Find the app's start time BLVC app__find ;Find the app's data block LDMVSFD R13!,{R11,PC} ;If failed, return error ; --- Find out what there is to do --- LDR R14,[R0,#app_stackPtr] ;Load the old pointer CMP R11,R14 ;How does it shape up? LDMEQFD R13!,{R11,PC}^ ;Nothing doing here ; --- Put back the new stack pointer and set relocation --- STR R11,[R0,#app_stackPtr] ;Store new pointer CMP R11,#0 ;Was the stack at top level? ADDNE R0,R0,#app_stack ;Point to base of stack SUBNE R11,R11,#8 ;Point to base of stack entry LDRNE R0,[R0,R11] ;Find data relocation LDREQ R0,[R0,#app_owndata] ;If toplevel, get client data STR R0,[R1,#-536] ;Store in stack limit struct LDMFD R13!,{R11,PC}^ ;Return to caller LTORG ; --- app_prologue --- ; ; On entry: R0 == return address for routine ; R1 == pointer to stack limit structure ; R2 == pointer to base of DLL code ; On exit: R0 == new return address ; ; Note -- I'm directly accessing the DLL data here, which may be considered ; naughty by some. I don't care. EXPORT app_prologue app_prologue ROUT STMFD R13!,{R9-R11,R14} ;Stack some registers ; --- Find application block --- MOV R11,R0 ;Keep hold of this BL app__add ;Make sure the app exists LDMVSFD R13!,{R9-R11,PC} ;Return the error on fail ; --- Stack current relocation and return address --- LDR R14,[R0,#app_stackPtr] ;Find the stack pointer CMP R14,#4096 ;Where is it currently? BGE %00app_prologue ;Give error on overflow ADD R10,R0,#app_stack ;Point to stack base ADD R10,R10,R14 ;Add on stack pointer LDR R9,[R1,#-536] ;Find the current reloc STMIA R10,{R9,R11} ;Store registers on the stack MOV R10,R1 ;Keep pointer to stack limit ADD R14,R14,#8 ;Bump along stack pointer STR R14,[R0,#app_stackPtr] ;Store stack pointer ; --- Find workspace pointer --- CMP R2,#0 ;What's the DLL pointer? LDREQ R1,[R0,#app_owndata] ;0 -- find app workspace BEQ %10app_prologue ;... and finish search LDR R14,[R2,#dl_next-dl_extra] ;Find DLL's next ptr CMP R14,#-1 ;Is it shared? LDREQ R1,[R2,#dl_wspace-dl_extra] ;No -- find DLL workspace BEQ %10app_prologue ;... and finish search ; --- Get shared DLL workspace pointer --- SUB R1,R2,#dl_extra ;Point to DLL handle BL app__findLink ;Find the link block LDMVSFD R13!,{R9-R11,PC} ;Return error if it failed LDR R1,[R0,#lk_work] ;Find relocation offset ; --- Round everything off --- 10app_prologue ADR R0,app__epilogue ;Point to tidy-up routine STR R1,[R10,#-536] ;Store new data relocation LDMFD R13!,{R9-R11,PC}^ ;Return to caller happy ; --- Stack overflow error --- 00app_prologue ADRL R0,msg_errStackOvf ;Point to error LDMFD R13!,{R9-R11,R14} ;Unstack registers ORRS PC,R14,#V_flag ;Return the error LTORG ; --- app_restoreHandle --- ; ; On entry: R0 == an application handle to assume ; On exit: -- EXPORT app_restoreHandle app_restoreHandle ROUT [ :LNOT::DEF:ddeutils_pid STMFD R13!,{R0-R2,R14} ;Save some registers SWI XOS_GetEnv ;Read current command string MOV R1,R13 ;Point to new start time SWI XOS_WriteEnv ;Set the start time back LDMFD R13!,{R0-R2,PC}^ ;And return to caller | MOVS PC,R14 ;No need to do this ] LTORG ; --- app_getHandle --- ; ; On entry: -- ; On exit: R0 == application's start time ; ; Since the application's start time is held in *five* bytes we use only the ; least significant 4 (the four that change most). EXPORT app_getHandle app_getHandle ROUT [ :LNOT::DEF:ddeutils_pid STMFD R13!,{R1,R2,R14} ;Save some registers SWI XOS_GetEnv ;Get the session info LDR R0,[R2,#0] ;Load the start time nicely LDMFD R13!,{R1,R2,PC}^ ;And return to caller | LDR R0,app__pidAddr ;Load the PID address LDR R0,[R0] ;And load the current PID MOVS PC,R14 ;Return to caller when done ] LTORG ;----- Private routines ----------------------------------------------------- ; --- app__epilogue --- ; ; On entry: -- ; On exit: a1,a2 preserved. otherwise as APCS-R ; ; I've used APCS register names throughout here. app__epilogue ROUT STMFD sp!,{a1,a2} ;Keep two return values LDR ip,app__pw ;Point to private word ptr BL app_getHandle ;Find app's start time BL app__find ;Find app block LDR a2,[a1,#app_stackPtr] ;Find the stack pointer ADD a3,a1,#app_stack ;Point to the stack base ADD a3,a3,a2 ;Point to current stack pos LDMDB a3!,{a4,lr} ;Find relocation and ret addr SUB a2,a2,#8 ;Bump down the stack ptr STR a2,[a1,#app_stackPtr] ;Store back in app block STR a4,[sl,#-536] ;Store relocation offset LDMFD sp!,{a1,a2} ;Restore return values MOVS pc,lr ;Return to caller LTORG ; --- app__find --- ; ; On entry: R0 == application handle (i.e. start time) ; On exit: R0 == pointer to application block, or error app__find ROUT STMFD R13!,{R1,R2,R14} ;Preserve nice registers ; --- Try looking at the cached value --- LDR R1,app__cacheHnd ;Load the cached handle CMP R1,R0 ;Is it a match? LDREQ R0,app__cachePtr ;Yes -- load the pointer LDMEQFD R13!,{R1,R2,PC}^ ;And return! ; --- Otherwise, scan the list --- LDR R2,app__list ;Get list head pointer CMP R2,#0 ;Is there an entry here? BEQ %10app__find ;No -- return an error 00app__find LDR R1,[R2,#app_handle] ;Get the app's handle CMP R1,R0 ;Is it a match? BEQ %01app__find ;Yes -- deal with it LDR R2,[R2,#app_next] ;No -- get the next pointer CMP R2,#0 ;Is this the end? BNE %00app__find ;No -- continue round ; --- Couldn't find the application --- 10app__find ADRL R0,msg_errUnknownApp ;Point to error message LDMFD R13!,{R1,R2,R14} ;Pull back registers ORRS PC,R14,#V_flag ;And return with an error ; --- Found an application -- update the cache --- 01app__find STR R0,app__cacheHnd ;Store the new handle STR R2,app__cachePtr ;And the new pointer MOV R0,R2 ;Return the pointer to caller LDMFD R13!,{R1,R2,PC}^ ;And live happily ever after LTORG ; --- app__add --- ; ; On entry: -- ; On exit: Application handle app__add ROUT STMFD R13!,{R1-R3,R14} ;Stack registers ; --- Find out whether the app is registered yet --- BL app_getHandle ;Find app's start time MOV R1,R0 ;Look after a copy BL app__find ;Call the find routine LDMVCFD R13!,{R1-R3,PC}^ ;If already there, return ; --- Allocate a block from the RMA --- MOV R0,#6 ;Code to allocate some store LDR R3,=app_strSize ;The size of an app block SWI XOS_Module ;Allocate the memory LDMVSFD R13!,{R1-R3,PC} ;If it failed, return error ; --- Link the block into the list --- LDR R0,app__list ;Find the list header STR R0,[R2,#app_next] ;Store in next pointer CMP R0,#0 ;Is there a next block? STRNE R2,[R0,#app_prev] ;Yes -- link in new block MOV R0,#0 ;Zero out the previous link STR R0,[R2,#app_prev] ;Store in previous entry STR R2,app__list ;Store this as new block ; --- Set this block up in the cache --- STR R1,app__cacheHnd ;Cache the app's start time STR R2,app__cachePtr ;Cache the app's pointer ; --- Set up the block's data --- MOV R0,#0 ;Zero some entries in block STR R0,[R2,#app_cachedll] ;No cached DLL yet STR R0,[R2,#app_cacheptr] ;No cached DLL yet STR R0,[R2,#app_dlls] ;No DLLs registered yet STR R0,[R2,#app_stackPtr] ;No entries on the stack STR R0,[R2,#app_btable] ;App has no entry table STR R1,[R2,#app_handle] ;Store the app's time info ADD R0,R2,#app_name ;Point to app's name field ADRL R1,msg_appName ;Point to default name BL misc_strcpy ;Copy the string across ; --- Return the app's handle --- MOV R0,R2 ;Return the app's pointer LDMFD R13!,{R1-R3,PC}^ ;Return to caller LTORG ; --- app__free --- ; ; On entry: R0 == pointer to app to free ; On exit: -- app__free ROUT STMFD R13!,{R1,R2,R14} ;Keep registers safe ; --- Remove the block from the list --- LDR R1,[R0,#app_next] ;Get next block in the list LDR R2,[R0,#app_prev] ;Get previous block too CMP R1,#0 ;Is there a next block? STRNE R2,[R1,#app_prev] ;Yes -- fix up its prev CMP R2,#0 ;Is there a previous block? ADREQ R2,app__list ;No -- point to list head STR R1,[R2,#app_next] ;Fix up next pointer ; --- Remove this app from the cache --- LDR R2,app__cachePtr ;Find which app was cached CMP R2,R0 ;Is it this one? MOVEQ R2,#0 ;Yes -- overwrite handle STREQ R2,app__cacheHnd ;Won't match this app now STREQ R2,app__cachePtr ; --- Free the block --- MOV R2,R0 ;Point to the block to free MOV R0,#7 ;Magic reason code SWI XOS_Module ;Free the block LDMFD R13!,{R1,R2,PC} ;Return to caller if failed LTORG ; --- app__freeUnused --- ; ; On entry: R0 == pointer to application ; On exit: -- app__freeUnused ROUT STMFD R13!,{R14} ;Keep link register LDR R14,[R0,#app_dlls] ;Find DLL link list CMP R14,#0 ;Are there any in the list? LDMFD R13!,{R14} ;Restore link register MOVNES PC,R14 ;Return is still attached B app__free ;Otherwise kill the app LTORG ; --- app__sFindDLL --- ; ; On entry: R0 == pointer to name of DLL to find ; R1 == version number to load ; On exit: R0 == DLL handle loaded app__sFindDLL ROUT STMFD R13!,{R1,R2,R9-R11,R14} ;Stack loads of registers MOV R11,R0 ;Keep pointer safe ; --- Ensure that the application structure is there --- BL app__add ;Add the application if reqd. LDMVSFD R13!,{R1,R2,R9-R11,PC} ;If it failed, return now MOV R10,R0 ;Keep pointer to app block ; --- Find out if there's anything to do --- MOV R2,R1 ;Put version number nicely MOV R1,R11 ;Point to required name BL app__findNamedLink ;Is there anything to do? LDMVCFD R13!,{R1,R2,R9-R11,PC}^ ;If found, return to caller MOV R1,R2 ;Put version number back ; --- Load the DLL if necessary --- MOV R0,R11 ;Move DLL pointer back BL dll_ensure ;Load the DLL into memory MOVVS R9,R0 ;If it failed, keep the error BVS %50app__sFindDLL ;And tidy up properly MOV R11,R0 ;Keep pointer to DLL BL dll_tentative ;Mark the DLL as tentative ; --- Add the link between the two --- MOV R0,R10 ;Point to application MOV R1,R11 ;Point to DLL block BL app__addLink ;Link them together MOVVS R9,R0 ;Keep error if any BVS %51app__sFindDLL ;And tidy things up ; --- Now we're done --- MOV R0,R11 ;Point to DLL structure LDMFD R13!,{R1,R2,R9-R11,PC}^ ;Restore registers ; --- Tidy up if link allocation failed --- 51app__sFindDLL 50app__sFindDLL MOV R0,R10 ;Point to application block BL app__freeUnused ;If not being used, kill it ; --- Return the error to the caller --- MOV R0,R9 ;Point to the error message LDMFD R13!,{R1,R2,R9-R11,R14} ;Restore registers ORRS PC,R14,#V_flag ;Return to caller LTORG ; --- app__ok --- ; ; On entry: -- ; On exit: All registers preserved ; ; Expects a stacked R11 and R14 app__ok ROUT MOV R11,R0 ;Look after error pointer BL dll_confirm ;Cancel tentative DLL blocks BL app_getHandle ;Find app time info BLVC app__find ;Find the application block BLVC app__confLink ;Cancel tentative links ; --- Resync code areas --- ; ; This seems as good a place as any to do this. I'm going ; to do a global resync, because I suspect that lots of ; local ones are going to be rather slower, actually. ; Besides, loading libraries isn't something which gets done ; /that/ often. MOV R0,#0 ;Resync everything SWI XOS_SynchroniseCodeAreas ;Do that then, please MOV R0,R11 ;Point to error again LDMFD R13!,{R11,R14} ;Restore registers BICS PC,R14,#V_flag ;Return to caller with V clr LTORG ; --- app__dead --- ; ; On entry: -- ; On exit: All registers preserved ; ; Expects a stacked R11 and R14 app__dead ROUT MOV R11,R0 ;Look after error pointer CMP R0,R0 ;Clear the V flag BL dll_retrace ;Destroy tentative DLL blocks BL app_getHandle ;Find app time info BLVC app__find ;Find the application block BLVC app__cancel ;Destroy tentative links MOV R0,R11 ;Point to error again LDMFD R13!,{R11,R14} ;Restore registers ORRS PC,R14,#V_flag ;Return to caller with V set LTORG ; --- app__findNamedLk --- ; ; On entry: R0 == pointer to application ; R1 == pointer to DLL's name ; R2 == DLL's version number ; On exit: R0 == V set if couldn't be found, clear otherwise app__findNamedLink ROUT STMFD R13!,{R3,R4,R14} ;Stack registers safely LDR R3,[R0,#app_dlls] ;Point to first DLL block CMP R3,#0 ;Is there anything to do? BEQ %20app__findNamedLink ;No -- that's an error ; --- Now construct the proper DLL name --- MOV R0,R1 ;Point to the DLL name 00 LDRB R14,[R0],#1 ;Load the next byte CMP R14,#'[' ;Is this a new-style DAN? BEQ %f05 ;Yes -- sort this out then CMP R14,#'.' ;Or is it a dot? MOVEQ R1,R0 ;Yes -- remember this place CMP R14,#&20 ;End of the string yet? BCS %b00 ;No -- keep going ADR R0,misc__sharedBuf ;Find the shared buffer 00 LDRB R14,[R1],#1 ;Load a byte from the name CMP R14,#&20 ;Finished yet? MOVCC R14,#0 ;Yes -- zero-terminate STRB R14,[R0],#1 ;And store it out BCS %b00 ;No -- keep going B %10app__findNamedLink ;And skip to main matcher ; --- Handle a new-style DAN --- 05 ADR R1,misc__sharedBuf ;Find the shared buffer 00 LDRB R14,[R0],#1 ;Load a byte from the name CMP R14,#']' ;End of the name yet? MOVEQ R14,#0 ;Yes -- terminate here then CMP R14,#&20 ;Finished yet? MOVCC R14,#0 ;Yes -- zero-terminate STRB R14,[R1],#1 ;And store it out BCS %b00 ;No -- keep going 10app__findNamedLink ADR R1,misc__sharedBuf ;Point to the DLL name 00 LDR R0,[R3,#lk_dll] ;Find DLL pointer for block BL dll_compare ;Compare with passed values CMP R0,#1 ;Did it return TRUE? BEQ %30app__findNamedLink ;Yes -- be happy LDR R3,[R3,#lk_next] ;Find next pointer CMP R3,#0 ;Is there any more to do? BNE %b00 ;Yes -- loop round and do it 20app__findNamedLink LDMFD R13!,{R3,R4,R14} ;Restore registers ORRS PC,R14,#V_flag ;Return with V set 30app__findNamedLink LDR R0,[R3,#lk_dll] ;Load DLL pointer again LDMFD R13!,{R3,R4,R14} ;Restore registers BICS PC,R14,#V_flag ;Return with V clear LTORG ; --- app__findLink --- ; ; On entry: R0 == pointer to application ; R1 == pointer to DLL ; On exit: R0 == pointer to link structure app__findLink ROUT STMFD R13!,{R1,R2,R14} ;Preserve nice registers ; --- Try looking at the cached value --- LDR R2,[R0,#app_cachedll] ;Load the cached handle CMP R2,R1 ;Is it a match? LDREQ R0,[R0,#app_cacheptr] ;Yes -- load the pointer LDMEQFD R13!,{R1,R2,PC}^ ;And return! ; --- Otherwise, scan the list --- LDR R2,[R0,#app_dlls] ;Get list head pointer CMP R2,#0 ;Is there an entry here? BEQ %10app__findLink ;No -- return an error 00app__findLink LDR R14,[R2,#lk_dll] ;Get the DLL's pointer CMP R1,R14 ;Is it a match? BEQ %01app__findLink ;Yes -- deal with it LDR R2,[R2,#lk_next] ;No -- get the next pointer CMP R2,#0 ;Is this the end? BNE %00app__findLink ;No -- continue round ; --- Couldn't find the application --- 10app__findLink ADRL R0,msg_errLinkNotFound ;Point to error message LDMFD R13!,{R1,R2,R14} ;Pull back registers ORRS PC,R14,#V_flag ;And return with an error ; --- Found an application -- update the cache --- 01app__findLink STR R1,[R0,#app_cachedll] ;Store the new handle STR R2,[R0,#app_cacheptr] ;And the new pointer MOV R0,R2 ;Return the pointer to caller LDMFD R13!,{R1,R2,PC}^ ;And live happily ever after LTORG ; --- app__addLink --- ; ; On entry: R0 == pointer to application ; R1 == pointer to DLL ; On exit: -- app__addLink ROUT STMFD R13!,{R1,R11,R14} ;Stack registers MOV R11,R0 ;Keep pointer to application ; --- Find out whether the link is registered yet --- BL app__findLink ;Call the find routine LDMVCFD R13!,{R1,R11,PC}^ ;If already there, return ; --- Allocate a block from the RMA --- CMP R0,R0 ;Clear V flag BL sub_alloc ;Allocate a link block LDMVSFD R13!,{R1,R11,PC} ;If it failed, return error ; --- Link the block into the list --- LDR R14,[R11,#app_dlls] ;Find the list header STR R14,[R0,#lk_next] ;Store in next pointer CMP R14,#0 ;Is there a next block? STRNE R0,[R14,#lk_prev] ;Yes -- link in new block MOV R14,#0 ;Zero out the previous link STR R14,[R0,#lk_prev] ;Store in previous entry STR R0,[R11,#app_dlls] ;Store this as new block ; --- Set this block up in the cache --- STR R1,[R11,#app_cachedll] ;Cache the DLL's pointer STR R0,[R11,#app_cacheptr] ;Cache the app's pointer ; --- Set up the block's data --- STR R1,[R0,#lk_dll] ;Store pointer to DLL MOV R1,#0 ;No workspace yet STR R1,[R0,#lk_work] ;So store in the block ; --- Mark as currently tentative --- MOV R1,#lk_tentative ;Tentative flag STR R1,[R0,#lk_flags] ;Store in block's flags area ; --- Return the app's handle --- LDMFD R13!,{R1,R11,PC}^ ;Return to caller LTORG ; --- app__freeLink --- ; ; On entry: R0 == pointer to application ; R1 == pointer to link structure ; On exit: -- app__freeLink ROUT STMFD R13!,{R1,R2,R14} ;Stack registers ; --- Fix up list --- LDR R2,[R1,#lk_next] ;Get next pointer LDR R14,[R1,#lk_prev] ;Get previous pointer CMP R2,#0 ;Is there a real next block? STRNE R14,[R2,#lk_prev] ;Yes -- fix backwards link CMP R14,#0 ;Is there a real prev block? ADDEQ R14,R0,#app_dlls ;No -- point to list head STR R2,[R14,#lk_next] ;Fix forwards link ; --- Free the link --- MOV R0,R1 ;Point to the link LDMFD R13!,{R1,R2,R14} ;Retreive registers B sub_free ;Free the link block LTORG ; --- app__confLk --- ; ; On entry: R0 == application to confirm ; On exit: -- app__confLink ROUT STMFD R13!,{R1,R14} ;Stack registers LDR R0,[R0,#app_dlls] ;Find head of the link list CMP R0,#0 ;Is it empty? LDMEQFD R13!,{R1,PC}^ ;Yes -- return to caller 00app__confLink LDR R1,[R0,#lk_next] ;Find the next entry LDR R14,[R0,#lk_flags] ;Load flags word BIC R14,R14,#lk_tentative ;Clear the magic flag STR R14,[R0,#lk_flags] ;Store the flags word back MOVS R0,R1 ;Move to next entry BNE %00app__confLink ;If more to do, do next one LDMFD R13!,{R1,PC}^ ;Return to caller, confirmed LTORG ; --- app__cancel --- ; ; On entry: R0 == app to cancel ; On exit: -- app__cancel ROUT STMFD R13!,{R1,R2,R14} ;Stack registers MOV R2,R0 ;Keep pointer to app block LDR R0,[R0,#app_dlls] ;Find head of the link list CMP R0,#0 ;Is it empty? LDMEQFD R13!,{R1,R2,PC}^ ;Yes -- return to caller 00app__cancel LDR R1,[R0,#lk_next] ;Find the next entry LDR R14,[R0,#lk_flags] ;Load flags word TST R14,#lk_tentative ;Is the flag set? BEQ %01app__cancel ;No -- move on to next one LDR R14,[R0,#lk_prev] ;Find pointer to previous CMP R1,#0 ;Is there a next block? STRNE R14,[R1,#lk_prev] ;Fix up previous pointer CMP R14,#0 ;Is there a previous block? ADDEQ R14,R2,#app_dlls ;No -- point to list base STR R1,[R14,#lk_next] ;Fix up next pointer BL sub_free ;Free the block 01app__cancel MOVS R0,R1 ;Move to next entry BNE %00app__cancel ;If more to do, do next one MOV R0,R2 ;Point to application block BL app__freeUnused ;If nothing left, kill app LDMFD R13!,{R1,R2,PC}^ ;Return to caller, cancelled LTORG ;----- That's all folks ----------------------------------------------------- END