blob: 45d8ed27f07564ccc96c96f57008de926105ddc4 [file] [log] [blame]
// Copyright 2017 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 CacheLinePadSize = 256
var HWCap uint
// 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 function code for the named 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
)
const (
// KDSA function codes
ecdsaVerifyP256 function = 1 // NIST P256
ecdsaVerifyP384 function = 2 // NIST P384
ecdsaVerifyP521 function = 3 // NIST P521
ecdsaSignP256 function = 9 // NIST P256
ecdsaSignP384 function = 10 // NIST P384
ecdsaSignP521 function = 11 // NIST P521
eddsaVerifyEd25519 function = 32 // Curve25519
eddsaVerifyEd448 function = 36 // Curve448
eddsaSignEd25519 function = 40 // Curve25519
eddsaSignEd448 function = 44 // Curve448
)
// 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 (
// mandatory facilities
zarch facility = 1 // z architecture mode is active
stflef facility = 7 // store-facility-list-extended
ldisp facility = 18 // long-displacement
eimm facility = 21 // extended-immediate
// miscellaneous facilities
dfp facility = 42 // decimal-floating-point
etf3eh facility = 30 // extended-translation 3 enhancement
// cryptography facilities
msa facility = 17 // message-security-assist
msa3 facility = 76 // message-security-assist extension 3
msa4 facility = 77 // message-security-assist extension 4
msa5 facility = 57 // message-security-assist extension 5
msa8 facility = 146 // message-security-assist extension 8
msa9 facility = 155 // message-security-assist extension 9
// vector facilities
vxe facility = 135 // vector-enhancements 1
// Note: vx requires kernel support
// and so must be fetched from HWCAP.
hwcap_VX = 1 << 11 // vector facility
)
// 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
}
// The following feature detection functions are defined in cpu_s390x.s.
// They are likely to be expensive to call so the results should be cached.
func stfle() facilityList
func kmQuery() queryResult
func kmcQuery() queryResult
func kmctrQuery() queryResult
func kmaQuery() queryResult
func kimdQuery() queryResult
func klmdQuery() queryResult
func kdsaQuery() queryResult
func doinit() {
options = []option{
{Name: "zarch", Feature: &S390X.HasZARCH},
{Name: "stfle", Feature: &S390X.HasSTFLE},
{Name: "ldisp", Feature: &S390X.HasLDISP},
{Name: "msa", Feature: &S390X.HasMSA},
{Name: "eimm", Feature: &S390X.HasEIMM},
{Name: "dfp", Feature: &S390X.HasDFP},
{Name: "etf3eh", Feature: &S390X.HasETF3EH},
{Name: "vx", Feature: &S390X.HasVX},
{Name: "vxe", Feature: &S390X.HasVXE},
{Name: "kdsa", Feature: &S390X.HasKDSA},
}
aes := []function{aes128, aes192, aes256}
facilities := stfle()
S390X.HasZARCH = facilities.Has(zarch)
S390X.HasSTFLE = facilities.Has(stflef)
S390X.HasLDISP = facilities.Has(ldisp)
S390X.HasEIMM = facilities.Has(eimm)
S390X.HasDFP = facilities.Has(dfp)
S390X.HasETF3EH = facilities.Has(etf3eh)
S390X.HasMSA = facilities.Has(msa)
if S390X.HasMSA {
// cipher message
km, kmc := kmQuery(), kmcQuery()
S390X.HasAES = km.Has(aes...)
S390X.HasAESCBC = kmc.Has(aes...)
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...)
S390X.HasKDSA = facilities.Has(msa9) // elliptic curves
if S390X.HasKDSA {
kdsa := kdsaQuery()
S390X.HasECDSA = kdsa.Has(ecdsaVerifyP256, ecdsaSignP256, ecdsaVerifyP384, ecdsaSignP384, ecdsaVerifyP521, ecdsaSignP521)
S390X.HasEDDSA = kdsa.Has(eddsaVerifyEd25519, eddsaSignEd25519, eddsaVerifyEd448, eddsaSignEd448)
}
}
S390X.HasVX = isSet(HWCap, hwcap_VX)
if S390X.HasVX {
S390X.HasVXE = facilities.Has(vxe)
}
}
func isSet(hwc uint, value uint) bool {
return hwc&value != 0
}