detect_arm64.go raw

   1  // Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
   2  
   3  //go:build arm64 && !gccgo && !noasm && !appengine
   4  // +build arm64,!gccgo,!noasm,!appengine
   5  
   6  package cpuid
   7  
   8  import "runtime"
   9  
  10  func getMidr() (midr uint64)
  11  func getProcFeatures() (procFeatures uint64)
  12  func getInstAttributes() (instAttrReg0, instAttrReg1 uint64)
  13  func getVectorLength() (vl, pl uint64)
  14  
  15  func initCPU() {
  16  	cpuid = func(uint32) (a, b, c, d uint32) { return 0, 0, 0, 0 }
  17  	cpuidex = func(x, y uint32) (a, b, c, d uint32) { return 0, 0, 0, 0 }
  18  	xgetbv = func(uint32) (a, b uint32) { return 0, 0 }
  19  	rdtscpAsm = func() (a, b, c, d uint32) { return 0, 0, 0, 0 }
  20  }
  21  
  22  func addInfo(c *CPUInfo, safe bool) {
  23  	// Seems to be safe to assume on ARM64
  24  	c.CacheLine = 64
  25  	detectOS(c)
  26  
  27  	// ARM64 disabled since it may crash if interrupt is not intercepted by OS.
  28  	if safe && !c.Has(ARMCPUID) && runtime.GOOS != "freebsd" {
  29  		return
  30  	}
  31  	midr := getMidr()
  32  
  33  	// MIDR_EL1 - Main ID Register
  34  	// https://developer.arm.com/docs/ddi0595/h/aarch64-system-registers/midr_el1
  35  	//  x--------------------------------------------------x
  36  	//  | Name                         |  bits   | visible |
  37  	//  |--------------------------------------------------|
  38  	//  | Implementer                  | [31-24] |    y    |
  39  	//  |--------------------------------------------------|
  40  	//  | Variant                      | [23-20] |    y    |
  41  	//  |--------------------------------------------------|
  42  	//  | Architecture                 | [19-16] |    y    |
  43  	//  |--------------------------------------------------|
  44  	//  | PartNum                      | [15-4]  |    y    |
  45  	//  |--------------------------------------------------|
  46  	//  | Revision                     | [3-0]   |    y    |
  47  	//  x--------------------------------------------------x
  48  
  49  	switch (midr >> 24) & 0xff {
  50  	case 0xC0:
  51  		c.VendorString = "Ampere Computing"
  52  		c.VendorID = Ampere
  53  	case 0x41:
  54  		c.VendorString = "Arm Limited"
  55  		c.VendorID = ARM
  56  	case 0x42:
  57  		c.VendorString = "Broadcom Corporation"
  58  		c.VendorID = Broadcom
  59  	case 0x43:
  60  		c.VendorString = "Cavium Inc"
  61  		c.VendorID = Cavium
  62  	case 0x44:
  63  		c.VendorString = "Digital Equipment Corporation"
  64  		c.VendorID = DEC
  65  	case 0x46:
  66  		c.VendorString = "Fujitsu Ltd"
  67  		c.VendorID = Fujitsu
  68  	case 0x49:
  69  		c.VendorString = "Infineon Technologies AG"
  70  		c.VendorID = Infineon
  71  	case 0x4D:
  72  		c.VendorString = "Motorola or Freescale Semiconductor Inc"
  73  		c.VendorID = Motorola
  74  	case 0x4E:
  75  		c.VendorString = "NVIDIA Corporation"
  76  		c.VendorID = NVIDIA
  77  	case 0x50:
  78  		c.VendorString = "Applied Micro Circuits Corporation"
  79  		c.VendorID = AMCC
  80  	case 0x51:
  81  		c.VendorString = "Qualcomm Inc"
  82  		c.VendorID = Qualcomm
  83  	case 0x56:
  84  		c.VendorString = "Marvell International Ltd"
  85  		c.VendorID = Marvell
  86  	case 0x69:
  87  		c.VendorString = "Intel Corporation"
  88  		c.VendorID = Intel
  89  	}
  90  
  91  	// Lower 4 bits: Architecture
  92  	// Architecture	Meaning
  93  	// 0b0001		Armv4.
  94  	// 0b0010		Armv4T.
  95  	// 0b0011		Armv5 (obsolete).
  96  	// 0b0100		Armv5T.
  97  	// 0b0101		Armv5TE.
  98  	// 0b0110		Armv5TEJ.
  99  	// 0b0111		Armv6.
 100  	// 0b1111		Architectural features are individually identified in the ID_* registers, see 'ID registers'.
 101  	// Upper 4 bit: Variant
 102  	// An IMPLEMENTATION DEFINED variant number.
 103  	// Typically, this field is used to distinguish between different product variants, or major revisions of a product.
 104  	c.Family = int(midr>>16) & 0xff
 105  
 106  	// PartNum, bits [15:4]
 107  	// An IMPLEMENTATION DEFINED primary part number for the device.
 108  	// On processors implemented by Arm, if the top four bits of the primary
 109  	// part number are 0x0 or 0x7, the variant and architecture are encoded differently.
 110  	// Revision, bits [3:0]
 111  	// An IMPLEMENTATION DEFINED revision number for the device.
 112  	c.Model = int(midr) & 0xffff
 113  
 114  	procFeatures := getProcFeatures()
 115  
 116  	// ID_AA64PFR0_EL1 - Processor Feature Register 0
 117  	// x--------------------------------------------------x
 118  	// | Name                         |  bits   | visible |
 119  	// |--------------------------------------------------|
 120  	// | DIT                          | [51-48] |    y    |
 121  	// |--------------------------------------------------|
 122  	// | SVE                          | [35-32] |    y    |
 123  	// |--------------------------------------------------|
 124  	// | GIC                          | [27-24] |    n    |
 125  	// |--------------------------------------------------|
 126  	// | AdvSIMD                      | [23-20] |    y    |
 127  	// |--------------------------------------------------|
 128  	// | FP                           | [19-16] |    y    |
 129  	// |--------------------------------------------------|
 130  	// | EL3                          | [15-12] |    n    |
 131  	// |--------------------------------------------------|
 132  	// | EL2                          | [11-8]  |    n    |
 133  	// |--------------------------------------------------|
 134  	// | EL1                          | [7-4]   |    n    |
 135  	// |--------------------------------------------------|
 136  	// | EL0                          | [3-0]   |    n    |
 137  	// x--------------------------------------------------x
 138  
 139  	var f flagSet
 140  	// if procFeatures&(0xf<<48) != 0 {
 141  	// 	fmt.Println("DIT")
 142  	// }
 143  	f.setIf(procFeatures&(0xf<<32) != 0, SVE)
 144  	if procFeatures&(0xf<<20) != 15<<20 {
 145  		f.set(ASIMD)
 146  		// https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64pfr0_el1
 147  		// 0b0001 --> As for 0b0000, and also includes support for half-precision floating-point arithmetic.
 148  		f.setIf(procFeatures&(0xf<<20) == 1<<20, FPHP, ASIMDHP)
 149  	}
 150  	f.setIf(procFeatures&(0xf<<16) != 0, FP)
 151  
 152  	instAttrReg0, instAttrReg1 := getInstAttributes()
 153  
 154  	// https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64isar0_el1
 155  	//
 156  	// ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0
 157  	// x--------------------------------------------------x
 158  	// | Name                         |  bits   | visible |
 159  	// |--------------------------------------------------|
 160  	// | RNDR                         | [63-60] |    y    |
 161  	// |--------------------------------------------------|
 162  	// | TLB                          | [59-56] |    y    |
 163  	// |--------------------------------------------------|
 164  	// | TS                           | [55-52] |    y    |
 165  	// |--------------------------------------------------|
 166  	// | FHM                          | [51-48] |    y    |
 167  	// |--------------------------------------------------|
 168  	// | DP                           | [47-44] |    y    |
 169  	// |--------------------------------------------------|
 170  	// | SM4                          | [43-40] |    y    |
 171  	// |--------------------------------------------------|
 172  	// | SM3                          | [39-36] |    y    |
 173  	// |--------------------------------------------------|
 174  	// | SHA3                         | [35-32] |    y    |
 175  	// |--------------------------------------------------|
 176  	// | RDM                          | [31-28] |    y    |
 177  	// |--------------------------------------------------|
 178  	// | ATOMICS                      | [23-20] |    y    |
 179  	// |--------------------------------------------------|
 180  	// | CRC32                        | [19-16] |    y    |
 181  	// |--------------------------------------------------|
 182  	// | SHA2                         | [15-12] |    y    |
 183  	// |--------------------------------------------------|
 184  	// | SHA1                         | [11-8]  |    y    |
 185  	// |--------------------------------------------------|
 186  	// | AES                          | [7-4]   |    y    |
 187  	// x--------------------------------------------------x
 188  
 189  	f.setIf(instAttrReg0&(0xf<<60) != 0, RNDR)
 190  	f.setIf(instAttrReg0&(0xf<<56) != 0, TLB)
 191  	f.setIf(instAttrReg0&(0xf<<52) != 0, TS)
 192  	f.setIf(instAttrReg0&(0xf<<48) != 0, FHM)
 193  	f.setIf(instAttrReg0&(0xf<<44) != 0, ASIMDDP)
 194  	f.setIf(instAttrReg0&(0xf<<40) != 0, SM4)
 195  	f.setIf(instAttrReg0&(0xf<<36) != 0, SM3)
 196  	f.setIf(instAttrReg0&(0xf<<32) != 0, SHA3)
 197  	f.setIf(instAttrReg0&(0xf<<28) != 0, ASIMDRDM)
 198  	f.setIf(instAttrReg0&(0xf<<20) != 0, ATOMICS)
 199  	f.setIf(instAttrReg0&(0xf<<16) != 0, CRC32)
 200  	f.setIf(instAttrReg0&(0xf<<12) != 0, SHA2)
 201  	// https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64isar0_el1
 202  	// 0b0010 --> As 0b0001, plus SHA512H, SHA512H2, SHA512SU0, and SHA512SU1 instructions implemented.
 203  	f.setIf(instAttrReg0&(0xf<<12) == 2<<12, SHA512)
 204  	f.setIf(instAttrReg0&(0xf<<8) != 0, SHA1)
 205  	f.setIf(instAttrReg0&(0xf<<4) != 0, AESARM)
 206  	// https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64isar0_el1
 207  	// 0b0010 --> As for 0b0001, plus PMULL/PMULL2 instructions operating on 64-bit data quantities.
 208  	f.setIf(instAttrReg0&(0xf<<4) == 2<<4, PMULL)
 209  
 210  	// https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64isar1_el1
 211  	//
 212  	// ID_AA64ISAR1_EL1 - Instruction set attribute register 1
 213  	// x--------------------------------------------------x
 214  	// | Name                         |  bits   | visible |
 215  	// |--------------------------------------------------|
 216  	// | GPI                          | [31-28] |    y    |
 217  	// |--------------------------------------------------|
 218  	// | GPA                          | [27-24] |    y    |
 219  	// |--------------------------------------------------|
 220  	// | LRCPC                        | [23-20] |    y    |
 221  	// |--------------------------------------------------|
 222  	// | FCMA                         | [19-16] |    y    |
 223  	// |--------------------------------------------------|
 224  	// | JSCVT                        | [15-12] |    y    |
 225  	// |--------------------------------------------------|
 226  	// | API                          | [11-8]  |    y    |
 227  	// |--------------------------------------------------|
 228  	// | APA                          | [7-4]   |    y    |
 229  	// |--------------------------------------------------|
 230  	// | DPB                          | [3-0]   |    y    |
 231  	// x--------------------------------------------------x
 232  
 233  	// if instAttrReg1&(0xf<<28) != 0 {
 234  	// 	fmt.Println("GPI")
 235  	// }
 236  	f.setIf(instAttrReg1&(0xf<<28) != 24, GPA)
 237  	f.setIf(instAttrReg1&(0xf<<20) != 0, LRCPC)
 238  	f.setIf(instAttrReg1&(0xf<<16) != 0, FCMA)
 239  	f.setIf(instAttrReg1&(0xf<<12) != 0, JSCVT)
 240  	// if instAttrReg1&(0xf<<8) != 0 {
 241  	// 	fmt.Println("API")
 242  	// }
 243  	// if instAttrReg1&(0xf<<4) != 0 {
 244  	// 	fmt.Println("APA")
 245  	// }
 246  	f.setIf(instAttrReg1&(0xf<<0) != 0, DCPOP)
 247  
 248  	// Store
 249  	c.featureSet.or(f)
 250  }
 251