mirror of https://go.googlesource.com/go
91 lines
1.9 KiB
Go
91 lines
1.9 KiB
Go
// Copyright 2018 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
//go:build freebsd && (386 || amd64)
|
|
|
|
package runtime
|
|
|
|
import (
|
|
"internal/runtime/atomic"
|
|
"unsafe"
|
|
)
|
|
|
|
const (
|
|
_VDSO_TH_ALGO_X86_TSC = 1
|
|
_VDSO_TH_ALGO_X86_HPET = 2
|
|
)
|
|
|
|
const (
|
|
_HPET_DEV_MAP_MAX = 10
|
|
_HPET_MAIN_COUNTER = 0xf0 /* Main counter register */
|
|
|
|
hpetDevPath = "/dev/hpetX\x00"
|
|
)
|
|
|
|
var hpetDevMap [_HPET_DEV_MAP_MAX]uintptr
|
|
|
|
//go:nosplit
|
|
func (th *vdsoTimehands) getTSCTimecounter() uint32 {
|
|
tsc := cputicks()
|
|
if th.x86_shift > 0 {
|
|
tsc >>= th.x86_shift
|
|
}
|
|
return uint32(tsc)
|
|
}
|
|
|
|
//go:nosplit
|
|
func (th *vdsoTimehands) getHPETTimecounter() (uint32, bool) {
|
|
idx := int(th.x86_hpet_idx)
|
|
if idx >= len(hpetDevMap) {
|
|
return 0, false
|
|
}
|
|
|
|
p := atomic.Loaduintptr(&hpetDevMap[idx])
|
|
if p == 0 {
|
|
systemstack(func() { initHPETTimecounter(idx) })
|
|
p = atomic.Loaduintptr(&hpetDevMap[idx])
|
|
}
|
|
if p == ^uintptr(0) {
|
|
return 0, false
|
|
}
|
|
return *(*uint32)(unsafe.Pointer(p + _HPET_MAIN_COUNTER)), true
|
|
}
|
|
|
|
//go:systemstack
|
|
func initHPETTimecounter(idx int) {
|
|
const digits = "0123456789"
|
|
|
|
var devPath [len(hpetDevPath)]byte
|
|
copy(devPath[:], hpetDevPath)
|
|
devPath[9] = digits[idx]
|
|
|
|
fd := open(&devPath[0], 0 /* O_RDONLY */ |_O_CLOEXEC, 0)
|
|
if fd < 0 {
|
|
atomic.Casuintptr(&hpetDevMap[idx], 0, ^uintptr(0))
|
|
return
|
|
}
|
|
|
|
addr, mmapErr := mmap(nil, physPageSize, _PROT_READ, _MAP_SHARED, fd, 0)
|
|
closefd(fd)
|
|
newP := uintptr(addr)
|
|
if mmapErr != 0 {
|
|
newP = ^uintptr(0)
|
|
}
|
|
if !atomic.Casuintptr(&hpetDevMap[idx], 0, newP) && mmapErr == 0 {
|
|
munmap(addr, physPageSize)
|
|
}
|
|
}
|
|
|
|
//go:nosplit
|
|
func (th *vdsoTimehands) getTimecounter() (uint32, bool) {
|
|
switch th.algo {
|
|
case _VDSO_TH_ALGO_X86_TSC:
|
|
return th.getTSCTimecounter(), true
|
|
case _VDSO_TH_ALGO_X86_HPET:
|
|
return th.getHPETTimecounter()
|
|
default:
|
|
return 0, false
|
|
}
|
|
}
|