cpu_netbsd_arm64.mx raw

   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 := []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 [][]byte
  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 := []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  }
 174