1// Copyright 2011 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
12//go:cgo_export_dynamic runtime.end _end
13//go:cgo_export_dynamic runtime.etext _etext
14//go:cgo_export_dynamic runtime.edata _edata
15
16//go:cgo_import_dynamic libc____errno ___errno "libc.so"
17//go:cgo_import_dynamic libc_clock_gettime clock_gettime "libc.so"
18//go:cgo_import_dynamic libc_exit exit "libc.so"
19//go:cgo_import_dynamic libc_getcontext getcontext "libc.so"
20//go:cgo_import_dynamic libc_kill kill "libc.so"
21//go:cgo_import_dynamic libc_madvise madvise "libc.so"
22//go:cgo_import_dynamic libc_malloc malloc "libc.so"
23//go:cgo_import_dynamic libc_mmap mmap "libc.so"
24//go:cgo_import_dynamic libc_munmap munmap "libc.so"
25//go:cgo_import_dynamic libc_open open "libc.so"
26//go:cgo_import_dynamic libc_pthread_attr_destroy pthread_attr_destroy "libc.so"
27//go:cgo_import_dynamic libc_pthread_attr_getstack pthread_attr_getstack "libc.so"
28//go:cgo_import_dynamic libc_pthread_attr_init pthread_attr_init "libc.so"
29//go:cgo_import_dynamic libc_pthread_attr_setdetachstate pthread_attr_setdetachstate "libc.so"
30//go:cgo_import_dynamic libc_pthread_attr_setstack pthread_attr_setstack "libc.so"
31//go:cgo_import_dynamic libc_pthread_create pthread_create "libc.so"
32//go:cgo_import_dynamic libc_pthread_self pthread_self "libc.so"
33//go:cgo_import_dynamic libc_pthread_kill pthread_kill "libc.so"
34//go:cgo_import_dynamic libc_raise raise "libc.so"
35//go:cgo_import_dynamic libc_read read "libc.so"
36//go:cgo_import_dynamic libc_select select "libc.so"
37//go:cgo_import_dynamic libc_sched_yield sched_yield "libc.so"
38//go:cgo_import_dynamic libc_sem_init sem_init "libc.so"
39//go:cgo_import_dynamic libc_sem_post sem_post "libc.so"
40//go:cgo_import_dynamic libc_sem_reltimedwait_np sem_reltimedwait_np "libc.so"
41//go:cgo_import_dynamic libc_sem_wait sem_wait "libc.so"
42//go:cgo_import_dynamic libc_setitimer setitimer "libc.so"
43//go:cgo_import_dynamic libc_sigaction sigaction "libc.so"
44//go:cgo_import_dynamic libc_sigaltstack sigaltstack "libc.so"
45//go:cgo_import_dynamic libc_sigprocmask sigprocmask "libc.so"
46//go:cgo_import_dynamic libc_sysconf sysconf "libc.so"
47//go:cgo_import_dynamic libc_usleep usleep "libc.so"
48//go:cgo_import_dynamic libc_write write "libc.so"
49//go:cgo_import_dynamic libc_pipe pipe "libc.so"
50//go:cgo_import_dynamic libc_pipe2 pipe2 "libc.so"
51
52//go:linkname libc____errno libc____errno
53//go:linkname libc_clock_gettime libc_clock_gettime
54//go:linkname libc_exit libc_exit
55//go:linkname libc_getcontext libc_getcontext
56//go:linkname libc_kill libc_kill
57//go:linkname libc_madvise libc_madvise
58//go:linkname libc_malloc libc_malloc
59//go:linkname libc_mmap libc_mmap
60//go:linkname libc_munmap libc_munmap
61//go:linkname libc_open libc_open
62//go:linkname libc_pthread_attr_destroy libc_pthread_attr_destroy
63//go:linkname libc_pthread_attr_getstack libc_pthread_attr_getstack
64//go:linkname libc_pthread_attr_init libc_pthread_attr_init
65//go:linkname libc_pthread_attr_setdetachstate libc_pthread_attr_setdetachstate
66//go:linkname libc_pthread_attr_setstack libc_pthread_attr_setstack
67//go:linkname libc_pthread_create libc_pthread_create
68//go:linkname libc_pthread_self libc_pthread_self
69//go:linkname libc_pthread_kill libc_pthread_kill
70//go:linkname libc_raise libc_raise
71//go:linkname libc_read libc_read
72//go:linkname libc_select libc_select
73//go:linkname libc_sched_yield libc_sched_yield
74//go:linkname libc_sem_init libc_sem_init
75//go:linkname libc_sem_post libc_sem_post
76//go:linkname libc_sem_reltimedwait_np libc_sem_reltimedwait_np
77//go:linkname libc_sem_wait libc_sem_wait
78//go:linkname libc_setitimer libc_setitimer
79//go:linkname libc_sigaction libc_sigaction
80//go:linkname libc_sigaltstack libc_sigaltstack
81//go:linkname libc_sigprocmask libc_sigprocmask
82//go:linkname libc_sysconf libc_sysconf
83//go:linkname libc_usleep libc_usleep
84//go:linkname libc_write libc_write
85//go:linkname libc_pipe libc_pipe
86//go:linkname libc_pipe2 libc_pipe2
87
88var (
89	libc____errno,
90	libc_clock_gettime,
91	libc_exit,
92	libc_getcontext,
93	libc_kill,
94	libc_madvise,
95	libc_malloc,
96	libc_mmap,
97	libc_munmap,
98	libc_open,
99	libc_pthread_attr_destroy,
100	libc_pthread_attr_getstack,
101	libc_pthread_attr_init,
102	libc_pthread_attr_setdetachstate,
103	libc_pthread_attr_setstack,
104	libc_pthread_create,
105	libc_pthread_self,
106	libc_pthread_kill,
107	libc_raise,
108	libc_read,
109	libc_sched_yield,
110	libc_select,
111	libc_sem_init,
112	libc_sem_post,
113	libc_sem_reltimedwait_np,
114	libc_sem_wait,
115	libc_setitimer,
116	libc_sigaction,
117	libc_sigaltstack,
118	libc_sigprocmask,
119	libc_sysconf,
120	libc_usleep,
121	libc_write,
122	libc_pipe,
123	libc_pipe2 libcFunc
124)
125
126var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
127
128func getPageSize() uintptr {
129	n := int32(sysconf(__SC_PAGESIZE))
130	if n <= 0 {
131		return 0
132	}
133	return uintptr(n)
134}
135
136func osinit() {
137	ncpu = getncpu()
138	if physPageSize == 0 {
139		physPageSize = getPageSize()
140	}
141}
142
143func tstart_sysvicall(newm *m) uint32
144
145// May run with m.p==nil, so write barriers are not allowed.
146//go:nowritebarrier
147func newosproc(mp *m) {
148	var (
149		attr pthreadattr
150		oset sigset
151		tid  pthread
152		ret  int32
153		size uint64
154	)
155
156	if pthread_attr_init(&attr) != 0 {
157		throw("pthread_attr_init")
158	}
159	// Allocate a new 2MB stack.
160	if pthread_attr_setstack(&attr, 0, 0x200000) != 0 {
161		throw("pthread_attr_setstack")
162	}
163	// Read back the allocated stack.
164	if pthread_attr_getstack(&attr, unsafe.Pointer(&mp.g0.stack.hi), &size) != 0 {
165		throw("pthread_attr_getstack")
166	}
167	mp.g0.stack.lo = mp.g0.stack.hi - uintptr(size)
168	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
169		throw("pthread_attr_setdetachstate")
170	}
171
172	// Disable signals during create, so that the new thread starts
173	// with signals disabled. It will enable them in minit.
174	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
175	ret = pthread_create(&tid, &attr, funcPC(tstart_sysvicall), unsafe.Pointer(mp))
176	sigprocmask(_SIG_SETMASK, &oset, nil)
177	if ret != 0 {
178		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", ret, ")\n")
179		if ret == -_EAGAIN {
180			println("runtime: may need to increase max user processes (ulimit -u)")
181		}
182		throw("newosproc")
183	}
184}
185
186func exitThread(wait *uint32) {
187	// We should never reach exitThread on Solaris because we let
188	// libc clean up threads.
189	throw("exitThread")
190}
191
192var urandom_dev = []byte("/dev/urandom\x00")
193
194//go:nosplit
195func getRandomData(r []byte) {
196	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
197	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
198	closefd(fd)
199	extendRandom(r, int(n))
200}
201
202func goenvs() {
203	goenvs_unix()
204}
205
206// Called to initialize a new m (including the bootstrap m).
207// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
208func mpreinit(mp *m) {
209	mp.gsignal = malg(32 * 1024)
210	mp.gsignal.m = mp
211}
212
213func miniterrno()
214
215// Called to initialize a new m (including the bootstrap m).
216// Called on the new thread, cannot allocate memory.
217func minit() {
218	asmcgocall(unsafe.Pointer(funcPC(miniterrno)), unsafe.Pointer(&libc____errno))
219
220	minitSignals()
221
222	getg().m.procid = uint64(pthread_self())
223}
224
225// Called from dropm to undo the effect of an minit.
226func unminit() {
227	unminitSignals()
228}
229
230func sigtramp()
231
232//go:nosplit
233//go:nowritebarrierrec
234func setsig(i uint32, fn uintptr) {
235	var sa sigactiont
236
237	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
238	sa.sa_mask = sigset_all
239	if fn == funcPC(sighandler) {
240		fn = funcPC(sigtramp)
241	}
242	*((*uintptr)(unsafe.Pointer(&sa._funcptr))) = fn
243	sigaction(i, &sa, nil)
244}
245
246//go:nosplit
247//go:nowritebarrierrec
248func setsigstack(i uint32) {
249	var sa sigactiont
250	sigaction(i, nil, &sa)
251	if sa.sa_flags&_SA_ONSTACK != 0 {
252		return
253	}
254	sa.sa_flags |= _SA_ONSTACK
255	sigaction(i, &sa, nil)
256}
257
258//go:nosplit
259//go:nowritebarrierrec
260func getsig(i uint32) uintptr {
261	var sa sigactiont
262	sigaction(i, nil, &sa)
263	return *((*uintptr)(unsafe.Pointer(&sa._funcptr)))
264}
265
266// setSignaltstackSP sets the ss_sp field of a stackt.
267//go:nosplit
268func setSignalstackSP(s *stackt, sp uintptr) {
269	*(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp
270}
271
272//go:nosplit
273//go:nowritebarrierrec
274func sigaddset(mask *sigset, i int) {
275	mask.__sigbits[(i-1)/32] |= 1 << ((uint32(i) - 1) & 31)
276}
277
278func sigdelset(mask *sigset, i int) {
279	mask.__sigbits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
280}
281
282//go:nosplit
283func (c *sigctxt) fixsigcode(sig uint32) {
284}
285
286//go:nosplit
287func semacreate(mp *m) {
288	if mp.waitsema != 0 {
289		return
290	}
291
292	var sem *semt
293	_g_ := getg()
294
295	// Call libc's malloc rather than malloc. This will
296	// allocate space on the C heap. We can't call malloc
297	// here because it could cause a deadlock.
298	_g_.m.libcall.fn = uintptr(unsafe.Pointer(&libc_malloc))
299	_g_.m.libcall.n = 1
300	_g_.m.scratch = mscratch{}
301	_g_.m.scratch.v[0] = unsafe.Sizeof(*sem)
302	_g_.m.libcall.args = uintptr(unsafe.Pointer(&_g_.m.scratch))
303	asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&_g_.m.libcall))
304	sem = (*semt)(unsafe.Pointer(_g_.m.libcall.r1))
305	if sem_init(sem, 0, 0) != 0 {
306		throw("sem_init")
307	}
308	mp.waitsema = uintptr(unsafe.Pointer(sem))
309}
310
311//go:nosplit
312func semasleep(ns int64) int32 {
313	_m_ := getg().m
314	if ns >= 0 {
315		_m_.ts.tv_sec = ns / 1000000000
316		_m_.ts.tv_nsec = ns % 1000000000
317
318		_m_.libcall.fn = uintptr(unsafe.Pointer(&libc_sem_reltimedwait_np))
319		_m_.libcall.n = 2
320		_m_.scratch = mscratch{}
321		_m_.scratch.v[0] = _m_.waitsema
322		_m_.scratch.v[1] = uintptr(unsafe.Pointer(&_m_.ts))
323		_m_.libcall.args = uintptr(unsafe.Pointer(&_m_.scratch))
324		asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&_m_.libcall))
325		if *_m_.perrno != 0 {
326			if *_m_.perrno == _ETIMEDOUT || *_m_.perrno == _EAGAIN || *_m_.perrno == _EINTR {
327				return -1
328			}
329			throw("sem_reltimedwait_np")
330		}
331		return 0
332	}
333	for {
334		_m_.libcall.fn = uintptr(unsafe.Pointer(&libc_sem_wait))
335		_m_.libcall.n = 1
336		_m_.scratch = mscratch{}
337		_m_.scratch.v[0] = _m_.waitsema
338		_m_.libcall.args = uintptr(unsafe.Pointer(&_m_.scratch))
339		asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&_m_.libcall))
340		if _m_.libcall.r1 == 0 {
341			break
342		}
343		if *_m_.perrno == _EINTR {
344			continue
345		}
346		throw("sem_wait")
347	}
348	return 0
349}
350
351//go:nosplit
352func semawakeup(mp *m) {
353	if sem_post((*semt)(unsafe.Pointer(mp.waitsema))) != 0 {
354		throw("sem_post")
355	}
356}
357
358//go:nosplit
359func closefd(fd int32) int32 {
360	return int32(sysvicall1(&libc_close, uintptr(fd)))
361}
362
363//go:nosplit
364func exit(r int32) {
365	sysvicall1(&libc_exit, uintptr(r))
366}
367
368//go:nosplit
369func getcontext(context *ucontext) /* int32 */ {
370	sysvicall1(&libc_getcontext, uintptr(unsafe.Pointer(context)))
371}
372
373//go:nosplit
374func madvise(addr unsafe.Pointer, n uintptr, flags int32) {
375	sysvicall3(&libc_madvise, uintptr(addr), uintptr(n), uintptr(flags))
376}
377
378//go:nosplit
379func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) (unsafe.Pointer, int) {
380	p, err := doMmap(uintptr(addr), n, uintptr(prot), uintptr(flags), uintptr(fd), uintptr(off))
381	if p == ^uintptr(0) {
382		return nil, int(err)
383	}
384	return unsafe.Pointer(p), 0
385}
386
387//go:nosplit
388func doMmap(addr, n, prot, flags, fd, off uintptr) (uintptr, uintptr) {
389	var libcall libcall
390	libcall.fn = uintptr(unsafe.Pointer(&libc_mmap))
391	libcall.n = 6
392	libcall.args = uintptr(noescape(unsafe.Pointer(&addr)))
393	asmcgocall(unsafe.Pointer(&asmsysvicall6x), unsafe.Pointer(&libcall))
394	return libcall.r1, libcall.err
395}
396
397//go:nosplit
398func munmap(addr unsafe.Pointer, n uintptr) {
399	sysvicall2(&libc_munmap, uintptr(addr), uintptr(n))
400}
401
402const (
403	_CLOCK_REALTIME  = 3
404	_CLOCK_MONOTONIC = 4
405)
406
407//go:nosplit
408func nanotime1() int64 {
409	var ts mts
410	sysvicall2(&libc_clock_gettime, _CLOCK_MONOTONIC, uintptr(unsafe.Pointer(&ts)))
411	return ts.tv_sec*1e9 + ts.tv_nsec
412}
413
414//go:nosplit
415func open(path *byte, mode, perm int32) int32 {
416	return int32(sysvicall3(&libc_open, uintptr(unsafe.Pointer(path)), uintptr(mode), uintptr(perm)))
417}
418
419func pthread_attr_destroy(attr *pthreadattr) int32 {
420	return int32(sysvicall1(&libc_pthread_attr_destroy, uintptr(unsafe.Pointer(attr))))
421}
422
423func pthread_attr_getstack(attr *pthreadattr, addr unsafe.Pointer, size *uint64) int32 {
424	return int32(sysvicall3(&libc_pthread_attr_getstack, uintptr(unsafe.Pointer(attr)), uintptr(addr), uintptr(unsafe.Pointer(size))))
425}
426
427func pthread_attr_init(attr *pthreadattr) int32 {
428	return int32(sysvicall1(&libc_pthread_attr_init, uintptr(unsafe.Pointer(attr))))
429}
430
431func pthread_attr_setdetachstate(attr *pthreadattr, state int32) int32 {
432	return int32(sysvicall2(&libc_pthread_attr_setdetachstate, uintptr(unsafe.Pointer(attr)), uintptr(state)))
433}
434
435func pthread_attr_setstack(attr *pthreadattr, addr uintptr, size uint64) int32 {
436	return int32(sysvicall3(&libc_pthread_attr_setstack, uintptr(unsafe.Pointer(attr)), uintptr(addr), uintptr(size)))
437}
438
439func pthread_create(thread *pthread, attr *pthreadattr, fn uintptr, arg unsafe.Pointer) int32 {
440	return int32(sysvicall4(&libc_pthread_create, uintptr(unsafe.Pointer(thread)), uintptr(unsafe.Pointer(attr)), uintptr(fn), uintptr(arg)))
441}
442
443func pthread_self() pthread {
444	return pthread(sysvicall0(&libc_pthread_self))
445}
446
447func signalM(mp *m, sig int) {
448	sysvicall2(&libc_pthread_kill, uintptr(pthread(mp.procid)), uintptr(sig))
449}
450
451//go:nosplit
452//go:nowritebarrierrec
453func raise(sig uint32) /* int32 */ {
454	sysvicall1(&libc_raise, uintptr(sig))
455}
456
457func raiseproc(sig uint32) /* int32 */ {
458	pid := sysvicall0(&libc_getpid)
459	sysvicall2(&libc_kill, pid, uintptr(sig))
460}
461
462//go:nosplit
463func read(fd int32, buf unsafe.Pointer, nbyte int32) int32 {
464	r1, err := sysvicall3Err(&libc_read, uintptr(fd), uintptr(buf), uintptr(nbyte))
465	if c := int32(r1); c >= 0 {
466		return c
467	}
468	return -int32(err)
469}
470
471//go:nosplit
472func sem_init(sem *semt, pshared int32, value uint32) int32 {
473	return int32(sysvicall3(&libc_sem_init, uintptr(unsafe.Pointer(sem)), uintptr(pshared), uintptr(value)))
474}
475
476//go:nosplit
477func sem_post(sem *semt) int32 {
478	return int32(sysvicall1(&libc_sem_post, uintptr(unsafe.Pointer(sem))))
479}
480
481//go:nosplit
482func sem_reltimedwait_np(sem *semt, timeout *timespec) int32 {
483	return int32(sysvicall2(&libc_sem_reltimedwait_np, uintptr(unsafe.Pointer(sem)), uintptr(unsafe.Pointer(timeout))))
484}
485
486//go:nosplit
487func sem_wait(sem *semt) int32 {
488	return int32(sysvicall1(&libc_sem_wait, uintptr(unsafe.Pointer(sem))))
489}
490
491func setitimer(which int32, value *itimerval, ovalue *itimerval) /* int32 */ {
492	sysvicall3(&libc_setitimer, uintptr(which), uintptr(unsafe.Pointer(value)), uintptr(unsafe.Pointer(ovalue)))
493}
494
495//go:nosplit
496//go:nowritebarrierrec
497func sigaction(sig uint32, act *sigactiont, oact *sigactiont) /* int32 */ {
498	sysvicall3(&libc_sigaction, uintptr(sig), uintptr(unsafe.Pointer(act)), uintptr(unsafe.Pointer(oact)))
499}
500
501//go:nosplit
502//go:nowritebarrierrec
503func sigaltstack(ss *stackt, oss *stackt) /* int32 */ {
504	sysvicall2(&libc_sigaltstack, uintptr(unsafe.Pointer(ss)), uintptr(unsafe.Pointer(oss)))
505}
506
507//go:nosplit
508//go:nowritebarrierrec
509func sigprocmask(how int32, set *sigset, oset *sigset) /* int32 */ {
510	sysvicall3(&libc_sigprocmask, uintptr(how), uintptr(unsafe.Pointer(set)), uintptr(unsafe.Pointer(oset)))
511}
512
513func sysconf(name int32) int64 {
514	return int64(sysvicall1(&libc_sysconf, uintptr(name)))
515}
516
517func usleep1(usec uint32)
518
519//go:nosplit
520func usleeps uint32) {
521	usleep1s)
522}
523
524func walltime1() (sec int64, nsec int32) {
525	var ts mts
526	sysvicall2(&libc_clock_gettime, _CLOCK_REALTIME, uintptr(unsafe.Pointer(&ts)))
527	return ts.tv_sec, int32(ts.tv_nsec)
528}
529
530//go:nosplit
531func write1(fd uintptr, buf unsafe.Pointer, nbyte int32) int32 {
532	r1, err := sysvicall3Err(&libc_write, fd, uintptr(buf), uintptr(nbyte))
533	if c := int32(r1); c >= 0 {
534		return c
535	}
536	return -int32(err)
537}
538
539//go:nosplit
540func pipe() (r, w int32, errno int32) {
541	var p [2]int32
542	_, e := sysvicall1Err(&libc_pipe, uintptr(noescape(unsafe.Pointer(&p))))
543	return p[0], p[1], int32(e)
544}
545
546//go:nosplit
547func pipe2(flags int32) (r, w int32, errno int32) {
548	var p [2]int32
549	_, e := sysvicall2Err(&libc_pipe2, uintptr(noescape(unsafe.Pointer(&p))), uintptr(flags))
550	return p[0], p[1], int32(e)
551}
552
553//go:nosplit
554func closeonexec(fd int32) {
555	fcntl(fd, _F_SETFD, _FD_CLOEXEC)
556}
557
558//go:nosplit
559func setNonblock(fd int32) {
560	flags := fcntl(fd, _F_GETFL, 0)
561	fcntl(fd, _F_SETFL, flags|_O_NONBLOCK)
562}
563
564func osyield1()
565
566//go:nosplit
567func osyield() {
568	_g_ := getg()
569
570	// Check the validity of m because we might be called in cgo callback
571	// path early enough where there isn't a m available yet.
572	if _g_ != nil && _g_.m != nil {
573		sysvicall0(&libc_sched_yield)
574		return
575	}
576	osyield1()
577}
578
579//go:linkname executablePath os.executablePath
580var executablePath string
581
582func sysargs(argc int32, argv **byte) {
583	n := argc + 1
584
585	// skip over argv, envp to get to auxv
586	for argv_index(argv, n) != nil {
587		n++
588	}
589
590	// skip NULL separator
591	n++
592
593	// now argv+n is auxv
594	auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize))
595	sysauxv(auxv[:])
596}
597
598const (
599	_AT_NULL         = 0    // Terminates the vector
600	_AT_PAGESZ       = 6    // Page size in bytes
601	_AT_SUN_EXECNAME = 2014 // exec() path name
602)
603
604func sysauxv(auxv []uintptr) {
605	for i := 0; auxv[i] != _AT_NULL; i += 2 {
606		tag, val := auxv[i], auxv[i+1]
607		switch tag {
608		case _AT_PAGESZ:
609			physPageSize = val
610		case _AT_SUN_EXECNAME:
611			executablePath = gostringnocopy((*byte)(unsafe.Pointer(val)))
612		}
613	}
614}
615