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
  6package cpuid
  7
  8import "runtime"
  9
 10func getMidr() (midr uint64)
 11func getProcFeatures() (procFeatures uint64)
 12func getInstAttributes() (instAttrReg0, instAttrReg1 uint64)
 13func getVectorLength() (vl, pl uint64)
 14
 15func 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
 22func 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}