| // Copyright 2020 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| //go:build zos && s390x && gc |
| |
| #include "textflag.h" |
| |
| #define PSALAA 1208(R0) |
| #define GTAB64(x) 80(x) |
| #define LCA64(x) 88(x) |
| #define SAVSTACK_ASYNC(x) 336(x) // in the LCA |
| #define CAA(x) 8(x) |
| #define CEECAATHDID(x) 976(x) // in the CAA |
| #define EDCHPXV(x) 1016(x) // in the CAA |
| #define GOCB(x) 1104(x) // in the CAA |
| |
| // SS_*, where x=SAVSTACK_ASYNC |
| #define SS_LE(x) 0(x) |
| #define SS_GO(x) 8(x) |
| #define SS_ERRNO(x) 16(x) |
| #define SS_ERRNOJR(x) 20(x) |
| |
| // Function Descriptor Offsets |
| #define __errno 0x156*16 |
| #define __err2ad 0x16C*16 |
| |
| // Call Instructions |
| #define LE_CALL BYTE $0x0D; BYTE $0x76 // BL R7, R6 |
| #define SVC_LOAD BYTE $0x0A; BYTE $0x08 // SVC 08 LOAD |
| #define SVC_DELETE BYTE $0x0A; BYTE $0x09 // SVC 09 DELETE |
| |
| DATA zosLibVec<>(SB)/8, $0 |
| GLOBL zosLibVec<>(SB), NOPTR, $8 |
| |
| TEXT ·initZosLibVec(SB), NOSPLIT|NOFRAME, $0-0 |
| MOVW PSALAA, R8 |
| MOVD LCA64(R8), R8 |
| MOVD CAA(R8), R8 |
| MOVD EDCHPXV(R8), R8 |
| MOVD R8, zosLibVec<>(SB) |
| RET |
| |
| TEXT ·GetZosLibVec(SB), NOSPLIT|NOFRAME, $0-0 |
| MOVD zosLibVec<>(SB), R8 |
| MOVD R8, ret+0(FP) |
| RET |
| |
| TEXT ·clearErrno(SB), NOSPLIT, $0-0 |
| BL addrerrno<>(SB) |
| MOVD $0, 0(R3) |
| RET |
| |
| // Returns the address of errno in R3. |
| TEXT addrerrno<>(SB), NOSPLIT|NOFRAME, $0-0 |
| // Get library control area (LCA). |
| MOVW PSALAA, R8 |
| MOVD LCA64(R8), R8 |
| |
| // Get __errno FuncDesc. |
| MOVD CAA(R8), R9 |
| MOVD EDCHPXV(R9), R9 |
| ADD $(__errno), R9 |
| LMG 0(R9), R5, R6 |
| |
| // Switch to saved LE stack. |
| MOVD SAVSTACK_ASYNC(R8), R9 |
| MOVD 0(R9), R4 |
| MOVD $0, 0(R9) |
| |
| // Call __errno function. |
| LE_CALL |
| NOPH |
| |
| // Switch back to Go stack. |
| XOR R0, R0 // Restore R0 to $0. |
| MOVD R4, 0(R9) // Save stack pointer. |
| RET |
| |
| // func svcCall(fnptr unsafe.Pointer, argv *unsafe.Pointer, dsa *uint64) |
| TEXT ·svcCall(SB), NOSPLIT, $0 |
| BL runtime·save_g(SB) // Save g and stack pointer |
| MOVW PSALAA, R8 |
| MOVD LCA64(R8), R8 |
| MOVD SAVSTACK_ASYNC(R8), R9 |
| MOVD R15, 0(R9) |
| |
| MOVD argv+8(FP), R1 // Move function arguments into registers |
| MOVD dsa+16(FP), g |
| MOVD fnptr+0(FP), R15 |
| |
| BYTE $0x0D // Branch to function |
| BYTE $0xEF |
| |
| BL runtime·load_g(SB) // Restore g and stack pointer |
| MOVW PSALAA, R8 |
| MOVD LCA64(R8), R8 |
| MOVD SAVSTACK_ASYNC(R8), R9 |
| MOVD 0(R9), R15 |
| |
| RET |
| |
| // func svcLoad(name *byte) unsafe.Pointer |
| TEXT ·svcLoad(SB), NOSPLIT, $0 |
| MOVD R15, R2 // Save go stack pointer |
| MOVD name+0(FP), R0 // Move SVC args into registers |
| MOVD $0x80000000, R1 |
| MOVD $0, R15 |
| SVC_LOAD |
| MOVW R15, R3 // Save return code from SVC |
| MOVD R2, R15 // Restore go stack pointer |
| CMP R3, $0 // Check SVC return code |
| BNE error |
| |
| MOVD $-2, R3 // Reset last bit of entry point to zero |
| AND R0, R3 |
| MOVD R3, ret+8(FP) // Return entry point returned by SVC |
| CMP R0, R3 // Check if last bit of entry point was set |
| BNE done |
| |
| MOVD R15, R2 // Save go stack pointer |
| MOVD $0, R15 // Move SVC args into registers (entry point still in r0 from SVC 08) |
| SVC_DELETE |
| MOVD R2, R15 // Restore go stack pointer |
| |
| error: |
| MOVD $0, ret+8(FP) // Return 0 on failure |
| |
| done: |
| XOR R0, R0 // Reset r0 to 0 |
| RET |
| |
| // func svcUnload(name *byte, fnptr unsafe.Pointer) int64 |
| TEXT ·svcUnload(SB), NOSPLIT, $0 |
| MOVD R15, R2 // Save go stack pointer |
| MOVD name+0(FP), R0 // Move SVC args into registers |
| MOVD fnptr+8(FP), R15 |
| SVC_DELETE |
| XOR R0, R0 // Reset r0 to 0 |
| MOVD R15, R1 // Save SVC return code |
| MOVD R2, R15 // Restore go stack pointer |
| MOVD R1, ret+16(FP) // Return SVC return code |
| RET |
| |
| // func gettid() uint64 |
| TEXT ·gettid(SB), NOSPLIT, $0 |
| // Get library control area (LCA). |
| MOVW PSALAA, R8 |
| MOVD LCA64(R8), R8 |
| |
| // Get CEECAATHDID |
| MOVD CAA(R8), R9 |
| MOVD CEECAATHDID(R9), R9 |
| MOVD R9, ret+0(FP) |
| |
| RET |
| |
| // |
| // Call LE function, if the return is -1 |
| // errno and errno2 is retrieved |
| // |
| TEXT ·CallLeFuncWithErr(SB), NOSPLIT, $0 |
| MOVW PSALAA, R8 |
| MOVD LCA64(R8), R8 |
| MOVD CAA(R8), R9 |
| MOVD g, GOCB(R9) |
| |
| // Restore LE stack. |
| MOVD SAVSTACK_ASYNC(R8), R9 // R9-> LE stack frame saving address |
| MOVD 0(R9), R4 // R4-> restore previously saved stack frame pointer |
| |
| MOVD parms_base+8(FP), R7 // R7 -> argument array |
| MOVD parms_len+16(FP), R8 // R8 number of arguments |
| |
| // arg 1 ---> R1 |
| CMP R8, $0 |
| BEQ docall |
| SUB $1, R8 |
| MOVD 0(R7), R1 |
| |
| // arg 2 ---> R2 |
| CMP R8, $0 |
| BEQ docall |
| SUB $1, R8 |
| ADD $8, R7 |
| MOVD 0(R7), R2 |
| |
| // arg 3 --> R3 |
| CMP R8, $0 |
| BEQ docall |
| SUB $1, R8 |
| ADD $8, R7 |
| MOVD 0(R7), R3 |
| |
| CMP R8, $0 |
| BEQ docall |
| MOVD $2176+16, R6 // starting LE stack address-8 to store 4th argument |
| |
| repeat: |
| ADD $8, R7 |
| MOVD 0(R7), R0 // advance arg pointer by 8 byte |
| ADD $8, R6 // advance LE argument address by 8 byte |
| MOVD R0, (R4)(R6*1) // copy argument from go-slice to le-frame |
| SUB $1, R8 |
| CMP R8, $0 |
| BNE repeat |
| |
| docall: |
| MOVD funcdesc+0(FP), R8 // R8-> function descriptor |
| LMG 0(R8), R5, R6 |
| MOVD $0, 0(R9) // R9 address of SAVSTACK_ASYNC |
| LE_CALL // balr R7, R6 (return #1) |
| NOPH |
| MOVD R3, ret+32(FP) |
| CMP R3, $-1 // compare result to -1 |
| BNE done |
| |
| // retrieve errno and errno2 |
| MOVD zosLibVec<>(SB), R8 |
| ADD $(__errno), R8 |
| LMG 0(R8), R5, R6 |
| LE_CALL // balr R7, R6 __errno (return #3) |
| NOPH |
| MOVWZ 0(R3), R3 |
| MOVD R3, err+48(FP) |
| MOVD zosLibVec<>(SB), R8 |
| ADD $(__err2ad), R8 |
| LMG 0(R8), R5, R6 |
| LE_CALL // balr R7, R6 __err2ad (return #2) |
| NOPH |
| MOVW (R3), R2 // retrieve errno2 |
| MOVD R2, errno2+40(FP) // store in return area |
| |
| done: |
| MOVD R4, 0(R9) // Save stack pointer. |
| RET |
| |
| // |
| // Call LE function, if the return is 0 |
| // errno and errno2 is retrieved |
| // |
| TEXT ·CallLeFuncWithPtrReturn(SB), NOSPLIT, $0 |
| MOVW PSALAA, R8 |
| MOVD LCA64(R8), R8 |
| MOVD CAA(R8), R9 |
| MOVD g, GOCB(R9) |
| |
| // Restore LE stack. |
| MOVD SAVSTACK_ASYNC(R8), R9 // R9-> LE stack frame saving address |
| MOVD 0(R9), R4 // R4-> restore previously saved stack frame pointer |
| |
| MOVD parms_base+8(FP), R7 // R7 -> argument array |
| MOVD parms_len+16(FP), R8 // R8 number of arguments |
| |
| // arg 1 ---> R1 |
| CMP R8, $0 |
| BEQ docall |
| SUB $1, R8 |
| MOVD 0(R7), R1 |
| |
| // arg 2 ---> R2 |
| CMP R8, $0 |
| BEQ docall |
| SUB $1, R8 |
| ADD $8, R7 |
| MOVD 0(R7), R2 |
| |
| // arg 3 --> R3 |
| CMP R8, $0 |
| BEQ docall |
| SUB $1, R8 |
| ADD $8, R7 |
| MOVD 0(R7), R3 |
| |
| CMP R8, $0 |
| BEQ docall |
| MOVD $2176+16, R6 // starting LE stack address-8 to store 4th argument |
| |
| repeat: |
| ADD $8, R7 |
| MOVD 0(R7), R0 // advance arg pointer by 8 byte |
| ADD $8, R6 // advance LE argument address by 8 byte |
| MOVD R0, (R4)(R6*1) // copy argument from go-slice to le-frame |
| SUB $1, R8 |
| CMP R8, $0 |
| BNE repeat |
| |
| docall: |
| MOVD funcdesc+0(FP), R8 // R8-> function descriptor |
| LMG 0(R8), R5, R6 |
| MOVD $0, 0(R9) // R9 address of SAVSTACK_ASYNC |
| LE_CALL // balr R7, R6 (return #1) |
| NOPH |
| MOVD R3, ret+32(FP) |
| CMP R3, $0 // compare result to 0 |
| BNE done |
| |
| // retrieve errno and errno2 |
| MOVD zosLibVec<>(SB), R8 |
| ADD $(__errno), R8 |
| LMG 0(R8), R5, R6 |
| LE_CALL // balr R7, R6 __errno (return #3) |
| NOPH |
| MOVWZ 0(R3), R3 |
| MOVD R3, err+48(FP) |
| MOVD zosLibVec<>(SB), R8 |
| ADD $(__err2ad), R8 |
| LMG 0(R8), R5, R6 |
| LE_CALL // balr R7, R6 __err2ad (return #2) |
| NOPH |
| MOVW (R3), R2 // retrieve errno2 |
| MOVD R2, errno2+40(FP) // store in return area |
| XOR R2, R2 |
| MOVWZ R2, (R3) // clear errno2 |
| |
| done: |
| MOVD R4, 0(R9) // Save stack pointer. |
| RET |
| |
| // |
| // function to test if a pointer can be safely dereferenced (content read) |
| // return 0 for succces |
| // |
| TEXT ·ptrtest(SB), NOSPLIT, $0-16 |
| MOVD arg+0(FP), R10 // test pointer in R10 |
| |
| // set up R2 to point to CEECAADMC |
| BYTE $0xE3; BYTE $0x20; BYTE $0x04; BYTE $0xB8; BYTE $0x00; BYTE $0x17 // llgt 2,1208 |
| BYTE $0xB9; BYTE $0x17; BYTE $0x00; BYTE $0x22 // llgtr 2,2 |
| BYTE $0xA5; BYTE $0x26; BYTE $0x7F; BYTE $0xFF // nilh 2,32767 |
| BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x58; BYTE $0x00; BYTE $0x04 // lg 2,88(2) |
| BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x08; BYTE $0x00; BYTE $0x04 // lg 2,8(2) |
| BYTE $0x41; BYTE $0x22; BYTE $0x03; BYTE $0x68 // la 2,872(2) |
| |
| // set up R5 to point to the "shunt" path which set 1 to R3 (failure) |
| BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x33 // xgr 3,3 |
| BYTE $0xA7; BYTE $0x55; BYTE $0x00; BYTE $0x04 // bras 5,lbl1 |
| BYTE $0xA7; BYTE $0x39; BYTE $0x00; BYTE $0x01 // lghi 3,1 |
| |
| // if r3 is not zero (failed) then branch to finish |
| BYTE $0xB9; BYTE $0x02; BYTE $0x00; BYTE $0x33 // lbl1 ltgr 3,3 |
| BYTE $0xA7; BYTE $0x74; BYTE $0x00; BYTE $0x08 // brc b'0111',lbl2 |
| |
| // stomic store shunt address in R5 into CEECAADMC |
| BYTE $0xE3; BYTE $0x52; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 5,0(2) |
| |
| // now try reading from the test pointer in R10, if it fails it branches to the "lghi" instruction above |
| BYTE $0xE3; BYTE $0x9A; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x04 // lg 9,0(10) |
| |
| // finish here, restore 0 into CEECAADMC |
| BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x99 // lbl2 xgr 9,9 |
| BYTE $0xE3; BYTE $0x92; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 9,0(2) |
| MOVD R3, ret+8(FP) // result in R3 |
| RET |
| |
| // |
| // function to test if a untptr can be loaded from a pointer |
| // return 1: the 8-byte content |
| // 2: 0 for success, 1 for failure |
| // |
| // func safeload(ptr uintptr) ( value uintptr, error uintptr) |
| TEXT ·safeload(SB), NOSPLIT, $0-24 |
| MOVD ptr+0(FP), R10 // test pointer in R10 |
| MOVD $0x0, R6 |
| BYTE $0xE3; BYTE $0x20; BYTE $0x04; BYTE $0xB8; BYTE $0x00; BYTE $0x17 // llgt 2,1208 |
| BYTE $0xB9; BYTE $0x17; BYTE $0x00; BYTE $0x22 // llgtr 2,2 |
| BYTE $0xA5; BYTE $0x26; BYTE $0x7F; BYTE $0xFF // nilh 2,32767 |
| BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x58; BYTE $0x00; BYTE $0x04 // lg 2,88(2) |
| BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x08; BYTE $0x00; BYTE $0x04 // lg 2,8(2) |
| BYTE $0x41; BYTE $0x22; BYTE $0x03; BYTE $0x68 // la 2,872(2) |
| BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x33 // xgr 3,3 |
| BYTE $0xA7; BYTE $0x55; BYTE $0x00; BYTE $0x04 // bras 5,lbl1 |
| BYTE $0xA7; BYTE $0x39; BYTE $0x00; BYTE $0x01 // lghi 3,1 |
| BYTE $0xB9; BYTE $0x02; BYTE $0x00; BYTE $0x33 // lbl1 ltgr 3,3 |
| BYTE $0xA7; BYTE $0x74; BYTE $0x00; BYTE $0x08 // brc b'0111',lbl2 |
| BYTE $0xE3; BYTE $0x52; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 5,0(2) |
| BYTE $0xE3; BYTE $0x6A; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x04 // lg 6,0(10) |
| BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x99 // lbl2 xgr 9,9 |
| BYTE $0xE3; BYTE $0x92; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 9,0(2) |
| MOVD R6, value+8(FP) // result in R6 |
| MOVD R3, error+16(FP) // error in R3 |
| RET |