1// Copyright 2020 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5//go:build zos && s390x && gc 6 7#include "textflag.h" 8 9#define PSALAA 1208(R0) 10#define GTAB64(x) 80(x) 11#define LCA64(x) 88(x) 12#define SAVSTACK_ASYNC(x) 336(x) // in the LCA 13#define CAA(x) 8(x) 14#define CEECAATHDID(x) 976(x) // in the CAA 15#define EDCHPXV(x) 1016(x) // in the CAA 16#define GOCB(x) 1104(x) // in the CAA 17 18// SS_*, where x=SAVSTACK_ASYNC 19#define SS_LE(x) 0(x) 20#define SS_GO(x) 8(x) 21#define SS_ERRNO(x) 16(x) 22#define SS_ERRNOJR(x) 20(x) 23 24// Function Descriptor Offsets 25#define __errno 0x156*16 26#define __err2ad 0x16C*16 27 28// Call Instructions 29#define LE_CALL BYTE $0x0D; BYTE $0x76 // BL R7, R6 30#define SVC_LOAD BYTE $0x0A; BYTE $0x08 // SVC 08 LOAD 31#define SVC_DELETE BYTE $0x0A; BYTE $0x09 // SVC 09 DELETE 32 33DATA zosLibVec<>(SB)/8, $0 34GLOBL zosLibVec<>(SB), NOPTR, $8 35 36TEXT ·initZosLibVec(SB), NOSPLIT|NOFRAME, $0-0 37 MOVW PSALAA, R8 38 MOVD LCA64(R8), R8 39 MOVD CAA(R8), R8 40 MOVD EDCHPXV(R8), R8 41 MOVD R8, zosLibVec<>(SB) 42 RET 43 44TEXT ·GetZosLibVec(SB), NOSPLIT|NOFRAME, $0-0 45 MOVD zosLibVec<>(SB), R8 46 MOVD R8, ret+0(FP) 47 RET 48 49TEXT ·clearErrno(SB), NOSPLIT, $0-0 50 BL addrerrno<>(SB) 51 MOVD $0, 0(R3) 52 RET 53 54// Returns the address of errno in R3. 55TEXT addrerrno<>(SB), NOSPLIT|NOFRAME, $0-0 56 // Get library control area (LCA). 57 MOVW PSALAA, R8 58 MOVD LCA64(R8), R8 59 60 // Get __errno FuncDesc. 61 MOVD CAA(R8), R9 62 MOVD EDCHPXV(R9), R9 63 ADD $(__errno), R9 64 LMG 0(R9), R5, R6 65 66 // Switch to saved LE stack. 67 MOVD SAVSTACK_ASYNC(R8), R9 68 MOVD 0(R9), R4 69 MOVD $0, 0(R9) 70 71 // Call __errno function. 72 LE_CALL 73 NOPH 74 75 // Switch back to Go stack. 76 XOR R0, R0 // Restore R0 to $0. 77 MOVD R4, 0(R9) // Save stack pointer. 78 RET 79 80// func svcCall(fnptr unsafe.Pointer, argv *unsafe.Pointer, dsa *uint64) 81TEXT ·svcCall(SB), NOSPLIT, $0 82 BL runtime·save_g(SB) // Save g and stack pointer 83 MOVW PSALAA, R8 84 MOVD LCA64(R8), R8 85 MOVD SAVSTACK_ASYNC(R8), R9 86 MOVD R15, 0(R9) 87 88 MOVD argv+8(FP), R1 // Move function arguments into registers 89 MOVD dsa+16(FP), g 90 MOVD fnptr+0(FP), R15 91 92 BYTE $0x0D // Branch to function 93 BYTE $0xEF 94 95 BL runtime·load_g(SB) // Restore g and stack pointer 96 MOVW PSALAA, R8 97 MOVD LCA64(R8), R8 98 MOVD SAVSTACK_ASYNC(R8), R9 99 MOVD 0(R9), R15 100 101 RET 102 103// func svcLoad(name *byte) unsafe.Pointer 104TEXT ·svcLoad(SB), NOSPLIT, $0 105 MOVD R15, R2 // Save go stack pointer 106 MOVD name+0(FP), R0 // Move SVC args into registers 107 MOVD $0x80000000, R1 108 MOVD $0, R15 109 SVC_LOAD 110 MOVW R15, R3 // Save return code from SVC 111 MOVD R2, R15 // Restore go stack pointer 112 CMP R3, $0 // Check SVC return code 113 BNE error 114 115 MOVD $-2, R3 // Reset last bit of entry point to zero 116 AND R0, R3 117 MOVD R3, ret+8(FP) // Return entry point returned by SVC 118 CMP R0, R3 // Check if last bit of entry point was set 119 BNE done 120 121 MOVD R15, R2 // Save go stack pointer 122 MOVD $0, R15 // Move SVC args into registers (entry point still in r0 from SVC 08) 123 SVC_DELETE 124 MOVD R2, R15 // Restore go stack pointer 125 126error: 127 MOVD $0, ret+8(FP) // Return 0 on failure 128 129done: 130 XOR R0, R0 // Reset r0 to 0 131 RET 132 133// func svcUnload(name *byte, fnptr unsafe.Pointer) int64 134TEXT ·svcUnload(SB), NOSPLIT, $0 135 MOVD R15, R2 // Save go stack pointer 136 MOVD name+0(FP), R0 // Move SVC args into registers 137 MOVD fnptr+8(FP), R15 138 SVC_DELETE 139 XOR R0, R0 // Reset r0 to 0 140 MOVD R15, R1 // Save SVC return code 141 MOVD R2, R15 // Restore go stack pointer 142 MOVD R1, ret+16(FP) // Return SVC return code 143 RET 144 145// func gettid() uint64 146TEXT ·gettid(SB), NOSPLIT, $0 147 // Get library control area (LCA). 148 MOVW PSALAA, R8 149 MOVD LCA64(R8), R8 150 151 // Get CEECAATHDID 152 MOVD CAA(R8), R9 153 MOVD CEECAATHDID(R9), R9 154 MOVD R9, ret+0(FP) 155 156 RET 157 158// 159// Call LE function, if the return is -1 160// errno and errno2 is retrieved 161// 162TEXT ·CallLeFuncWithErr(SB), NOSPLIT, $0 163 MOVW PSALAA, R8 164 MOVD LCA64(R8), R8 165 MOVD CAA(R8), R9 166 MOVD g, GOCB(R9) 167 168 // Restore LE stack. 169 MOVD SAVSTACK_ASYNC(R8), R9 // R9-> LE stack frame saving address 170 MOVD 0(R9), R4 // R4-> restore previously saved stack frame pointer 171 172 MOVD parms_base+8(FP), R7 // R7 -> argument array 173 MOVD parms_len+16(FP), R8 // R8 number of arguments 174 175 // arg 1 ---> R1 176 CMP R8, $0 177 BEQ docall 178 SUB $1, R8 179 MOVD 0(R7), R1 180 181 // arg 2 ---> R2 182 CMP R8, $0 183 BEQ docall 184 SUB $1, R8 185 ADD $8, R7 186 MOVD 0(R7), R2 187 188 // arg 3 --> R3 189 CMP R8, $0 190 BEQ docall 191 SUB $1, R8 192 ADD $8, R7 193 MOVD 0(R7), R3 194 195 CMP R8, $0 196 BEQ docall 197 MOVD $2176+16, R6 // starting LE stack address-8 to store 4th argument 198 199repeat: 200 ADD $8, R7 201 MOVD 0(R7), R0 // advance arg pointer by 8 byte 202 ADD $8, R6 // advance LE argument address by 8 byte 203 MOVD R0, (R4)(R6*1) // copy argument from go-slice to le-frame 204 SUB $1, R8 205 CMP R8, $0 206 BNE repeat 207 208docall: 209 MOVD funcdesc+0(FP), R8 // R8-> function descriptor 210 LMG 0(R8), R5, R6 211 MOVD $0, 0(R9) // R9 address of SAVSTACK_ASYNC 212 LE_CALL // balr R7, R6 (return #1) 213 NOPH 214 MOVD R3, ret+32(FP) 215 CMP R3, $-1 // compare result to -1 216 BNE done 217 218 // retrieve errno and errno2 219 MOVD zosLibVec<>(SB), R8 220 ADD $(__errno), R8 221 LMG 0(R8), R5, R6 222 LE_CALL // balr R7, R6 __errno (return #3) 223 NOPH 224 MOVWZ 0(R3), R3 225 MOVD R3, err+48(FP) 226 MOVD zosLibVec<>(SB), R8 227 ADD $(__err2ad), R8 228 LMG 0(R8), R5, R6 229 LE_CALL // balr R7, R6 __err2ad (return #2) 230 NOPH 231 MOVW (R3), R2 // retrieve errno2 232 MOVD R2, errno2+40(FP) // store in return area 233 234done: 235 MOVD R4, 0(R9) // Save stack pointer. 236 RET 237 238// 239// Call LE function, if the return is 0 240// errno and errno2 is retrieved 241// 242TEXT ·CallLeFuncWithPtrReturn(SB), NOSPLIT, $0 243 MOVW PSALAA, R8 244 MOVD LCA64(R8), R8 245 MOVD CAA(R8), R9 246 MOVD g, GOCB(R9) 247 248 // Restore LE stack. 249 MOVD SAVSTACK_ASYNC(R8), R9 // R9-> LE stack frame saving address 250 MOVD 0(R9), R4 // R4-> restore previously saved stack frame pointer 251 252 MOVD parms_base+8(FP), R7 // R7 -> argument array 253 MOVD parms_len+16(FP), R8 // R8 number of arguments 254 255 // arg 1 ---> R1 256 CMP R8, $0 257 BEQ docall 258 SUB $1, R8 259 MOVD 0(R7), R1 260 261 // arg 2 ---> R2 262 CMP R8, $0 263 BEQ docall 264 SUB $1, R8 265 ADD $8, R7 266 MOVD 0(R7), R2 267 268 // arg 3 --> R3 269 CMP R8, $0 270 BEQ docall 271 SUB $1, R8 272 ADD $8, R7 273 MOVD 0(R7), R3 274 275 CMP R8, $0 276 BEQ docall 277 MOVD $2176+16, R6 // starting LE stack address-8 to store 4th argument 278 279repeat: 280 ADD $8, R7 281 MOVD 0(R7), R0 // advance arg pointer by 8 byte 282 ADD $8, R6 // advance LE argument address by 8 byte 283 MOVD R0, (R4)(R6*1) // copy argument from go-slice to le-frame 284 SUB $1, R8 285 CMP R8, $0 286 BNE repeat 287 288docall: 289 MOVD funcdesc+0(FP), R8 // R8-> function descriptor 290 LMG 0(R8), R5, R6 291 MOVD $0, 0(R9) // R9 address of SAVSTACK_ASYNC 292 LE_CALL // balr R7, R6 (return #1) 293 NOPH 294 MOVD R3, ret+32(FP) 295 CMP R3, $0 // compare result to 0 296 BNE done 297 298 // retrieve errno and errno2 299 MOVD zosLibVec<>(SB), R8 300 ADD $(__errno), R8 301 LMG 0(R8), R5, R6 302 LE_CALL // balr R7, R6 __errno (return #3) 303 NOPH 304 MOVWZ 0(R3), R3 305 MOVD R3, err+48(FP) 306 MOVD zosLibVec<>(SB), R8 307 ADD $(__err2ad), R8 308 LMG 0(R8), R5, R6 309 LE_CALL // balr R7, R6 __err2ad (return #2) 310 NOPH 311 MOVW (R3), R2 // retrieve errno2 312 MOVD R2, errno2+40(FP) // store in return area 313 XOR R2, R2 314 MOVWZ R2, (R3) // clear errno2 315 316done: 317 MOVD R4, 0(R9) // Save stack pointer. 318 RET 319 320// 321// function to test if a pointer can be safely dereferenced (content read) 322// return 0 for succces 323// 324TEXT ·ptrtest(SB), NOSPLIT, $0-16 325 MOVD arg+0(FP), R10 // test pointer in R10 326 327 // set up R2 to point to CEECAADMC 328 BYTE $0xE3; BYTE $0x20; BYTE $0x04; BYTE $0xB8; BYTE $0x00; BYTE $0x17 // llgt 2,1208 329 BYTE $0xB9; BYTE $0x17; BYTE $0x00; BYTE $0x22 // llgtr 2,2 330 BYTE $0xA5; BYTE $0x26; BYTE $0x7F; BYTE $0xFF // nilh 2,32767 331 BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x58; BYTE $0x00; BYTE $0x04 // lg 2,88(2) 332 BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x08; BYTE $0x00; BYTE $0x04 // lg 2,8(2) 333 BYTE $0x41; BYTE $0x22; BYTE $0x03; BYTE $0x68 // la 2,872(2) 334 335 // set up R5 to point to the "shunt" path which set 1 to R3 (failure) 336 BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x33 // xgr 3,3 337 BYTE $0xA7; BYTE $0x55; BYTE $0x00; BYTE $0x04 // bras 5,lbl1 338 BYTE $0xA7; BYTE $0x39; BYTE $0x00; BYTE $0x01 // lghi 3,1 339 340 // if r3 is not zero (failed) then branch to finish 341 BYTE $0xB9; BYTE $0x02; BYTE $0x00; BYTE $0x33 // lbl1 ltgr 3,3 342 BYTE $0xA7; BYTE $0x74; BYTE $0x00; BYTE $0x08 // brc b'0111',lbl2 343 344 // stomic store shunt address in R5 into CEECAADMC 345 BYTE $0xE3; BYTE $0x52; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 5,0(2) 346 347 // now try reading from the test pointer in R10, if it fails it branches to the "lghi" instruction above 348 BYTE $0xE3; BYTE $0x9A; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x04 // lg 9,0(10) 349 350 // finish here, restore 0 into CEECAADMC 351 BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x99 // lbl2 xgr 9,9 352 BYTE $0xE3; BYTE $0x92; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 9,0(2) 353 MOVD R3, ret+8(FP) // result in R3 354 RET 355 356// 357// function to test if a untptr can be loaded from a pointer 358// return 1: the 8-byte content 359// 2: 0 for success, 1 for failure 360// 361// func safeload(ptr uintptr) ( value uintptr, error uintptr) 362TEXT ·safeload(SB), NOSPLIT, $0-24 363 MOVD ptr+0(FP), R10 // test pointer in R10 364 MOVD $0x0, R6 365 BYTE $0xE3; BYTE $0x20; BYTE $0x04; BYTE $0xB8; BYTE $0x00; BYTE $0x17 // llgt 2,1208 366 BYTE $0xB9; BYTE $0x17; BYTE $0x00; BYTE $0x22 // llgtr 2,2 367 BYTE $0xA5; BYTE $0x26; BYTE $0x7F; BYTE $0xFF // nilh 2,32767 368 BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x58; BYTE $0x00; BYTE $0x04 // lg 2,88(2) 369 BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x08; BYTE $0x00; BYTE $0x04 // lg 2,8(2) 370 BYTE $0x41; BYTE $0x22; BYTE $0x03; BYTE $0x68 // la 2,872(2) 371 BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x33 // xgr 3,3 372 BYTE $0xA7; BYTE $0x55; BYTE $0x00; BYTE $0x04 // bras 5,lbl1 373 BYTE $0xA7; BYTE $0x39; BYTE $0x00; BYTE $0x01 // lghi 3,1 374 BYTE $0xB9; BYTE $0x02; BYTE $0x00; BYTE $0x33 // lbl1 ltgr 3,3 375 BYTE $0xA7; BYTE $0x74; BYTE $0x00; BYTE $0x08 // brc b'0111',lbl2 376 BYTE $0xE3; BYTE $0x52; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 5,0(2) 377 BYTE $0xE3; BYTE $0x6A; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x04 // lg 6,0(10) 378 BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x99 // lbl2 xgr 9,9 379 BYTE $0xE3; BYTE $0x92; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 9,0(2) 380 MOVD R6, value+8(FP) // result in R6 381 MOVD R3, error+16(FP) // error in R3 382 RET 383