cpu_netbsd_arm64.go 4.3 KB

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