mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
crypto, internal/cpu: fix s390x AES feature detection and update SHA implementations
Hardware AES support in Go on s390x currently requires ECB, CBC
and CTR modes be available. It also requires that either the
GHASH or GCM facilities are available. The existing checks missed
some of these constraints.
While we're here simplify the cpu package on s390x, moving masking
code out of assembly and into Go code. Also, update SHA-{1,256,512}
implementations to use the cpu package since that is now trivial.
Finally I also added a test for internal/cpu on s390x which loads
/proc/cpuinfo and checks it against the flags set by internal/cpu.
Updates #25822 for changes to vet whitelist.
Change-Id: Iac4183f571643209e027f730989c60a811c928eb
Reviewed-on: https://go-review.googlesource.com/114397
Run-TryBot: Michael Munday <mike.munday@ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
40fc4bbfb8
commit
7ba0c6235f
15 changed files with 319 additions and 204 deletions
|
|
@ -5,3 +5,10 @@ runtime/memclr_s390x.s: [s390x] memclr_s390x_exrl_xc: function memclr_s390x_exrl
|
||||||
runtime/memmove_s390x.s: [s390x] memmove_s390x_exrl_mvc: function memmove_s390x_exrl_mvc missing Go declaration
|
runtime/memmove_s390x.s: [s390x] memmove_s390x_exrl_mvc: function memmove_s390x_exrl_mvc missing Go declaration
|
||||||
runtime/tls_s390x.s: [s390x] save_g: function save_g missing Go declaration
|
runtime/tls_s390x.s: [s390x] save_g: function save_g missing Go declaration
|
||||||
runtime/tls_s390x.s: [s390x] load_g: function load_g missing Go declaration
|
runtime/tls_s390x.s: [s390x] load_g: function load_g missing Go declaration
|
||||||
|
internal/cpu/cpu_s390x.s: [s390x] stfle: invalid MOVD of ret+0(FP); cpu.facilityList is 32-byte value
|
||||||
|
internal/cpu/cpu_s390x.s: [s390x] kmQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
|
||||||
|
internal/cpu/cpu_s390x.s: [s390x] kmcQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
|
||||||
|
internal/cpu/cpu_s390x.s: [s390x] kmctrQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
|
||||||
|
internal/cpu/cpu_s390x.s: [s390x] kmaQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
|
||||||
|
internal/cpu/cpu_s390x.s: [s390x] kimdQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
|
||||||
|
internal/cpu/cpu_s390x.s: [s390x] klmdQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
|
||||||
|
|
|
||||||
|
|
@ -31,12 +31,11 @@ type aesCipherAsm struct {
|
||||||
func cryptBlocks(c code, key, dst, src *byte, length int)
|
func cryptBlocks(c code, key, dst, src *byte, length int)
|
||||||
|
|
||||||
func newCipher(key []byte) (cipher.Block, error) {
|
func newCipher(key []byte) (cipher.Block, error) {
|
||||||
// Strictly speaking, this check should be for HasKM.
|
// The aesCipherAsm type implements the cbcEncAble, cbcDecAble,
|
||||||
// The check for HasKMC and HasKMCTR provides compatibility
|
// ctrAble and gcmAble interfaces. We therefore need to check
|
||||||
// with the existing optimized s390x CBC and CTR implementations
|
// for all the features required to implement these modes.
|
||||||
// in this package, which already assert that they meet the
|
// Keep in sync with crypto/tls/common.go.
|
||||||
// cbcEncAble, cbcDecAble, and ctrAble interfaces
|
if !(cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)) {
|
||||||
if !(cpu.S390X.HasKM && cpu.S390X.HasKMC && cpu.S390X.HasKMCTR) {
|
|
||||||
return newCipherGeneric(key)
|
return newCipherGeneric(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ func (c *aesCipherAsm) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
|
||||||
nonceSize: nonceSize,
|
nonceSize: nonceSize,
|
||||||
tagSize: tagSize,
|
tagSize: tagSize,
|
||||||
}
|
}
|
||||||
if cpu.S390X.HasKMA {
|
if cpu.S390X.HasAESGCM {
|
||||||
g := gcmKMA{g}
|
g := gcmKMA{g}
|
||||||
return &g, nil
|
return &g, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,6 @@
|
||||||
|
|
||||||
package sha1
|
package sha1
|
||||||
|
|
||||||
// featureCheck reports whether the CPU supports the
|
import "internal/cpu"
|
||||||
// SHA-1 compute intermediate message digest (KIMD)
|
|
||||||
// function code.
|
|
||||||
func featureCheck() bool
|
|
||||||
|
|
||||||
var useAsm = featureCheck()
|
var useAsm = cpu.S390X.HasSHA1
|
||||||
|
|
|
||||||
|
|
@ -4,31 +4,17 @@
|
||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
// func featureCheck() bool
|
// func block(dig *digest, p []byte)
|
||||||
TEXT ·featureCheck(SB),NOSPLIT,$16-1
|
TEXT ·block(SB), NOSPLIT|NOFRAME, $0-32
|
||||||
LA tmp-16(SP), R1
|
MOVBZ ·useAsm(SB), R4
|
||||||
XOR R0, R0 // query function code is 0
|
LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
|
||||||
WORD $0xB93E0006 // KIMD (R6 is ignored)
|
MOVBZ $1, R0 // SHA-1 function code
|
||||||
MOVBZ tmp-16(SP), R4 // get the first byte
|
CMPBEQ R4, $0, generic
|
||||||
AND $0x40, R4 // bit 1 (big endian) for SHA-1
|
|
||||||
CMPBEQ R4, $0, nosha1
|
loop:
|
||||||
MOVB $1, ret+0(FP)
|
WORD $0xB93E0002 // KIMD R2
|
||||||
RET
|
BVS loop // continue if interrupted
|
||||||
nosha1:
|
|
||||||
MOVB $0, ret+0(FP)
|
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// func block(dig *digest, p []byte)
|
|
||||||
TEXT ·block(SB),NOSPLIT,$0-32
|
|
||||||
MOVBZ ·useAsm(SB), R4
|
|
||||||
LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
|
|
||||||
CMPBNE R4, $1, generic
|
|
||||||
MOVBZ $1, R0 // SHA-1 function code
|
|
||||||
loop:
|
|
||||||
WORD $0xB93E0002 // KIMD R2
|
|
||||||
BVS loop // continue if interrupted
|
|
||||||
done:
|
|
||||||
XOR R0, R0 // restore R0
|
|
||||||
RET
|
|
||||||
generic:
|
generic:
|
||||||
BR ·blockGeneric(SB)
|
BR ·blockGeneric(SB)
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,6 @@
|
||||||
|
|
||||||
package sha256
|
package sha256
|
||||||
|
|
||||||
// featureCheck reports whether the CPU supports the
|
import "internal/cpu"
|
||||||
// SHA256 compute intermediate message digest (KIMD)
|
|
||||||
// function code.
|
|
||||||
func featureCheck() bool
|
|
||||||
|
|
||||||
var useAsm = featureCheck()
|
var useAsm = cpu.S390X.HasSHA256
|
||||||
|
|
|
||||||
|
|
@ -4,31 +4,17 @@
|
||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
// func featureCheck() bool
|
// func block(dig *digest, p []byte)
|
||||||
TEXT ·featureCheck(SB),NOSPLIT,$16-1
|
TEXT ·block(SB), NOSPLIT|NOFRAME, $0-32
|
||||||
LA tmp-16(SP), R1
|
MOVBZ ·useAsm(SB), R4
|
||||||
XOR R0, R0 // query function code is 0
|
LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
|
||||||
WORD $0xB93E0006 // KIMD (R6 is ignored)
|
MOVBZ $2, R0 // SHA-256 function code
|
||||||
MOVBZ tmp-16(SP), R4 // get the first byte
|
CMPBEQ R4, $0, generic
|
||||||
AND $0x20, R4 // bit 2 (big endian) for SHA256
|
|
||||||
CMPBEQ R4, $0, nosha256
|
loop:
|
||||||
MOVB $1, ret+0(FP)
|
WORD $0xB93E0002 // KIMD R2
|
||||||
RET
|
BVS loop // continue if interrupted
|
||||||
nosha256:
|
|
||||||
MOVB $0, ret+0(FP)
|
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// func block(dig *digest, p []byte)
|
|
||||||
TEXT ·block(SB),NOSPLIT,$0-32
|
|
||||||
MOVBZ ·useAsm(SB), R4
|
|
||||||
LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
|
|
||||||
CMPBNE R4, $1, generic
|
|
||||||
MOVBZ $2, R0 // SHA256 function code
|
|
||||||
loop:
|
|
||||||
WORD $0xB93E0002 // KIMD R2
|
|
||||||
BVS loop // continue if interrupted
|
|
||||||
done:
|
|
||||||
XOR R0, R0 // restore R0
|
|
||||||
RET
|
|
||||||
generic:
|
generic:
|
||||||
BR ·blockGeneric(SB)
|
BR ·blockGeneric(SB)
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,6 @@
|
||||||
|
|
||||||
package sha512
|
package sha512
|
||||||
|
|
||||||
// featureCheck reports whether the CPU supports the
|
import "internal/cpu"
|
||||||
// SHA512 compute intermediate message digest (KIMD)
|
|
||||||
// function code.
|
|
||||||
func featureCheck() bool
|
|
||||||
|
|
||||||
var useAsm = featureCheck()
|
var useAsm = cpu.S390X.HasSHA512
|
||||||
|
|
|
||||||
|
|
@ -4,31 +4,17 @@
|
||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
// func featureCheck() bool
|
// func block(dig *digest, p []byte)
|
||||||
TEXT ·featureCheck(SB),NOSPLIT,$16-1
|
TEXT ·block(SB), NOSPLIT|NOFRAME, $0-32
|
||||||
LA tmp-16(SP), R1
|
MOVBZ ·useAsm(SB), R4
|
||||||
XOR R0, R0 // query function code is 0
|
LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
|
||||||
WORD $0xB93E0006 // KIMD (R6 is ignored)
|
MOVBZ $3, R0 // SHA-512 function code
|
||||||
MOVBZ tmp-16(SP), R4 // get the first byte
|
CMPBEQ R4, $0, generic
|
||||||
AND $0x10, R4 // bit 3 (big endian) for SHA512
|
|
||||||
CMPBEQ R4, $0, nosha512
|
loop:
|
||||||
MOVB $1, ret+0(FP)
|
WORD $0xB93E0002 // KIMD R2
|
||||||
RET
|
BVS loop // continue if interrupted
|
||||||
nosha512:
|
|
||||||
MOVB $0, ret+0(FP)
|
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// func block(dig *digest, p []byte)
|
|
||||||
TEXT ·block(SB),NOSPLIT,$0-32
|
|
||||||
MOVBZ ·useAsm(SB), R4
|
|
||||||
LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
|
|
||||||
CMPBNE R4, $1, generic
|
|
||||||
MOVBZ $3, R0 // SHA512 function code
|
|
||||||
loop:
|
|
||||||
WORD $0xB93E0002 // KIMD R2
|
|
||||||
BVS loop // continue if interrupted
|
|
||||||
done:
|
|
||||||
XOR R0, R0 // restore R0
|
|
||||||
RET
|
|
||||||
generic:
|
generic:
|
||||||
BR ·blockGeneric(SB)
|
BR ·blockGeneric(SB)
|
||||||
|
|
|
||||||
|
|
@ -930,7 +930,8 @@ func initDefaultCipherSuites() {
|
||||||
hasGCMAsmARM64 := false
|
hasGCMAsmARM64 := false
|
||||||
// hasGCMAsmARM64 := cpu.ARM64.HasAES && cpu.ARM64.HasPMULL
|
// hasGCMAsmARM64 := cpu.ARM64.HasAES && cpu.ARM64.HasPMULL
|
||||||
|
|
||||||
hasGCMAsmS390X := cpu.S390X.HasKM && (cpu.S390X.HasKMA || (cpu.S390X.HasKMCTR && cpu.S390X.HasKIMD))
|
// Keep in sync with crypto/aes/cipher_s390x.go.
|
||||||
|
hasGCMAsmS390X := cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)
|
||||||
|
|
||||||
hasGCMAsm := hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X
|
hasGCMAsm := hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -98,14 +98,24 @@ type arm64 struct {
|
||||||
var S390X s390x
|
var S390X s390x
|
||||||
|
|
||||||
type s390x struct {
|
type s390x struct {
|
||||||
_ [CacheLineSize]byte
|
_ [CacheLineSize]byte
|
||||||
HasVX bool // vector facility. Note: the runtime sets this when it processes auxv records.
|
HasZArch bool // z architecture mode is active [mandatory]
|
||||||
HasKM bool // cipher message (KM)
|
HasSTFLE bool // store facility list extended [mandatory]
|
||||||
HasKMA bool // cipher message assist (KMA)
|
HasLDisp bool // long (20-bit) displacements [mandatory]
|
||||||
HasKMC bool // cipher message with chaining (KMC)
|
HasEImm bool // 32-bit immediates [mandatory]
|
||||||
HasKMCTR bool // cipher message with counter (KMCTR)
|
HasDFP bool // decimal floating point
|
||||||
HasKIMD bool // compute intermediate message digest (KIMD)
|
HasETF3Enhanced bool // ETF-3 enhanced
|
||||||
_ [CacheLineSize]byte
|
HasMSA bool // message security assist (CPACF)
|
||||||
|
HasAES bool // KM-AES{128,192,256} functions
|
||||||
|
HasAESCBC bool // KMC-AES{128,192,256} functions
|
||||||
|
HasAESCTR bool // KMCTR-AES{128,192,256} functions
|
||||||
|
HasAESGCM bool // KMA-GCM-AES{128,192,256} functions
|
||||||
|
HasGHASH bool // KIMD-GHASH function
|
||||||
|
HasSHA1 bool // K{I,L}MD-SHA-1 functions
|
||||||
|
HasSHA256 bool // K{I,L}MD-SHA-256 functions
|
||||||
|
HasSHA512 bool // K{I,L}MD-SHA-512 functions
|
||||||
|
HasVX bool // vector facility. Note: the runtime sets this when it processes auxv records.
|
||||||
|
_ [CacheLineSize]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize examines the processor and sets the relevant variables above.
|
// initialize examines the processor and sets the relevant variables above.
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
// +build !arm64
|
// +build !arm64
|
||||||
// +build !ppc64
|
// +build !ppc64
|
||||||
// +build !ppc64le
|
// +build !ppc64le
|
||||||
|
// +build !s390x
|
||||||
|
|
||||||
package cpu
|
package cpu
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,17 +6,148 @@ package cpu
|
||||||
|
|
||||||
const CacheLineSize = 256
|
const CacheLineSize = 256
|
||||||
|
|
||||||
// the following cpu feature detection functions are defined in cpu_s390x.s
|
// bitIsSet reports whether the bit at index is set. The bit index
|
||||||
func hasKM() bool
|
// is in big endian order, so bit index 0 is the leftmost bit.
|
||||||
func hasKMC() bool
|
func bitIsSet(bits []uint64, index uint) bool {
|
||||||
func hasKMCTR() bool
|
return bits[index/64]&((1<<63)>>(index%64)) != 0
|
||||||
func hasKMA() bool
|
}
|
||||||
func hasKIMD() bool
|
|
||||||
|
// function is the function code for the named function.
|
||||||
func init() {
|
type function uint8
|
||||||
S390X.HasKM = hasKM()
|
|
||||||
S390X.HasKMC = hasKMC()
|
const (
|
||||||
S390X.HasKMCTR = hasKMCTR()
|
// KM{,A,C,CTR} function codes
|
||||||
S390X.HasKMA = hasKMA()
|
aes128 function = 18 // AES-128
|
||||||
S390X.HasKIMD = hasKIMD()
|
aes192 = 19 // AES-192
|
||||||
|
aes256 = 20 // AES-256
|
||||||
|
|
||||||
|
// K{I,L}MD function codes
|
||||||
|
sha1 = 1 // SHA-1
|
||||||
|
sha256 = 2 // SHA-256
|
||||||
|
sha512 = 3 // SHA-512
|
||||||
|
|
||||||
|
// KLMD function codes
|
||||||
|
ghash = 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 (
|
||||||
|
// mandatory facilities
|
||||||
|
zarch facility = 1 // z architecture mode is active
|
||||||
|
stflef = 7 // store-facility-list-extended
|
||||||
|
ldisp = 18 // long-displacement
|
||||||
|
eimm = 21 // extended-immediate
|
||||||
|
|
||||||
|
// miscellaneous facilities
|
||||||
|
dfp = 42 // decimal-floating-point
|
||||||
|
etf3eh = 30 // extended-translation 3 enhancement
|
||||||
|
|
||||||
|
// cryptography facilities
|
||||||
|
msa = 17 // message-security-assist
|
||||||
|
msa3 = 76 // message-security-assist extension 3
|
||||||
|
msa4 = 77 // message-security-assist extension 4
|
||||||
|
msa5 = 57 // message-security-assist extension 5
|
||||||
|
msa8 = 146 // message-security-assist extension 8
|
||||||
|
|
||||||
|
// Note: vx and highgprs are excluded because they require
|
||||||
|
// kernel support and so must be fetched from HWCAP.
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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 doinit() {
|
||||||
|
options = []option{
|
||||||
|
{"zarch", &S390X.HasZArch},
|
||||||
|
{"stfle", &S390X.HasSTFLE},
|
||||||
|
{"ldisp", &S390X.HasLDisp},
|
||||||
|
{"msa", &S390X.HasMSA},
|
||||||
|
{"eimm", &S390X.HasEImm},
|
||||||
|
{"dfp", &S390X.HasDFP},
|
||||||
|
{"etf3eh", &S390X.HasETF3Enhanced},
|
||||||
|
{"vx", &S390X.HasVX},
|
||||||
|
}
|
||||||
|
|
||||||
|
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.HasETF3Enhanced = 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,98 +4,52 @@
|
||||||
|
|
||||||
#include "textflag.h"
|
#include "textflag.h"
|
||||||
|
|
||||||
// func hasKM() bool
|
// func stfle() facilityList
|
||||||
TEXT ·hasKM(SB),NOSPLIT,$16-1
|
TEXT ·stfle(SB), NOSPLIT|NOFRAME, $0-32
|
||||||
XOR R0, R0 // set function code to 0 (query)
|
MOVD $ret+0(FP), R1
|
||||||
LA mask-16(SP), R1 // 16-byte stack variable for mask
|
MOVD $3, R0 // last doubleword index to store
|
||||||
MOVD $(0x38<<40), R3 // mask for bits 18-20 (big endian)
|
XC $32, (R1), (R1) // clear 4 doublewords (32 bytes)
|
||||||
|
WORD $0xb2b01000 // store facility list extended (STFLE)
|
||||||
// check for KM AES functions
|
|
||||||
WORD $0xB92E0024 // cipher message (KM)
|
|
||||||
MOVD mask-16(SP), R2
|
|
||||||
AND R3, R2
|
|
||||||
CMPBNE R2, R3, notfound
|
|
||||||
|
|
||||||
MOVB $1, ret+0(FP)
|
|
||||||
RET
|
|
||||||
notfound:
|
|
||||||
MOVB $0, ret+0(FP)
|
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// func hasKMC() bool
|
// func kmQuery() queryResult
|
||||||
TEXT ·hasKMC(SB),NOSPLIT,$16-1
|
TEXT ·kmQuery(SB), NOSPLIT|NOFRAME, $0-16
|
||||||
XOR R0, R0 // set function code to 0 (query)
|
MOVD $0, R0 // set function code to 0 (KM-Query)
|
||||||
LA mask-16(SP), R1 // 16-byte stack variable for mask
|
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
||||||
MOVD $(0x38<<40), R3 // mask for bits 18-20 (big endian)
|
WORD $0xB92E0024 // cipher message (KM)
|
||||||
|
|
||||||
// check for KMC AES functions
|
|
||||||
WORD $0xB92F0024 // cipher message with chaining (KMC)
|
|
||||||
MOVD mask-16(SP), R2
|
|
||||||
AND R3, R2
|
|
||||||
CMPBNE R2, R3, notfound
|
|
||||||
|
|
||||||
MOVB $1, ret+0(FP)
|
|
||||||
RET
|
|
||||||
notfound:
|
|
||||||
MOVB $0, ret+0(FP)
|
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// func hasKMCTR() bool
|
// func kmcQuery() queryResult
|
||||||
TEXT ·hasKMCTR(SB),NOSPLIT,$16-1
|
TEXT ·kmcQuery(SB), NOSPLIT|NOFRAME, $0-16
|
||||||
XOR R0, R0 // set function code to 0 (query)
|
MOVD $0, R0 // set function code to 0 (KMC-Query)
|
||||||
LA mask-16(SP), R1 // 16-byte stack variable for mask
|
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
||||||
MOVD $(0x38<<40), R3 // mask for bits 18-20 (big endian)
|
WORD $0xB92F0024 // cipher message with chaining (KMC)
|
||||||
|
|
||||||
// check for KMCTR AES functions
|
|
||||||
WORD $0xB92D4024 // cipher message with counter (KMCTR)
|
|
||||||
MOVD mask-16(SP), R2
|
|
||||||
AND R3, R2
|
|
||||||
CMPBNE R2, R3, notfound
|
|
||||||
|
|
||||||
MOVB $1, ret+0(FP)
|
|
||||||
RET
|
|
||||||
notfound:
|
|
||||||
MOVB $0, ret+0(FP)
|
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// func hasKMA() bool
|
// func kmctrQuery() queryResult
|
||||||
TEXT ·hasKMA(SB),NOSPLIT,$24-1
|
TEXT ·kmctrQuery(SB), NOSPLIT|NOFRAME, $0-16
|
||||||
MOVD $tmp-24(SP), R1
|
MOVD $0, R0 // set function code to 0 (KMCTR-Query)
|
||||||
MOVD $2, R0 // store 24-bytes
|
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
||||||
XC $24, (R1), (R1)
|
WORD $0xB92D4024 // cipher message with counter (KMCTR)
|
||||||
WORD $0xb2b01000 // STFLE (R1)
|
|
||||||
MOVWZ 16(R1), R2
|
|
||||||
ANDW $(1<<13), R2 // test bit 146 (message-security-assist 8)
|
|
||||||
BEQ no
|
|
||||||
|
|
||||||
MOVD $0, R0 // KMA-Query
|
|
||||||
XC $16, (R1), (R1)
|
|
||||||
WORD $0xb9296024 // kma %r6,%r2,%r4
|
|
||||||
MOVWZ (R1), R2
|
|
||||||
WORD $0xa7213800 // TMLL R2, $0x3800
|
|
||||||
BVS yes
|
|
||||||
no:
|
|
||||||
MOVB $0, ret+0(FP)
|
|
||||||
RET
|
|
||||||
yes:
|
|
||||||
MOVB $1, ret+0(FP)
|
|
||||||
RET
|
RET
|
||||||
|
|
||||||
// func hasKIMD() bool
|
// func kmaQuery() queryResult
|
||||||
TEXT ·hasKIMD(SB),NOSPLIT,$16-1
|
TEXT ·kmaQuery(SB), NOSPLIT|NOFRAME, $0-16
|
||||||
XOR R0, R0 // set function code to 0 (query)
|
MOVD $0, R0 // set function code to 0 (KMA-Query)
|
||||||
LA mask-16(SP), R1 // 16-byte stack variable for mask
|
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
||||||
MOVD $(0x38<<40), R3 // mask for bits 18-20 (big endian)
|
WORD $0xb9296024 // cipher message with authentication (KMA)
|
||||||
|
|
||||||
// check for KIMD GHASH function
|
|
||||||
WORD $0xB93E0024 // compute intermediate message digest (KIMD)
|
|
||||||
MOVD mask-8(SP), R2 // bits 64-127
|
|
||||||
MOVD $(1<<62), R5
|
|
||||||
AND R5, R2
|
|
||||||
CMPBNE R2, R5, notfound
|
|
||||||
|
|
||||||
MOVB $1, ret+0(FP)
|
|
||||||
RET
|
RET
|
||||||
notfound:
|
|
||||||
MOVB $0, ret+0(FP)
|
// func kimdQuery() queryResult
|
||||||
|
TEXT ·kimdQuery(SB), NOSPLIT|NOFRAME, $0-16
|
||||||
|
MOVD $0, R0 // set function code to 0 (KIMD-Query)
|
||||||
|
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
||||||
|
WORD $0xB93E0024 // compute intermediate message digest (KIMD)
|
||||||
|
RET
|
||||||
|
|
||||||
|
// func klmdQuery() queryResult
|
||||||
|
TEXT ·klmdQuery(SB), NOSPLIT|NOFRAME, $0-16
|
||||||
|
MOVD $0, R0 // set function code to 0 (KLMD-Query)
|
||||||
|
MOVD $ret+0(FP), R1 // address of 16-byte return value
|
||||||
|
WORD $0xB93F0024 // compute last message digest (KLMD)
|
||||||
RET
|
RET
|
||||||
|
|
|
||||||
63
src/internal/cpu/cpu_s390x_test.go
Normal file
63
src/internal/cpu/cpu_s390x_test.go
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
// Copyright 2018 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_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
. "internal/cpu"
|
||||||
|
"io/ioutil"
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getFeatureList() ([]string, error) {
|
||||||
|
cpuinfo, err := ioutil.ReadFile("/proc/cpuinfo")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r := regexp.MustCompile("features\\s*:\\s*(.*)")
|
||||||
|
b := r.FindSubmatch(cpuinfo)
|
||||||
|
if len(b) < 2 {
|
||||||
|
return nil, errors.New("no feature list in /proc/cpuinfo")
|
||||||
|
}
|
||||||
|
return regexp.MustCompile("\\s+").Split(string(b[1]), -1), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestS390XAgainstCPUInfo(t *testing.T) {
|
||||||
|
// mapping of linux feature strings to S390X fields
|
||||||
|
mapping := make(map[string]*bool)
|
||||||
|
for _, option := range Options {
|
||||||
|
mapping[option.Name] = option.Feature
|
||||||
|
}
|
||||||
|
|
||||||
|
// these must be true on the machines Go supports
|
||||||
|
mandatory := make(map[string]bool)
|
||||||
|
mandatory["zarch"] = false
|
||||||
|
mandatory["eimm"] = false
|
||||||
|
mandatory["ldisp"] = false
|
||||||
|
mandatory["stfle"] = false
|
||||||
|
|
||||||
|
features, err := getFeatureList()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
for _, feature := range features {
|
||||||
|
if _, ok := mandatory[feature]; ok {
|
||||||
|
mandatory[feature] = true
|
||||||
|
}
|
||||||
|
if flag, ok := mapping[feature]; ok {
|
||||||
|
if !*flag {
|
||||||
|
t.Errorf("feature '%v' not detected", feature)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Logf("no entry for '%v'", feature)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for k, v := range mandatory {
|
||||||
|
if !v {
|
||||||
|
t.Errorf("mandatory feature '%v' not detected", k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue