1// Copyright 2014 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// System calls and other sys.stuff for AMD64, SunOS
6// /usr/include/sys/syscall.h for syscall numbers.
7//
8
9#include "go_asm.h"
10#include "go_tls.h"
11#include "textflag.h"
12
13// This is needed by asm_amd64.s
14TEXT runtime·settls(SB),NOSPLIT,$8
15	RET
16
17// void libc_miniterrno(void *(*___errno)(void));
18//
19// Set the TLS errno pointer in M.
20//
21// Called using runtime·asmcgocall from os_solaris.c:/minit.
22// NOT USING GO CALLING CONVENTION.
23TEXT runtime·miniterrno(SB),NOSPLIT,$0
24	// asmcgocall will put first argument into DI.
25	CALL	DI	// SysV ABI so returns in AX
26	get_tls(CX)
27	MOVQ	g(CX), BX
28	MOVQ	g_m(BX), BX
29	MOVQ	AX,	(m_mOS+mOS_perrno)(BX)
30	RET
31
32// Call a library function with SysV calling conventions.
33// The called function can take a maximum of 6 INTEGER class arguments,
34// see
35//   Michael Matz, Jan Hubicka, Andreas Jaeger, and Mark Mitchell
36//   System V Application Binary Interface
37//   AMD64 Architecture Processor Supplement
38// section 3.2.3.
39//
40// Called by runtime·asmcgocall or runtime·cgocall.
41// NOT USING GO CALLING CONVENTION.
42TEXT runtime·asmsysvicall6(SB),NOSPLIT,$0
43	// asmcgocall will put first argument into DI.
44	PUSHQ	DI			// save for later
45	MOVQ	libcall_fn(DI), AX
46	MOVQ	libcall_args(DI), R11
47	MOVQ	libcall_n(DI), R10
48
49	get_tls(CX)
50	MOVQ	g(CX), BX
51	CMPQ	BX, $0
52	JEQ	skiperrno1
53	MOVQ	g_m(BX), BX
54	MOVQ	(m_mOS+mOS_perrno)(BX), DX
55	CMPQ	DX, $0
56	JEQ	skiperrno1
57	MOVL	$0, 0(DX)
58
59skiperrno1:
60	CMPQ	R11, $0
61	JEQ	skipargs
62	// Load 6 args into correspondent registers.
63	MOVQ	0(R11), DI
64	MOVQ	8(R11), SI
65	MOVQ	16(R11), DX
66	MOVQ	24(R11), CX
67	MOVQ	32(R11), R8
68	MOVQ	40(R11), R9
69skipargs:
70
71	// Call SysV function
72	CALL	AX
73
74	// Return result
75	POPQ	DI
76	MOVQ	AX, libcall_r1(DI)
77	MOVQ	DX, libcall_r2(DI)
78
79	get_tls(CX)
80	MOVQ	g(CX), BX
81	CMPQ	BX, $0
82	JEQ	skiperrno2
83	MOVQ	g_m(BX), BX
84	MOVQ	(m_mOS+mOS_perrno)(BX), AX
85	CMPQ	AX, $0
86	JEQ	skiperrno2
87	MOVL	0(AX), AX
88	MOVQ	AX, libcall_err(DI)
89
90skiperrno2:
91	RET
92
93// uint32 tstart_sysvicall(M *newm);
94TEXT runtime·tstart_sysvicall(SB),NOSPLIT,$0
95	// DI contains first arg newm
96	MOVQ	m_g0(DI), DX		// g
97
98	// Make TLS entries point at g and m.
99	get_tls(BX)
100	MOVQ	DX, g(BX)
101	MOVQ	DI, g_m(DX)
102
103	// Layout new m scheduler stack on os stack.
104	MOVQ	SP, AX
105	MOVQ	AX, (g_stack+stack_hi)(DX)
106	SUBQ	$(0x100000), AX		// stack size
107	MOVQ	AX, (g_stack+stack_lo)(DX)
108	ADDQ	$const_stackGuard, AX
109	MOVQ	AX, g_stackguard0(DX)
110	MOVQ	AX, g_stackguard1(DX)
111
112	// Someday the convention will be D is always cleared.
113	CLD
114
115	CALL	runtime·stackcheck(SB)	// clobbers AX,CX
116	CALL	runtime·mstart(SB)
117
118	XORL	AX, AX			// return 0 == success
119	MOVL	AX, ret+8(FP)
120	RET
121
122// Careful, this is called by __sighndlr, a libc function. We must preserve
123// registers as per AMD 64 ABI.
124TEXT runtime·sigtramp(SB),NOSPLIT|TOPFRAME|NOFRAME,$0
125	// Note that we are executing on altsigstack here, so we have
126	// more stack available than NOSPLIT would have us believe.
127	// To defeat the linker, we make our own stack frame with
128	// more space:
129	SUBQ    $168, SP
130	// save registers
131	MOVQ    BX, 24(SP)
132	MOVQ    BP, 32(SP)
133	MOVQ	R12, 40(SP)
134	MOVQ	R13, 48(SP)
135	MOVQ	R14, 56(SP)
136	MOVQ	R15, 64(SP)
137
138	get_tls(BX)
139	// check that g exists
140	MOVQ	g(BX), R10
141	CMPQ	R10, $0
142	JNE	allgood
143	MOVQ	SI, 72(SP)
144	MOVQ	DX, 80(SP)
145	LEAQ	72(SP), AX
146	MOVQ	DI, 0(SP)
147	MOVQ	AX, 8(SP)
148	MOVQ	$runtime·badsignal(SB), AX
149	CALL	AX
150	JMP	exit
151
152allgood:
153	// Save m->libcall and m->scratch. We need to do this because we
154	// might get interrupted by a signal in runtime·asmcgocall.
155
156	// save m->libcall
157	MOVQ	g_m(R10), BP
158	LEAQ	m_libcall(BP), R11
159	MOVQ	libcall_fn(R11), R10
160	MOVQ	R10, 72(SP)
161	MOVQ	libcall_args(R11), R10
162	MOVQ	R10, 80(SP)
163	MOVQ	libcall_n(R11), R10
164	MOVQ	R10, 88(SP)
165	MOVQ    libcall_r1(R11), R10
166	MOVQ    R10, 152(SP)
167	MOVQ    libcall_r2(R11), R10
168	MOVQ    R10, 160(SP)
169
170	// save m->scratch
171	LEAQ	(m_mOS+mOS_scratch)(BP), R11
172	MOVQ	0(R11), R10
173	MOVQ	R10, 96(SP)
174	MOVQ	8(R11), R10
175	MOVQ	R10, 104(SP)
176	MOVQ	16(R11), R10
177	MOVQ	R10, 112(SP)
178	MOVQ	24(R11), R10
179	MOVQ	R10, 120(SP)
180	MOVQ	32(R11), R10
181	MOVQ	R10, 128(SP)
182	MOVQ	40(R11), R10
183	MOVQ	R10, 136(SP)
184
185	// save errno, it might be EINTR; stuff we do here might reset it.
186	MOVQ	(m_mOS+mOS_perrno)(BP), R10
187	MOVL	0(R10), R10
188	MOVQ	R10, 144(SP)
189
190	// prepare call
191	MOVQ	DI, 0(SP)
192	MOVQ	SI, 8(SP)
193	MOVQ	DX, 16(SP)
194	CALL	runtime·sigtrampgo(SB)
195
196	get_tls(BX)
197	MOVQ	g(BX), BP
198	MOVQ	g_m(BP), BP
199	// restore libcall
200	LEAQ	m_libcall(BP), R11
201	MOVQ	72(SP), R10
202	MOVQ	R10, libcall_fn(R11)
203	MOVQ	80(SP), R10
204	MOVQ	R10, libcall_args(R11)
205	MOVQ	88(SP), R10
206	MOVQ	R10, libcall_n(R11)
207	MOVQ    152(SP), R10
208	MOVQ    R10, libcall_r1(R11)
209	MOVQ    160(SP), R10
210	MOVQ    R10, libcall_r2(R11)
211
212	// restore scratch
213	LEAQ	(m_mOS+mOS_scratch)(BP), R11
214	MOVQ	96(SP), R10
215	MOVQ	R10, 0(R11)
216	MOVQ	104(SP), R10
217	MOVQ	R10, 8(R11)
218	MOVQ	112(SP), R10
219	MOVQ	R10, 16(R11)
220	MOVQ	120(SP), R10
221	MOVQ	R10, 24(R11)
222	MOVQ	128(SP), R10
223	MOVQ	R10, 32(R11)
224	MOVQ	136(SP), R10
225	MOVQ	R10, 40(R11)
226
227	// restore errno
228	MOVQ	(m_mOS+mOS_perrno)(BP), R11
229	MOVQ	144(SP), R10
230	MOVL	R10, 0(R11)
231
232exit:
233	// restore registers
234	MOVQ	24(SP), BX
235	MOVQ	32(SP), BP
236	MOVQ	40(SP), R12
237	MOVQ	48(SP), R13
238	MOVQ	56(SP), R14
239	MOVQ	64(SP), R15
240	ADDQ    $168, SP
241	RET
242
243TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
244	MOVQ	fn+0(FP),    AX
245	MOVL	sig+8(FP),   DI
246	MOVQ	info+16(FP), SI
247	MOVQ	ctx+24(FP),  DX
248	MOVQ	SP, BX		// callee-saved
249	ANDQ	$~15, SP	// alignment for x86_64 ABI
250	CALL	AX
251	MOVQ	BX, SP
252	RET
253
254// Called from runtime·usleep (Go). Can be called on Go stack, on OS stack,
255// can also be called in cgo callback path without a g->m.
256TEXT runtime·usleep1(SB),NOSPLIT,$0
257	MOVL	usec+0(FP), DI
258	MOVQ	$usleep2<>(SB), AX // to hide from 6l
259
260	// Execute call on m->g0.
261	get_tls(R15)
262	CMPQ	R15, $0
263	JE	noswitch
264
265	MOVQ	g(R15), R13
266	CMPQ	R13, $0
267	JE	noswitch
268	MOVQ	g_m(R13), R13
269	CMPQ	R13, $0
270	JE	noswitch
271	// TODO(aram): do something about the cpu profiler here.
272
273	MOVQ	m_g0(R13), R14
274	CMPQ	g(R15), R14
275	JNE	switch
276	// executing on m->g0 already
277	CALL	AX
278	RET
279
280switch:
281	// Switch to m->g0 stack and back.
282	MOVQ	(g_sched+gobuf_sp)(R14), R14
283	MOVQ	SP, -8(R14)
284	LEAQ	-8(R14), SP
285	CALL	AX
286	MOVQ	0(SP), SP
287	RET
288
289noswitch:
290	// Not a Go-managed thread. Do not switch stack.
291	CALL	AX
292	RET
293
294// Runs on OS stack. duration (in µs units) is in DI.
295TEXT usleep2<>(SB),NOSPLIT,$0
296	LEAQ	libc_usleep(SB), AX
297	CALL	AX
298	RET
299
300// Runs on OS stack, called from runtime·osyield.
301TEXT runtime·osyield1(SB),NOSPLIT,$0
302	LEAQ	libc_sched_yield(SB), AX
303	CALL	AX
304	RET
305