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}