1// Copyright 2017 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 cpu
6
7const CacheLinePadSize = 256
8
9var HWCap uint
10
11// bitIsSet reports whether the bit at index is set. The bit index
12// is in big endian order, so bit index 0 is the leftmost bit.
13func bitIsSet(bits []uint64, index uint) bool {
14	return bits[index/64]&((1<<63)>>(index%64)) != 0
15}
16
17// function is the function code for the named function.
18type function uint8
19
20const (
21	// KM{,A,C,CTR} function codes
22	aes128 function = 18 // AES-128
23	aes192 function = 19 // AES-192
24	aes256 function = 20 // AES-256
25
26	// K{I,L}MD function codes
27	sha1     function = 1  // SHA-1
28	sha256   function = 2  // SHA-256
29	sha512   function = 3  // SHA-512
30	sha3_224 function = 32 // SHA3-224
31	sha3_256 function = 33 // SHA3-256
32	sha3_384 function = 34 // SHA3-384
33	sha3_512 function = 35 // SHA3-512
34	shake128 function = 36 // SHAKE-128
35	shake256 function = 37 // SHAKE-256
36
37	// KLMD function codes
38	ghash function = 65 // GHASH
39)
40
41const (
42	// KDSA function codes
43	ecdsaVerifyP256    function = 1  // NIST P256
44	ecdsaVerifyP384    function = 2  // NIST P384
45	ecdsaVerifyP521    function = 3  // NIST P521
46	ecdsaSignP256      function = 9  // NIST P256
47	ecdsaSignP384      function = 10 // NIST P384
48	ecdsaSignP521      function = 11 // NIST P521
49	eddsaVerifyEd25519 function = 32 // Curve25519
50	eddsaVerifyEd448   function = 36 // Curve448
51	eddsaSignEd25519   function = 40 // Curve25519
52	eddsaSignEd448     function = 44 // Curve448
53)
54
55// queryResult contains the result of a Query function
56// call. Bits are numbered in big endian order so the
57// leftmost bit (the MSB) is at index 0.
58type queryResult struct {
59	bits [2]uint64
60}
61
62// Has reports whether the given functions are present.
63func (q *queryResult) Has(fns ...function) bool {
64	if len(fns) == 0 {
65		panic("no function codes provided")
66	}
67	for _, f := range fns {
68		if !bitIsSet(q.bits[:], uint(f)) {
69			return false
70		}
71	}
72	return true
73}
74
75// facility is a bit index for the named facility.
76type facility uint8
77
78const (
79	// mandatory facilities
80	zarch  facility = 1  // z architecture mode is active
81	stflef facility = 7  // store-facility-list-extended
82	ldisp  facility = 18 // long-displacement
83	eimm   facility = 21 // extended-immediate
84
85	// miscellaneous facilities
86	dfp    facility = 42 // decimal-floating-point
87	etf3eh facility = 30 // extended-translation 3 enhancement
88
89	// cryptography facilities
90	msa  facility = 17  // message-security-assist
91	msa3 facility = 76  // message-security-assist extension 3
92	msa4 facility = 77  // message-security-assist extension 4
93	msa5 facility = 57  // message-security-assist extension 5
94	msa8 facility = 146 // message-security-assist extension 8
95	msa9 facility = 155 // message-security-assist extension 9
96
97	// vector facilities
98	vxe facility = 135 // vector-enhancements 1
99
100	// Note: vx requires kernel support
101	// and so must be fetched from HWCAP.
102
103	hwcap_VX = 1 << 11 // vector facility
104)
105
106// facilityList contains the result of an STFLE call.
107// Bits are numbered in big endian order so the
108// leftmost bit (the MSB) is at index 0.
109type facilityList struct {
110	bits [4]uint64
111}
112
113// Has reports whether the given facilities are present.
114func (s *facilityList) Has(fs ...facility) bool {
115	if len(fs) == 0 {
116		panic("no facility bits provided")
117	}
118	for _, f := range fs {
119		if !bitIsSet(s.bits[:], uint(f)) {
120			return false
121		}
122	}
123	return true
124}
125
126// The following feature detection functions are defined in cpu_s390x.s.
127// They are likely to be expensive to call so the results should be cached.
128func stfle() facilityList
129func kmQuery() queryResult
130func kmcQuery() queryResult
131func kmctrQuery() queryResult
132func kmaQuery() queryResult
133func kimdQuery() queryResult
134func klmdQuery() queryResult
135func kdsaQuery() queryResult
136
137func doinit() {
138	options = []option{
139		{Name: "zarch", Feature: &S390X.HasZARCH},
140		{Name: "stfle", Feature: &S390X.HasSTFLE},
141		{Name: "ldisp", Feature: &S390X.HasLDISP},
142		{Name: "msa", Feature: &S390X.HasMSA},
143		{Name: "eimm", Feature: &S390X.HasEIMM},
144		{Name: "dfp", Feature: &S390X.HasDFP},
145		{Name: "etf3eh", Feature: &S390X.HasETF3EH},
146		{Name: "vx", Feature: &S390X.HasVX},
147		{Name: "vxe", Feature: &S390X.HasVXE},
148		{Name: "kdsa", Feature: &S390X.HasKDSA},
149	}
150
151	aes := []function{aes128, aes192, aes256}
152	facilities := stfle()
153
154	S390X.HasZARCH = facilities.Has(zarch)
155	S390X.HasSTFLE = facilities.Has(stflef)
156	S390X.HasLDISP = facilities.Has(ldisp)
157	S390X.HasEIMM = facilities.Has(eimm)
158	S390X.HasDFP = facilities.Has(dfp)
159	S390X.HasETF3EH = facilities.Has(etf3eh)
160	S390X.HasMSA = facilities.Has(msa)
161
162	if S390X.HasMSA {
163		// cipher message
164		km, kmc := kmQuery(), kmcQuery()
165		S390X.HasAES = km.Has(aes...)
166		S390X.HasAESCBC = kmc.Has(aes...)
167		if facilities.Has(msa4) {
168			kmctr := kmctrQuery()
169			S390X.HasAESCTR = kmctr.Has(aes...)
170		}
171		if facilities.Has(msa8) {
172			kma := kmaQuery()
173			S390X.HasAESGCM = kma.Has(aes...)
174		}
175
176		// compute message digest
177		kimd := kimdQuery() // intermediate (no padding)
178		klmd := klmdQuery() // last (padding)
179		S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1)
180		S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256)
181		S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512)
182		S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist
183		sha3 := []function{
184			sha3_224, sha3_256, sha3_384, sha3_512,
185			shake128, shake256,
186		}
187		S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...)
188		S390X.HasKDSA = facilities.Has(msa9) // elliptic curves
189		if S390X.HasKDSA {
190			kdsa := kdsaQuery()
191			S390X.HasECDSA = kdsa.Has(ecdsaVerifyP256, ecdsaSignP256, ecdsaVerifyP384, ecdsaSignP384, ecdsaVerifyP521, ecdsaSignP521)
192			S390X.HasEDDSA = kdsa.Has(eddsaVerifyEd25519, eddsaSignEd25519, eddsaVerifyEd448, eddsaSignEd448)
193		}
194	}
195
196	S390X.HasVX = isSet(HWCap, hwcap_VX)
197
198	if S390X.HasVX {
199		S390X.HasVXE = facilities.Has(vxe)
200	}
201}
202
203func isSet(hwc uint, value uint) bool {
204	return hwc&value != 0
205}
206