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
5package runtime
6
7import (
8	"internal/abi"
9	"internal/goarch"
10	"unsafe"
11)
12
13const (
14	_NSIG        = 33
15	_SI_USER     = 0
16	_SS_DISABLE  = 4
17	_SIG_BLOCK   = 1
18	_SIG_UNBLOCK = 2
19	_SIG_SETMASK = 3
20)
21
22type mOS struct{}
23
24//go:noescape
25func lwp_create(param *lwpparams) int32
26
27//go:noescape
28func sigaltstack(new, old *stackt)
29
30//go:noescape
31func sigaction(sig uint32, new, old *sigactiont)
32
33//go:noescape
34func sigprocmask(how int32, new, old *sigset)
35
36//go:noescape
37func setitimer(mode int32, new, old *itimerval)
38
39//go:noescape
40func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
41
42func raiseproc(sig uint32)
43
44func lwp_gettid() int32
45func lwp_kill(pid, tid int32, sig int)
46
47//go:noescape
48func sys_umtx_sleep(addr *uint32, val, timeout int32) int32
49
50//go:noescape
51func sys_umtx_wakeup(addr *uint32, val int32) int32
52
53func osyield()
54
55//go:nosplit
56func osyield_no_g() {
57	osyield()
58}
59
60func kqueue() int32
61
62//go:noescape
63func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
64
65func pipe2(flags int32) (r, w int32, errno int32)
66func fcntl(fd, cmd, arg int32) (ret int32, errno int32)
67
68func issetugid() int32
69
70// From DragonFly's <sys/sysctl.h>
71const (
72	_CTL_HW      = 6
73	_HW_NCPU     = 3
74	_HW_PAGESIZE = 7
75)
76
77var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
78
79func getncpu() int32 {
80	mib := [2]uint32{_CTL_HW, _HW_NCPU}
81	out := uint32(0)
82	nout := unsafe.Sizeof(out)
83	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
84	if ret >= 0 {
85		return int32(out)
86	}
87	return 1
88}
89
90func getPageSize() uintptr {
91	mib := [2]uint32{_CTL_HW, _HW_PAGESIZE}
92	out := uint32(0)
93	nout := unsafe.Sizeof(out)
94	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
95	if ret >= 0 {
96		return uintptr(out)
97	}
98	return 0
99}
100
101//go:nosplit
102func futexsleep(addr *uint32, val uint32, ns int64) {
103	systemstack(func() {
104		futexsleep1(addr, val, ns)
105	})
106}
107
108func futexsleep1(addr *uint32, val uint32, ns int64) {
109	var timeout int32
110	if ns >= 0 {
111		// The timeout is specified in microseconds - ensure that we
112		// do not end up dividing to zero, which would put us to sleep
113		// indefinitely...
114		timeout = timediv(ns, 1000, nil)
115		if timeout == 0 {
116			timeout = 1
117		}
118	}
119
120	// sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout
121	// expires or EBUSY if the mutex value does not match.
122	ret := sys_umtx_sleep(addr, int32(val), timeout)
123	if ret >= 0 || ret == -_EINTR || ret == -_EAGAIN || ret == -_EBUSY {
124		return
125	}
126
127	print("umtx_sleep addr=", addr, " val=", val, " ret=", ret, "\n")
128	*(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
129}
130
131//go:nosplit
132func futexwakeup(addr *uint32, cnt uint32) {
133	ret := sys_umtx_wakeup(addr, int32(cnt))
134	if ret >= 0 {
135		return
136	}
137
138	systemstack(func() {
139		print("umtx_wake_addr=", addr, " ret=", ret, "\n")
140		*(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
141	})
142}
143
144func lwp_start(uintptr)
145
146// May run with m.p==nil, so write barriers are not allowed.
147//
148//go:nowritebarrier
149func newosproc(mp *m) {
150	stk := unsafe.Pointer(mp.g0.stack.hi)
151	if false {
152		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " lwp_start=", abi.FuncPCABI0(lwp_start), " id=", mp.id, " ostk=", &mp, "\n")
153	}
154
155	var oset sigset
156	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
157
158	params := lwpparams{
159		start_func: abi.FuncPCABI0(lwp_start),
160		arg:        unsafe.Pointer(mp),
161		stack:      uintptr(stk),
162		tid1:       nil, // minit will record tid
163		tid2:       nil,
164	}
165
166	// TODO: Check for error.
167	retryOnEAGAIN(func() int32 {
168		lwp_create(&params)
169		return 0
170	})
171	sigprocmask(_SIG_SETMASK, &oset, nil)
172}
173
174func osinit() {
175	ncpu = getncpu()
176	if physPageSize == 0 {
177		physPageSize = getPageSize()
178	}
179}
180
181var urandom_dev = []byte("/dev/urandom\x00")
182
183//go:nosplit
184func readRandom(r []byte) int {
185	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
186	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
187	closefd(fd)
188	return int(n)
189}
190
191func goenvs() {
192	goenvs_unix()
193}
194
195// Called to initialize a new m (including the bootstrap m).
196// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
197func mpreinit(mp *m) {
198	mp.gsignal = malg(32 * 1024)
199	mp.gsignal.m = mp
200}
201
202// Called to initialize a new m (including the bootstrap m).
203// Called on the new thread, cannot allocate memory.
204func minit() {
205	getg().m.procid = uint64(lwp_gettid())
206	minitSignals()
207}
208
209// Called from dropm to undo the effect of an minit.
210//
211//go:nosplit
212func unminit() {
213	unminitSignals()
214	getg().m.procid = 0
215}
216
217// Called from exitm, but not from drop, to undo the effect of thread-owned
218// resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
219func mdestroy(mp *m) {
220}
221
222func sigtramp()
223
224type sigactiont struct {
225	sa_sigaction uintptr
226	sa_flags     int32
227	sa_mask      sigset
228}
229
230//go:nosplit
231//go:nowritebarrierrec
232func setsig(i uint32, fn uintptr) {
233	var sa sigactiont
234	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
235	sa.sa_mask = sigset_all
236	if fn == abi.FuncPCABIInternal(sighandler) { // abi.FuncPCABIInternal(sighandler) matches the callers in signal_unix.go
237		fn = abi.FuncPCABI0(sigtramp)
238	}
239	sa.sa_sigaction = fn
240	sigaction(i, &sa, nil)
241}
242
243//go:nosplit
244//go:nowritebarrierrec
245func setsigstack(i uint32) {
246	throw("setsigstack")
247}
248
249//go:nosplit
250//go:nowritebarrierrec
251func getsig(i uint32) uintptr {
252	var sa sigactiont
253	sigaction(i, nil, &sa)
254	return sa.sa_sigaction
255}
256
257// setSignalstackSP sets the ss_sp field of a stackt.
258//
259//go:nosplit
260func setSignalstackSP(s *stackt, sp uintptr) {
261	s.ss_sp = sp
262}
263
264//go:nosplit
265//go:nowritebarrierrec
266func sigaddset(mask *sigset, i int) {
267	mask.__bits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
268}
269
270func sigdelset(mask *sigset, i int) {
271	mask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
272}
273
274//go:nosplit
275func (c *sigctxt) fixsigcode(sig uint32) {
276}
277
278func setProcessCPUProfiler(hz int32) {
279	setProcessCPUProfilerTimer(hz)
280}
281
282func setThreadCPUProfiler(hz int32) {
283	setThreadCPUProfilerHz(hz)
284}
285
286//go:nosplit
287func validSIGPROF(mp *m, c *sigctxt) bool {
288	return true
289}
290
291func sysargs(argc int32, argv **byte) {
292	n := argc + 1
293
294	// skip over argv, envp to get to auxv
295	for argv_index(argv, n) != nil {
296		n++
297	}
298
299	// skip NULL separator
300	n++
301
302	auxvp := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*goarch.PtrSize))
303	pairs := sysauxv(auxvp[:])
304	auxv = auxvp[: pairs*2 : pairs*2]
305}
306
307const (
308	_AT_NULL   = 0
309	_AT_PAGESZ = 6
310)
311
312func sysauxv(auxv []uintptr) (pairs int) {
313	var i int
314	for i = 0; auxv[i] != _AT_NULL; i += 2 {
315		tag, val := auxv[i], auxv[i+1]
316		switch tag {
317		case _AT_PAGESZ:
318			physPageSize = val
319		}
320	}
321	return i / 2
322}
323
324// raise sends a signal to the calling thread.
325//
326// It must be nosplit because it is used by the signal handler before
327// it definitely has a Go stack.
328//
329//go:nosplit
330func raise(sig uint32) {
331	lwp_kill(-1, lwp_gettid(), int(sig))
332}
333
334func signalM(mp *m, sig int) {
335	lwp_kill(-1, int32(mp.procid), sig)
336}
337
338// sigPerThreadSyscall is only used on linux, so we assign a bogus signal
339// number.
340const sigPerThreadSyscall = 1 << 31
341
342//go:nosplit
343func runPerThreadSyscall() {
344	throw("runPerThreadSyscall only valid on linux")
345}
346