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  	"runtime/internal/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:systemstack
    38  func (th *vdsoTimehands) getHPETTimecounter() (uint32, bool) {
    39  	const digits = "0123456789"
    40  
    41  	idx := int(th.x86_hpet_idx)
    42  	if idx >= len(hpetDevMap) {
    43  		return 0, false
    44  	}
    45  
    46  	p := atomic.Loaduintptr(&hpetDevMap[idx])
    47  	if p == 0 {
    48  		var devPath [len(hpetDevPath)]byte
    49  		copy(devPath[:], hpetDevPath)
    50  		devPath[9] = digits[idx]
    51  
    52  		fd := open(&devPath[0], 0 /* O_RDONLY */, 0)
    53  		if fd < 0 {
    54  			atomic.Casuintptr(&hpetDevMap[idx], 0, ^uintptr(0))
    55  			return 0, false
    56  		}
    57  
    58  		addr, mmapErr := mmap(nil, physPageSize, _PROT_READ, _MAP_SHARED, fd, 0)
    59  		closefd(fd)
    60  		newP := uintptr(addr)
    61  		if mmapErr != 0 {
    62  			newP = ^uintptr(0)
    63  		}
    64  		if !atomic.Casuintptr(&hpetDevMap[idx], 0, newP) && mmapErr == 0 {
    65  			munmap(addr, physPageSize)
    66  		}
    67  		p = atomic.Loaduintptr(&hpetDevMap[idx])
    68  	}
    69  	if p == ^uintptr(0) {
    70  		return 0, false
    71  	}
    72  	return *(*uint32)(unsafe.Pointer(p + _HPET_MAIN_COUNTER)), true
    73  }
    74  
    75  //go:nosplit
    76  func (th *vdsoTimehands) getTimecounter() (uint32, bool) {
    77  	switch th.algo {
    78  	case _VDSO_TH_ALGO_X86_TSC:
    79  		return th.getTSCTimecounter(), true
    80  	case _VDSO_TH_ALGO_X86_HPET:
    81  		var (
    82  			tc uint32
    83  			ok bool
    84  		)
    85  		systemstack(func() {
    86  			tc, ok = th.getHPETTimecounter()
    87  		})
    88  		return tc, ok
    89  	default:
    90  		return 0, false
    91  	}
    92  }
    93  

View as plain text