; Copyright 1996 Acorn Computers Ltd ; ; Licensed under the Apache License, Version 2.0 (the "License"); ; you may not use this file except in compliance with the License. ; You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. ; ; -*- Mode: Assembler -*- ;* module initialisation for shared libraries ;* Lastedit: 03 Apr 90 10:51:05 by Harry Meekings * ; Copyright (C) Acorn Computers Ltd., 1988 ; ; IDJ: 19-Jul-91: removed message C03 GBLL SharedLibrary SharedLibrary SETL {TRUE} GBLL NoStubEntries NoStubEntries SETL {TRUE} ; stop h_modmacro defining Entry AREA |AA$$code|, CODE, READONLY GET s.h_Regs GET s.h_Brazil GET s.h_stack GET s.h_modmacro GET s.h_workspc GET Hdr:Proc IMPORT |Lib$$Init$$Base| IMPORT |Lib$$Init$$Limit| IMPORT |Image$$ZI$$Base| [ Code_Destination = "RAM" IMPORT |__RelocCode| ] IMPORT |_kernel_copyerror| IMPORT |_kernel_getmessage| EXPORT |_Lib$Reloc$Off| EXPORT |_Mod$Reloc$Off| EXPORT |_Shared_Lib_Module_SWI_Code| EXPORT |_Shared_Lib_Module_Init_Code| EXPORT |_Shared_Lib_Module_Die_Code| |_Lib$Reloc$Off| * -SL_Lib_Offset |_Mod$Reloc$Off| * -SL_Client_Offset OverflowBit * &10000000 n_module_claim EQU 6 sharedclibrary_path DCB "SharedCLibrary$Path" DCB 0 risc_oslibrary_path DCB "RISC_OSLibrary$Path" DCB 0 sharedclibrary_resources DCB "Resources:$.Resources.CLib." DCB 0 risc_oslibrary_resources DCB "Resources:$.Resources.RISC_OSLib." DCB 0 ALIGN |_Shared_Lib_Module_Init_Code| STMFD r13!, {r7-r11, lr} [ Code_Destination = "RAM" BL |__RelocCode| ] MOV r14, #0 STR r14, [r14, #CLibWorkSpace] STR r14, [r14, #RISCOSLibWorkSpace] ADR r0, sharedclibrary_path ADR r1, sharedclibrary_resources MOV r5, #?sharedclibrary_resources BL setresourcevar ADR r0, risc_oslibrary_path ADR r1, risc_oslibrary_resources MOV r5, #?risc_oslibrary_resources BL setresourcevar LDMFD r13!, {r7-r11, pc}^ setresourcevar MOV r11, lr MOV r10, r0 MOV r2, #-1 MOV r3, #0 MOV r4, #0 SWI ReadVarVal MOV r0, r10 CMP r2, #0 MOVEQ r2, r5 MOVEQ r3, #0 MOVEQ r4, #0 SWIEQ SetVarVal MOVS pc, r11 XMessageTrans_CloseFile EQU &61504 ; Put in hdr file someday |_Shared_Lib_Module_Die_Code| STMDB r13!, {lr} MOV r3, #0 LDR r2, [r3, #CLibWorkSpace] CMP r2, #0 BEQ %F00 MOV r0, r2 SWI XMessageTrans_CloseFile MOV r0, #Module_Free SWI Module STR r3, [r3, #CLibWorkSpace] 00 LDMIA r13!, {pc}^ ;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; This is the SWI Lib_Init code ; ; Entered with r0 pointer to description of stubs present in image ; each having format ; library chunk id ; entry vector base ; entry vector limit ; static data base ; static data limit ; terminated by an entry with stub id -1 ; For each of these, there must be an entry in the shared ; library description (in the Lib$$Init area) with the same ; id and the the same static data size. ; r1 pointer to low end of workspace ; r2 pointer to high end of workspace ; r3 base of client's zero-initialise area (at end of statics) ; r4 pointer to start of client's statics ; r5 pointer to end of clients's statics ; (old stubs) r6 = 0 ; r6 [0] = 0 if client is running in a 26-bit mode (may still be APCS-32) ; = 1 if client is running in a 32-bit mode (=> must be APCS-32, ; and address constant table must follow vectors) ; r6 [1:15] = 0 ; r6 [16:31] = requested root stack size (Kb) ; Returns with stub vector patched ; if input r5>r4, user statics copied and [sl, #SL_Client_Offset] ; initialised ; library statics copied and [sl, #SL_Lib_Offset] initialised ; r1 stack base ; r2 stack top (sp value) ; r6 = library version number ;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ^ 0 ; Format of Lib$$Init area entry LI_Id # 4 LI_EntryBase # 4 LI_EntryEnd # 4 LI_DataStart # 4 LI_DataEnd # 4 LI_ItemSize # 0 |_Shared_Lib_Module_SWI_Code| ; Relative SWI number in r11. ; 0 old-style init. Client uses APCS_A. No longer supported. ; 1 new-style init. Client uses APCS_U; so must this module. ; 2 (new-style) module init. Stack is SWI stack, not in the heap. ; 3 APCS-32 init. Client uses APCS-3/32bit. ; 4 APCS-32 module init. Stack is SWI stack, not in the heap. EntryS "r0-r6" ; Check SWI in valid range [ {CONFIG}=26 CMP r11, #1 | CMP r11, #3 ] ADRLO r0, E_OldAPCS BLO Failed CMP r11, #4 ADRHI r0, E_UnknownSWI BHI Failed CLRPSR F_bit:OR:I_bit, lr ; ensure IRQs enabled NOP ; Check memory constraints work: ; lr = end of required workspace (data + stack), ie stack top for non-modules ; r12 = stack base SUBS lr, r5, r4 ; size of client's statics MOVMI lr, #0 ; no client statics really. CMP r11, #2 ; module? CMPNE r11, #4 MOVEQ r12, sp, LSR #20 MOVEQ r12, r12, ASL #20 ADDEQ lr, lr, r1 BEQ CheckEnoughStore ADD r12, r1, lr ; heap base plus size of copied statics ; For things linked with old stubs r6 may be zero - if so, ; we use the old default root stack size MOVS r6, r6, LSR #6 MOVEQ r6, #OldRootStackSize ADD lr, r12, r6 ; plus size of root stack CheckEnoughStore CMP lr, r2 ; must fit within available workspace ADRGT r0, E_BadMemory BGT Failed [ Proc_RegOffset = 0 STMIA r13, {r2, r12, lr} ; return values of r0, r1 & r2 (Data end, stack base and stack top) | [ Proc_RegOffset = 4 STMIB r13, {r2, r12, lr} ; return values of r0, r1 & r2 (Data end, stack base and stack top) | ! 1, "Proc_RegOffset = ?" ] ] CMP r11, #2 ; module? CMPNE r11, #4 STRNE r6, [r12, #SC_size] ; Start filling stack chunk header for non-modules ; Copy the non-zeroed client statics SUBS lr, r5, r4 ; see again whether client statics to copy MOVMI r4, r1 SUBS r6, r3, r4 BLE ZeroInitClientStatics CopyClientStatics LDR lr, [r4], #+4 STR lr, [r1], #+4 SUBS r6, r6, #4 BNE CopyClientStatics ; Zero the client statics which need zeroing ZeroInitClientStatics SUB lr, r1, r4 ; the value for SL_Client_Offset SUBS r5, r5, r3 BLE DoneClientStatics MOV r6, #0 01 STMIA r1!, {r6} SUBS r5, r5, #4 BGT %B01 ; Client statics copied/zeroed, fill in SC_Client_Offset for -zm1 clients DoneClientStatics STR lr, [r12, #SC_SLOffset+SL_Client_Offset] ; r5 is used to hold SL_Lib_Offset - if a library chunk has an different value ; its time to barf! r5=0 is the initial value to indicate 'r5 isn't set yet' MOV r5, #0 NextLibraryChunk ; Pick up: ; r14 = Start of our table of libraries ; r12 = End of our table of libraries ; r1 = next client library chunk number ; r2 = next client library chunk branch table start ; r3 = next client library chunk branch table end LDR r14, =|Lib$$Init$$Base| LDR r12, =|Lib$$Init$$Limit| LDMIA r0!, {r1, r2, r3} ; If end of client's library table we've finished CMP r1, #0 BLT EndStubInit FindLibraryChunk ; If finished with our table of libraries then the client's chunk isn't recognised CMP r14, r12 ADRGE r0, E_UnknownLib BGE Failed ; Check if this chunk matches the client's, if yes, then drop through LDR r4, [r14], #LI_ItemSize BIC r4, r4, #library_segment_is_ROM_only CMP r4, r1 BNE FindLibraryChunk FoundLibraryChunk ; We've now matched a client library chunk to a library chunk we know about ; so, we should now patch the branches and copy and initialise the data ; Check not attempting to bind ROM chunk to RAM application LDR r4, [r14, #LI_Id - LI_ItemSize] TST r4, #library_segment_is_ROM_only TEQNE r2, r3 ADRNE r0, E_UnknownLib BNE Failed ; I suppose it would be friendly to check here that there are ; no fewer entries in the library than in the stub. LDR r12, StubInitValue ; Branch patchup for SWI Lib_Init1 to 4 ; r2 = entry vector base ; r3 = entry vector limit ; r6 bit 0 set => 32-bit mode (so BL not valid), and address constant table ; of same size follows immediately after LDR r6, [r13, #Proc_RegOffset + 6*4] TST r6, #1 ; if in 26-bit mode, just use the BL form BEQ FixBranches ; as it works, and is faster ; Create a table of LDR PC,&xxx followed by the address constants LDR r1, =&E59FF000 ; LDR PC,[PC,#+0] SUB r4, r3, r2 ; r4 = size of table (remember for later) SUBS r6, r4, #8 ; r6 = offset to use in LDR BICMI r1, r1, #1:SHL:23 ; handle the negative case (just possible RSBMI r6, r6, #0 ; for a single entry stub table) CMP r6, #&1000 ; Offset must be <= &FFF ADRHS r0, E_UnknownLib ; Can't be bothered to make a new error BHS Failed ORR r6, r1, r6 FixLDRs CMP r2, r3 STRNE r6, [r2], #4 BNE FixLDRs ; Write the LDR PC,[PC,#] into each entry ADD r3, r2, r4 ; r2, r3 now point to address constant table LDR r4, [r14, #LI_EntryBase-LI_ItemSize] ; Our entry table FixAddresses CMP r2, r3 BEQ ChunkEntriesDone LDR r1, [r4], #+4 MOV r1, r1, ASL #8 ; sign-extend branch offset ADD r1, r4, r1, ASR #6 ; and convert to bytes ADD r1, r1, #8-4 ; +8 for pc, -4 for ,#+4 above LDR r6, [r2], #4 ; patch the stub entry only if it's CMP r6, r1 ; not already right. STRNE r1, [r2, #-4] B FixAddresses ; Create a table of BL &xxx FixBranches LDR r4, [r14, #LI_EntryBase-LI_ItemSize] ; Our entry table FixEntries CMP r2, r3 BEQ ChunkEntriesDone LDR r1, [r4] ADD r1, r1, r4, LSR #2 SUB r1, r1, r2, LSR #2 BIC r1, r1, #&FF000000 ORR r1, r1, #&EA000000 ; le branch! ADD r4, r4, #4 LDR r6, [r2], #4 ; patch the stub entry only if it's CMP r6, r1 ; not already right. STRNE r1, [r2, #-4] B FixEntries ChunkEntriesDone ; Having patched up the branch table, lets copy the library's static data ; The space reserved in the image for static data for this chunk ; must match the actual size in the shared library. LDMIA r0!, {r2, r3} LDMDB r14, {r4, r6} SUB r1, r2, r3 ADD r1, r1, r6 SUBS r1, r1, r4 [ 1 = 1 ADRNE r0, E_StaticSizeWrong BNE Failed | BEQ staticsizeok STMDB sp!, {r0, r1, r2} [ :DEF:DEFAULT_TEXT ADR r0, stubdatasize_text ADR r1, stubdatasize_tag | ADR r0, stubdatasize_tag ] BL |_kernel_getmessage| BL writectrl SUB r0, r3, r2 SUB r1, sp, #12 MOV r2, #9 SWI &d4 SWI 2 SWI 3 [ :DEF:DEFAULT_TEXT ADR r0, libdatasize_text ADR r1, libdatasize_tag | ADR r0, libdatasize_tag ] BL |_kernel_getmessage| BL writectrl SUB r0, r6, r4 MOV r1, sp MOV r2, #9 SWI &d4 SWI 2 SWI 3 ADD sp, sp, #8 LDMIA sp!, {r0, r1, r2} ADR r0, E_StaticSizeWrong B Failed writectrl STMDB sp!, {r1,lr} MOV r1, r0 01 LDRB r0, [r1], #1 CMP r0, #" " LDMCCIA sp!, {r1,pc} SWI 0 B %BT01 stubdatasize_tag DCB "C67",0 libdatasize_tag DCB "C68",0 [ :DEF:DEFAULT_TEXT stubdatasize_text DCB "Stub data size = ",0 libdatasize_text DCB "Library data size = ",0 ALIGN ] staticsizeok ] SUB r3, r3, r2 ; size of library chunk statics ; and the offset must agree with that for all earlier chunks LDR r1, [r13, #Proc_RegOffset + 4] LDR r1, [r1, #SC_SLOffset+SL_Client_Offset] ADD r2, r2, r1 ; relocate address to copy to!! SUB r1, r2, r4 CMP r5, #0 CMPNE r5, r1 ADRNE r0, E_StaticOffsetInconsistent BNE Failed MOV r5, r1 CMP r3, #0 BLE NextLibraryChunk ; no statics for this chunk ; Copy the data from our fixed static data area to the clients dynamic ; static data area. No zero initialised data at all. CopyLibStatics LDR r1, [r4], #+4 STR r1, [r2], #+4 SUBS r3, r3, #4 BNE CopyLibStatics LDR r1, [r14, #LI_Id-LI_ItemSize] CMP r1, #1 ; was this the library kernel? BNE NextLibraryChunk CMP r11, #3 ORRGE r3, r3, #ClientFlag_APCS_32 05 STRB r3, [r2, #-32*4] ; yuck! - set ClientFlags B NextLibraryChunk EndStubInit ; Set up SL_Lib_Offset LDR r12, [r13, #Proc_RegOffset + 4] ; r1 out STR r5, [r12, #SC_SLOffset+SL_Lib_Offset] [ StrongARM ; patched branch code requires SynchroniseCodeAreas MOV r0,#0 ;fully synchronise (too lazy to narrow down address range) SWI XOS_SynchroniseCodeAreas ] MOV r6, #LibraryVersionNumber Proc_RegList SETS "r0-r5, r12" ; don't restore r6 (hacky :)) EXITS Failed ; Here with r0=error block if failed for one reason or another BL |_kernel_copyerror| STR r0, [r13, #Proc_RegOffset] EXITVS StubInitValue MOV pc, #0 ErrorBlock UnknownSWI, "SWI value out of range for module %0", BadSWI ErrorBlock BadMemory, "Not enough memory for C library", C01 ErrorBlock UnknownLib, "Unknown library chunk", C02 ErrorBlock StaticSizeWrong, "Static data size in library and stub disagree", C04 ErrorBlock StaticOffsetInconsistent, "Static data offset not the same for all library chunks", C05 ErrorBlock OldAPCS, "Calling standard no longer supported by C library", C71, withdefault ALIGN LTORG END