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