Source file src/runtime/vdso_freebsd_x86.go

     1  // Copyright 2018 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  //go:build freebsd && (386 || amd64)
     6  
     7  package runtime
     8  
     9  import (
    10  	"internal/runtime/atomic"
    11  	"unsafe"
    12  )
    13  
    14  const (
    15  	_VDSO_TH_ALGO_X86_TSC  = 1
    16  	_VDSO_TH_ALGO_X86_HPET = 2
    17  )
    18  
    19  const (
    20  	_HPET_DEV_MAP_MAX  = 10
    21  	_HPET_MAIN_COUNTER = 0xf0 /* Main counter register */
    22  
    23  	hpetDevPath = "/dev/hpetX\x00"
    24  )
    25  
    26  var hpetDevMap [_HPET_DEV_MAP_MAX]uintptr
    27  
    28  //go:nosplit
    29  func (th *vdsoTimehands) getTSCTimecounter() uint32 {
    30  	tsc := cputicks()
    31  	if th.x86_shift > 0 {
    32  		tsc >>= th.x86_shift
    33  	}
    34  	return uint32(tsc)
    35  }
    36  
    37  //go:nosplit
    38  func (th *vdsoTimehands) getHPETTimecounter() (uint32, bool) {
    39  	idx := int(th.x86_hpet_idx)
    40  	if idx >= len(hpetDevMap) {
    41  		return 0, false
    42  	}
    43  
    44  	p := atomic.Loaduintptr(&hpetDevMap[idx])
    45  	if p == 0 {
    46  		systemstack(func() { initHPETTimecounter(idx) })
    47  		p = atomic.Loaduintptr(&hpetDevMap[idx])
    48  	}
    49  	if p == ^uintptr(0) {
    50  		return 0, false
    51  	}
    52  	return *(*uint32)(unsafe.Pointer(p + _HPET_MAIN_COUNTER)), true
    53  }
    54  
    55  //go:systemstack
    56  func initHPETTimecounter(idx int) {
    57  	const digits = "0123456789"
    58  
    59  	var devPath [len(hpetDevPath)]byte
    60  	copy(devPath[:], hpetDevPath)
    61  	devPath[9] = digits[idx]
    62  
    63  	fd := open(&devPath[0], 0 /* O_RDONLY */ |_O_CLOEXEC, 0)
    64  	if fd < 0 {
    65  		atomic.Casuintptr(&hpetDevMap[idx], 0, ^uintptr(0))
    66  		return
    67  	}
    68  
    69  	addr, mmapErr := mmap(nil, physPageSize, _PROT_READ, _MAP_SHARED, fd, 0)
    70  	closefd(fd)
    71  	newP := uintptr(addr)
    72  	if mmapErr != 0 {
    73  		newP = ^uintptr(0)
    74  	}
    75  	if !atomic.Casuintptr(&hpetDevMap[idx], 0, newP) && mmapErr == 0 {
    76  		munmap(addr, physPageSize)
    77  	}
    78  }
    79  
    80  //go:nosplit
    81  func (th *vdsoTimehands) getTimecounter() (uint32, bool) {
    82  	switch th.algo {
    83  	case _VDSO_TH_ALGO_X86_TSC:
    84  		return th.getTSCTimecounter(), true
    85  	case _VDSO_TH_ALGO_X86_HPET:
    86  		return th.getHPETTimecounter()
    87  	default:
    88  		return 0, false
    89  	}
    90  }
    91  

View as plain text