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
View as plain text