github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/src/runtime/os_linux.go (about) 1 // Copyright 2009 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 package runtime 6 7 import ( 8 "runtime/internal/sys" 9 "unsafe" 10 ) 11 12 type mOS struct{} 13 14 //go:noescape 15 func futex(addr unsafe.Pointer, op int32, val uint32, ts, addr2 unsafe.Pointer, val3 uint32) int32 16 17 // Linux futex. 18 // 19 // futexsleep(uint32 *addr, uint32 val) 20 // futexwakeup(uint32 *addr) 21 // 22 // Futexsleep atomically checks if *addr == val and if so, sleeps on addr. 23 // Futexwakeup wakes up threads sleeping on addr. 24 // Futexsleep is allowed to wake up spuriously. 25 26 const ( 27 _FUTEX_WAIT = 0 28 _FUTEX_WAKE = 1 29 ) 30 31 // Atomically, 32 // if(*addr == val) sleep 33 // Might be woken up spuriously; that's allowed. 34 // Don't sleep longer than ns; ns < 0 means forever. 35 //go:nosplit 36 func futexsleep(addr *uint32, val uint32, ns int64) { 37 if isEnclave { 38 futexsleep0(addr, val, ns) 39 return 40 } 41 var ts timespec 42 // TODO @aghosn: just a check for the moment. Seems we have a problem here. 43 if _ap := uintptr(unsafe.Pointer(addr)); !isEnclave && _ap >= ENCLMASK && _ap <= ENCLMASK+ENCLSIZE { 44 panic("[DEBUG] trying to futexsleep from untrusted on trusted object.") 45 } 46 // Some Linux kernels have a bug where futex of 47 // FUTEX_WAIT returns an internal error code 48 // as an errno. Libpthread ignores the return value 49 // here, and so can we: as it says a few lines up, 50 // spurious wakeups are allowed. 51 if ns < 0 { 52 futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, nil, nil, 0) 53 return 54 } 55 56 // It's difficult to live within the no-split stack limits here. 57 // On ARM and 386, a 64-bit divide invokes a general software routine 58 // that needs more stack than we can afford. So we use timediv instead. 59 // But on real 64-bit systems, where words are larger but the stack limit 60 // is not, even timediv is too heavy, and we really need to use just an 61 // ordinary machine instruction. 62 if sys.PtrSize == 8 { 63 ts.set_sec(ns / 1000000000) 64 ts.set_nsec(int32(ns % 1000000000)) 65 } else { 66 ts.tv_nsec = 0 67 ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec))))) 68 } 69 futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, unsafe.Pointer(&ts), nil, 0) 70 } 71 72 // If any procs are sleeping on addr, wake up at most cnt. 73 //go:nosplit 74 func futexwakeup(addr *uint32, cnt uint32) { 75 if isEnclave { 76 futexwakeup0(addr, cnt) 77 return 78 } 79 ret := futex(unsafe.Pointer(addr), _FUTEX_WAKE, cnt, nil, nil, 0) 80 if ret >= 0 { 81 return 82 } 83 84 // I don't know that futex wakeup can return 85 // EAGAIN or EINTR, but if it does, it would be 86 // safe to loop and call futex again. 87 systemstack(func() { 88 print("futexwakeup addr=", addr, " returned ", ret, "\n") 89 }) 90 91 *(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006 92 } 93 94 func getproccount() int32 { 95 // This buffer is huge (8 kB) but we are on the system stack 96 // and there should be plenty of space (64 kB). 97 // Also this is a leaf, so we're not holding up the memory for long. 98 // See golang.org/issue/11823. 99 // The suggested behavior here is to keep trying with ever-larger 100 // buffers, but we don't have a dynamic memory allocator at the 101 // moment, so that's a bit tricky and seems like overkill. 102 const maxCPUs = 64 * 1024 103 var buf [maxCPUs / 8]byte 104 r := sched_getaffinity(0, unsafe.Sizeof(buf), &buf[0]) 105 if r < 0 { 106 return 1 107 } 108 n := int32(0) 109 for _, v := range buf[:r] { 110 for v != 0 { 111 n += int32(v & 1) 112 v >>= 1 113 } 114 } 115 if n == 0 { 116 n = 1 117 } 118 return n 119 } 120 121 // Clone, the Linux rfork. 122 const ( 123 _CLONE_VM = 0x100 124 _CLONE_FS = 0x200 125 _CLONE_FILES = 0x400 126 _CLONE_SIGHAND = 0x800 127 _CLONE_PTRACE = 0x2000 128 _CLONE_VFORK = 0x4000 129 _CLONE_PARENT = 0x8000 130 _CLONE_THREAD = 0x10000 131 _CLONE_NEWNS = 0x20000 132 _CLONE_SYSVSEM = 0x40000 133 _CLONE_SETTLS = 0x80000 134 _CLONE_PARENT_SETTID = 0x100000 135 _CLONE_CHILD_CLEARTID = 0x200000 136 _CLONE_UNTRACED = 0x800000 137 _CLONE_CHILD_SETTID = 0x1000000 138 _CLONE_STOPPED = 0x2000000 139 _CLONE_NEWUTS = 0x4000000 140 _CLONE_NEWIPC = 0x8000000 141 142 cloneFlags = _CLONE_VM | /* share memory */ 143 _CLONE_FS | /* share cwd, etc */ 144 _CLONE_FILES | /* share fd table */ 145 _CLONE_SIGHAND | /* share sig handler table */ 146 _CLONE_SYSVSEM | /* share SysV semaphore undo lists (see issue #20763) */ 147 _CLONE_THREAD /* revisit - okay for now */ 148 ) 149 150 //go:noescape 151 func clone(flags int32, stk, mp, gp, fn unsafe.Pointer) int32 152 153 //go:nowritebarrier 154 func newosproc(mp *m, stk unsafe.Pointer) { 155 if !isEnclave { 156 newosproc1(mp, stk) 157 return 158 } 159 if Cooprt == nil { 160 throw("Cooprt is nil.") 161 } 162 163 gp := getg() 164 if gp == nil || gp.m == nil || gp.m.g0 == nil { 165 throw("Something is not inited according to previsions.") 166 } 167 ustk := gp.m.g0.sched.usp 168 ubp := gp.m.g0.sched.ubp 169 aptr := UnsafeAllocator.Malloc(unsafe.Sizeof(OExitRequest{})) 170 args := (*OExitRequest)(unsafe.Pointer(aptr)) 171 args.Cid = SpawnRequest 172 args.Sid = gp.m.procid 173 args.Did = mp.procid 174 args.Gp = uintptr(unsafe.Pointer(mp.g0)) 175 args.Mp = uintptr(unsafe.Pointer(mp)) 176 sgx_ocall(Cooprt.OEntry, aptr, ustk, ubp) 177 UnsafeAllocator.Free(aptr, unsafe.Sizeof(OExitRequest{})) 178 } 179 180 // May run with m.p==nil, so write barriers are not allowed. 181 //go:nowritebarrier 182 func newosproc1(mp *m, stk unsafe.Pointer) { 183 /* 184 * note: strace gets confused if we use CLONE_PTRACE here. 185 */ 186 if false { 187 print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " clone=", funcPC(clone), " id=", mp.id, " ostk=", &mp, "\n") 188 } 189 190 // Disable signals during clone, so that the new thread starts 191 // with signals disabled. It will enable them in minit. 192 var oset sigset 193 sigprocmask(_SIG_SETMASK, &sigset_all, &oset) 194 ret := clone(cloneFlags, stk, unsafe.Pointer(mp), unsafe.Pointer(mp.g0), unsafe.Pointer(funcPC(mstart))) 195 sigprocmask(_SIG_SETMASK, &oset, nil) 196 197 if ret < 0 { 198 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", -ret, ")\n") 199 if ret == -_EAGAIN { 200 println("runtime: may need to increase max user processes (ulimit -u)") 201 } 202 throw("newosproc") 203 } 204 } 205 206 // Version of newosproc that doesn't require a valid G. 207 //go:nosplit 208 func newosproc0(stacksize uintptr, fn unsafe.Pointer) { 209 stack := sysAlloc(stacksize, &memstats.stacks_sys) 210 if stack == nil { 211 write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack))) 212 exit(1) 213 } 214 ret := clone(cloneFlags, unsafe.Pointer(uintptr(stack)+stacksize), nil, nil, fn) 215 if ret < 0 { 216 write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate))) 217 exit(1) 218 } 219 } 220 221 var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n") 222 var failthreadcreate = []byte("runtime: failed to create new OS thread\n") 223 224 const ( 225 _AT_NULL = 0 // End of vector 226 _AT_PAGESZ = 6 // System physical page size 227 _AT_HWCAP = 16 // hardware capability bit vector 228 _AT_RANDOM = 25 // introduced in 2.6.29 229 _AT_HWCAP2 = 26 // hardware capability bit vector 2 230 ) 231 232 var procAuxv = []byte("/proc/self/auxv\x00") 233 234 func mincore(addr unsafe.Pointer, n uintptr, dst *byte) int32 235 236 func sysargs(argc int32, argv **byte) { 237 n := argc + 1 238 239 // skip over argv, envp to get to auxv 240 for argv_index(argv, n) != nil { 241 n++ 242 } 243 244 // skip NULL separator 245 n++ 246 247 // now argv+n is auxv 248 auxv := (*[1 << 28]uintptr)(add(unsafe.Pointer(argv), uintptr(n)*sys.PtrSize)) 249 if sysauxv(auxv[:]) != 0 { 250 return 251 } 252 // In some situations we don't get a loader-provided 253 // auxv, such as when loaded as a library on Android. 254 // Fall back to /proc/self/auxv. 255 fd := open(&procAuxv[0], 0 /* O_RDONLY */, 0) 256 if fd < 0 { 257 // On Android, /proc/self/auxv might be unreadable (issue 9229), so we fallback to 258 // try using mincore to detect the physical page size. 259 // mincore should return EINVAL when address is not a multiple of system page size. 260 const size = 256 << 10 // size of memory region to allocate 261 p, err := mmap(nil, size, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0) 262 if err != 0 { 263 return 264 } 265 var n uintptr 266 for n = 4 << 10; n < size; n <<= 1 { 267 err := mincore(unsafe.Pointer(uintptr(p)+n), 1, &addrspace_vec[0]) 268 if err == 0 { 269 physPageSize = n 270 break 271 } 272 } 273 if physPageSize == 0 { 274 physPageSize = size 275 } 276 munmap(p, size) 277 return 278 } 279 var buf [128]uintptr 280 n = read(fd, noescape(unsafe.Pointer(&buf[0])), int32(unsafe.Sizeof(buf))) 281 closefd(fd) 282 if n < 0 { 283 return 284 } 285 // Make sure buf is terminated, even if we didn't read 286 // the whole file. 287 buf[len(buf)-2] = _AT_NULL 288 sysauxv(buf[:]) 289 } 290 291 func sysauxv(auxv []uintptr) int { 292 var i int 293 for ; auxv[i] != _AT_NULL; i += 2 { 294 tag, val := auxv[i], auxv[i+1] 295 switch tag { 296 case _AT_RANDOM: 297 // The kernel provides a pointer to 16-bytes 298 // worth of random data. 299 startupRandomData = (*[16]byte)(unsafe.Pointer(val))[:] 300 301 case _AT_PAGESZ: 302 physPageSize = val 303 } 304 305 archauxv(tag, val) 306 } 307 return i / 2 308 } 309 310 func osinit() { 311 _MHeapMap_TotalBitsEncl = _64bit * 27 //(previous was 25) 312 _MHeapMap_BitsEncl = _MHeapMap_BitsEncl - _PageShift 313 _MaxMemEncl = 1<<_MHeapMap_TotalBitsEncl - 1 314 if isEnclave { 315 gomaxprocs = 0 316 ncpu = 1 317 return 318 } 319 ncpu = getproccount() 320 } 321 322 var urandom_dev = []byte("/dev/urandom\x00") 323 324 func getRandomData(r []byte) { 325 if startupRandomData != nil { 326 n := copy(r, startupRandomData) 327 extendRandom(r, n) 328 return 329 } 330 fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0) 331 n := read(fd, unsafe.Pointer(&r[0]), int32(len(r))) 332 closefd(fd) 333 extendRandom(r, int(n)) 334 } 335 336 func goenvs() { 337 goenvs_unix() 338 } 339 340 // Called to do synchronous initialization of Go code built with 341 // -buildmode=c-archive or -buildmode=c-shared. 342 // None of the Go runtime is initialized. 343 //go:nosplit 344 //go:nowritebarrierrec 345 func libpreinit() { 346 initsig(true) 347 } 348 349 // Called to initialize a new m (including the bootstrap m). 350 // Called on the parent thread (main thread in case of bootstrap), can allocate memory. 351 func mpreinit(mp *m) { 352 mp.gsignal = malg(32 * 1024) // Linux wants >= 2K 353 mp.gsignal.m = mp 354 } 355 356 func gettid() uint32 357 358 // Called to initialize a new m (including the bootstrap m). 359 // Called on the new thread, cannot allocate memory. 360 func minit() { 361 if isEnclave { 362 return 363 } 364 minitSignals() 365 366 // for debuggers, in case cgo created the thread 367 getg().m.procid = uint64(gettid()) 368 } 369 370 // Called from dropm to undo the effect of an minit. 371 //go:nosplit 372 func unminit() { 373 unminitSignals() 374 } 375 376 func memlimit() uintptr { 377 /* 378 TODO: Convert to Go when something actually uses the result. 379 380 Rlimit rl; 381 extern byte runtime·text[], runtime·end[]; 382 uintptr used; 383 384 if(runtime·getrlimit(RLIMIT_AS, &rl) != 0) 385 return 0; 386 if(rl.rlim_cur >= 0x7fffffff) 387 return 0; 388 389 // Estimate our VM footprint excluding the heap. 390 // Not an exact science: use size of binary plus 391 // some room for thread stacks. 392 used = runtime·end - runtime·text + (64<<20); 393 if(used >= rl.rlim_cur) 394 return 0; 395 396 // If there's not at least 16 MB left, we're probably 397 // not going to be able to do much. Treat as no limit. 398 rl.rlim_cur -= used; 399 if(rl.rlim_cur < (16<<20)) 400 return 0; 401 402 return rl.rlim_cur - used; 403 */ 404 405 return 0 406 } 407 408 //#ifdef GOARCH_386 409 //#define sa_handler k_sa_handler 410 //#endif 411 412 func sigreturn() 413 func sigtramp(sig uint32, info *siginfo, ctx unsafe.Pointer) 414 func cgoSigtramp() 415 416 //go:noescape 417 func sigaltstack(new, old *stackt) 418 419 //go:noescape 420 func setitimer(mode int32, new, old *itimerval) 421 422 //go:noescape 423 func rtsigprocmask(how int32, new, old *sigset, size int32) 424 425 //go:nosplit 426 //go:nowritebarrierrec 427 func sigprocmask(how int32, new, old *sigset) { 428 rtsigprocmask(how, new, old, int32(unsafe.Sizeof(*new))) 429 } 430 431 //go:noescape 432 func getrlimit(kind int32, limit unsafe.Pointer) int32 433 func raise(sig uint32) 434 func raiseproc(sig uint32) 435 436 //go:noescape 437 func sched_getaffinity(pid, len uintptr, buf *byte) int32 438 func osyield() 439 440 //go:nosplit 441 //go:nowritebarrierrec 442 func setsig(i uint32, fn uintptr) { 443 var sa sigactiont 444 sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTORER | _SA_RESTART 445 sigfillset(&sa.sa_mask) 446 // Although Linux manpage says "sa_restorer element is obsolete and 447 // should not be used". x86_64 kernel requires it. Only use it on 448 // x86. 449 if GOARCH == "386" || GOARCH == "amd64" { 450 sa.sa_restorer = funcPC(sigreturn) 451 } 452 if fn == funcPC(sighandler) { 453 if iscgo { 454 fn = funcPC(cgoSigtramp) 455 } else { 456 fn = funcPC(sigtramp) 457 } 458 } 459 sa.sa_handler = fn 460 rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask)) 461 } 462 463 //go:nosplit 464 //go:nowritebarrierrec 465 func setsigstack(i uint32) { 466 var sa sigactiont 467 rt_sigaction(uintptr(i), nil, &sa, unsafe.Sizeof(sa.sa_mask)) 468 if sa.sa_flags&_SA_ONSTACK != 0 { 469 return 470 } 471 sa.sa_flags |= _SA_ONSTACK 472 rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask)) 473 } 474 475 //go:nosplit 476 //go:nowritebarrierrec 477 func getsig(i uint32) uintptr { 478 var sa sigactiont 479 if rt_sigaction(uintptr(i), nil, &sa, unsafe.Sizeof(sa.sa_mask)) != 0 { 480 throw("rt_sigaction read failure") 481 } 482 return sa.sa_handler 483 } 484 485 // setSignaltstackSP sets the ss_sp field of a stackt. 486 //go:nosplit 487 func setSignalstackSP(s *stackt, sp uintptr) { 488 *(*uintptr)(unsafe.Pointer(&s.ss_sp)) = sp 489 } 490 491 func (c *sigctxt) fixsigcode(sig uint32) { 492 }