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 cpu
6
7const cacheLineSize = 256
8
9const (
10	// bit mask values from /usr/include/bits/hwcap.h
11	hwcap_ZARCH  = 2
12	hwcap_STFLE  = 4
13	hwcap_MSA    = 8
14	hwcap_LDISP  = 16
15	hwcap_EIMM   = 32
16	hwcap_DFP    = 64
17	hwcap_ETF3EH = 256
18	hwcap_VX     = 2048
19	hwcap_VXE    = 8192
20)
21
22// bitIsSet reports whether the bit at index is set. The bit index
23// is in big endian order, so bit index 0 is the leftmost bit.
24func bitIsSet(bits []uint64, index uint) bool {
25	return bits[index/64]&((1<<63)>>(index%64)) != 0
26}
27
28// function is the code for the named cryptographic function.
29type function uint8
30
31const (
32	// KM{,A,C,CTR} function codes
33	aes128 function = 18 // AES-128
34	aes192 function = 19 // AES-192
35	aes256 function = 20 // AES-256
36
37	// K{I,L}MD function codes
38	sha1     function = 1  // SHA-1
39	sha256   function = 2  // SHA-256
40	sha512   function = 3  // SHA-512
41	sha3_224 function = 32 // SHA3-224
42	sha3_256 function = 33 // SHA3-256
43	sha3_384 function = 34 // SHA3-384
44	sha3_512 function = 35 // SHA3-512
45	shake128 function = 36 // SHAKE-128
46	shake256 function = 37 // SHAKE-256
47
48	// KLMD function codes
49	ghash function = 65 // GHASH
50)
51
52// queryResult contains the result of a Query function
53// call. Bits are numbered in big endian order so the
54// leftmost bit (the MSB) is at index 0.
55type queryResult struct {
56	bits [2]uint64
57}
58
59// Has reports whether the given functions are present.
60func (q *queryResult) Has(fns ...function) bool {
61	if len(fns) == 0 {
62		panic("no function codes provided")
63	}
64	for _, f := range fns {
65		if !bitIsSet(q.bits[:], uint(f)) {
66			return false
67		}
68	}
69	return true
70}
71
72// facility is a bit index for the named facility.
73type facility uint8
74
75const (
76	// cryptography facilities
77	msa4 facility = 77  // message-security-assist extension 4
78	msa8 facility = 146 // message-security-assist extension 8
79)
80
81// facilityList contains the result of an STFLE call.
82// Bits are numbered in big endian order so the
83// leftmost bit (the MSB) is at index 0.
84type facilityList struct {
85	bits [4]uint64
86}
87
88// Has reports whether the given facilities are present.
89func (s *facilityList) Has(fs ...facility) bool {
90	if len(fs) == 0 {
91		panic("no facility bits provided")
92	}
93	for _, f := range fs {
94		if !bitIsSet(s.bits[:], uint(f)) {
95			return false
96		}
97	}
98	return true
99}
100
101func doinit() {
102	// test HWCAP bit vector
103	has := func(featureMask uint) bool {
104		return hwCap&featureMask == featureMask
105	}
106
107	// mandatory
108	S390X.HasZARCH = has(hwcap_ZARCH)
109
110	// optional
111	S390X.HasSTFLE = has(hwcap_STFLE)
112	S390X.HasLDISP = has(hwcap_LDISP)
113	S390X.HasEIMM = has(hwcap_EIMM)
114	S390X.HasETF3EH = has(hwcap_ETF3EH)
115	S390X.HasDFP = has(hwcap_DFP)
116	S390X.HasMSA = has(hwcap_MSA)
117	S390X.HasVX = has(hwcap_VX)
118	if S390X.HasVX {
119		S390X.HasVXE = has(hwcap_VXE)
120	}
121
122	// We need implementations of stfle, km and so on
123	// to detect cryptographic features.
124	if !haveAsmFunctions() {
125		return
126	}
127
128	// optional cryptographic functions
129	if S390X.HasMSA {
130		aes := []function{aes128, aes192, aes256}
131
132		// cipher message
133		km, kmc := kmQuery(), kmcQuery()
134		S390X.HasAES = km.Has(aes...)
135		S390X.HasAESCBC = kmc.Has(aes...)
136		if S390X.HasSTFLE {
137			facilities := stfle()
138			if facilities.Has(msa4) {
139				kmctr := kmctrQuery()
140				S390X.HasAESCTR = kmctr.Has(aes...)
141			}
142			if facilities.Has(msa8) {
143				kma := kmaQuery()
144				S390X.HasAESGCM = kma.Has(aes...)
145			}
146		}
147
148		// compute message digest
149		kimd := kimdQuery() // intermediate (no padding)
150		klmd := klmdQuery() // last (padding)
151		S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1)
152		S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256)
153		S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512)
154		S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist
155		sha3 := []function{
156			sha3_224, sha3_256, sha3_384, sha3_512,
157			shake128, shake256,
158		}
159		S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...)
160	}
161}
162