@@ -907,6 +907,7 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL | |||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= | |||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY= | |||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= | |||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= | |||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= | |||
golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
@@ -927,6 +928,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ | |||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o= | |||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= | |||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
@@ -971,6 +973,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= | |||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | |||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= | |||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | |||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | |||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | |||
@@ -97,6 +97,7 @@ package module | |||
import ( | |||
"fmt" | |||
"path" | |||
"sort" | |||
"strings" | |||
"unicode" | |||
@@ -223,14 +224,18 @@ func firstPathOK(r rune) bool { | |||
'a' <= r && r <= 'z' | |||
} | |||
// pathOK reports whether r can appear in an import path element. | |||
// Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: + - . _ and ~. | |||
// This matches what "go get" has historically recognized in import paths. | |||
// modPathOK reports whether r can appear in a module path element. | |||
// Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~. | |||
// | |||
// This matches what "go get" has historically recognized in import paths, | |||
// and avoids confusing sequences like '%20' or '+' that would change meaning | |||
// if used in a URL. | |||
// | |||
// TODO(rsc): We would like to allow Unicode letters, but that requires additional | |||
// care in the safe encoding (see "escaped paths" above). | |||
func pathOK(r rune) bool { | |||
func modPathOK(r rune) bool { | |||
if r < utf8.RuneSelf { | |||
return r == '+' || r == '-' || r == '.' || r == '_' || r == '~' || | |||
return r == '-' || r == '.' || r == '_' || r == '~' || | |||
'0' <= r && r <= '9' || | |||
'A' <= r && r <= 'Z' || | |||
'a' <= r && r <= 'z' | |||
@@ -238,6 +243,17 @@ func pathOK(r rune) bool { | |||
return false | |||
} | |||
// modPathOK reports whether r can appear in a package import path element. | |||
// | |||
// Import paths are intermediate between module paths and file paths: we allow | |||
// disallow characters that would be confusing or ambiguous as arguments to | |||
// 'go get' (such as '@' and ' ' ), but allow certain characters that are | |||
// otherwise-unambiguous on the command line and historically used for some | |||
// binary names (such as '++' as a suffix for compiler binaries and wrappers). | |||
func importPathOK(r rune) bool { | |||
return modPathOK(r) || r == '+' | |||
} | |||
// fileNameOK reports whether r can appear in a file name. | |||
// For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters. | |||
// If we expand the set of allowed characters here, we have to | |||
@@ -269,7 +285,7 @@ func fileNameOK(r rune) bool { | |||
// CheckPath checks that a module path is valid. | |||
// A valid module path is a valid import path, as checked by CheckImportPath, | |||
// with two additional constraints. | |||
// with three additional constraints. | |||
// First, the leading path element (up to the first slash, if any), | |||
// by convention a domain name, must contain only lower-case ASCII letters, | |||
// ASCII digits, dots (U+002E), and dashes (U+002D); | |||
@@ -279,8 +295,9 @@ func fileNameOK(r rune) bool { | |||
// and must not contain any dots. For paths beginning with "gopkg.in/", | |||
// this second requirement is replaced by a requirement that the path | |||
// follow the gopkg.in server's conventions. | |||
// Third, no path element may begin with a dot. | |||
func CheckPath(path string) error { | |||
if err := checkPath(path, false); err != nil { | |||
if err := checkPath(path, modulePath); err != nil { | |||
return fmt.Errorf("malformed module path %q: %v", path, err) | |||
} | |||
i := strings.Index(path, "/") | |||
@@ -313,29 +330,41 @@ func CheckPath(path string) error { | |||
// separated by slashes (U+002F). (It must not begin with nor end in a slash.) | |||
// | |||
// A valid path element is a non-empty string made up of | |||
// ASCII letters, ASCII digits, and limited ASCII punctuation: + - . _ and ~. | |||
// It must not begin or end with a dot (U+002E), nor contain two dots in a row. | |||
// ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~. | |||
// It must not end with a dot (U+002E), nor contain two dots in a row. | |||
// | |||
// The element prefix up to the first dot must not be a reserved file name | |||
// on Windows, regardless of case (CON, com1, NuL, and so on). | |||
// on Windows, regardless of case (CON, com1, NuL, and so on). The element | |||
// must not have a suffix of a tilde followed by one or more ASCII digits | |||
// (to exclude paths elements that look like Windows short-names). | |||
// | |||
// CheckImportPath may be less restrictive in the future, but see the | |||
// top-level package documentation for additional information about | |||
// subtleties of Unicode. | |||
func CheckImportPath(path string) error { | |||
if err := checkPath(path, false); err != nil { | |||
if err := checkPath(path, importPath); err != nil { | |||
return fmt.Errorf("malformed import path %q: %v", path, err) | |||
} | |||
return nil | |||
} | |||
// pathKind indicates what kind of path we're checking. Module paths, | |||
// import paths, and file paths have different restrictions. | |||
type pathKind int | |||
const ( | |||
modulePath pathKind = iota | |||
importPath | |||
filePath | |||
) | |||
// checkPath checks that a general path is valid. | |||
// It returns an error describing why but not mentioning path. | |||
// Because these checks apply to both module paths and import paths, | |||
// the caller is expected to add the "malformed ___ path %q: " prefix. | |||
// fileName indicates whether the final element of the path is a file name | |||
// (as opposed to a directory name). | |||
func checkPath(path string, fileName bool) error { | |||
func checkPath(path string, kind pathKind) error { | |||
if !utf8.ValidString(path) { | |||
return fmt.Errorf("invalid UTF-8") | |||
} | |||
@@ -354,39 +383,45 @@ func checkPath(path string, fileName bool) error { | |||
elemStart := 0 | |||
for i, r := range path { | |||
if r == '/' { | |||
if err := checkElem(path[elemStart:i], fileName); err != nil { | |||
if err := checkElem(path[elemStart:i], kind); err != nil { | |||
return err | |||
} | |||
elemStart = i + 1 | |||
} | |||
} | |||
if err := checkElem(path[elemStart:], fileName); err != nil { | |||
if err := checkElem(path[elemStart:], kind); err != nil { | |||
return err | |||
} | |||
return nil | |||
} | |||
// checkElem checks whether an individual path element is valid. | |||
// fileName indicates whether the element is a file name (not a directory name). | |||
func checkElem(elem string, fileName bool) error { | |||
func checkElem(elem string, kind pathKind) error { | |||
if elem == "" { | |||
return fmt.Errorf("empty path element") | |||
} | |||
if strings.Count(elem, ".") == len(elem) { | |||
return fmt.Errorf("invalid path element %q", elem) | |||
} | |||
if elem[0] == '.' && !fileName { | |||
if elem[0] == '.' && kind == modulePath { | |||
return fmt.Errorf("leading dot in path element") | |||
} | |||
if elem[len(elem)-1] == '.' { | |||
return fmt.Errorf("trailing dot in path element") | |||
} | |||
charOK := pathOK | |||
if fileName { | |||
charOK = fileNameOK | |||
} | |||
for _, r := range elem { | |||
if !charOK(r) { | |||
ok := false | |||
switch kind { | |||
case modulePath: | |||
ok = modPathOK(r) | |||
case importPath: | |||
ok = importPathOK(r) | |||
case filePath: | |||
ok = fileNameOK(r) | |||
default: | |||
panic(fmt.Sprintf("internal error: invalid kind %v", kind)) | |||
} | |||
if !ok { | |||
return fmt.Errorf("invalid char %q", r) | |||
} | |||
} | |||
@@ -402,6 +437,29 @@ func checkElem(elem string, fileName bool) error { | |||
return fmt.Errorf("%q disallowed as path element component on Windows", short) | |||
} | |||
} | |||
if kind == filePath { | |||
// don't check for Windows short-names in file names. They're | |||
// only an issue for import paths. | |||
return nil | |||
} | |||
// Reject path components that look like Windows short-names. | |||
// Those usually end in a tilde followed by one or more ASCII digits. | |||
if tilde := strings.LastIndexByte(short, '~'); tilde >= 0 && tilde < len(short)-1 { | |||
suffix := short[tilde+1:] | |||
suffixIsDigits := true | |||
for _, r := range suffix { | |||
if r < '0' || r > '9' { | |||
suffixIsDigits = false | |||
break | |||
} | |||
} | |||
if suffixIsDigits { | |||
return fmt.Errorf("trailing tilde and digits in path element") | |||
} | |||
} | |||
return nil | |||
} | |||
@@ -418,7 +476,7 @@ func checkElem(elem string, fileName bool) error { | |||
// top-level package documentation for additional information about | |||
// subtleties of Unicode. | |||
func CheckFilePath(path string) error { | |||
if err := checkPath(path, true); err != nil { | |||
if err := checkPath(path, filePath); err != nil { | |||
return fmt.Errorf("malformed file path %q: %v", path, err) | |||
} | |||
return nil | |||
@@ -621,7 +679,7 @@ func EscapePath(path string) (escaped string, err error) { | |||
// Versions are allowed to be in non-semver form but must be valid file names | |||
// and not contain exclamation marks. | |||
func EscapeVersion(v string) (escaped string, err error) { | |||
if err := checkElem(v, true); err != nil || strings.Contains(v, "!") { | |||
if err := checkElem(v, filePath); err != nil || strings.Contains(v, "!") { | |||
return "", &InvalidVersionError{ | |||
Version: v, | |||
Err: fmt.Errorf("disallowed version string"), | |||
@@ -680,7 +738,7 @@ func UnescapeVersion(escaped string) (v string, err error) { | |||
if !ok { | |||
return "", fmt.Errorf("invalid escaped version %q", escaped) | |||
} | |||
if err := checkElem(v, true); err != nil { | |||
if err := checkElem(v, filePath); err != nil { | |||
return "", fmt.Errorf("invalid escaped version %q: %v", v, err) | |||
} | |||
return v, nil | |||
@@ -716,3 +774,49 @@ func unescapeString(escaped string) (string, bool) { | |||
} | |||
return string(buf), true | |||
} | |||
// MatchPrefixPatterns reports whether any path prefix of target matches one of | |||
// the glob patterns (as defined by path.Match) in the comma-separated globs | |||
// list. This implements the algorithm used when matching a module path to the | |||
// GOPRIVATE environment variable, as described by 'go help module-private'. | |||
// | |||
// It ignores any empty or malformed patterns in the list. | |||
func MatchPrefixPatterns(globs, target string) bool { | |||
for globs != "" { | |||
// Extract next non-empty glob in comma-separated list. | |||
var glob string | |||
if i := strings.Index(globs, ","); i >= 0 { | |||
glob, globs = globs[:i], globs[i+1:] | |||
} else { | |||
glob, globs = globs, "" | |||
} | |||
if glob == "" { | |||
continue | |||
} | |||
// A glob with N+1 path elements (N slashes) needs to be matched | |||
// against the first N+1 path elements of target, | |||
// which end just before the N+1'th slash. | |||
n := strings.Count(glob, "/") | |||
prefix := target | |||
// Walk target, counting slashes, truncating at the N+1'th slash. | |||
for i := 0; i < len(target); i++ { | |||
if target[i] == '/' { | |||
if n == 0 { | |||
prefix = target[:i] | |||
break | |||
} | |||
n-- | |||
} | |||
} | |||
if n > 0 { | |||
// Not enough prefix elements. | |||
continue | |||
} | |||
matched, _ := path.Match(glob, prefix) | |||
if matched { | |||
return true | |||
} | |||
} | |||
return false | |||
} |
@@ -138,6 +138,9 @@ func Compare(v, w string) int { | |||
// Max canonicalizes its arguments and then returns the version string | |||
// that compares greater. | |||
// | |||
// Deprecated: use Compare instead. In most cases, returning a canonicalized | |||
// version is not expected or desired. | |||
func Max(v, w string) string { | |||
v = Canonical(v) | |||
w = Canonical(w) | |||
@@ -2,6 +2,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build go1.7 | |||
// +build go1.7 | |||
package context | |||
@@ -2,6 +2,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build go1.9 | |||
// +build go1.9 | |||
package context | |||
@@ -2,6 +2,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build !go1.7 | |||
// +build !go1.7 | |||
package context | |||
@@ -2,6 +2,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build !go1.9 | |||
// +build !go1.9 | |||
package context | |||
@@ -52,7 +52,7 @@ var isSpecialElementMap = map[string]bool{ | |||
"iframe": true, | |||
"img": true, | |||
"input": true, | |||
"keygen": true, | |||
"keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility. | |||
"li": true, | |||
"link": true, | |||
"listing": true, | |||
@@ -161,65 +161,62 @@ var mathMLAttributeAdjustments = map[string]string{ | |||
} | |||
var svgAttributeAdjustments = map[string]string{ | |||
"attributename": "attributeName", | |||
"attributetype": "attributeType", | |||
"basefrequency": "baseFrequency", | |||
"baseprofile": "baseProfile", | |||
"calcmode": "calcMode", | |||
"clippathunits": "clipPathUnits", | |||
"contentscripttype": "contentScriptType", | |||
"contentstyletype": "contentStyleType", | |||
"diffuseconstant": "diffuseConstant", | |||
"edgemode": "edgeMode", | |||
"externalresourcesrequired": "externalResourcesRequired", | |||
"filterunits": "filterUnits", | |||
"glyphref": "glyphRef", | |||
"gradienttransform": "gradientTransform", | |||
"gradientunits": "gradientUnits", | |||
"kernelmatrix": "kernelMatrix", | |||
"kernelunitlength": "kernelUnitLength", | |||
"keypoints": "keyPoints", | |||
"keysplines": "keySplines", | |||
"keytimes": "keyTimes", | |||
"lengthadjust": "lengthAdjust", | |||
"limitingconeangle": "limitingConeAngle", | |||
"markerheight": "markerHeight", | |||
"markerunits": "markerUnits", | |||
"markerwidth": "markerWidth", | |||
"maskcontentunits": "maskContentUnits", | |||
"maskunits": "maskUnits", | |||
"numoctaves": "numOctaves", | |||
"pathlength": "pathLength", | |||
"patterncontentunits": "patternContentUnits", | |||
"patterntransform": "patternTransform", | |||
"patternunits": "patternUnits", | |||
"pointsatx": "pointsAtX", | |||
"pointsaty": "pointsAtY", | |||
"pointsatz": "pointsAtZ", | |||
"preservealpha": "preserveAlpha", | |||
"preserveaspectratio": "preserveAspectRatio", | |||
"primitiveunits": "primitiveUnits", | |||
"refx": "refX", | |||
"refy": "refY", | |||
"repeatcount": "repeatCount", | |||
"repeatdur": "repeatDur", | |||
"requiredextensions": "requiredExtensions", | |||
"requiredfeatures": "requiredFeatures", | |||
"specularconstant": "specularConstant", | |||
"specularexponent": "specularExponent", | |||
"spreadmethod": "spreadMethod", | |||
"startoffset": "startOffset", | |||
"stddeviation": "stdDeviation", | |||
"stitchtiles": "stitchTiles", | |||
"surfacescale": "surfaceScale", | |||
"systemlanguage": "systemLanguage", | |||
"tablevalues": "tableValues", | |||
"targetx": "targetX", | |||
"targety": "targetY", | |||
"textlength": "textLength", | |||
"viewbox": "viewBox", | |||
"viewtarget": "viewTarget", | |||
"xchannelselector": "xChannelSelector", | |||
"ychannelselector": "yChannelSelector", | |||
"zoomandpan": "zoomAndPan", | |||
"attributename": "attributeName", | |||
"attributetype": "attributeType", | |||
"basefrequency": "baseFrequency", | |||
"baseprofile": "baseProfile", | |||
"calcmode": "calcMode", | |||
"clippathunits": "clipPathUnits", | |||
"diffuseconstant": "diffuseConstant", | |||
"edgemode": "edgeMode", | |||
"filterunits": "filterUnits", | |||
"glyphref": "glyphRef", | |||
"gradienttransform": "gradientTransform", | |||
"gradientunits": "gradientUnits", | |||
"kernelmatrix": "kernelMatrix", | |||
"kernelunitlength": "kernelUnitLength", | |||
"keypoints": "keyPoints", | |||
"keysplines": "keySplines", | |||
"keytimes": "keyTimes", | |||
"lengthadjust": "lengthAdjust", | |||
"limitingconeangle": "limitingConeAngle", | |||
"markerheight": "markerHeight", | |||
"markerunits": "markerUnits", | |||
"markerwidth": "markerWidth", | |||
"maskcontentunits": "maskContentUnits", | |||
"maskunits": "maskUnits", | |||
"numoctaves": "numOctaves", | |||
"pathlength": "pathLength", | |||
"patterncontentunits": "patternContentUnits", | |||
"patterntransform": "patternTransform", | |||
"patternunits": "patternUnits", | |||
"pointsatx": "pointsAtX", | |||
"pointsaty": "pointsAtY", | |||
"pointsatz": "pointsAtZ", | |||
"preservealpha": "preserveAlpha", | |||
"preserveaspectratio": "preserveAspectRatio", | |||
"primitiveunits": "primitiveUnits", | |||
"refx": "refX", | |||
"refy": "refY", | |||
"repeatcount": "repeatCount", | |||
"repeatdur": "repeatDur", | |||
"requiredextensions": "requiredExtensions", | |||
"requiredfeatures": "requiredFeatures", | |||
"specularconstant": "specularConstant", | |||
"specularexponent": "specularExponent", | |||
"spreadmethod": "spreadMethod", | |||
"startoffset": "startOffset", | |||
"stddeviation": "stdDeviation", | |||
"stitchtiles": "stitchTiles", | |||
"surfacescale": "surfaceScale", | |||
"systemlanguage": "systemLanguage", | |||
"tablevalues": "tableValues", | |||
"targetx": "targetX", | |||
"targety": "targetY", | |||
"textlength": "textLength", | |||
"viewbox": "viewBox", | |||
"viewtarget": "viewTarget", | |||
"xchannelselector": "xChannelSelector", | |||
"ychannelselector": "yChannelSelector", | |||
"zoomandpan": "zoomAndPan", | |||
} |
@@ -728,7 +728,13 @@ func inHeadNoscriptIM(p *parser) bool { | |||
return inBodyIM(p) | |||
case a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Style: | |||
return inHeadIM(p) | |||
case a.Head, a.Noscript: | |||
case a.Head: | |||
// Ignore the token. | |||
return true | |||
case a.Noscript: | |||
// Don't let the tokenizer go into raw text mode even when a <noscript> | |||
// tag is in "in head noscript" insertion mode. | |||
p.tokenizer.NextIsNotRawText() | |||
// Ignore the token. | |||
return true | |||
} | |||
@@ -1790,6 +1796,13 @@ func inSelectIM(p *parser) bool { | |||
return true | |||
case a.Script, a.Template: | |||
return inHeadIM(p) | |||
case a.Iframe, a.Noembed, a.Noframes, a.Noscript, a.Plaintext, a.Style, a.Title, a.Xmp: | |||
// Don't let the tokenizer go into raw text mode when there are raw tags | |||
// to be ignored. These tags should be ignored from the tokenizer | |||
// properly. | |||
p.tokenizer.NextIsNotRawText() | |||
// Ignore the token. | |||
return true | |||
} | |||
case EndTagToken: | |||
switch p.tok.DataAtom { | |||
@@ -263,7 +263,7 @@ var voidElements = map[string]bool{ | |||
"hr": true, | |||
"img": true, | |||
"input": true, | |||
"keygen": true, | |||
"keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility. | |||
"link": true, | |||
"meta": true, | |||
"param": true, | |||
@@ -2,6 +2,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build go1.11 | |||
// +build go1.11 | |||
package http2 | |||
@@ -2,6 +2,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build !go1.11 | |||
// +build !go1.11 | |||
package http2 | |||
@@ -1293,7 +1293,9 @@ func (sc *serverConn) startGracefulShutdown() { | |||
sc.shutdownOnce.Do(func() { sc.sendServeMsg(gracefulShutdownMsg) }) | |||
} | |||
// After sending GOAWAY, the connection will close after goAwayTimeout. | |||
// After sending GOAWAY with an error code (non-graceful shutdown), the | |||
// connection will close after goAwayTimeout. | |||
// | |||
// If we close the connection immediately after sending GOAWAY, there may | |||
// be unsent data in our kernel receive buffer, which will cause the kernel | |||
// to send a TCP RST on close() instead of a FIN. This RST will abort the | |||
@@ -1629,23 +1631,37 @@ func (sc *serverConn) processSettingInitialWindowSize(val uint32) error { | |||
func (sc *serverConn) processData(f *DataFrame) error { | |||
sc.serveG.check() | |||
if sc.inGoAway && sc.goAwayCode != ErrCodeNo { | |||
id := f.Header().StreamID | |||
if sc.inGoAway && (sc.goAwayCode != ErrCodeNo || id > sc.maxClientStreamID) { | |||
// Discard all DATA frames if the GOAWAY is due to an | |||
// error, or: | |||
// | |||
// Section 6.8: After sending a GOAWAY frame, the sender | |||
// can discard frames for streams initiated by the | |||
// receiver with identifiers higher than the identified | |||
// last stream. | |||
return nil | |||
} | |||
data := f.Data() | |||
// "If a DATA frame is received whose stream is not in "open" | |||
// or "half closed (local)" state, the recipient MUST respond | |||
// with a stream error (Section 5.4.2) of type STREAM_CLOSED." | |||
id := f.Header().StreamID | |||
data := f.Data() | |||
state, st := sc.state(id) | |||
if id == 0 || state == stateIdle { | |||
// Section 6.1: "DATA frames MUST be associated with a | |||
// stream. If a DATA frame is received whose stream | |||
// identifier field is 0x0, the recipient MUST respond | |||
// with a connection error (Section 5.4.1) of type | |||
// PROTOCOL_ERROR." | |||
// | |||
// Section 5.1: "Receiving any frame other than HEADERS | |||
// or PRIORITY on a stream in this state MUST be | |||
// treated as a connection error (Section 5.4.1) of | |||
// type PROTOCOL_ERROR." | |||
return ConnectionError(ErrCodeProtocol) | |||
} | |||
// "If a DATA frame is received whose stream is not in "open" | |||
// or "half closed (local)" state, the recipient MUST respond | |||
// with a stream error (Section 5.4.2) of type STREAM_CLOSED." | |||
if st == nil || state != stateOpen || st.gotTrailerHeader || st.resetQueued { | |||
// This includes sending a RST_STREAM if the stream is | |||
// in stateHalfClosedLocal (which currently means that | |||
@@ -1694,6 +1710,7 @@ func (sc *serverConn) processData(f *DataFrame) error { | |||
if len(data) > 0 { | |||
wrote, err := st.body.Write(data) | |||
if err != nil { | |||
sc.sendWindowUpdate(nil, int(f.Length)-wrote) | |||
return streamError(id, ErrCodeStreamClosed) | |||
} | |||
if wrote != len(data) { | |||
@@ -2020,7 +2037,11 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res | |||
} | |||
if bodyOpen { | |||
if vv, ok := rp.header["Content-Length"]; ok { | |||
req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64) | |||
if cl, err := strconv.ParseUint(vv[0], 10, 63); err == nil { | |||
req.ContentLength = int64(cl) | |||
} else { | |||
req.ContentLength = 0 | |||
} | |||
} else { | |||
req.ContentLength = -1 | |||
} | |||
@@ -2403,9 +2424,8 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { | |||
var ctype, clen string | |||
if clen = rws.snapHeader.Get("Content-Length"); clen != "" { | |||
rws.snapHeader.Del("Content-Length") | |||
clen64, err := strconv.ParseInt(clen, 10, 64) | |||
if err == nil && clen64 >= 0 { | |||
rws.sentContentLen = clen64 | |||
if cl, err := strconv.ParseUint(clen, 10, 63); err == nil { | |||
rws.sentContentLen = int64(cl) | |||
} else { | |||
clen = "" | |||
} | |||
@@ -108,6 +108,19 @@ type Transport struct { | |||
// waiting for their turn. | |||
StrictMaxConcurrentStreams bool | |||
// ReadIdleTimeout is the timeout after which a health check using ping | |||
// frame will be carried out if no frame is received on the connection. | |||
// Note that a ping response will is considered a received frame, so if | |||
// there is no other traffic on the connection, the health check will | |||
// be performed every ReadIdleTimeout interval. | |||
// If zero, no health check is performed. | |||
ReadIdleTimeout time.Duration | |||
// PingTimeout is the timeout after which the connection will be closed | |||
// if a response to Ping is not received. | |||
// Defaults to 15s. | |||
PingTimeout time.Duration | |||
// t1, if non-nil, is the standard library Transport using | |||
// this transport. Its settings are used (but not its | |||
// RoundTrip method, etc). | |||
@@ -131,14 +144,31 @@ func (t *Transport) disableCompression() bool { | |||
return t.DisableCompression || (t.t1 != nil && t.t1.DisableCompression) | |||
} | |||
func (t *Transport) pingTimeout() time.Duration { | |||
if t.PingTimeout == 0 { | |||
return 15 * time.Second | |||
} | |||
return t.PingTimeout | |||
} | |||
// ConfigureTransport configures a net/http HTTP/1 Transport to use HTTP/2. | |||
// It returns an error if t1 has already been HTTP/2-enabled. | |||
// | |||
// Use ConfigureTransports instead to configure the HTTP/2 Transport. | |||
func ConfigureTransport(t1 *http.Transport) error { | |||
_, err := configureTransport(t1) | |||
_, err := ConfigureTransports(t1) | |||
return err | |||
} | |||
func configureTransport(t1 *http.Transport) (*Transport, error) { | |||
// ConfigureTransports configures a net/http HTTP/1 Transport to use HTTP/2. | |||
// It returns a new HTTP/2 Transport for further configuration. | |||
// It returns an error if t1 has already been HTTP/2-enabled. | |||
func ConfigureTransports(t1 *http.Transport) (*Transport, error) { | |||
return configureTransports(t1) | |||
} | |||
func configureTransports(t1 *http.Transport) (*Transport, error) { | |||
connPool := new(clientConnPool) | |||
t2 := &Transport{ | |||
ConnPool: noDialClientConnPool{connPool}, | |||
@@ -668,6 +698,7 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro | |||
cc.inflow.add(transportDefaultConnFlow + initialWindowSize) | |||
cc.bw.Flush() | |||
if cc.werr != nil { | |||
cc.Close() | |||
return nil, cc.werr | |||
} | |||
@@ -675,6 +706,20 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro | |||
return cc, nil | |||
} | |||
func (cc *ClientConn) healthCheck() { | |||
pingTimeout := cc.t.pingTimeout() | |||
// We don't need to periodically ping in the health check, because the readLoop of ClientConn will | |||
// trigger the healthCheck again if there is no frame received. | |||
ctx, cancel := context.WithTimeout(context.Background(), pingTimeout) | |||
defer cancel() | |||
err := cc.Ping(ctx) | |||
if err != nil { | |||
cc.closeForLostPing() | |||
cc.t.connPool().MarkDead(cc) | |||
return | |||
} | |||
} | |||
func (cc *ClientConn) setGoAway(f *GoAwayFrame) { | |||
cc.mu.Lock() | |||
defer cc.mu.Unlock() | |||
@@ -846,14 +891,12 @@ func (cc *ClientConn) sendGoAway() error { | |||
return nil | |||
} | |||
// Close closes the client connection immediately. | |||
// | |||
// In-flight requests are interrupted. For a graceful shutdown, use Shutdown instead. | |||
func (cc *ClientConn) Close() error { | |||
// closes the client connection immediately. In-flight requests are interrupted. | |||
// err is sent to streams. | |||
func (cc *ClientConn) closeForError(err error) error { | |||
cc.mu.Lock() | |||
defer cc.cond.Broadcast() | |||
defer cc.mu.Unlock() | |||
err := errors.New("http2: client connection force closed via ClientConn.Close") | |||
for id, cs := range cc.streams { | |||
select { | |||
case cs.resc <- resAndError{err: err}: | |||
@@ -866,6 +909,20 @@ func (cc *ClientConn) Close() error { | |||
return cc.tconn.Close() | |||
} | |||
// Close closes the client connection immediately. | |||
// | |||
// In-flight requests are interrupted. For a graceful shutdown, use Shutdown instead. | |||
func (cc *ClientConn) Close() error { | |||
err := errors.New("http2: client connection force closed via ClientConn.Close") | |||
return cc.closeForError(err) | |||
} | |||
// closes the client connection immediately. In-flight requests are interrupted. | |||
func (cc *ClientConn) closeForLostPing() error { | |||
err := errors.New("http2: client connection lost") | |||
return cc.closeForError(err) | |||
} | |||
const maxAllocFrameSize = 512 << 10 | |||
// frameBuffer returns a scratch buffer suitable for writing DATA frames. | |||
@@ -1033,6 +1090,15 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf | |||
bodyWriter := cc.t.getBodyWriterState(cs, body) | |||
cs.on100 = bodyWriter.on100 | |||
defer func() { | |||
cc.wmu.Lock() | |||
werr := cc.werr | |||
cc.wmu.Unlock() | |||
if werr != nil { | |||
cc.Close() | |||
} | |||
}() | |||
cc.wmu.Lock() | |||
endStream := !hasBody && !hasTrailers | |||
werr := cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs) | |||
@@ -1082,6 +1148,9 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf | |||
// we can keep it. | |||
bodyWriter.cancel() | |||
cs.abortRequestBodyWrite(errStopReqBodyWrite) | |||
if hasBody && !bodyWritten { | |||
<-bodyWriter.resc | |||
} | |||
} | |||
if re.err != nil { | |||
cc.forgetStreamID(cs.ID) | |||
@@ -1102,6 +1171,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf | |||
} else { | |||
bodyWriter.cancel() | |||
cs.abortRequestBodyWrite(errStopReqBodyWriteAndCancel) | |||
<-bodyWriter.resc | |||
} | |||
cc.forgetStreamID(cs.ID) | |||
return nil, cs.getStartedWrite(), errTimeout | |||
@@ -1111,6 +1181,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf | |||
} else { | |||
bodyWriter.cancel() | |||
cs.abortRequestBodyWrite(errStopReqBodyWriteAndCancel) | |||
<-bodyWriter.resc | |||
} | |||
cc.forgetStreamID(cs.ID) | |||
return nil, cs.getStartedWrite(), ctx.Err() | |||
@@ -1120,6 +1191,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf | |||
} else { | |||
bodyWriter.cancel() | |||
cs.abortRequestBodyWrite(errStopReqBodyWriteAndCancel) | |||
<-bodyWriter.resc | |||
} | |||
cc.forgetStreamID(cs.ID) | |||
return nil, cs.getStartedWrite(), errRequestCanceled | |||
@@ -1129,6 +1201,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf | |||
// forgetStreamID. | |||
return nil, cs.getStartedWrite(), cs.resetErr | |||
case err := <-bodyWriter.resc: | |||
bodyWritten = true | |||
// Prefer the read loop's response, if available. Issue 16102. | |||
select { | |||
case re := <-readLoopResCh: | |||
@@ -1139,7 +1212,6 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf | |||
cc.forgetStreamID(cs.ID) | |||
return nil, cs.getStartedWrite(), err | |||
} | |||
bodyWritten = true | |||
if d := cc.responseHeaderTimeout(); d != 0 { | |||
timer := time.NewTimer(d) | |||
defer timer.Stop() | |||
@@ -1737,8 +1809,17 @@ func (rl *clientConnReadLoop) run() error { | |||
rl.closeWhenIdle = cc.t.disableKeepAlives() || cc.singleUse | |||
gotReply := false // ever saw a HEADERS reply | |||
gotSettings := false | |||
readIdleTimeout := cc.t.ReadIdleTimeout | |||
var t *time.Timer | |||
if readIdleTimeout != 0 { | |||
t = time.AfterFunc(readIdleTimeout, cc.healthCheck) | |||
defer t.Stop() | |||
} | |||
for { | |||
f, err := cc.fr.ReadFrame() | |||
if t != nil { | |||
t.Reset(readIdleTimeout) | |||
} | |||
if err != nil { | |||
cc.vlogf("http2: Transport readFrame error on conn %p: (%T) %v", cc, err, err) | |||
} | |||
@@ -1950,8 +2031,8 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra | |||
if !streamEnded || isHead { | |||
res.ContentLength = -1 | |||
if clens := res.Header["Content-Length"]; len(clens) == 1 { | |||
if clen64, err := strconv.ParseInt(clens[0], 10, 64); err == nil { | |||
res.ContentLength = clen64 | |||
if cl, err := strconv.ParseUint(clens[0], 10, 63); err == nil { | |||
res.ContentLength = int64(cl) | |||
} else { | |||
// TODO: care? unlike http/1, it won't mess up our framing, so it's | |||
// more safe smuggling-wise to ignore. | |||
@@ -2469,6 +2550,7 @@ func strSliceContains(ss []string, s string) bool { | |||
type erringRoundTripper struct{ err error } | |||
func (rt erringRoundTripper) RoundTripErr() error { return rt.err } | |||
func (rt erringRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { return nil, rt.err } | |||
// gzipReader wraps a response body so it can lazily | |||
@@ -2550,7 +2632,9 @@ func (t *Transport) getBodyWriterState(cs *clientStream, body io.Reader) (s body | |||
func (s bodyWriterState) cancel() { | |||
if s.timer != nil { | |||
s.timer.Stop() | |||
if s.timer.Stop() { | |||
s.resc <- nil | |||
} | |||
} | |||
} | |||
@@ -4,6 +4,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build go1.10 | |||
// +build go1.10 | |||
// Package idna implements IDNA2008 using the compatibility processing | |||
@@ -4,6 +4,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build !go1.10 | |||
// +build !go1.10 | |||
// Package idna implements IDNA2008 using the compatibility processing | |||
@@ -1,5 +1,6 @@ | |||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. | |||
//go:build go1.10 && !go1.13 | |||
// +build go1.10,!go1.13 | |||
package idna | |||
@@ -1,5 +1,6 @@ | |||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. | |||
//go:build go1.13 && !go1.14 | |||
// +build go1.13,!go1.14 | |||
package idna | |||
@@ -1,6 +1,7 @@ | |||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. | |||
// +build go1.14 | |||
//go:build go1.14 && !go1.16 | |||
// +build go1.14,!go1.16 | |||
package idna | |||
@@ -1,5 +1,6 @@ | |||
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. | |||
//go:build !go1.10 | |||
// +build !go1.10 | |||
package idna | |||
@@ -2,7 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build !gccgo | |||
//go:build gc | |||
// +build gc | |||
#include "textflag.h" | |||
@@ -39,20 +39,25 @@ func (bigEndian) Uint64(b []byte) uint64 { | |||
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 | |||
} | |||
// hostByteOrder returns binary.LittleEndian on little-endian machines and | |||
// binary.BigEndian on big-endian machines. | |||
// hostByteOrder returns littleEndian on little-endian machines and | |||
// bigEndian on big-endian machines. | |||
func hostByteOrder() byteOrder { | |||
switch runtime.GOARCH { | |||
case "386", "amd64", "amd64p32", | |||
"alpha", | |||
"arm", "arm64", | |||
"mipsle", "mips64le", "mips64p32le", | |||
"nios2", | |||
"ppc64le", | |||
"riscv", "riscv64": | |||
"riscv", "riscv64", | |||
"sh": | |||
return littleEndian{} | |||
case "armbe", "arm64be", | |||
"m68k", | |||
"mips", "mips64", "mips64p32", | |||
"ppc", "ppc64", | |||
"s390", "s390x", | |||
"shbe", | |||
"sparc", "sparc64": | |||
return bigEndian{} | |||
} | |||
@@ -6,6 +6,11 @@ | |||
// various CPU architectures. | |||
package cpu | |||
import ( | |||
"os" | |||
"strings" | |||
) | |||
// Initialized reports whether the CPU features were initialized. | |||
// | |||
// For some GOOS/GOARCH combinations initialization of the CPU features depends | |||
@@ -24,26 +29,46 @@ type CacheLinePad struct{ _ [cacheLineSize]byte } | |||
// and HasAVX2 are only set if the OS supports XMM and YMM | |||
// registers in addition to the CPUID feature bit being set. | |||
var X86 struct { | |||
_ CacheLinePad | |||
HasAES bool // AES hardware implementation (AES NI) | |||
HasADX bool // Multi-precision add-carry instruction extensions | |||
HasAVX bool // Advanced vector extension | |||
HasAVX2 bool // Advanced vector extension 2 | |||
HasBMI1 bool // Bit manipulation instruction set 1 | |||
HasBMI2 bool // Bit manipulation instruction set 2 | |||
HasERMS bool // Enhanced REP for MOVSB and STOSB | |||
HasFMA bool // Fused-multiply-add instructions | |||
HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers. | |||
HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM | |||
HasPOPCNT bool // Hamming weight instruction POPCNT. | |||
HasRDRAND bool // RDRAND instruction (on-chip random number generator) | |||
HasRDSEED bool // RDSEED instruction (on-chip random number generator) | |||
HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64) | |||
HasSSE3 bool // Streaming SIMD extension 3 | |||
HasSSSE3 bool // Supplemental streaming SIMD extension 3 | |||
HasSSE41 bool // Streaming SIMD extension 4 and 4.1 | |||
HasSSE42 bool // Streaming SIMD extension 4 and 4.2 | |||
_ CacheLinePad | |||
_ CacheLinePad | |||
HasAES bool // AES hardware implementation (AES NI) | |||
HasADX bool // Multi-precision add-carry instruction extensions | |||
HasAVX bool // Advanced vector extension | |||
HasAVX2 bool // Advanced vector extension 2 | |||
HasAVX512 bool // Advanced vector extension 512 | |||
HasAVX512F bool // Advanced vector extension 512 Foundation Instructions | |||
HasAVX512CD bool // Advanced vector extension 512 Conflict Detection Instructions | |||
HasAVX512ER bool // Advanced vector extension 512 Exponential and Reciprocal Instructions | |||
HasAVX512PF bool // Advanced vector extension 512 Prefetch Instructions Instructions | |||
HasAVX512VL bool // Advanced vector extension 512 Vector Length Extensions | |||
HasAVX512BW bool // Advanced vector extension 512 Byte and Word Instructions | |||
HasAVX512DQ bool // Advanced vector extension 512 Doubleword and Quadword Instructions | |||
HasAVX512IFMA bool // Advanced vector extension 512 Integer Fused Multiply Add | |||
HasAVX512VBMI bool // Advanced vector extension 512 Vector Byte Manipulation Instructions | |||
HasAVX5124VNNIW bool // Advanced vector extension 512 Vector Neural Network Instructions Word variable precision | |||
HasAVX5124FMAPS bool // Advanced vector extension 512 Fused Multiply Accumulation Packed Single precision | |||
HasAVX512VPOPCNTDQ bool // Advanced vector extension 512 Double and quad word population count instructions | |||
HasAVX512VPCLMULQDQ bool // Advanced vector extension 512 Vector carry-less multiply operations | |||
HasAVX512VNNI bool // Advanced vector extension 512 Vector Neural Network Instructions | |||
HasAVX512GFNI bool // Advanced vector extension 512 Galois field New Instructions | |||
HasAVX512VAES bool // Advanced vector extension 512 Vector AES instructions | |||
HasAVX512VBMI2 bool // Advanced vector extension 512 Vector Byte Manipulation Instructions 2 | |||
HasAVX512BITALG bool // Advanced vector extension 512 Bit Algorithms | |||
HasAVX512BF16 bool // Advanced vector extension 512 BFloat16 Instructions | |||
HasBMI1 bool // Bit manipulation instruction set 1 | |||
HasBMI2 bool // Bit manipulation instruction set 2 | |||
HasERMS bool // Enhanced REP for MOVSB and STOSB | |||
HasFMA bool // Fused-multiply-add instructions | |||
HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers. | |||
HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM | |||
HasPOPCNT bool // Hamming weight instruction POPCNT. | |||
HasRDRAND bool // RDRAND instruction (on-chip random number generator) | |||
HasRDSEED bool // RDSEED instruction (on-chip random number generator) | |||
HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64) | |||
HasSSE3 bool // Streaming SIMD extension 3 | |||
HasSSSE3 bool // Supplemental streaming SIMD extension 3 | |||
HasSSE41 bool // Streaming SIMD extension 4 and 4.1 | |||
HasSSE42 bool // Streaming SIMD extension 4 and 4.2 | |||
_ CacheLinePad | |||
} | |||
// ARM64 contains the supported CPU features of the | |||
@@ -169,3 +194,94 @@ var S390X struct { | |||
HasVXE bool // vector-enhancements facility 1 | |||
_ CacheLinePad | |||
} | |||
func init() { | |||
archInit() | |||
initOptions() | |||
processOptions() | |||
} | |||
// options contains the cpu debug options that can be used in GODEBUG. | |||
// Options are arch dependent and are added by the arch specific initOptions functions. | |||
// Features that are mandatory for the specific GOARCH should have the Required field set | |||
// (e.g. SSE2 on amd64). | |||
var options []option | |||
// Option names should be lower case. e.g. avx instead of AVX. | |||
type option struct { | |||
Name string | |||
Feature *bool | |||
Specified bool // whether feature value was specified in GODEBUG | |||
Enable bool // whether feature should be enabled | |||
Required bool // whether feature is mandatory and can not be disabled | |||
} | |||
func processOptions() { | |||
env := os.Getenv("GODEBUG") | |||
field: | |||
for env != "" { | |||
field := "" | |||
i := strings.IndexByte(env, ',') | |||
if i < 0 { | |||
field, env = env, "" | |||
} else { | |||
field, env = env[:i], env[i+1:] | |||
} | |||
if len(field) < 4 || field[:4] != "cpu." { | |||
continue | |||
} | |||
i = strings.IndexByte(field, '=') | |||
if i < 0 { | |||
print("GODEBUG sys/cpu: no value specified for \"", field, "\"\n") | |||
continue | |||
} | |||
key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on" | |||
var enable bool | |||
switch value { | |||
case "on": | |||
enable = true | |||
case "off": | |||
enable = false | |||
default: | |||
print("GODEBUG sys/cpu: value \"", value, "\" not supported for cpu option \"", key, "\"\n") | |||
continue field | |||
} | |||
if key == "all" { | |||
for i := range options { | |||
options[i].Specified = true | |||
options[i].Enable = enable || options[i].Required | |||
} | |||
continue field | |||
} | |||
for i := range options { | |||
if options[i].Name == key { | |||
options[i].Specified = true | |||
options[i].Enable = enable | |||
continue field | |||
} | |||
} | |||
print("GODEBUG sys/cpu: unknown cpu feature \"", key, "\"\n") | |||
} | |||
for _, o := range options { | |||
if !o.Specified { | |||
continue | |||
} | |||
if o.Enable && !*o.Feature { | |||
print("GODEBUG sys/cpu: can not enable \"", o.Name, "\", missing CPU support\n") | |||
continue | |||
} | |||
if !o.Enable && o.Required { | |||
print("GODEBUG sys/cpu: can not disable \"", o.Name, "\", required CPU feature\n") | |||
continue | |||
} | |||
*o.Feature = o.Enable | |||
} | |||
} |
@@ -2,12 +2,11 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build aix,ppc64 | |||
//go:build aix | |||
// +build aix | |||
package cpu | |||
const cacheLineSize = 128 | |||
const ( | |||
// getsystemcfg constants | |||
_SC_IMPL = 2 | |||
@@ -15,7 +14,7 @@ const ( | |||
_IMPL_POWER9 = 0x20000 | |||
) | |||
func init() { | |||
func archInit() { | |||
impl := getsystemcfg(_SC_IMPL) | |||
if impl&_IMPL_POWER8 != 0 { | |||
PPC64.IsPOWER8 = true |
@@ -38,3 +38,36 @@ const ( | |||
hwcap2_SHA2 = 1 << 3 | |||
hwcap2_CRC32 = 1 << 4 | |||
) | |||
func initOptions() { | |||
options = []option{ | |||
{Name: "pmull", Feature: &ARM.HasPMULL}, | |||
{Name: "sha1", Feature: &ARM.HasSHA1}, | |||
{Name: "sha2", Feature: &ARM.HasSHA2}, | |||
{Name: "swp", Feature: &ARM.HasSWP}, | |||
{Name: "thumb", Feature: &ARM.HasTHUMB}, | |||
{Name: "thumbee", Feature: &ARM.HasTHUMBEE}, | |||
{Name: "tls", Feature: &ARM.HasTLS}, | |||
{Name: "vfp", Feature: &ARM.HasVFP}, | |||
{Name: "vfpd32", Feature: &ARM.HasVFPD32}, | |||
{Name: "vfpv3", Feature: &ARM.HasVFPv3}, | |||
{Name: "vfpv3d16", Feature: &ARM.HasVFPv3D16}, | |||
{Name: "vfpv4", Feature: &ARM.HasVFPv4}, | |||
{Name: "half", Feature: &ARM.HasHALF}, | |||
{Name: "26bit", Feature: &ARM.Has26BIT}, | |||
{Name: "fastmul", Feature: &ARM.HasFASTMUL}, | |||
{Name: "fpa", Feature: &ARM.HasFPA}, | |||
{Name: "edsp", Feature: &ARM.HasEDSP}, | |||
{Name: "java", Feature: &ARM.HasJAVA}, | |||
{Name: "iwmmxt", Feature: &ARM.HasIWMMXT}, | |||
{Name: "crunch", Feature: &ARM.HasCRUNCH}, | |||
{Name: "neon", Feature: &ARM.HasNEON}, | |||
{Name: "idivt", Feature: &ARM.HasIDIVT}, | |||
{Name: "idiva", Feature: &ARM.HasIDIVA}, | |||
{Name: "lpae", Feature: &ARM.HasLPAE}, | |||
{Name: "evtstrm", Feature: &ARM.HasEVTSTRM}, | |||
{Name: "aes", Feature: &ARM.HasAES}, | |||
{Name: "crc32", Feature: &ARM.HasCRC32}, | |||
} | |||
} |
@@ -8,27 +8,65 @@ import "runtime" | |||
const cacheLineSize = 64 | |||
func init() { | |||
func initOptions() { | |||
options = []option{ | |||
{Name: "fp", Feature: &ARM64.HasFP}, | |||
{Name: "asimd", Feature: &ARM64.HasASIMD}, | |||
{Name: "evstrm", Feature: &ARM64.HasEVTSTRM}, | |||
{Name: "aes", Feature: &ARM64.HasAES}, | |||
{Name: "fphp", Feature: &ARM64.HasFPHP}, | |||
{Name: "jscvt", Feature: &ARM64.HasJSCVT}, | |||
{Name: "lrcpc", Feature: &ARM64.HasLRCPC}, | |||
{Name: "pmull", Feature: &ARM64.HasPMULL}, | |||
{Name: "sha1", Feature: &ARM64.HasSHA1}, | |||
{Name: "sha2", Feature: &ARM64.HasSHA2}, | |||
{Name: "sha3", Feature: &ARM64.HasSHA3}, | |||
{Name: "sha512", Feature: &ARM64.HasSHA512}, | |||
{Name: "sm3", Feature: &ARM64.HasSM3}, | |||
{Name: "sm4", Feature: &ARM64.HasSM4}, | |||
{Name: "sve", Feature: &ARM64.HasSVE}, | |||
{Name: "crc32", Feature: &ARM64.HasCRC32}, | |||
{Name: "atomics", Feature: &ARM64.HasATOMICS}, | |||
{Name: "asimdhp", Feature: &ARM64.HasASIMDHP}, | |||
{Name: "cpuid", Feature: &ARM64.HasCPUID}, | |||
{Name: "asimrdm", Feature: &ARM64.HasASIMDRDM}, | |||
{Name: "fcma", Feature: &ARM64.HasFCMA}, | |||
{Name: "dcpop", Feature: &ARM64.HasDCPOP}, | |||
{Name: "asimddp", Feature: &ARM64.HasASIMDDP}, | |||
{Name: "asimdfhm", Feature: &ARM64.HasASIMDFHM}, | |||
} | |||
} | |||
func archInit() { | |||
switch runtime.GOOS { | |||
case "android", "darwin": | |||
// Android and iOS don't seem to allow reading these registers. | |||
// Fake the minimal features expected by | |||
// TestARM64minimalFeatures. | |||
ARM64.HasASIMD = true | |||
ARM64.HasFP = true | |||
case "linux": | |||
case "freebsd": | |||
readARM64Registers() | |||
case "linux", "netbsd": | |||
doinit() | |||
default: | |||
readARM64Registers() | |||
// Most platforms don't seem to allow reading these registers. | |||
// | |||
// OpenBSD: | |||
// See https://golang.org/issue/31746 | |||
setMinimalFeatures() | |||
} | |||
} | |||
// setMinimalFeatures fakes the minimal ARM64 features expected by | |||
// TestARM64minimalFeatures. | |||
func setMinimalFeatures() { | |||
ARM64.HasASIMD = true | |||
ARM64.HasFP = true | |||
} | |||
func readARM64Registers() { | |||
Initialized = true | |||
// ID_AA64ISAR0_EL1 | |||
isar0 := getisar0() | |||
parseARM64SystemRegisters(getisar0(), getisar1(), getpfr0()) | |||
} | |||
func parseARM64SystemRegisters(isar0, isar1, pfr0 uint64) { | |||
// ID_AA64ISAR0_EL1 | |||
switch extractBits(isar0, 4, 7) { | |||
case 1: | |||
ARM64.HasAES = true | |||
@@ -86,8 +124,6 @@ func readARM64Registers() { | |||
} | |||
// ID_AA64ISAR1_EL1 | |||
isar1 := getisar1() | |||
switch extractBits(isar1, 0, 3) { | |||
case 1: | |||
ARM64.HasDCPOP = true | |||
@@ -109,8 +145,6 @@ func readARM64Registers() { | |||
} | |||
// ID_AA64PFR0_EL1 | |||
pfr0 := getpfr0() | |||
switch extractBits(pfr0, 16, 19) { | |||
case 0: | |||
ARM64.HasFP = true | |||
@@ -2,7 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build !gccgo | |||
//go:build gc | |||
// +build gc | |||
#include "textflag.h" | |||
@@ -2,7 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build !gccgo | |||
//go:build gc | |||
// +build gc | |||
package cpu | |||
@@ -2,7 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build !gccgo | |||
//go:build gc | |||
// +build gc | |||
package cpu | |||
@@ -2,8 +2,9 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build (386 || amd64 || amd64p32) && gc | |||
// +build 386 amd64 amd64p32 | |||
// +build !gccgo | |||
// +build gc | |||
package cpu | |||
@@ -14,3 +15,7 @@ func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) | |||
// xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler | |||
// and in cpu_gccgo.c for gccgo. | |||
func xgetbv() (eax, edx uint32) | |||
// darwinSupportsAVX512 is implemented in cpu_x86.s for gc compiler | |||
// and in cpu_gccgo_x86.go for gccgo. | |||
func darwinSupportsAVX512() bool |
@@ -2,6 +2,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build gccgo | |||
// +build gccgo | |||
package cpu | |||
@@ -2,6 +2,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build gccgo | |||
// +build gccgo | |||
package cpu | |||
@@ -2,6 +2,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build (386 || amd64 || amd64p32) && gccgo | |||
// +build 386 amd64 amd64p32 | |||
// +build gccgo | |||
@@ -24,3 +25,9 @@ func xgetbv() (eax, edx uint32) { | |||
gccgoXgetbv(&a, &d) | |||
return a, d | |||
} | |||
// gccgo doesn't build on Darwin, per: | |||
// https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/gcc.rb#L76 | |||
func darwinSupportsAVX512() bool { | |||
return false | |||
} |
@@ -2,11 +2,12 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build !386 && !amd64 && !amd64p32 && !arm64 | |||
// +build !386,!amd64,!amd64p32,!arm64 | |||
package cpu | |||
func init() { | |||
func archInit() { | |||
if err := readHWCAP(); err != nil { | |||
return | |||
} | |||
@@ -2,6 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build linux && (mips64 || mips64le) | |||
// +build linux | |||
// +build mips64 mips64le | |||
package cpu | |||
@@ -2,6 +2,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x | |||
// +build linux,!arm,!arm64,!mips64,!mips64le,!ppc64,!ppc64le,!s390x | |||
package cpu | |||
@@ -2,13 +2,12 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build linux && (ppc64 || ppc64le) | |||
// +build linux | |||
// +build ppc64 ppc64le | |||
package cpu | |||
const cacheLineSize = 128 | |||
// HWCAP/HWCAP2 bits. These are exposed by the kernel. | |||
const ( | |||
// ISA Level | |||
@@ -4,8 +4,6 @@ | |||
package cpu | |||
const cacheLineSize = 256 | |||
const ( | |||
// bit mask values from /usr/include/bits/hwcap.h | |||
hwcap_ZARCH = 2 | |||
@@ -19,86 +17,7 @@ const ( | |||
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() { | |||
func initS390Xbase() { | |||
// test HWCAP bit vector | |||
has := func(featureMask uint) bool { | |||
return hwCap&featureMask == featureMask | |||
@@ -118,44 +37,4 @@ func doinit() { | |||
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...) | |||
} | |||
} |
@@ -2,8 +2,15 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build mips64 || mips64le | |||
// +build mips64 mips64le | |||
package cpu | |||
const cacheLineSize = 32 | |||
func initOptions() { | |||
options = []option{ | |||
{Name: "msa", Feature: &MIPS64X.HasMSA}, | |||
} | |||
} |
@@ -2,8 +2,11 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build mips || mipsle | |||
// +build mips mipsle | |||
package cpu | |||
const cacheLineSize = 32 | |||
func initOptions() {} |
@@ -0,0 +1,173 @@ | |||
// Copyright 2020 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 | |||
import ( | |||
"syscall" | |||
"unsafe" | |||
) | |||
// Minimal copy of functionality from x/sys/unix so the cpu package can call | |||
// sysctl without depending on x/sys/unix. | |||
const ( | |||
_CTL_QUERY = -2 | |||
_SYSCTL_VERS_1 = 0x1000000 | |||
) | |||
var _zero uintptr | |||
func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { | |||
var _p0 unsafe.Pointer | |||
if len(mib) > 0 { | |||
_p0 = unsafe.Pointer(&mib[0]) | |||
} else { | |||
_p0 = unsafe.Pointer(&_zero) | |||
} | |||
_, _, errno := syscall.Syscall6( | |||
syscall.SYS___SYSCTL, | |||
uintptr(_p0), | |||
uintptr(len(mib)), | |||
uintptr(unsafe.Pointer(old)), | |||
uintptr(unsafe.Pointer(oldlen)), | |||
uintptr(unsafe.Pointer(new)), | |||
uintptr(newlen)) | |||
if errno != 0 { | |||
return errno | |||
} | |||
return nil | |||
} | |||
type sysctlNode struct { | |||
Flags uint32 | |||
Num int32 | |||
Name [32]int8 | |||
Ver uint32 | |||
__rsvd uint32 | |||
Un [16]byte | |||
_sysctl_size [8]byte | |||
_sysctl_func [8]byte | |||
_sysctl_parent [8]byte | |||
_sysctl_desc [8]byte | |||
} | |||
func sysctlNodes(mib []int32) ([]sysctlNode, error) { | |||
var olen uintptr | |||
// Get a list of all sysctl nodes below the given MIB by performing | |||
// a sysctl for the given MIB with CTL_QUERY appended. | |||
mib = append(mib, _CTL_QUERY) | |||
qnode := sysctlNode{Flags: _SYSCTL_VERS_1} | |||
qp := (*byte)(unsafe.Pointer(&qnode)) | |||
sz := unsafe.Sizeof(qnode) | |||
if err := sysctl(mib, nil, &olen, qp, sz); err != nil { | |||
return nil, err | |||
} | |||
// Now that we know the size, get the actual nodes. | |||
nodes := make([]sysctlNode, olen/sz) | |||
np := (*byte)(unsafe.Pointer(&nodes[0])) | |||
if err := sysctl(mib, np, &olen, qp, sz); err != nil { | |||
return nil, err | |||
} | |||
return nodes, nil | |||
} | |||
func nametomib(name string) ([]int32, error) { | |||
// Split name into components. | |||
var parts []string | |||
last := 0 | |||
for i := 0; i < len(name); i++ { | |||
if name[i] == '.' { | |||
parts = append(parts, name[last:i]) | |||
last = i + 1 | |||
} | |||
} | |||
parts = append(parts, name[last:]) | |||
mib := []int32{} | |||
// Discover the nodes and construct the MIB OID. | |||
for partno, part := range parts { | |||
nodes, err := sysctlNodes(mib) | |||
if err != nil { | |||
return nil, err | |||
} | |||
for _, node := range nodes { | |||
n := make([]byte, 0) | |||
for i := range node.Name { | |||
if node.Name[i] != 0 { | |||
n = append(n, byte(node.Name[i])) | |||
} | |||
} | |||
if string(n) == part { | |||
mib = append(mib, int32(node.Num)) | |||
break | |||
} | |||
} | |||
if len(mib) != partno+1 { | |||
return nil, err | |||
} | |||
} | |||
return mib, nil | |||
} | |||
// aarch64SysctlCPUID is struct aarch64_sysctl_cpu_id from NetBSD's <aarch64/armreg.h> | |||
type aarch64SysctlCPUID struct { | |||
midr uint64 /* Main ID Register */ | |||
revidr uint64 /* Revision ID Register */ | |||
mpidr uint64 /* Multiprocessor Affinity Register */ | |||
aa64dfr0 uint64 /* A64 Debug Feature Register 0 */ | |||
aa64dfr1 uint64 /* A64 Debug Feature Register 1 */ | |||
aa64isar0 uint64 /* A64 Instruction Set Attribute Register 0 */ | |||
aa64isar1 uint64 /* A64 Instruction Set Attribute Register 1 */ | |||
aa64mmfr0 uint64 /* A64 Memory Model Feature Register 0 */ | |||
aa64mmfr1 uint64 /* A64 Memory Model Feature Register 1 */ | |||
aa64mmfr2 uint64 /* A64 Memory Model Feature Register 2 */ | |||
aa64pfr0 uint64 /* A64 Processor Feature Register 0 */ | |||
aa64pfr1 uint64 /* A64 Processor Feature Register 1 */ | |||
aa64zfr0 uint64 /* A64 SVE Feature ID Register 0 */ | |||
mvfr0 uint32 /* Media and VFP Feature Register 0 */ | |||
mvfr1 uint32 /* Media and VFP Feature Register 1 */ | |||
mvfr2 uint32 /* Media and VFP Feature Register 2 */ | |||
pad uint32 | |||
clidr uint64 /* Cache Level ID Register */ | |||
ctr uint64 /* Cache Type Register */ | |||
} | |||
func sysctlCPUID(name string) (*aarch64SysctlCPUID, error) { | |||
mib, err := nametomib(name) | |||
if err != nil { | |||
return nil, err | |||
} | |||
out := aarch64SysctlCPUID{} | |||
n := unsafe.Sizeof(out) | |||
_, _, errno := syscall.Syscall6( | |||
syscall.SYS___SYSCTL, | |||
uintptr(unsafe.Pointer(&mib[0])), | |||
uintptr(len(mib)), | |||
uintptr(unsafe.Pointer(&out)), | |||
uintptr(unsafe.Pointer(&n)), | |||
uintptr(0), | |||
uintptr(0)) | |||
if errno != 0 { | |||
return nil, errno | |||
} | |||
return &out, nil | |||
} | |||
func doinit() { | |||
cpuid, err := sysctlCPUID("machdep.cpu0.cpu_id") | |||
if err != nil { | |||
setMinimalFeatures() | |||
return | |||
} | |||
parseARM64SystemRegisters(cpuid.aa64isar0, cpuid.aa64isar1, cpuid.aa64pfr0) | |||
Initialized = true | |||
} |
@@ -0,0 +1,10 @@ | |||
// Copyright 2020 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. | |||
//go:build !linux && arm | |||
// +build !linux,arm | |||
package cpu | |||
func archInit() {} |
@@ -2,7 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build !linux,arm64 | |||
//go:build !linux && !netbsd && arm64 | |||
// +build !linux,!netbsd,arm64 | |||
package cpu | |||
@@ -0,0 +1,13 @@ | |||
// Copyright 2020 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. | |||
//go:build !linux && (mips64 || mips64le) | |||
// +build !linux | |||
// +build mips64 mips64le | |||
package cpu | |||
func archInit() { | |||
Initialized = true | |||
} |
@@ -0,0 +1,17 @@ | |||
// Copyright 2020 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. | |||
//go:build ppc64 || ppc64le | |||
// +build ppc64 ppc64le | |||
package cpu | |||
const cacheLineSize = 128 | |||
func initOptions() { | |||
options = []option{ | |||
{Name: "darn", Feature: &PPC64.HasDARN}, | |||
{Name: "scv", Feature: &PPC64.HasSCV}, | |||
} | |||
} |
@@ -2,8 +2,11 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build riscv64 | |||
// +build riscv64 | |||
package cpu | |||
const cacheLineSize = 32 | |||
func initOptions() {} |
@@ -0,0 +1,172 @@ | |||
// Copyright 2020 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 cacheLineSize = 256 | |||
func initOptions() { | |||
options = []option{ | |||
{Name: "zarch", Feature: &S390X.HasZARCH, Required: true}, | |||
{Name: "stfle", Feature: &S390X.HasSTFLE, Required: true}, | |||
{Name: "ldisp", Feature: &S390X.HasLDISP, Required: true}, | |||
{Name: "eimm", Feature: &S390X.HasEIMM, Required: true}, | |||
{Name: "dfp", Feature: &S390X.HasDFP}, | |||
{Name: "etf3eh", Feature: &S390X.HasETF3EH}, | |||
{Name: "msa", Feature: &S390X.HasMSA}, | |||
{Name: "aes", Feature: &S390X.HasAES}, | |||
{Name: "aescbc", Feature: &S390X.HasAESCBC}, | |||
{Name: "aesctr", Feature: &S390X.HasAESCTR}, | |||
{Name: "aesgcm", Feature: &S390X.HasAESGCM}, | |||
{Name: "ghash", Feature: &S390X.HasGHASH}, | |||
{Name: "sha1", Feature: &S390X.HasSHA1}, | |||
{Name: "sha256", Feature: &S390X.HasSHA256}, | |||
{Name: "sha3", Feature: &S390X.HasSHA3}, | |||
{Name: "sha512", Feature: &S390X.HasSHA512}, | |||
{Name: "vx", Feature: &S390X.HasVX}, | |||
{Name: "vxe", Feature: &S390X.HasVXE}, | |||
} | |||
} | |||
// 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 | |||
} | |||
// 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 | |||
vx facility = 129 // vector facility | |||
vxe facility = 135 // vector-enhancements 1 | |||
vxe2 facility = 148 // vector-enhancements 2 | |||
) | |||
// 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 | |||
} | |||
// 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 | |||
} | |||
func doinit() { | |||
initS390Xbase() | |||
// 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...) | |||
} | |||
} |
@@ -2,7 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build !gccgo | |||
//go:build gc | |||
// +build gc | |||
#include "textflag.h" | |||
@@ -2,6 +2,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build wasm | |||
// +build wasm | |||
package cpu | |||
@@ -11,3 +12,7 @@ package cpu | |||
// rules are good enough. | |||
const cacheLineSize = 0 | |||
func initOptions() {} | |||
func archInit() {} |
@@ -2,13 +2,62 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build 386 || amd64 || amd64p32 | |||
// +build 386 amd64 amd64p32 | |||
package cpu | |||
import "runtime" | |||
const cacheLineSize = 64 | |||
func init() { | |||
func initOptions() { | |||
options = []option{ | |||
{Name: "adx", Feature: &X86.HasADX}, | |||
{Name: "aes", Feature: &X86.HasAES}, | |||
{Name: "avx", Feature: &X86.HasAVX}, | |||
{Name: "avx2", Feature: &X86.HasAVX2}, | |||
{Name: "avx512", Feature: &X86.HasAVX512}, | |||
{Name: "avx512f", Feature: &X86.HasAVX512F}, | |||
{Name: "avx512cd", Feature: &X86.HasAVX512CD}, | |||
{Name: "avx512er", Feature: &X86.HasAVX512ER}, | |||
{Name: "avx512pf", Feature: &X86.HasAVX512PF}, | |||
{Name: "avx512vl", Feature: &X86.HasAVX512VL}, | |||
{Name: "avx512bw", Feature: &X86.HasAVX512BW}, | |||
{Name: "avx512dq", Feature: &X86.HasAVX512DQ}, | |||
{Name: "avx512ifma", Feature: &X86.HasAVX512IFMA}, | |||
{Name: "avx512vbmi", Feature: &X86.HasAVX512VBMI}, | |||
{Name: "avx512vnniw", Feature: &X86.HasAVX5124VNNIW}, | |||
{Name: "avx5124fmaps", Feature: &X86.HasAVX5124FMAPS}, | |||
{Name: "avx512vpopcntdq", Feature: &X86.HasAVX512VPOPCNTDQ}, | |||
{Name: "avx512vpclmulqdq", Feature: &X86.HasAVX512VPCLMULQDQ}, | |||
{Name: "avx512vnni", Feature: &X86.HasAVX512VNNI}, | |||
{Name: "avx512gfni", Feature: &X86.HasAVX512GFNI}, | |||
{Name: "avx512vaes", Feature: &X86.HasAVX512VAES}, | |||
{Name: "avx512vbmi2", Feature: &X86.HasAVX512VBMI2}, | |||
{Name: "avx512bitalg", Feature: &X86.HasAVX512BITALG}, | |||
{Name: "avx512bf16", Feature: &X86.HasAVX512BF16}, | |||
{Name: "bmi1", Feature: &X86.HasBMI1}, | |||
{Name: "bmi2", Feature: &X86.HasBMI2}, | |||
{Name: "erms", Feature: &X86.HasERMS}, | |||
{Name: "fma", Feature: &X86.HasFMA}, | |||
{Name: "osxsave", Feature: &X86.HasOSXSAVE}, | |||
{Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ}, | |||
{Name: "popcnt", Feature: &X86.HasPOPCNT}, | |||
{Name: "rdrand", Feature: &X86.HasRDRAND}, | |||
{Name: "rdseed", Feature: &X86.HasRDSEED}, | |||
{Name: "sse3", Feature: &X86.HasSSE3}, | |||
{Name: "sse41", Feature: &X86.HasSSE41}, | |||
{Name: "sse42", Feature: &X86.HasSSE42}, | |||
{Name: "ssse3", Feature: &X86.HasSSSE3}, | |||
// These capabilities should always be enabled on amd64: | |||
{Name: "sse2", Feature: &X86.HasSSE2, Required: runtime.GOARCH == "amd64"}, | |||
} | |||
} | |||
func archInit() { | |||
Initialized = true | |||
maxID, _, _, _ := cpuid(0, 0) | |||
@@ -31,12 +80,21 @@ func init() { | |||
X86.HasOSXSAVE = isSet(27, ecx1) | |||
X86.HasRDRAND = isSet(30, ecx1) | |||
osSupportsAVX := false | |||
var osSupportsAVX, osSupportsAVX512 bool | |||
// For XGETBV, OSXSAVE bit is required and sufficient. | |||
if X86.HasOSXSAVE { | |||
eax, _ := xgetbv() | |||
// Check if XMM and YMM registers have OS support. | |||
osSupportsAVX = isSet(1, eax) && isSet(2, eax) | |||
if runtime.GOOS == "darwin" { | |||
// Check darwin commpage for AVX512 support. Necessary because: | |||
// https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/osfmk/i386/fpu.c#L175-L201 | |||
osSupportsAVX512 = osSupportsAVX && darwinSupportsAVX512() | |||
} else { | |||
// Check if OPMASK and ZMM registers have OS support. | |||
osSupportsAVX512 = osSupportsAVX && isSet(5, eax) && isSet(6, eax) && isSet(7, eax) | |||
} | |||
} | |||
X86.HasAVX = isSet(28, ecx1) && osSupportsAVX | |||
@@ -45,13 +103,38 @@ func init() { | |||
return | |||
} | |||
_, ebx7, _, _ := cpuid(7, 0) | |||
_, ebx7, ecx7, edx7 := cpuid(7, 0) | |||
X86.HasBMI1 = isSet(3, ebx7) | |||
X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX | |||
X86.HasBMI2 = isSet(8, ebx7) | |||
X86.HasERMS = isSet(9, ebx7) | |||
X86.HasRDSEED = isSet(18, ebx7) | |||
X86.HasADX = isSet(19, ebx7) | |||
X86.HasAVX512 = isSet(16, ebx7) && osSupportsAVX512 // Because avx-512 foundation is the core required extension | |||
if X86.HasAVX512 { | |||
X86.HasAVX512F = true | |||
X86.HasAVX512CD = isSet(28, ebx7) | |||
X86.HasAVX512ER = isSet(27, ebx7) | |||
X86.HasAVX512PF = isSet(26, ebx7) | |||
X86.HasAVX512VL = isSet(31, ebx7) | |||
X86.HasAVX512BW = isSet(30, ebx7) | |||
X86.HasAVX512DQ = isSet(17, ebx7) | |||
X86.HasAVX512IFMA = isSet(21, ebx7) | |||
X86.HasAVX512VBMI = isSet(1, ecx7) | |||
X86.HasAVX5124VNNIW = isSet(2, edx7) | |||
X86.HasAVX5124FMAPS = isSet(3, edx7) | |||
X86.HasAVX512VPOPCNTDQ = isSet(14, ecx7) | |||
X86.HasAVX512VPCLMULQDQ = isSet(10, ecx7) | |||
X86.HasAVX512VNNI = isSet(11, ecx7) | |||
X86.HasAVX512GFNI = isSet(8, ecx7) | |||
X86.HasAVX512VAES = isSet(9, ecx7) | |||
X86.HasAVX512VBMI2 = isSet(6, ecx7) | |||
X86.HasAVX512BITALG = isSet(12, ecx7) | |||
eax71, _, _, _ := cpuid(7, 1) | |||
X86.HasAVX512BF16 = isSet(5, eax71) | |||
} | |||
} | |||
func isSet(bitpos uint, value uint32) bool { | |||
@@ -2,8 +2,9 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build (386 || amd64 || amd64p32) && gc | |||
// +build 386 amd64 amd64p32 | |||
// +build !gccgo | |||
// +build gc | |||
#include "textflag.h" | |||
@@ -25,3 +26,27 @@ TEXT ·xgetbv(SB),NOSPLIT,$0-8 | |||
MOVL AX, eax+0(FP) | |||
MOVL DX, edx+4(FP) | |||
RET | |||
// func darwinSupportsAVX512() bool | |||
TEXT ·darwinSupportsAVX512(SB), NOSPLIT, $0-1 | |||
MOVB $0, ret+0(FP) // default to false | |||
#ifdef GOOS_darwin // return if not darwin | |||
#ifdef GOARCH_amd64 // return if not amd64 | |||
// These values from: | |||
// https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/osfmk/i386/cpu_capabilities.h | |||
#define commpage64_base_address 0x00007fffffe00000 | |||
#define commpage64_cpu_capabilities64 (commpage64_base_address+0x010) | |||
#define commpage64_version (commpage64_base_address+0x01E) | |||
#define hasAVX512F 0x0000004000000000 | |||
MOVQ $commpage64_version, BX | |||
CMPW (BX), $13 // cpu_capabilities64 undefined in versions < 13 | |||
JL no_avx512 | |||
MOVQ $commpage64_cpu_capabilities64, BX | |||
MOVQ $hasAVX512F, CX | |||
TESTQ (BX), CX | |||
JZ no_avx512 | |||
MOVB $1, ret+0(FP) | |||
no_avx512: | |||
#endif | |||
#endif | |||
RET |
@@ -0,0 +1,10 @@ | |||
// Copyright 2020 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 | |||
func archInit() { | |||
doinit() | |||
Initialized = true | |||
} |
@@ -0,0 +1,25 @@ | |||
// Copyright 2020 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 | |||
func initS390Xbase() { | |||
// get the facilities list | |||
facilities := stfle() | |||
// mandatory | |||
S390X.HasZARCH = facilities.Has(zarch) | |||
S390X.HasSTFLE = facilities.Has(stflef) | |||
S390X.HasLDISP = facilities.Has(ldisp) | |||
S390X.HasEIMM = facilities.Has(eimm) | |||
// optional | |||
S390X.HasETF3EH = facilities.Has(etf3eh) | |||
S390X.HasDFP = facilities.Has(dfp) | |||
S390X.HasMSA = facilities.Has(msa) | |||
S390X.HasVX = facilities.Has(vx) | |||
if S390X.HasVX { | |||
S390X.HasVXE = facilities.Has(vxe) | |||
} | |||
} |
@@ -0,0 +1,27 @@ | |||
// Copyright 2020 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. | |||
// Recreate a getsystemcfg syscall handler instead of | |||
// using the one provided by x/sys/unix to avoid having | |||
// the dependency between them. (See golang.org/issue/32102) | |||
// Morever, this file will be used during the building of | |||
// gccgo's libgo and thus must not used a CGo method. | |||
//go:build aix && gccgo | |||
// +build aix,gccgo | |||
package cpu | |||
import ( | |||
"syscall" | |||
) | |||
//extern getsystemcfg | |||
func gccgoGetsystemcfg(label uint32) (r uint64) | |||
func callgetsystemcfg(label int) (r1 uintptr, e1 syscall.Errno) { | |||
r1 = uintptr(gccgoGetsystemcfg(uint32(label))) | |||
e1 = syscall.GetErrno() | |||
return | |||
} |
@@ -6,8 +6,8 @@ | |||
// system call on AIX without depending on x/sys/unix. | |||
// (See golang.org/issue/32102) | |||
// +build aix,ppc64 | |||
// +build !gccgo | |||
//go:build aix && ppc64 && gc | |||
// +build aix,ppc64,gc | |||
package cpu | |||
@@ -0,0 +1,102 @@ | |||
// Copyright 2020 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 execabs is a drop-in replacement for os/exec | |||
// that requires PATH lookups to find absolute paths. | |||
// That is, execabs.Command("cmd") runs the same PATH lookup | |||
// as exec.Command("cmd"), but if the result is a path | |||
// which is relative, the Run and Start methods will report | |||
// an error instead of running the executable. | |||
// | |||
// See https://blog.golang.org/path-security for more information | |||
// about when it may be necessary or appropriate to use this package. | |||
package execabs | |||
import ( | |||
"context" | |||
"fmt" | |||
"os/exec" | |||
"path/filepath" | |||
"reflect" | |||
"unsafe" | |||
) | |||
// ErrNotFound is the error resulting if a path search failed to find an executable file. | |||
// It is an alias for exec.ErrNotFound. | |||
var ErrNotFound = exec.ErrNotFound | |||
// Cmd represents an external command being prepared or run. | |||
// It is an alias for exec.Cmd. | |||
type Cmd = exec.Cmd | |||
// Error is returned by LookPath when it fails to classify a file as an executable. | |||
// It is an alias for exec.Error. | |||
type Error = exec.Error | |||
// An ExitError reports an unsuccessful exit by a command. | |||
// It is an alias for exec.ExitError. | |||
type ExitError = exec.ExitError | |||
func relError(file, path string) error { | |||
return fmt.Errorf("%s resolves to executable in current directory (.%c%s)", file, filepath.Separator, path) | |||
} | |||
// LookPath searches for an executable named file in the directories | |||
// named by the PATH environment variable. If file contains a slash, | |||
// it is tried directly and the PATH is not consulted. The result will be | |||
// an absolute path. | |||
// | |||
// LookPath differs from exec.LookPath in its handling of PATH lookups, | |||
// which are used for file names without slashes. If exec.LookPath's | |||
// PATH lookup would have returned an executable from the current directory, | |||
// LookPath instead returns an error. | |||
func LookPath(file string) (string, error) { | |||
path, err := exec.LookPath(file) | |||
if err != nil { | |||
return "", err | |||
} | |||
if filepath.Base(file) == file && !filepath.IsAbs(path) { | |||
return "", relError(file, path) | |||
} | |||
return path, nil | |||
} | |||
func fixCmd(name string, cmd *exec.Cmd) { | |||
if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) { | |||
// exec.Command was called with a bare binary name and | |||
// exec.LookPath returned a path which is not absolute. | |||
// Set cmd.lookPathErr and clear cmd.Path so that it | |||
// cannot be run. | |||
lookPathErr := (*error)(unsafe.Pointer(reflect.ValueOf(cmd).Elem().FieldByName("lookPathErr").Addr().Pointer())) | |||
if *lookPathErr == nil { | |||
*lookPathErr = relError(name, cmd.Path) | |||
} | |||
cmd.Path = "" | |||
} | |||
} | |||
// CommandContext is like Command but includes a context. | |||
// | |||
// The provided context is used to kill the process (by calling os.Process.Kill) | |||
// if the context becomes done before the command completes on its own. | |||
func CommandContext(ctx context.Context, name string, arg ...string) *exec.Cmd { | |||
cmd := exec.CommandContext(ctx, name, arg...) | |||
fixCmd(name, cmd) | |||
return cmd | |||
} | |||
// Command returns the Cmd struct to execute the named program with the given arguments. | |||
// See exec.Command for most details. | |||
// | |||
// Command differs from exec.Command in its handling of PATH lookups, | |||
// which are used when the program name contains no slashes. | |||
// If exec.Command would have returned an exec.Cmd configured to run an | |||
// executable from the current directory, Command instead | |||
// returns an exec.Cmd that will return an error from Start or Run. | |||
func Command(name string, arg ...string) *exec.Cmd { | |||
cmd := exec.Command(name, arg...) | |||
fixCmd(name, cmd) | |||
return cmd | |||
} |
@@ -2,7 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris | |||
//go:build (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos) && go1.9 | |||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos | |||
// +build go1.9 | |||
package unix | |||
@@ -2,7 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build !gccgo | |||
//go:build gc | |||
// +build gc | |||
#include "textflag.h" | |||
@@ -1,14 +1,14 @@ | |||
// Copyright 2009 The Go Authors. All rights reserved. | |||
// Copyright 2021 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. | |||
// +build !gccgo | |||
//go:build (darwin || freebsd || netbsd || openbsd) && gc | |||
// +build darwin freebsd netbsd openbsd | |||
// +build gc | |||
#include "textflag.h" | |||
// | |||
// System call support for 386, NetBSD | |||
// | |||
// System call support for 386 BSD | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. | |||
@@ -22,7 +22,7 @@ TEXT ·Syscall6(SB),NOSPLIT,$0-40 | |||
TEXT ·Syscall9(SB),NOSPLIT,$0-52 | |||
JMP syscall·Syscall9(SB) | |||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 | |||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 | |||
JMP syscall·RawSyscall(SB) | |||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 |
@@ -1,14 +1,14 @@ | |||
// Copyright 2009 The Go Authors. All rights reserved. | |||
// Copyright 2021 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. | |||
// +build !gccgo | |||
//go:build (darwin || dragonfly || freebsd || netbsd || openbsd) && gc | |||
// +build darwin dragonfly freebsd netbsd openbsd | |||
// +build gc | |||
#include "textflag.h" | |||
// | |||
// System call support for AMD64, OpenBSD | |||
// | |||
// System call support for AMD64 BSD | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. |
@@ -1,15 +1,14 @@ | |||
// Copyright 2015 The Go Authors. All rights reserved. | |||
// Copyright 2021 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. | |||
// +build !gccgo | |||
// +build arm,darwin | |||
//go:build (darwin || freebsd || netbsd || openbsd) && gc | |||
// +build darwin freebsd netbsd openbsd | |||
// +build gc | |||
#include "textflag.h" | |||
// | |||
// System call support for ARM, Darwin | |||
// | |||
// System call support for ARM BSD | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. |
@@ -1,14 +1,14 @@ | |||
// Copyright 2009 The Go Authors. All rights reserved. | |||
// Copyright 2021 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. | |||
// +build !gccgo | |||
//go:build (darwin || freebsd || netbsd || openbsd) && gc | |||
// +build darwin freebsd netbsd openbsd | |||
// +build gc | |||
#include "textflag.h" | |||
// | |||
// System call support for AMD64, NetBSD | |||
// | |||
// System call support for ARM64 BSD | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. |
@@ -1,29 +0,0 @@ | |||
// Copyright 2009 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. | |||
// +build !gccgo | |||
#include "textflag.h" | |||
// | |||
// System call support for 386, Darwin | |||
// | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. | |||
TEXT ·Syscall(SB),NOSPLIT,$0-28 | |||
JMP syscall·Syscall(SB) | |||
TEXT ·Syscall6(SB),NOSPLIT,$0-40 | |||
JMP syscall·Syscall6(SB) | |||
TEXT ·Syscall9(SB),NOSPLIT,$0-52 | |||
JMP syscall·Syscall9(SB) | |||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 | |||
JMP syscall·RawSyscall(SB) | |||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 | |||
JMP syscall·RawSyscall6(SB) |
@@ -1,29 +0,0 @@ | |||
// Copyright 2009 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. | |||
// +build !gccgo | |||
#include "textflag.h" | |||
// | |||
// System call support for AMD64, Darwin | |||
// | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. | |||
TEXT ·Syscall(SB),NOSPLIT,$0-56 | |||
JMP syscall·Syscall(SB) | |||
TEXT ·Syscall6(SB),NOSPLIT,$0-80 | |||
JMP syscall·Syscall6(SB) | |||
TEXT ·Syscall9(SB),NOSPLIT,$0-104 | |||
JMP syscall·Syscall9(SB) | |||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 | |||
JMP syscall·RawSyscall(SB) | |||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 | |||
JMP syscall·RawSyscall6(SB) |
@@ -1,30 +0,0 @@ | |||
// Copyright 2015 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. | |||
// +build !gccgo | |||
// +build arm64,darwin | |||
#include "textflag.h" | |||
// | |||
// System call support for AMD64, Darwin | |||
// | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. | |||
TEXT ·Syscall(SB),NOSPLIT,$0-56 | |||
B syscall·Syscall(SB) | |||
TEXT ·Syscall6(SB),NOSPLIT,$0-80 | |||
B syscall·Syscall6(SB) | |||
TEXT ·Syscall9(SB),NOSPLIT,$0-104 | |||
B syscall·Syscall9(SB) | |||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 | |||
B syscall·RawSyscall(SB) | |||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 | |||
B syscall·RawSyscall6(SB) |
@@ -1,29 +0,0 @@ | |||
// Copyright 2009 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. | |||
// +build !gccgo | |||
#include "textflag.h" | |||
// | |||
// System call support for AMD64, DragonFly | |||
// | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. | |||
TEXT ·Syscall(SB),NOSPLIT,$0-56 | |||
JMP syscall·Syscall(SB) | |||
TEXT ·Syscall6(SB),NOSPLIT,$0-80 | |||
JMP syscall·Syscall6(SB) | |||
TEXT ·Syscall9(SB),NOSPLIT,$0-104 | |||
JMP syscall·Syscall9(SB) | |||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 | |||
JMP syscall·RawSyscall(SB) | |||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 | |||
JMP syscall·RawSyscall6(SB) |
@@ -1,29 +0,0 @@ | |||
// Copyright 2009 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. | |||
// +build !gccgo | |||
#include "textflag.h" | |||
// | |||
// System call support for 386, FreeBSD | |||
// | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. | |||
TEXT ·Syscall(SB),NOSPLIT,$0-28 | |||
JMP syscall·Syscall(SB) | |||
TEXT ·Syscall6(SB),NOSPLIT,$0-40 | |||
JMP syscall·Syscall6(SB) | |||
TEXT ·Syscall9(SB),NOSPLIT,$0-52 | |||
JMP syscall·Syscall9(SB) | |||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 | |||
JMP syscall·RawSyscall(SB) | |||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 | |||
JMP syscall·RawSyscall6(SB) |
@@ -1,29 +0,0 @@ | |||
// Copyright 2009 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. | |||
// +build !gccgo | |||
#include "textflag.h" | |||
// | |||
// System call support for AMD64, FreeBSD | |||
// | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. | |||
TEXT ·Syscall(SB),NOSPLIT,$0-56 | |||
JMP syscall·Syscall(SB) | |||
TEXT ·Syscall6(SB),NOSPLIT,$0-80 | |||
JMP syscall·Syscall6(SB) | |||
TEXT ·Syscall9(SB),NOSPLIT,$0-104 | |||
JMP syscall·Syscall9(SB) | |||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 | |||
JMP syscall·RawSyscall(SB) | |||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 | |||
JMP syscall·RawSyscall6(SB) |
@@ -1,29 +0,0 @@ | |||
// Copyright 2012 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. | |||
// +build !gccgo | |||
#include "textflag.h" | |||
// | |||
// System call support for ARM, FreeBSD | |||
// | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. | |||
TEXT ·Syscall(SB),NOSPLIT,$0-28 | |||
B syscall·Syscall(SB) | |||
TEXT ·Syscall6(SB),NOSPLIT,$0-40 | |||
B syscall·Syscall6(SB) | |||
TEXT ·Syscall9(SB),NOSPLIT,$0-52 | |||
B syscall·Syscall9(SB) | |||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 | |||
B syscall·RawSyscall(SB) | |||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 | |||
B syscall·RawSyscall6(SB) |
@@ -1,29 +0,0 @@ | |||
// 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. | |||
// +build !gccgo | |||
#include "textflag.h" | |||
// | |||
// System call support for ARM64, FreeBSD | |||
// | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. | |||
TEXT ·Syscall(SB),NOSPLIT,$0-56 | |||
JMP syscall·Syscall(SB) | |||
TEXT ·Syscall6(SB),NOSPLIT,$0-80 | |||
JMP syscall·Syscall6(SB) | |||
TEXT ·Syscall9(SB),NOSPLIT,$0-104 | |||
JMP syscall·Syscall9(SB) | |||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 | |||
JMP syscall·RawSyscall(SB) | |||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 | |||
JMP syscall·RawSyscall6(SB) |
@@ -2,7 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build !gccgo | |||
//go:build gc | |||
// +build gc | |||
#include "textflag.h" | |||
@@ -2,7 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build !gccgo | |||
//go:build gc | |||
// +build gc | |||
#include "textflag.h" | |||
@@ -2,7 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build !gccgo | |||
//go:build gc | |||
// +build gc | |||
#include "textflag.h" | |||
@@ -2,9 +2,10 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build linux && arm64 && gc | |||
// +build linux | |||
// +build arm64 | |||
// +build !gccgo | |||
// +build gc | |||
#include "textflag.h" | |||
@@ -2,9 +2,10 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build linux && (mips64 || mips64le) && gc | |||
// +build linux | |||
// +build mips64 mips64le | |||
// +build !gccgo | |||
// +build gc | |||
#include "textflag.h" | |||
@@ -2,9 +2,10 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build linux && (mips || mipsle) && gc | |||
// +build linux | |||
// +build mips mipsle | |||
// +build !gccgo | |||
// +build gc | |||
#include "textflag.h" | |||
@@ -2,9 +2,10 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build linux && (ppc64 || ppc64le) && gc | |||
// +build linux | |||
// +build ppc64 ppc64le | |||
// +build !gccgo | |||
// +build gc | |||
#include "textflag.h" | |||
@@ -2,7 +2,9 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build riscv64,!gccgo | |||
//go:build riscv64 && gc | |||
// +build riscv64 | |||
// +build gc | |||
#include "textflag.h" | |||
@@ -2,9 +2,10 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build s390x | |||
//go:build linux && s390x && gc | |||
// +build linux | |||
// +build !gccgo | |||
// +build s390x | |||
// +build gc | |||
#include "textflag.h" | |||
@@ -1,29 +0,0 @@ | |||
// Copyright 2013 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. | |||
// +build !gccgo | |||
#include "textflag.h" | |||
// | |||
// System call support for ARM, NetBSD | |||
// | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. | |||
TEXT ·Syscall(SB),NOSPLIT,$0-28 | |||
B syscall·Syscall(SB) | |||
TEXT ·Syscall6(SB),NOSPLIT,$0-40 | |||
B syscall·Syscall6(SB) | |||
TEXT ·Syscall9(SB),NOSPLIT,$0-52 | |||
B syscall·Syscall9(SB) | |||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 | |||
B syscall·RawSyscall(SB) | |||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 | |||
B syscall·RawSyscall6(SB) |
@@ -1,29 +0,0 @@ | |||
// 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. | |||
// +build !gccgo | |||
#include "textflag.h" | |||
// | |||
// System call support for ARM64, NetBSD | |||
// | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. | |||
TEXT ·Syscall(SB),NOSPLIT,$0-56 | |||
B syscall·Syscall(SB) | |||
TEXT ·Syscall6(SB),NOSPLIT,$0-80 | |||
B syscall·Syscall6(SB) | |||
TEXT ·Syscall9(SB),NOSPLIT,$0-104 | |||
B syscall·Syscall9(SB) | |||
TEXT ·RawSyscall(SB),NOSPLIT,$0-56 | |||
B syscall·RawSyscall(SB) | |||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 | |||
B syscall·RawSyscall6(SB) |
@@ -1,29 +0,0 @@ | |||
// Copyright 2009 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. | |||
// +build !gccgo | |||
#include "textflag.h" | |||
// | |||
// System call support for 386, OpenBSD | |||
// | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. | |||
TEXT ·Syscall(SB),NOSPLIT,$0-28 | |||
JMP syscall·Syscall(SB) | |||
TEXT ·Syscall6(SB),NOSPLIT,$0-40 | |||
JMP syscall·Syscall6(SB) | |||
TEXT ·Syscall9(SB),NOSPLIT,$0-52 | |||
JMP syscall·Syscall9(SB) | |||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 | |||
JMP syscall·RawSyscall(SB) | |||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 | |||
JMP syscall·RawSyscall6(SB) |
@@ -1,29 +0,0 @@ | |||
// 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. | |||
// +build !gccgo | |||
#include "textflag.h" | |||
// | |||
// System call support for ARM, OpenBSD | |||
// | |||
// Just jump to package syscall's implementation for all these functions. | |||
// The runtime may know about them. | |||
TEXT ·Syscall(SB),NOSPLIT,$0-28 | |||
B syscall·Syscall(SB) | |||
TEXT ·Syscall6(SB),NOSPLIT,$0-40 | |||
B syscall·Syscall6(SB) | |||
TEXT ·Syscall9(SB),NOSPLIT,$0-52 | |||
B syscall·Syscall9(SB) | |||
TEXT ·RawSyscall(SB),NOSPLIT,$0-28 | |||
B syscall·RawSyscall(SB) | |||
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 | |||
B syscall·RawSyscall6(SB) |
@@ -2,12 +2,13 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build !gccgo | |||
//go:build gc | |||
// +build gc | |||
#include "textflag.h" | |||
// | |||
// System call support for arm64, OpenBSD | |||
// System call support for mips64, OpenBSD | |||
// | |||
// Just jump to package syscall's implementation for all these functions. |
@@ -2,7 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build !gccgo | |||
//go:build gc | |||
// +build gc | |||
#include "textflag.h" | |||
@@ -0,0 +1,426 @@ | |||
// Copyright 2020 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. | |||
//go:build zos && s390x && gc | |||
// +build zos | |||
// +build s390x | |||
// +build gc | |||
#include "textflag.h" | |||
#define PSALAA 1208(R0) | |||
#define GTAB64(x) 80(x) | |||
#define LCA64(x) 88(x) | |||
#define CAA(x) 8(x) | |||
#define EDCHPXV(x) 1016(x) // in the CAA | |||
#define SAVSTACK_ASYNC(x) 336(x) // in the LCA | |||
// SS_*, where x=SAVSTACK_ASYNC | |||
#define SS_LE(x) 0(x) | |||
#define SS_GO(x) 8(x) | |||
#define SS_ERRNO(x) 16(x) | |||
#define SS_ERRNOJR(x) 20(x) | |||
#define LE_CALL BYTE $0x0D; BYTE $0x76; // BL R7, R6 | |||
TEXT ·clearErrno(SB),NOSPLIT,$0-0 | |||
BL addrerrno<>(SB) | |||
MOVD $0, 0(R3) | |||
RET | |||
// Returns the address of errno in R3. | |||
TEXT addrerrno<>(SB),NOSPLIT|NOFRAME,$0-0 | |||
// Get library control area (LCA). | |||
MOVW PSALAA, R8 | |||
MOVD LCA64(R8), R8 | |||
// Get __errno FuncDesc. | |||
MOVD CAA(R8), R9 | |||
MOVD EDCHPXV(R9), R9 | |||
ADD $(0x156*16), R9 | |||
LMG 0(R9), R5, R6 | |||
// Switch to saved LE stack. | |||
MOVD SAVSTACK_ASYNC(R8), R9 | |||
MOVD 0(R9), R4 | |||
MOVD $0, 0(R9) | |||
// Call __errno function. | |||
LE_CALL | |||
NOPH | |||
// Switch back to Go stack. | |||
XOR R0, R0 // Restore R0 to $0. | |||
MOVD R4, 0(R9) // Save stack pointer. | |||
RET | |||
TEXT ·syscall_syscall(SB),NOSPLIT,$0-56 | |||
BL runtime·entersyscall(SB) | |||
MOVD a1+8(FP), R1 | |||
MOVD a2+16(FP), R2 | |||
MOVD a3+24(FP), R3 | |||
// Get library control area (LCA). | |||
MOVW PSALAA, R8 | |||
MOVD LCA64(R8), R8 | |||
// Get function. | |||
MOVD CAA(R8), R9 | |||
MOVD EDCHPXV(R9), R9 | |||
MOVD trap+0(FP), R5 | |||
SLD $4, R5 | |||
ADD R5, R9 | |||
LMG 0(R9), R5, R6 | |||
// Restore LE stack. | |||
MOVD SAVSTACK_ASYNC(R8), R9 | |||
MOVD 0(R9), R4 | |||
MOVD $0, 0(R9) | |||
// Call function. | |||
LE_CALL | |||
NOPH | |||
XOR R0, R0 // Restore R0 to $0. | |||
MOVD R4, 0(R9) // Save stack pointer. | |||
MOVD R3, r1+32(FP) | |||
MOVD R0, r2+40(FP) | |||
MOVD R0, err+48(FP) | |||
MOVW R3, R4 | |||
CMP R4, $-1 | |||
BNE done | |||
BL addrerrno<>(SB) | |||
MOVWZ 0(R3), R3 | |||
MOVD R3, err+48(FP) | |||
done: | |||
BL runtime·exitsyscall(SB) | |||
RET | |||
TEXT ·syscall_rawsyscall(SB),NOSPLIT,$0-56 | |||
MOVD a1+8(FP), R1 | |||
MOVD a2+16(FP), R2 | |||
MOVD a3+24(FP), R3 | |||
// Get library control area (LCA). | |||
MOVW PSALAA, R8 | |||
MOVD LCA64(R8), R8 | |||
// Get function. | |||
MOVD CAA(R8), R9 | |||
MOVD EDCHPXV(R9), R9 | |||
MOVD trap+0(FP), R5 | |||
SLD $4, R5 | |||
ADD R5, R9 | |||
LMG 0(R9), R5, R6 | |||
// Restore LE stack. | |||
MOVD SAVSTACK_ASYNC(R8), R9 | |||
MOVD 0(R9), R4 | |||
MOVD $0, 0(R9) | |||
// Call function. | |||
LE_CALL | |||
NOPH | |||
XOR R0, R0 // Restore R0 to $0. | |||
MOVD R4, 0(R9) // Save stack pointer. | |||
MOVD R3, r1+32(FP) | |||
MOVD R0, r2+40(FP) | |||
MOVD R0, err+48(FP) | |||
MOVW R3, R4 | |||
CMP R4, $-1 | |||
BNE done | |||
BL addrerrno<>(SB) | |||
MOVWZ 0(R3), R3 | |||
MOVD R3, err+48(FP) | |||
done: | |||
RET | |||
TEXT ·syscall_syscall6(SB),NOSPLIT,$0-80 | |||
BL runtime·entersyscall(SB) | |||
MOVD a1+8(FP), R1 | |||
MOVD a2+16(FP), R2 | |||
MOVD a3+24(FP), R3 | |||
// Get library control area (LCA). | |||
MOVW PSALAA, R8 | |||
MOVD LCA64(R8), R8 | |||
// Get function. | |||
MOVD CAA(R8), R9 | |||
MOVD EDCHPXV(R9), R9 | |||
MOVD trap+0(FP), R5 | |||
SLD $4, R5 | |||
ADD R5, R9 | |||
LMG 0(R9), R5, R6 | |||
// Restore LE stack. | |||
MOVD SAVSTACK_ASYNC(R8), R9 | |||
MOVD 0(R9), R4 | |||
MOVD $0, 0(R9) | |||
// Fill in parameter list. | |||
MOVD a4+32(FP), R12 | |||
MOVD R12, (2176+24)(R4) | |||
MOVD a5+40(FP), R12 | |||
MOVD R12, (2176+32)(R4) | |||
MOVD a6+48(FP), R12 | |||
MOVD R12, (2176+40)(R4) | |||
// Call function. | |||
LE_CALL | |||
NOPH | |||
XOR R0, R0 // Restore R0 to $0. | |||
MOVD R4, 0(R9) // Save stack pointer. | |||
MOVD R3, r1+56(FP) | |||
MOVD R0, r2+64(FP) | |||
MOVD R0, err+72(FP) | |||
MOVW R3, R4 | |||
CMP R4, $-1 | |||
BNE done | |||
BL addrerrno<>(SB) | |||
MOVWZ 0(R3), R3 | |||
MOVD R3, err+72(FP) | |||
done: | |||
BL runtime·exitsyscall(SB) | |||
RET | |||
TEXT ·syscall_rawsyscall6(SB),NOSPLIT,$0-80 | |||
MOVD a1+8(FP), R1 | |||
MOVD a2+16(FP), R2 | |||
MOVD a3+24(FP), R3 | |||
// Get library control area (LCA). | |||
MOVW PSALAA, R8 | |||
MOVD LCA64(R8), R8 | |||
// Get function. | |||
MOVD CAA(R8), R9 | |||
MOVD EDCHPXV(R9), R9 | |||
MOVD trap+0(FP), R5 | |||
SLD $4, R5 | |||
ADD R5, R9 | |||
LMG 0(R9), R5, R6 | |||
// Restore LE stack. | |||
MOVD SAVSTACK_ASYNC(R8), R9 | |||
MOVD 0(R9), R4 | |||
MOVD $0, 0(R9) | |||
// Fill in parameter list. | |||
MOVD a4+32(FP), R12 | |||
MOVD R12, (2176+24)(R4) | |||
MOVD a5+40(FP), R12 | |||
MOVD R12, (2176+32)(R4) | |||
MOVD a6+48(FP), R12 | |||
MOVD R12, (2176+40)(R4) | |||
// Call function. | |||
LE_CALL | |||
NOPH | |||
XOR R0, R0 // Restore R0 to $0. | |||
MOVD R4, 0(R9) // Save stack pointer. | |||
MOVD R3, r1+56(FP) | |||
MOVD R0, r2+64(FP) | |||
MOVD R0, err+72(FP) | |||
MOVW R3, R4 | |||
CMP R4, $-1 | |||
BNE done | |||
BL ·rrno<>(SB) | |||
MOVWZ 0(R3), R3 | |||
MOVD R3, err+72(FP) | |||
done: | |||
RET | |||
TEXT ·syscall_syscall9(SB),NOSPLIT,$0 | |||
BL runtime·entersyscall(SB) | |||
MOVD a1+8(FP), R1 | |||
MOVD a2+16(FP), R2 | |||
MOVD a3+24(FP), R3 | |||
// Get library control area (LCA). | |||
MOVW PSALAA, R8 | |||
MOVD LCA64(R8), R8 | |||
// Get function. | |||
MOVD CAA(R8), R9 | |||
MOVD EDCHPXV(R9), R9 | |||
MOVD trap+0(FP), R5 | |||
SLD $4, R5 | |||
ADD R5, R9 | |||
LMG 0(R9), R5, R6 | |||
// Restore LE stack. | |||
MOVD SAVSTACK_ASYNC(R8), R9 | |||
MOVD 0(R9), R4 | |||
MOVD $0, 0(R9) | |||
// Fill in parameter list. | |||
MOVD a4+32(FP), R12 | |||
MOVD R12, (2176+24)(R4) | |||
MOVD a5+40(FP), R12 | |||
MOVD R12, (2176+32)(R4) | |||
MOVD a6+48(FP), R12 | |||
MOVD R12, (2176+40)(R4) | |||
MOVD a7+56(FP), R12 | |||
MOVD R12, (2176+48)(R4) | |||
MOVD a8+64(FP), R12 | |||
MOVD R12, (2176+56)(R4) | |||
MOVD a9+72(FP), R12 | |||
MOVD R12, (2176+64)(R4) | |||
// Call function. | |||
LE_CALL | |||
NOPH | |||
XOR R0, R0 // Restore R0 to $0. | |||
MOVD R4, 0(R9) // Save stack pointer. | |||
MOVD R3, r1+80(FP) | |||
MOVD R0, r2+88(FP) | |||
MOVD R0, err+96(FP) | |||
MOVW R3, R4 | |||
CMP R4, $-1 | |||
BNE done | |||
BL addrerrno<>(SB) | |||
MOVWZ 0(R3), R3 | |||
MOVD R3, err+96(FP) | |||
done: | |||
BL runtime·exitsyscall(SB) | |||
RET | |||
TEXT ·syscall_rawsyscall9(SB),NOSPLIT,$0 | |||
MOVD a1+8(FP), R1 | |||
MOVD a2+16(FP), R2 | |||
MOVD a3+24(FP), R3 | |||
// Get library control area (LCA). | |||
MOVW PSALAA, R8 | |||
MOVD LCA64(R8), R8 | |||
// Get function. | |||
MOVD CAA(R8), R9 | |||
MOVD EDCHPXV(R9), R9 | |||
MOVD trap+0(FP), R5 | |||
SLD $4, R5 | |||
ADD R5, R9 | |||
LMG 0(R9), R5, R6 | |||
// Restore LE stack. | |||
MOVD SAVSTACK_ASYNC(R8), R9 | |||
MOVD 0(R9), R4 | |||
MOVD $0, 0(R9) | |||
// Fill in parameter list. | |||
MOVD a4+32(FP), R12 | |||
MOVD R12, (2176+24)(R4) | |||
MOVD a5+40(FP), R12 | |||
MOVD R12, (2176+32)(R4) | |||
MOVD a6+48(FP), R12 | |||
MOVD R12, (2176+40)(R4) | |||
MOVD a7+56(FP), R12 | |||
MOVD R12, (2176+48)(R4) | |||
MOVD a8+64(FP), R12 | |||
MOVD R12, (2176+56)(R4) | |||
MOVD a9+72(FP), R12 | |||
MOVD R12, (2176+64)(R4) | |||
// Call function. | |||
LE_CALL | |||
NOPH | |||
XOR R0, R0 // Restore R0 to $0. | |||
MOVD R4, 0(R9) // Save stack pointer. | |||
MOVD R3, r1+80(FP) | |||
MOVD R0, r2+88(FP) | |||
MOVD R0, err+96(FP) | |||
MOVW R3, R4 | |||
CMP R4, $-1 | |||
BNE done | |||
BL addrerrno<>(SB) | |||
MOVWZ 0(R3), R3 | |||
MOVD R3, err+96(FP) | |||
done: | |||
RET | |||
// func svcCall(fnptr unsafe.Pointer, argv *unsafe.Pointer, dsa *uint64) | |||
TEXT ·svcCall(SB),NOSPLIT,$0 | |||
BL runtime·save_g(SB) // Save g and stack pointer | |||
MOVW PSALAA, R8 | |||
MOVD LCA64(R8), R8 | |||
MOVD SAVSTACK_ASYNC(R8), R9 | |||
MOVD R15, 0(R9) | |||
MOVD argv+8(FP), R1 // Move function arguments into registers | |||
MOVD dsa+16(FP), g | |||
MOVD fnptr+0(FP), R15 | |||
BYTE $0x0D // Branch to function | |||
BYTE $0xEF | |||
BL runtime·load_g(SB) // Restore g and stack pointer | |||
MOVW PSALAA, R8 | |||
MOVD LCA64(R8), R8 | |||
MOVD SAVSTACK_ASYNC(R8), R9 | |||
MOVD 0(R9), R15 | |||
RET | |||
// func svcLoad(name *byte) unsafe.Pointer | |||
TEXT ·svcLoad(SB),NOSPLIT,$0 | |||
MOVD R15, R2 // Save go stack pointer | |||
MOVD name+0(FP), R0 // Move SVC args into registers | |||
MOVD $0x80000000, R1 | |||
MOVD $0, R15 | |||
BYTE $0x0A // SVC 08 LOAD | |||
BYTE $0x08 | |||
MOVW R15, R3 // Save return code from SVC | |||
MOVD R2, R15 // Restore go stack pointer | |||
CMP R3, $0 // Check SVC return code | |||
BNE error | |||
MOVD $-2, R3 // Reset last bit of entry point to zero | |||
AND R0, R3 | |||
MOVD R3, addr+8(FP) // Return entry point returned by SVC | |||
CMP R0, R3 // Check if last bit of entry point was set | |||
BNE done | |||
MOVD R15, R2 // Save go stack pointer | |||
MOVD $0, R15 // Move SVC args into registers (entry point still in r0 from SVC 08) | |||
BYTE $0x0A // SVC 09 DELETE | |||
BYTE $0x09 | |||
MOVD R2, R15 // Restore go stack pointer | |||
error: | |||
MOVD $0, addr+8(FP) // Return 0 on failure | |||
done: | |||
XOR R0, R0 // Reset r0 to 0 | |||
RET | |||
// func svcUnload(name *byte, fnptr unsafe.Pointer) int64 | |||
TEXT ·svcUnload(SB),NOSPLIT,$0 | |||
MOVD R15, R2 // Save go stack pointer | |||
MOVD name+0(FP), R0 // Move SVC args into registers | |||
MOVD addr+8(FP), R15 | |||
BYTE $0x0A // SVC 09 | |||
BYTE $0x09 | |||
XOR R0, R0 // Reset r0 to 0 | |||
MOVD R15, R1 // Save SVC return code | |||
MOVD R2, R15 // Restore go stack pointer | |||
MOVD R1, rc+0(FP) // Return SVC return code | |||
RET | |||
// func gettid() uint64 | |||
TEXT ·gettid(SB), NOSPLIT, $0 | |||
// Get library control area (LCA). | |||
MOVW PSALAA, R8 | |||
MOVD LCA64(R8), R8 | |||
// Get CEECAATHDID | |||
MOVD CAA(R8), R9 | |||
MOVD 0x3D0(R9), R9 | |||
MOVD R9, ret+0(FP) | |||
RET |
@@ -2,6 +2,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build freebsd | |||
// +build freebsd | |||
package unix | |||
@@ -2,7 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris | |||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos | |||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos | |||
package unix | |||
@@ -2,8 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build aix | |||
// +build ppc | |||
//go:build aix && ppc | |||
// +build aix,ppc | |||
// Functions to access/create device major and minor numbers matching the | |||
// encoding used by AIX. | |||
@@ -2,8 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build aix | |||
// +build ppc64 | |||
//go:build aix && ppc64 | |||
// +build aix,ppc64 | |||
// Functions to access/create device major and minor numbers matching the | |||
// encoding used AIX. | |||
@@ -0,0 +1,29 @@ | |||
// Copyright 2020 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. | |||
//go:build zos && s390x | |||
// +build zos,s390x | |||
// Functions to access/create device major and minor numbers matching the | |||
// encoding used by z/OS. | |||
// | |||
// The information below is extracted and adapted from <sys/stat.h> macros. | |||
package unix | |||
// Major returns the major component of a z/OS device number. | |||
func Major(dev uint64) uint32 { | |||
return uint32((dev >> 16) & 0x0000FFFF) | |||
} | |||
// Minor returns the minor component of a z/OS device number. | |||
func Minor(dev uint64) uint32 { | |||
return uint32(dev & 0x0000FFFF) | |||
} | |||
// Mkdev returns a z/OS device number generated from the given major and minor | |||
// components. | |||
func Mkdev(major, minor uint32) uint64 { | |||
return (uint64(major) << 16) | uint64(minor) | |||
} |
@@ -2,6 +2,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris | |||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris | |||
package unix | |||
@@ -2,7 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// | |||
// +build ppc64 s390x mips mips64 | |||
//go:build armbe || arm64be || m68k || mips || mips64 || mips64p32 || ppc || ppc64 || s390 || s390x || shbe || sparc || sparc64 | |||
// +build armbe arm64be m68k mips mips64 mips64p32 ppc ppc64 s390 s390x shbe sparc sparc64 | |||
package unix | |||
@@ -2,7 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// | |||
// +build 386 amd64 amd64p32 arm arm64 ppc64le mipsle mips64le riscv64 | |||
//go:build 386 || amd64 || amd64p32 || alpha || arm || arm64 || mipsle || mips64le || mips64p32le || nios2 || ppc64le || riscv || riscv64 || sh | |||
// +build 386 amd64 amd64p32 alpha arm arm64 mipsle mips64le mips64p32le nios2 ppc64le riscv riscv64 sh | |||
package unix | |||
@@ -2,7 +2,8 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris | |||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos | |||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos | |||
// Unix environment variables. | |||
@@ -0,0 +1,221 @@ | |||
// Copyright 2020 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. | |||
//go:build zos && s390x | |||
// +build zos,s390x | |||
package unix | |||
import ( | |||
"sync" | |||
) | |||
// This file simulates epoll on z/OS using poll. | |||
// Analogous to epoll_event on Linux. | |||
// TODO(neeilan): Pad is because the Linux kernel expects a 96-bit struct. We never pass this to the kernel; remove? | |||
type EpollEvent struct { | |||
Events uint32 | |||
Fd int32 | |||
Pad int32 | |||
} | |||
const ( | |||
EPOLLERR = 0x8 | |||
EPOLLHUP = 0x10 | |||
EPOLLIN = 0x1 | |||
EPOLLMSG = 0x400 | |||
EPOLLOUT = 0x4 | |||
EPOLLPRI = 0x2 | |||
EPOLLRDBAND = 0x80 | |||
EPOLLRDNORM = 0x40 | |||
EPOLLWRBAND = 0x200 | |||
EPOLLWRNORM = 0x100 | |||
EPOLL_CTL_ADD = 0x1 | |||
EPOLL_CTL_DEL = 0x2 | |||
EPOLL_CTL_MOD = 0x3 | |||
// The following constants are part of the epoll API, but represent | |||
// currently unsupported functionality on z/OS. | |||
// EPOLL_CLOEXEC = 0x80000 | |||
// EPOLLET = 0x80000000 | |||
// EPOLLONESHOT = 0x40000000 | |||
// EPOLLRDHUP = 0x2000 // Typically used with edge-triggered notis | |||
// EPOLLEXCLUSIVE = 0x10000000 // Exclusive wake-up mode | |||
// EPOLLWAKEUP = 0x20000000 // Relies on Linux's BLOCK_SUSPEND capability | |||
) | |||
// TODO(neeilan): We can eliminate these epToPoll / pToEpoll calls by using identical mask values for POLL/EPOLL | |||
// constants where possible The lower 16 bits of epoll events (uint32) can fit any system poll event (int16). | |||
// epToPollEvt converts epoll event field to poll equivalent. | |||
// In epoll, Events is a 32-bit field, while poll uses 16 bits. | |||
func epToPollEvt(events uint32) int16 { | |||
var ep2p = map[uint32]int16{ | |||
EPOLLIN: POLLIN, | |||
EPOLLOUT: POLLOUT, | |||
EPOLLHUP: POLLHUP, | |||
EPOLLPRI: POLLPRI, | |||
EPOLLERR: POLLERR, | |||
} | |||
var pollEvts int16 = 0 | |||
for epEvt, pEvt := range ep2p { | |||
if (events & epEvt) != 0 { | |||
pollEvts |= pEvt | |||
} | |||
} | |||
return pollEvts | |||
} | |||
// pToEpollEvt converts 16 bit poll event bitfields to 32-bit epoll event fields. | |||
func pToEpollEvt(revents int16) uint32 { | |||
var p2ep = map[int16]uint32{ | |||
POLLIN: EPOLLIN, | |||
POLLOUT: EPOLLOUT, | |||
POLLHUP: EPOLLHUP, | |||
POLLPRI: EPOLLPRI, | |||
POLLERR: EPOLLERR, | |||
} | |||
var epollEvts uint32 = 0 | |||
for pEvt, epEvt := range p2ep { | |||
if (revents & pEvt) != 0 { | |||
epollEvts |= epEvt | |||
} | |||
} | |||
return epollEvts | |||
} | |||
// Per-process epoll implementation. | |||
type epollImpl struct { | |||
mu sync.Mutex | |||
epfd2ep map[int]*eventPoll | |||
nextEpfd int | |||
} | |||
// eventPoll holds a set of file descriptors being watched by the process. A process can have multiple epoll instances. | |||
// On Linux, this is an in-kernel data structure accessed through a fd. | |||
type eventPoll struct { | |||
mu sync.Mutex | |||
fds map[int]*EpollEvent | |||
} | |||
// epoll impl for this process. | |||
var impl epollImpl = epollImpl{ | |||
epfd2ep: make(map[int]*eventPoll), | |||
nextEpfd: 0, | |||
} | |||
func (e *epollImpl) epollcreate(size int) (epfd int, err error) { | |||
e.mu.Lock() | |||
defer e.mu.Unlock() | |||
epfd = e.nextEpfd | |||
e.nextEpfd++ | |||
e.epfd2ep[epfd] = &eventPoll{ | |||
fds: make(map[int]*EpollEvent), | |||
} | |||
return epfd, nil | |||
} | |||
func (e *epollImpl) epollcreate1(flag int) (fd int, err error) { | |||
return e.epollcreate(4) | |||
} | |||
func (e *epollImpl) epollctl(epfd int, op int, fd int, event *EpollEvent) (err error) { | |||
e.mu.Lock() | |||
defer e.mu.Unlock() | |||
ep, ok := e.epfd2ep[epfd] | |||
if !ok { | |||
return EBADF | |||
} | |||
switch op { | |||
case EPOLL_CTL_ADD: | |||
// TODO(neeilan): When we make epfds and fds disjoint, detect epoll | |||
// loops here (instances watching each other) and return ELOOP. | |||
if _, ok := ep.fds[fd]; ok { | |||
return EEXIST | |||
} | |||
ep.fds[fd] = event | |||
case EPOLL_CTL_MOD: | |||
if _, ok := ep.fds[fd]; !ok { | |||
return ENOENT | |||
} | |||
ep.fds[fd] = event | |||
case EPOLL_CTL_DEL: | |||
if _, ok := ep.fds[fd]; !ok { | |||
return ENOENT | |||
} | |||
delete(ep.fds, fd) | |||
} | |||
return nil | |||
} | |||
// Must be called while holding ep.mu | |||
func (ep *eventPoll) getFds() []int { | |||
fds := make([]int, len(ep.fds)) | |||
for fd := range ep.fds { | |||
fds = append(fds, fd) | |||
} | |||
return fds | |||
} | |||
func (e *epollImpl) epollwait(epfd int, events []EpollEvent, msec int) (n int, err error) { | |||
e.mu.Lock() // in [rare] case of concurrent epollcreate + epollwait | |||
ep, ok := e.epfd2ep[epfd] | |||
if !ok { | |||
e.mu.Unlock() | |||
return 0, EBADF | |||
} | |||
pollfds := make([]PollFd, 4) | |||
for fd, epollevt := range ep.fds { | |||
pollfds = append(pollfds, PollFd{Fd: int32(fd), Events: epToPollEvt(epollevt.Events)}) | |||
} | |||
e.mu.Unlock() | |||
n, err = Poll(pollfds, msec) | |||
if err != nil { | |||
return n, err | |||
} | |||
i := 0 | |||
for _, pFd := range pollfds { | |||
if pFd.Revents != 0 { | |||
events[i] = EpollEvent{Fd: pFd.Fd, Events: pToEpollEvt(pFd.Revents)} | |||
i++ | |||
} | |||
if i == n { | |||
break | |||
} | |||
} | |||
return n, nil | |||
} | |||
func EpollCreate(size int) (fd int, err error) { | |||
return impl.epollcreate(size) | |||
} | |||
func EpollCreate1(flag int) (fd int, err error) { | |||
return impl.epollcreate1(flag) | |||
} | |||
func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { | |||
return impl.epollctl(epfd, op, fd, event) | |||
} | |||
// Because EpollWait mutates events, the caller is expected to coordinate | |||
// concurrent access if calling with the same epfd from multiple goroutines. | |||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { | |||
return impl.epollwait(epfd, events, msec) | |||
} |
@@ -2,6 +2,7 @@ | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
//go:build dragonfly || freebsd || linux || netbsd || openbsd | |||
// +build dragonfly freebsd linux netbsd openbsd | |||
package unix | |||