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