Skip to content

Commit 4c32b1c

Browse files
committed
runtime: fix plan9 monotonic time, crypto randomness
Open /dev/bintime at process start on Plan 9, marked close-on-exec, hold it open for the duration of the process, and use it for obtaining time. The change to using /dev/bintime also sets up for an upcoming Plan 9 change to add monotonic time to that file. If the monotonic field is available, then nanotime1 and time.now use that field. Otherwise they fall back to using Unix nanoseconds as "monotonic", as they always have. Before this CL, monotonic time went backward any time aux/timesync decided to adjust the system's time-of-day backward. Also use /dev/random for randomness (once at startup). Before this CL, there was no real randomness in the runtime on Plan 9 (the crypto/rand package still had some). Now there will be. Change-Id: I0c20ae79d3d96eff1a5f839a56cec5c4bc517e61 Reviewed-on: https://go-review.googlesource.com/c/go/+/656755 Reviewed-by: Brad Fitzpatrick <[email protected]> TryBot-Bypass: Russ Cox <[email protected]> Reviewed-by: Carlos Amedee <[email protected]>
1 parent 6d41809 commit 4c32b1c

7 files changed

+138
-78
lines changed

src/runtime/env_plan9.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const (
3030
func goenvs() {
3131
buf := make([]byte, envBufSize)
3232
copy(buf, envDir)
33-
dirfd := open(&buf[0], _OREAD, 0)
33+
dirfd := open(&buf[0], _OREAD|_OCEXEC, 0)
3434
if dirfd < 0 {
3535
return
3636
}
@@ -40,7 +40,7 @@ func goenvs() {
4040
buf = buf[:len(envDir)]
4141
copy(buf, envDir)
4242
buf = append(buf, name...)
43-
fd := open(&buf[0], _OREAD, 0)
43+
fd := open(&buf[0], _OREAD|_OCEXEC, 0)
4444
if fd < 0 {
4545
return
4646
}

src/runtime/os_plan9.go

+91-14
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type mOS struct {
1818
ignoreHangup bool
1919
}
2020

21+
func dupfd(old, new int32) int32
2122
func closefd(fd int32) int32
2223

2324
//go:noescape
@@ -226,7 +227,7 @@ var sysstat = []byte("/dev/sysstat\x00")
226227

227228
func getproccount() int32 {
228229
var buf [2048]byte
229-
fd := open(&sysstat[0], _OREAD, 0)
230+
fd := open(&sysstat[0], _OREAD|_OCEXEC, 0)
230231
if fd < 0 {
231232
return 1
232233
}
@@ -255,7 +256,7 @@ var pagesize = []byte(" pagesize\n")
255256
func getPageSize() uintptr {
256257
var buf [2048]byte
257258
var pos int
258-
fd := open(&devswap[0], _OREAD, 0)
259+
fd := open(&devswap[0], _OREAD|_OCEXEC, 0)
259260
if fd < 0 {
260261
// There's not much we can do if /dev/swap doesn't
261262
// exist. However, nothing in the memory manager uses
@@ -314,11 +315,36 @@ func getpid() uint64 {
314315
return uint64(_atoi(c))
315316
}
316317

318+
var (
319+
bintimeFD int32 = -1
320+
321+
bintimeDev = []byte("/dev/bintime\x00")
322+
randomDev = []byte("/dev/random\x00")
323+
)
324+
317325
func osinit() {
318326
physPageSize = getPageSize()
319327
initBloc()
320328
ncpu = getproccount()
321329
getg().m.procid = getpid()
330+
331+
fd := open(&bintimeDev[0], _OREAD|_OCEXEC, 0)
332+
if fd < 0 {
333+
fatal("cannot open /dev/bintime")
334+
}
335+
bintimeFD = fd
336+
337+
// Move fd high up, to avoid conflicts with smaller ones
338+
// that programs might hard code, and to make exec's job easier.
339+
// Plan 9 allocates chunks of DELTAFD=20 fds in a row,
340+
// so 18 is near the top of what's possible.
341+
if bintimeFD < 18 {
342+
if dupfd(bintimeFD, 18) < 0 {
343+
fatal("cannot dup /dev/bintime onto 18")
344+
}
345+
closefd(bintimeFD)
346+
bintimeFD = 18
347+
}
322348
}
323349

324350
//go:nosplit
@@ -329,7 +355,13 @@ func crash() {
329355

330356
//go:nosplit
331357
func readRandom(r []byte) int {
332-
return 0
358+
fd := open(&randomDev[0], _OREAD|_OCEXEC, 0)
359+
if fd < 0 {
360+
fatal("cannot open /dev/random")
361+
}
362+
n := int(read(fd, unsafe.Pointer(&r[0]), int32(len(r))))
363+
closefd(fd)
364+
return n
333365
}
334366

335367
func initsig(preinit bool) {
@@ -362,17 +394,6 @@ func usleep_no_g(usec uint32) {
362394
usleep(usec)
363395
}
364396

365-
//go:nosplit
366-
func nanotime1() int64 {
367-
var scratch int64
368-
ns := nsec(&scratch)
369-
// TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
370-
if ns == 0 {
371-
return scratch
372-
}
373-
return ns
374-
}
375-
376397
var goexits = []byte("go: exit ")
377398
var emptystatus = []byte("\x00")
378399
var exiting uint32
@@ -530,3 +551,59 @@ func preemptM(mp *m) {
530551
//
531552
// TODO: Use a note like we use signals on POSIX OSes
532553
}
554+
555+
//go:nosplit
556+
func readtime(t *uint64, min, n int) int {
557+
if bintimeFD < 0 {
558+
fatal("/dev/bintime not opened")
559+
}
560+
const uint64size = 8
561+
r := pread(bintimeFD, unsafe.Pointer(t), int32(n*uint64size), 0)
562+
if int(r) < min*uint64size {
563+
fatal("cannot read /dev/bintime")
564+
}
565+
return int(r) / uint64size
566+
}
567+
568+
// timesplit returns u/1e9, u%1e9
569+
func timesplit(u uint64) (sec int64, nsec int32)
570+
571+
func frombe(u uint64) uint64 {
572+
b := (*[8]byte)(unsafe.Pointer(&u))
573+
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
574+
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
575+
}
576+
577+
//go:nosplit
578+
func nanotime1() int64 {
579+
var t [4]uint64
580+
if readtime(&t[0], 1, 4) == 4 {
581+
// long read indicates new kernel sending monotonic time
582+
// (https://github.com/rsc/plan9/commit/baf076425).
583+
return int64(frombe(t[3]))
584+
}
585+
// fall back to unix time
586+
return int64(frombe(t[0]))
587+
}
588+
589+
//go:nosplit
590+
func walltime() (sec int64, nsec int32) {
591+
var t [1]uint64
592+
readtime(&t[0], 1, 1)
593+
return timesplit(frombe(t[0]))
594+
}
595+
596+
// Do not remove or change the type signature.
597+
// See comment in timestub.go.
598+
//
599+
//go:linkname time_now time.now
600+
func time_now() (sec int64, nsec int32, mono int64) {
601+
var t [4]uint64
602+
if readtime(&t[0], 1, 4) == 4 {
603+
mono = int64(frombe(t[3])) // new kernel, use monotonic time
604+
} else {
605+
mono = int64(frombe(t[0])) // old kernel, fall back to unix time
606+
}
607+
sec, nsec = timesplit(frombe(t[0]))
608+
return
609+
}

src/runtime/sys_plan9_386.s

+13-24
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ TEXT runtime·closefd(SB),NOSPLIT,$0
5858
MOVL AX, ret+4(FP)
5959
RET
6060

61+
TEXT runtime·dupfd(SB),NOSPLIT,$0
62+
MOVL $5, AX
63+
INT $64
64+
MOVL AX, ret+8(FP)
65+
RET
66+
6167
TEXT runtime·exits(SB),NOSPLIT,$0
6268
MOVL $8, AX
6369
INT $64
@@ -87,32 +93,15 @@ TEXT runtime·plan9_tsemacquire(SB),NOSPLIT,$0
8793
MOVL AX, ret+8(FP)
8894
RET
8995

90-
TEXT nsec<>(SB),NOSPLIT,$0
91-
MOVL $53, AX
92-
INT $64
93-
RET
94-
95-
TEXT runtime·nsec(SB),NOSPLIT,$8
96-
LEAL ret+4(FP), AX
97-
MOVL AX, 0(SP)
98-
CALL nsec<>(SB)
99-
CMPL AX, $0
100-
JGE 3(PC)
101-
MOVL $-1, ret_lo+4(FP)
102-
MOVL $-1, ret_hi+8(FP)
103-
RET
104-
105-
// func walltime() (sec int64, nsec int32)
106-
TEXT runtime·walltime(SB),NOSPLIT,$8-12
107-
CALL runtime·nanotime1(SB)
108-
MOVL 0(SP), AX
109-
MOVL 4(SP), DX
110-
96+
// func timesplit(u uint64) (sec int64, nsec int32)
97+
TEXT runtime·timesplit(SB),NOSPLIT,$0
98+
MOVL u_lo+0(FP), AX
99+
MOVL u_hi+4(FP), DX
111100
MOVL $1000000000, CX
112101
DIVL CX
113-
MOVL AX, sec_lo+0(FP)
114-
MOVL $0, sec_hi+4(FP)
115-
MOVL DX, nsec+8(FP)
102+
MOVL AX, sec_lo+8(FP)
103+
MOVL $0, sec_hi+12(FP)
104+
MOVL DX, nsec+16(FP)
116105
RET
117106

118107
TEXT runtime·notify(SB),NOSPLIT,$0

src/runtime/sys_plan9_amd64.s

+16-13
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,17 @@ TEXT runtime·closefd(SB),NOSPLIT,$0
5353
MOVL AX, ret+8(FP)
5454
RET
5555

56+
TEXT runtime·dupfd(SB),NOSPLIT,$0
57+
MOVQ $5, BP
58+
// Kernel expects each int32 arg to be 64-bit-aligned.
59+
// The return value slot is where the kernel
60+
// expects to find the second argument, so copy it there.
61+
MOVL new+4(FP), AX
62+
MOVL AX, ret+8(FP)
63+
SYSCALL
64+
MOVL AX, ret+8(FP)
65+
RET
66+
5667
TEXT runtime·exits(SB),NOSPLIT,$0
5768
MOVQ $8, BP
5869
SYSCALL
@@ -82,17 +93,9 @@ TEXT runtime·plan9_tsemacquire(SB),NOSPLIT,$0
8293
MOVL AX, ret+16(FP)
8394
RET
8495

85-
TEXT runtime·nsec(SB),NOSPLIT,$0
86-
MOVQ $53, BP
87-
SYSCALL
88-
MOVQ AX, ret+8(FP)
89-
RET
90-
91-
// func walltime() (sec int64, nsec int32)
92-
TEXT runtime·walltime(SB),NOSPLIT,$8-12
93-
CALL runtime·nanotime1(SB)
94-
MOVQ 0(SP), AX
95-
96+
// func timesplit(u uint64) (sec int64, nsec int32)
97+
TEXT runtime·timesplit(SB),NOSPLIT,$0
98+
MOVQ u+0(FP), AX
9699
// generated code for
97100
// func f(x uint64) (uint64, uint64) { return x/1000000000, x%1000000000 }
98101
// adapted to reduce duplication
@@ -102,10 +105,10 @@ TEXT runtime·walltime(SB),NOSPLIT,$8-12
102105
ADDQ CX, DX
103106
RCRQ $1, DX
104107
SHRQ $29, DX
105-
MOVQ DX, sec+0(FP)
108+
MOVQ DX, sec+8(FP)
106109
IMULQ $1000000000, DX
107110
SUBQ DX, CX
108-
MOVL CX, nsec+8(FP)
111+
MOVL CX, nsec+16(FP)
109112
RET
110113

111114
TEXT runtime·notify(SB),NOSPLIT,$0

src/runtime/sys_plan9_arm.s

+14-23
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ TEXT runtime·closefd(SB),NOSPLIT,$0-8
9393
MOVW R0, ret+4(FP)
9494
RET
9595

96+
//func dupfd(old, new int32) int32
97+
TEXT runtime·dupfd(SB),NOSPLIT,$0-12
98+
MOVW $SYS_DUP, R0
99+
SWI $0
100+
MOVW R0, ret+8(FP)
101+
RET
102+
96103
//func exits(msg *byte)
97104
TEXT runtime·exits(SB),NOSPLIT,$0-4
98105
MOVW $SYS_EXITS, R0
@@ -127,26 +134,10 @@ TEXT runtime·plan9_tsemacquire(SB),NOSPLIT,$0-12
127134
MOVW R0, ret+8(FP)
128135
RET
129136

130-
//func nsec(*int64) int64
131-
TEXT runtime·nsec(SB),NOSPLIT|NOFRAME,$0-12
132-
MOVW $SYS_NSEC, R0
133-
SWI $0
134-
MOVW arg+0(FP), R1
135-
MOVW 0(R1), R0
136-
MOVW R0, ret_lo+4(FP)
137-
MOVW 4(R1), R0
138-
MOVW R0, ret_hi+8(FP)
139-
RET
140-
141-
// func walltime() (sec int64, nsec int32)
142-
TEXT runtime·walltime(SB),NOSPLIT,$12-12
143-
// use nsec system call to get current time in nanoseconds
144-
MOVW $sysnsec_lo-8(SP), R0 // destination addr
145-
MOVW R0,res-12(SP)
146-
MOVW $SYS_NSEC, R0
147-
SWI $0
148-
MOVW sysnsec_lo-8(SP), R1 // R1:R2 = nsec
149-
MOVW sysnsec_hi-4(SP), R2
137+
// func timesplit(u uint64) (sec int64, nsec int32)
138+
TEXT runtime·timesplit(SB),NOSPLIT,$0
139+
MOVW u_lo+0(FP), R1 // R1:R2 = nsec
140+
MOVW u_hi+4(FP), R2
150141

151142
// multiply nanoseconds by reciprocal of 10**9 (scaled by 2**61)
152143
// to get seconds (96 bit scaled result)
@@ -173,9 +164,9 @@ TEXT runtime·walltime(SB),NOSPLIT,$12-12
173164
SUB.HS R5,R1 // remainder -= 10**9
174165
ADD.HS $1,R6 // sec += 1
175166

176-
MOVW R6,sec_lo+0(FP)
177-
MOVW R7,sec_hi+4(FP)
178-
MOVW R1,nsec+8(FP)
167+
MOVW R6,sec_lo+8(FP)
168+
MOVW R7,sec_hi+12(FP)
169+
MOVW R1,nsec+16(FP)
179170
RET
180171

181172
//func notify(fn unsafe.Pointer) int32

src/runtime/timestub.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// Declarations for operating systems implementing time.now
66
// indirectly, in terms of walltime and nanotime assembly.
77

8-
//go:build !faketime && !windows && !(linux && amd64)
8+
//go:build !faketime && !windows && !(linux && amd64) && !plan9
99

1010
package runtime
1111

src/runtime/timestub2.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
//go:build !aix && !darwin && !freebsd && !openbsd && !solaris && !wasip1 && !windows && !(linux && amd64)
5+
//go:build !aix && !darwin && !freebsd && !openbsd && !solaris && !wasip1 && !windows && !(linux && amd64) && !plan9
66

77
package runtime
88

0 commit comments

Comments
 (0)