1// Copyright 2019 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
5package runtime
6
7import "internal/cpu"
8
9const (
10	hwcap_FP       = 1 << 0
11	hwcap_ASIMD    = 1 << 1
12	hwcap_EVTSTRM  = 1 << 2
13	hwcap_AES      = 1 << 3
14	hwcap_PMULL    = 1 << 4
15	hwcap_SHA1     = 1 << 5
16	hwcap_SHA2     = 1 << 6
17	hwcap_CRC32    = 1 << 7
18	hwcap_ATOMICS  = 1 << 8
19	hwcap_FPHP     = 1 << 9
20	hwcap_ASIMDHP  = 1 << 10
21	hwcap_CPUID    = 1 << 11
22	hwcap_ASIMDRDM = 1 << 12
23	hwcap_JSCVT    = 1 << 13
24	hwcap_FCMA     = 1 << 14
25	hwcap_LRCPC    = 1 << 15
26	hwcap_DCPOP    = 1 << 16
27	hwcap_SHA3     = 1 << 17
28	hwcap_SM3      = 1 << 18
29	hwcap_SM4      = 1 << 19
30	hwcap_ASIMDDP  = 1 << 20
31	hwcap_SHA512   = 1 << 21
32	hwcap_SVE      = 1 << 22
33	hwcap_ASIMDFHM = 1 << 23
34)
35
36func getisar0() uint64
37func getisar1() uint64
38func getpfr0() uint64
39
40// no hwcap support on FreeBSD aarch64, we need to retrieve the info from
41// ID_AA64ISAR0_EL1, ID_AA64ISAR1_EL1 and ID_AA64PFR0_EL1
42func archauxv(tag, val uintptr) {
43	var isar0, isar1, pfr0 uint64
44
45	isar0 = getisar0()
46	isar1 = getisar1()
47	pfr0 = getpfr0()
48
49	// ID_AA64ISAR0_EL1
50	switch extractBits(isar0, 4, 7) {
51	case 1:
52		cpu.HWCap |= hwcap_AES
53	case 2:
54		cpu.HWCap |= hwcap_PMULL | hwcap_AES
55	}
56
57	switch extractBits(isar0, 8, 11) {
58	case 1:
59		cpu.HWCap |= hwcap_SHA1
60	}
61
62	switch extractBits(isar0, 12, 15) {
63	case 1:
64		cpu.HWCap |= hwcap_SHA2
65	case 2:
66		cpu.HWCap |= hwcap_SHA2 | hwcap_SHA512
67	}
68
69	switch extractBits(isar0, 16, 19) {
70	case 1:
71		cpu.HWCap |= hwcap_CRC32
72	}
73
74	switch extractBits(isar0, 20, 23) {
75	case 2:
76		cpu.HWCap |= hwcap_ATOMICS
77	}
78
79	switch extractBits(isar0, 28, 31) {
80	case 1:
81		cpu.HWCap |= hwcap_ASIMDRDM
82	}
83
84	switch extractBits(isar0, 32, 35) {
85	case 1:
86		cpu.HWCap |= hwcap_SHA3
87	}
88
89	switch extractBits(isar0, 36, 39) {
90	case 1:
91		cpu.HWCap |= hwcap_SM3
92	}
93
94	switch extractBits(isar0, 40, 43) {
95	case 1:
96		cpu.HWCap |= hwcap_SM4
97	}
98
99	switch extractBits(isar0, 44, 47) {
100	case 1:
101		cpu.HWCap |= hwcap_ASIMDDP
102	}
103
104	// ID_AA64ISAR1_EL1
105	switch extractBits(isar1, 0, 3) {
106	case 1:
107		cpu.HWCap |= hwcap_DCPOP
108	}
109
110	switch extractBits(isar1, 12, 15) {
111	case 1:
112		cpu.HWCap |= hwcap_JSCVT
113	}
114
115	switch extractBits(isar1, 16, 19) {
116	case 1:
117		cpu.HWCap |= hwcap_FCMA
118	}
119
120	switch extractBits(isar1, 20, 23) {
121	case 1:
122		cpu.HWCap |= hwcap_LRCPC
123	}
124
125	// ID_AA64PFR0_EL1
126	switch extractBits(pfr0, 16, 19) {
127	case 0:
128		cpu.HWCap |= hwcap_FP
129	case 1:
130		cpu.HWCap |= hwcap_FP | hwcap_FPHP
131	}
132
133	switch extractBits(pfr0, 20, 23) {
134	case 0:
135		cpu.HWCap |= hwcap_ASIMD
136	case 1:
137		cpu.HWCap |= hwcap_ASIMD | hwcap_ASIMDHP
138	}
139
140	switch extractBits(pfr0, 32, 35) {
141	case 1:
142		cpu.HWCap |= hwcap_SVE
143	}
144}
145
146func extractBits(data uint64, start, end uint) uint {
147	return (uint)(data>>start) & ((1 << (end - start + 1)) - 1)
148}
149
150//go:nosplit
151func cputicks() int64 {
152	// Currently cputicks() is used in blocking profiler and to seed fastrand().
153	// nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
154	return nanotime()
155}
156