golang.org/x/sys@v0.20.1-0.20240517151509-673e0f94c16d/cpu/cpu_netbsd_arm64.go (about)

     1  // Copyright 2020 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  package cpu
     6  
     7  import (
     8  	"syscall"
     9  	"unsafe"
    10  )
    11  
    12  // Minimal copy of functionality from x/sys/unix so the cpu package can call
    13  // sysctl without depending on x/sys/unix.
    14  
    15  const (
    16  	_CTL_QUERY = -2
    17  
    18  	_SYSCTL_VERS_1 = 0x1000000
    19  )
    20  
    21  var _zero uintptr
    22  
    23  func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
    24  	var _p0 unsafe.Pointer
    25  	if len(mib) > 0 {
    26  		_p0 = unsafe.Pointer(&mib[0])
    27  	} else {
    28  		_p0 = unsafe.Pointer(&_zero)
    29  	}
    30  	_, _, errno := syscall.Syscall6(
    31  		syscall.SYS___SYSCTL,
    32  		uintptr(_p0),
    33  		uintptr(len(mib)),
    34  		uintptr(unsafe.Pointer(old)),
    35  		uintptr(unsafe.Pointer(oldlen)),
    36  		uintptr(unsafe.Pointer(new)),
    37  		uintptr(newlen))
    38  	if errno != 0 {
    39  		return errno
    40  	}
    41  	return nil
    42  }
    43  
    44  type sysctlNode struct {
    45  	Flags          uint32
    46  	Num            int32
    47  	Name           [32]int8
    48  	Ver            uint32
    49  	__rsvd         uint32
    50  	Un             [16]byte
    51  	_sysctl_size   [8]byte
    52  	_sysctl_func   [8]byte
    53  	_sysctl_parent [8]byte
    54  	_sysctl_desc   [8]byte
    55  }
    56  
    57  func sysctlNodes(mib []int32) ([]sysctlNode, error) {
    58  	var olen uintptr
    59  
    60  	// Get a list of all sysctl nodes below the given MIB by performing
    61  	// a sysctl for the given MIB with CTL_QUERY appended.
    62  	mib = append(mib, _CTL_QUERY)
    63  	qnode := sysctlNode{Flags: _SYSCTL_VERS_1}
    64  	qp := (*byte)(unsafe.Pointer(&qnode))
    65  	sz := unsafe.Sizeof(qnode)
    66  	if err := sysctl(mib, nil, &olen, qp, sz); err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	// Now that we know the size, get the actual nodes.
    71  	nodes := make([]sysctlNode, olen/sz)
    72  	np := (*byte)(unsafe.Pointer(&nodes[0]))
    73  	if err := sysctl(mib, np, &olen, qp, sz); err != nil {
    74  		return nil, err
    75  	}
    76  
    77  	return nodes, nil
    78  }
    79  
    80  func nametomib(name string) ([]int32, error) {
    81  	// Split name into components.
    82  	var parts []string
    83  	last := 0
    84  	for i := 0; i < len(name); i++ {
    85  		if name[i] == '.' {
    86  			parts = append(parts, name[last:i])
    87  			last = i + 1
    88  		}
    89  	}
    90  	parts = append(parts, name[last:])
    91  
    92  	mib := []int32{}
    93  	// Discover the nodes and construct the MIB OID.
    94  	for partno, part := range parts {
    95  		nodes, err := sysctlNodes(mib)
    96  		if err != nil {
    97  			return nil, err
    98  		}
    99  		for _, node := range nodes {
   100  			n := make([]byte, 0)
   101  			for i := range node.Name {
   102  				if node.Name[i] != 0 {
   103  					n = append(n, byte(node.Name[i]))
   104  				}
   105  			}
   106  			if string(n) == part {
   107  				mib = append(mib, int32(node.Num))
   108  				break
   109  			}
   110  		}
   111  		if len(mib) != partno+1 {
   112  			return nil, err
   113  		}
   114  	}
   115  
   116  	return mib, nil
   117  }
   118  
   119  // aarch64SysctlCPUID is struct aarch64_sysctl_cpu_id from NetBSD's <aarch64/armreg.h>
   120  type aarch64SysctlCPUID struct {
   121  	midr      uint64 /* Main ID Register */
   122  	revidr    uint64 /* Revision ID Register */
   123  	mpidr     uint64 /* Multiprocessor Affinity Register */
   124  	aa64dfr0  uint64 /* A64 Debug Feature Register 0 */
   125  	aa64dfr1  uint64 /* A64 Debug Feature Register 1 */
   126  	aa64isar0 uint64 /* A64 Instruction Set Attribute Register 0 */
   127  	aa64isar1 uint64 /* A64 Instruction Set Attribute Register 1 */
   128  	aa64mmfr0 uint64 /* A64 Memory Model Feature Register 0 */
   129  	aa64mmfr1 uint64 /* A64 Memory Model Feature Register 1 */
   130  	aa64mmfr2 uint64 /* A64 Memory Model Feature Register 2 */
   131  	aa64pfr0  uint64 /* A64 Processor Feature Register 0 */
   132  	aa64pfr1  uint64 /* A64 Processor Feature Register 1 */
   133  	aa64zfr0  uint64 /* A64 SVE Feature ID Register 0 */
   134  	mvfr0     uint32 /* Media and VFP Feature Register 0 */
   135  	mvfr1     uint32 /* Media and VFP Feature Register 1 */
   136  	mvfr2     uint32 /* Media and VFP Feature Register 2 */
   137  	pad       uint32
   138  	clidr     uint64 /* Cache Level ID Register */
   139  	ctr       uint64 /* Cache Type Register */
   140  }
   141  
   142  func sysctlCPUID(name string) (*aarch64SysctlCPUID, error) {
   143  	mib, err := nametomib(name)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  
   148  	out := aarch64SysctlCPUID{}
   149  	n := unsafe.Sizeof(out)
   150  	_, _, errno := syscall.Syscall6(
   151  		syscall.SYS___SYSCTL,
   152  		uintptr(unsafe.Pointer(&mib[0])),
   153  		uintptr(len(mib)),
   154  		uintptr(unsafe.Pointer(&out)),
   155  		uintptr(unsafe.Pointer(&n)),
   156  		uintptr(0),
   157  		uintptr(0))
   158  	if errno != 0 {
   159  		return nil, errno
   160  	}
   161  	return &out, nil
   162  }
   163  
   164  func doinit() {
   165  	cpuid, err := sysctlCPUID("machdep.cpu0.cpu_id")
   166  	if err != nil {
   167  		setMinimalFeatures()
   168  		return
   169  	}
   170  	parseARM64SystemRegisters(cpuid.aa64isar0, cpuid.aa64isar1, cpuid.aa64pfr0)
   171  
   172  	Initialized = true
   173  }