; 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 -*-
;* Lastedit: 08 Mar 90 15:18:04 by Harry Meekings *
;* Shared C library: stub for clients to link with
;  2-Mar-89: IDJ: taken for RISC_OSLib purposes
;
; Copyright (C) Acorn Computers Ltd., 1988.
;

        GBLL    Brazil_Compatible
        GBLL    ModeMayBeNonUser
        GBLL    SharedLibrary

Brazil_Compatible  SETL  {FALSE}
ModeMayBeNonUser   SETL  {TRUE}
SharedLibrary      SETL  {TRUE}

        GET     s.h_Regs
        GET     s.h_Brazil
        GET     s.h_stubs
        GET     s.h_stack
        GET     s.h_workspc
        GET     clib.s.h_signal

        GET     Hdr:MsgTrans

        AREA    |Stub$$Code|, CODE, READONLY

        IMPORT  |__RelocCode|, WEAK
      [ Code_Destination <> "RAM"
        IMPORT  |_Shared_Lib_Module_SWI_Code|

        ; These in the RAM version are provided by the entry inclusions
        IMPORT  |_kernel_init|
        IMPORT  |_kernel_moduleinit|
        IMPORT  |_clib_initialise|
        IMPORT  |_kernel_entermodule|
        IMPORT  |TrapHandler|
        IMPORT  |UncaughtTrapHandler|
        IMPORT  |EventHandler|
        IMPORT  |UnhandledEventHandler|
        IMPORT  |_kernel_command_string|
        IMPORT  |_main|
      ]
        IMPORT  |Image$$RO$$Base|
        IMPORT  |RTSK$$Data$$Base|
        IMPORT  |RTSK$$Data$$Limit|
        IMPORT  |Image$$RW$$Base|
        IMPORT  |Image$$RW$$Limit|
        IMPORT  |Image$$ZI$$Base|
        IMPORT  |__root_stack_size|, WEAK

        EXPORT  |_Lib$Reloc$Off|
        EXPORT  |_Mod$Reloc$Off|
        EXPORT  |_Lib$Reloc$Off$DP|

|_Lib$Reloc$Off|        *       -SL_Lib_Offset
|_Mod$Reloc$Off|        *       -SL_Client_Offset
|_Lib$Reloc$Off$DP|     *       ((-SL_Lib_Offset):SHR:2)+&F00
                                ; A version of _Lib$Reloc$Off suitable for
                                ; insertion into a DP instruction

 [ :LNOT::DEF:Module_Only
        ENTRY

|_kernel_entrypoint|
        SWI     GetEnv
        MOV     r2, r1
        LDR     r1, =|Image$$RW$$Limit|
        MOV     r3, #-1
        MOV     r4, #0
        MOV     r5, #-1                 ; no copying of our statics wanted

; need r1 pointer to workspace start
;      r2 pointer to workspace end
;      r3 pointer to the base of zero-init statics
;      r4 pointer to start of our statics to copy
;      r5 pointer to end of statics to copy
;      r6 = requested stack size (in K) << 16
;      r6 bit 0 indicates 32-bit mode

        ADR     r0, |_lib_init_table|
        LDR     r6, =|__root_stack_size|
        CMP     r6, #0
        MOVEQ   r6, #RootStackSize
        LDRNE   r6, [r6]
        MOV     r6, r6, ASR #10
        MOV     r6, r6, ASL #16
  [ APCS_Type <> "APCS-R"
        MOV     r14, #0
        MRS     r14, CPSR       ; will be a NOP for 26-bit only processors
        TST     r14, #&1C       ; all these bits are clear if 26-bit
        ORRNE   r6, r6, #1
  ]
  [ Code_Destination = "RAM"
     [ APCS_Type = "APCS-R"
        SWI     X:OR:Lib_Init + 1
     |
        SWI     X:OR:Lib_Init + 3
     ]
   |
        ; For ROM BL to the SWI code directly (yuck!)
     [ APCS_Type = "APCS-R"
        MOV     r11, #1         ; SWI offset 1 for APCS-R
     |
        MOV     r11, #3         ; SWI offset 3 for APCS-32
     ]
        SWI     EnterSVC
        BL      |_Shared_Lib_Module_SWI_Code|
        WritePSR USR_mode
  ]
; returns r1 stack base
;         r2 stack top (sp value)
;         r6 library version (but preserved if old library)
; other registers preserved
  [ Code_Destination = "RAM"
        BVC     NoCLibError
        LDR     r14, [r0, #0]
        LDR     r6, =Error_UnknownSWI
        TEQ     r14, r6                 ; V unaffected
        BEQ     OldSharedLibrary
  ]
        SWIVS   GenerateError

  [ Code_Destination = "RAM"
NoCLibError
        MOV     r6, r6, ASL #16
        CMP     r6, #LibraryVersionNumber :SHL: 16
        MOVGE   r4, r0
        ADRGE   r0, |_k_init_block|
        MOVGE   r3, #0
        BGE     |_kernel_init|

OldSharedLibrary
        ADR     r0, E_OldSharedLibrary
LookupError
        MOV     r4, #0
        LDR     r1, [r4, #CLibWorkSpace]
        TEQ     r1, #0
        SWIEQ   GenerateError           ; Can we borrow CLib's message file?
        ADD     r0, r0, #4
04      LDRB    r14, [r0], #1           ; Skip over default message
        TEQ     r14, #0
        BNE     %B04
        ADD     r0, r0, #3
        BIC     r0, r0, #3
        MOV     r2, #0
        MOV     r5, #0
        MOV     r6, #0
        MOV     r7, #0
        SWI     MessageTrans_ErrorLookup

        ErrorBlock SharedLibraryNeeded, "Shared C library not loaded", C62
        ErrorBlock OldSharedLibrary, "Shared C library is out of date", C63
   |
        MOV     r4, r0
        ADR     r0, |_k_init_block|
        MOV     r3, #0
        B       |_kernel_init|
  ]
 ]


 [ :LNOT::DEF:Apps_Only
  [ ModeMayBeNonUser

|_kernel_moduleentry|
        ; r0 is non-0 if the module is to be capable of multiple instantiation
        ; (statics need copying) - if so, we must allocate RMA to hold them.
        ; Note that finalise always discards the RMA (whether fatal or not)
        ; so initialise always acquires it.  Is this reasonable?
        STMFD   sp!, {r14}
        MOV     r9, r0                  ; save 'copy statics' flag
;      [ Code_Destination = "RAM"
        LDR     r0, =|__RelocCode|      ; if __RelocCode is present, call it and
        TEQ     r0, #0                  ; note the address of the relocation table
        MOVEQ   r0, #-1                 ; in r8, else just set r8 to -1
        BLNE    __RelocCode             ; BL<cond> 32-bit OK
        MOV     r8, r0
;      ]
        MOV     r4, #0
        MOV     r5, #-1
        CMP     r9, #0
        MOVEQ   r3, #fixedwssize

        LDRNE   r4, =|Image$$RW$$Base|
        LDRNE   r5, =|Image$$RW$$Limit|
        SUBNE   r3, r5, r4
        ADDNE   r3, r3, #fixedwssize
        MOV     r0, #Module_Claim
        SWI     Module
        LDMVSIA sp!, {pc}
        STR     r2, [r12]               ; set private word to address our data
        STR     r3, [r2]                ; first word is size

        MOV     r9, r12
        LDR     r12, [r12]
        ADD     r1, r12, #fixedwssize   ; Pointer to low end of block
        LDR     r2, [r12, #blocksize]
        ADD     r2, r2, r1              ; Pointer to high end of block
        LDR     r3, =|Image$$ZI$$Base|
        ADR     r0, |_lib_init_table|
        LDR     r6, =|__root_stack_size|
        CMP     r6, #0
        MOVEQ   r6, #RootStackSize :SHL: 6
        LDRNE   r6, [r6]
        MOV     r6, r6, ASR #10
        MOVS    r6, r6, ASL #16
      [ Code_Destination = "RAM"
        STMFD   sp!, {r8}
       [ APCS_Type = "APCS-R"
        SWI     X:OR:Lib_Init + 2
       |
        SWI     X:OR:Lib_Init + 4
       ]
        LDMFD   sp!, {r8}               ; KJB - why preserve here???
      |
        ; For ROM BL to the SWI code directly (yuck!)
        STMFD   r13!,{r8,r11,r12}
       [ APCS_Type = "APCS-R"
        MOV     r11,#2          ; SWI offset
       |
        MOV     r11,#4          ; SWI offset
       ]
        MOV     r12,#-3         ; A number liable to address exception if used
        BL      |_Shared_Lib_Module_SWI_Code|
        LDMFD   r13!,{r8,r11,r12}
      ]
        BVS     %F99

; [ Code_Destination = "RAM"
        ; Chunk of code to relocate all the pointers in the data area
        STMFD   sp!, {r1-r5}
        LDR     r1, [r12]
        CMP     r1, #12
        BEQ     %F80
        CMP     r8, #0
        BMI     %F80
        LDR     r1, =|Image$$RO$$Base|  ; r1 = pointer to code
        LDR     r2, =|Image$$RW$$Base|  ; r2 = pointer to data template in module code area
        ADD     r3, r12, #fixedwssize   ; r3 = pointer to our real data area (XXXX what if r0 was 0 on entry?? XXXX)
        SUB     r3, r3, r2              ; r3 = offset from data template to real data
        ADD     r1, r1, r3              ; r1 = code + data offset (odd, but saves work below)
70      LDR     r4, [r8], #4            ; get a word from the relocation table
        MOVS    r4, r4, ASR #2
        BMI     %F80                    ; if top bit set, it's the end of the table
        BCC     %B70                    ; if bit 1 not set, it's not a data relocation
        LDR     r5, [r1, r4, LSL #2]    ; read in the word to be relocated from the data area
        ADD     r5, r5, r3              ; add the magic offset
        STR     r5, [r1, r4, LSL #2]    ; and put it back
        B       %B70
80      LDMFD   sp!, {r1-r5}

 [ Code_Destination = "RAM"
        MOV     r6, r6, ASL #16
        CMP     r6, #LibraryVersionNumber :SHL: 16
        BLT     OldSharedLibrary
 ]

        ADD     r8, r1, #SC_SLOffset+SL_Lib_Offset
        LDMIA   r8, {r7, r8}            ; move relocation offsets
        STMIB   r12, {r7, r8}           ; to standard place in RMA
        MOV     r4, r0
        ADR     r0, |_k_init_block|
        B       |_kernel_moduleinit|    ; Can't get error
99
        MOV     r1, r0                  ; Free workspace and return
        MOV     r0, #Module_Free        ; with error.
        MOV     r2, r12
        SWI     Module
        MOV     r0, #0
        STR     r0, [r9]
        MOV     r0, r1
        LDMIA   sp!, {lr}
        RETURNVS

        EXPORT  |_clib_initialisemodule|
|_clib_initialisemodule|
        STMFD   sp!, {r14}
        BL      |_kernel_moduleentry|
        LDMVSIA sp!, {pc}
        STMFD   sp!, {r9}               ; save preserved private word ptr
        BL      |_clib_initialise|
        CLRV
        LDMFD   sp!, {r0, pc}           ; return saved private word ptr

        EXPORT  |_clib_entermodule|
|_clib_entermodule|
        ; User-mode entry to a module.  The module's intialisation has always
        ; been called, so stubs have been patched and relocation entries are
        ; correct.  Almost everything can be done inside the shared library.
        ADR     r0, |_k_init_block|
        MOV     r8, r12
        MOV     r12, #-1
        LDR     r6, =|__root_stack_size|
        CMP     r6, #0
        MOVEQ   r6, #RootStackSize
        LDRNE   r6, [r6]
        B       |_kernel_entermodule|

  ]
 ]

|_lib_init_table|
        &       1
        &       |_k_entries_start|
        &       |_k_entries_end|
        &       |_k_data_start|
        &       |_k_data_end|

        &       2
        &       |_clib_entries_start|
        &       |_clib_entries_end|
        &       |_clib_data_start|
        &       |_clib_data_end|

 [ :DEF:RISC_OSStubs
  [ Code_Destination = "ROM"
; rlib only available to ROM
        &       3
        &       |_rlib_entries_start|
        &       |_rlib_entries_end|
        &       |_rlib_data_start|
        &       |_rlib_data_end|
  ]
 ]

        &       -1

|_k_init_block|
        &       |Image$$RO$$Base|
        &       |RTSK$$Data$$Base|
        &       |RTSK$$Data$$Limit|

        LTORG

        GET clib.s.cl_init

        LTORG

        AREA    |Stub$$Entries|, CODE, READONLY

; Don't GET the stub entries if in ROM

        GBLS    GetRoundObjAsm
|_k_entries_start|
      [ Code_Destination = "RAM"
GetRoundObjAsm SETS "        GET     kernel.s.k_entries"
      |
GetRoundObjAsm SETS ""
      ]
$GetRoundObjAsm
|_k_entries_end|
      [ Code_Destination = "RAM" :LAND: APCS_Type <> "APCS-R"
        %       |_k_entries_end| - |_k_entries_start|
      ]

|_clib_entries_start|
      [ Code_Destination = "RAM"
GetRoundObjAsm SETS "        GET     clib.s.cl_entries"
      |
GetRoundObjAsm SETS ""
      ]
$GetRoundObjAsm
|_clib_entries_end|
      [ Code_Destination = "RAM" :LAND: APCS_Type <> "APCS-R"
        %       |_clib_entries_end| - |_clib_entries_start|
      ]

|_rlib_entries_start|
 [ Code_Destination = "RAM":LAND::DEF:RISC_OSStubs
GetRoundObjAsm SETS "        GET     rlib.s.rl_entries"
 |
GetRoundObjAsm SETS ""
 ]
$GetRoundObjAsm
|_rlib_entries_end|
      [ Code_Destination = "RAM" :LAND: APCS_Type <> "APCS-R"
        %       |_rlib_entries_end| - |_rlib_entries_start|
      ]

        AREA    |Stub$$Data|, DATA, NOINIT

|_k_data_start|
        GET     kernel.s.k_data
|_k_data_end|

|_clib_data_start|
        GET     clib.s.cl_data
        GET     clib.s.clibdata
|_clib_data_end|

        GBLS    Bodge1
        GBLS    Bodge2
|_rlib_data_start|
 [ :DEF:RISC_OSStubs
Bodge1 SETS " GET     rlib.s.rl_data"
Bodge2 SETS " GET     rlib.s.rlibdata"
 |
Bodge1 SETS ""
Bodge2 SETS ""
 ]
$Bodge1
$Bodge2
|_rlib_data_end|

        END