summaryrefslogtreecommitdiff
path: root/vendor/golang.org/x/sys/cpu/cpu_linux_s390x.go
blob: b88d6b8f662bd8d8968c64c5af1ae2cad5832ba6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cpu

const (
	// bit mask values from /usr/include/bits/hwcap.h
	hwcap_ZARCH  = 2
	hwcap_STFLE  = 4
	hwcap_MSA    = 8
	hwcap_LDISP  = 16
	hwcap_EIMM   = 32
	hwcap_DFP    = 64
	hwcap_ETF3EH = 256
	hwcap_VX     = 2048
	hwcap_VXE    = 8192
)

// bitIsSet reports whether the bit at index is set. The bit index
// is in big endian order, so bit index 0 is the leftmost bit.
func bitIsSet(bits []uint64, index uint) bool {
	return bits[index/64]&((1<<63)>>(index%64)) != 0
}

// function is the code for the named cryptographic function.
type function uint8

const (
	// KM{,A,C,CTR} function codes
	aes128 function = 18 // AES-128
	aes192 function = 19 // AES-192
	aes256 function = 20 // AES-256

	// K{I,L}MD function codes
	sha1     function = 1  // SHA-1
	sha256   function = 2  // SHA-256
	sha512   function = 3  // SHA-512
	sha3_224 function = 32 // SHA3-224
	sha3_256 function = 33 // SHA3-256
	sha3_384 function = 34 // SHA3-384
	sha3_512 function = 35 // SHA3-512
	shake128 function = 36 // SHAKE-128
	shake256 function = 37 // SHAKE-256

	// KLMD function codes
	ghash function = 65 // GHASH
)

// queryResult contains the result of a Query function
// call. Bits are numbered in big endian order so the
// leftmost bit (the MSB) is at index 0.
type queryResult struct {
	bits [2]uint64
}

// Has reports whether the given functions are present.
func (q *queryResult) Has(fns ...function) bool {
	if len(fns) == 0 {
		panic("no function codes provided")
	}
	for _, f := range fns {
		if !bitIsSet(q.bits[:], uint(f)) {
			return false
		}
	}
	return true
}

// facility is a bit index for the named facility.
type facility uint8

const (
	// cryptography facilities
	msa4 facility = 77  // message-security-assist extension 4
	msa8 facility = 146 // message-security-assist extension 8
)

// facilityList contains the result of an STFLE call.
// Bits are numbered in big endian order so the
// leftmost bit (the MSB) is at index 0.
type facilityList struct {
	bits [4]uint64
}

// Has reports whether the given facilities are present.
func (s *facilityList) Has(fs ...facility) bool {
	if len(fs) == 0 {
		panic("no facility bits provided")
	}
	for _, f := range fs {
		if !bitIsSet(s.bits[:], uint(f)) {
			return false
		}
	}
	return true
}

func doinit() {
	// test HWCAP bit vector
	has := func(featureMask uint) bool {
		return hwCap&featureMask == featureMask
	}

	// mandatory
	S390X.HasZARCH = has(hwcap_ZARCH)

	// optional
	S390X.HasSTFLE = has(hwcap_STFLE)
	S390X.HasLDISP = has(hwcap_LDISP)
	S390X.HasEIMM = has(hwcap_EIMM)
	S390X.HasETF3EH = has(hwcap_ETF3EH)
	S390X.HasDFP = has(hwcap_DFP)
	S390X.HasMSA = has(hwcap_MSA)
	S390X.HasVX = has(hwcap_VX)
	if S390X.HasVX {
		S390X.HasVXE = has(hwcap_VXE)
	}

	// We need implementations of stfle, km and so on
	// to detect cryptographic features.
	if !haveAsmFunctions() {
		return
	}

	// optional cryptographic functions
	if S390X.HasMSA {
		aes := []function{aes128, aes192, aes256}

		// cipher message
		km, kmc := kmQuery(), kmcQuery()
		S390X.HasAES = km.Has(aes...)
		S390X.HasAESCBC = kmc.Has(aes...)
		if S390X.HasSTFLE {
			facilities := stfle()
			if facilities.Has(msa4) {
				kmctr := kmctrQuery()
				S390X.HasAESCTR = kmctr.Has(aes...)
			}
			if facilities.Has(msa8) {
				kma := kmaQuery()
				S390X.HasAESGCM = kma.Has(aes...)
			}
		}

		// compute message digest
		kimd := kimdQuery() // intermediate (no padding)
		klmd := klmdQuery() // last (padding)
		S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1)
		S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256)
		S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512)
		S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist
		sha3 := []function{
			sha3_224, sha3_256, sha3_384, sha3_512,
			shake128, shake256,
		}
		S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...)
	}
}