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