diff options
Diffstat (limited to 'src/runtime/vdso_freebsd_x86.go')
-rw-r--r-- | src/runtime/vdso_freebsd_x86.go | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/src/runtime/vdso_freebsd_x86.go b/src/runtime/vdso_freebsd_x86.go new file mode 100644 index 0000000..66d1c65 --- /dev/null +++ b/src/runtime/vdso_freebsd_x86.go @@ -0,0 +1,90 @@ +// 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 ( + "runtime/internal/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 + } +} |