]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: check amd64 microarchitecture level at startup
authorvpachkov <slava.pach@gmail.com>
Sun, 31 Oct 2021 11:06:27 +0000 (11:06 +0000)
committerKeith Randall <khr@golang.org>
Tue, 2 Nov 2021 16:40:04 +0000 (16:40 +0000)
Make Go runtime throw if it's been compiled to assume instruction
set extensions that aren't available on the CPU.
Updates #48506

Change-Id: Ic4d6696e1cd6b28d389a86fe64e8175ea3ca135a
GitHub-Last-Rev: ba338377f549344b416fbd519576e95ce5d523be
GitHub-Pull-Request: golang/go#48514
Reviewed-on: https://go-review.googlesource.com/c/go/+/351191
Run-TryBot: Martin Möhrmann <martin@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Martin Möhrmann <martin@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Trust: Martin Möhrmann <martin@golang.org>

src/runtime/asm_amd64.s

index 3ab6060ec0c60819f528c186f97cb95d257e83a2..0f0e5be21acac6be949293b5e71887f95814ed7f 100644 (file)
@@ -78,6 +78,87 @@ GLOBL _rt0_amd64_lib_argc<>(SB),NOPTR, $8
 DATA _rt0_amd64_lib_argv<>(SB)/8, $0
 GLOBL _rt0_amd64_lib_argv<>(SB),NOPTR, $8
 
+#ifdef GOAMD64_v2
+DATA bad_cpu_msg<>+0x00(SB)/84, $"This program can only be run on AMD64 processors with v2 microarchitecture support.\n"
+#endif
+
+#ifdef GOAMD64_v3
+DATA bad_cpu_msg<>+0x00(SB)/84, $"This program can only be run on AMD64 processors with v3 microarchitecture support.\n"
+#endif
+
+#ifdef GOAMD64_v4
+DATA bad_cpu_msg<>+0x00(SB)/84, $"This program can only be run on AMD64 processors with v4 microarchitecture support.\n"
+#endif
+
+GLOBL bad_cpu_msg<>(SB), RODATA, $84
+
+// Define a list of AMD64 microarchitecture level features
+// https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels
+
+                     // SSE3     SSSE3    CMPXCHNG16 SSE4.1    SSE4.2    POPCNT
+#define V2_FEATURES_CX (1 << 0 | 1 << 9 | 1 << 13  | 1 << 19 | 1 << 20 | 1 << 23)
+                         // LAHF/SAHF
+#define V2_EXT_FEATURES_CX (1 << 0)
+                                      // FMA       MOVBE     OSXSAVE   AVX       F16C
+#define V3_FEATURES_CX (V2_FEATURES_CX | 1 << 12 | 1 << 22 | 1 << 27 | 1 << 28 | 1 << 29)
+                                              // ABM (FOR LZNCT)
+#define V3_EXT_FEATURES_CX (V2_EXT_FEATURES_CX | 1 << 5)
+                         // BMI1     AVX2     BMI2
+#define V3_EXT_FEATURES_BX (1 << 3 | 1 << 5 | 1 << 8)
+                       // XMM      YMM
+#define V3_OS_SUPPORT_AX (1 << 1 | 1 << 2)
+
+#define V4_FEATURES_CX V3_FEATURES_CX
+
+#define V4_EXT_FEATURES_CX V3_EXT_FEATURES_CX
+                                              // AVX512F   AVX512DQ  AVX512CD  AVX512BW  AVX512VL
+#define V4_EXT_FEATURES_BX (V3_EXT_FEATURES_BX | 1 << 16 | 1 << 17 | 1 << 28 | 1 << 30 | 1 << 31)
+                                          // OPMASK   ZMM
+#define V4_OS_SUPPORT_AX (V3_OS_SUPPORT_AX | 1 << 5 | (1 << 6 | 1 << 7))
+
+#ifdef GOAMD64_v2
+#define NEED_MAX_CPUID 0x80000001
+#define NEED_FEATURES_CX V2_FEATURES_CX
+#define NEED_EXT_FEATURES_CX V2_EXT_FEATURES_CX
+#endif
+
+#ifdef GOAMD64_v3
+#define NEED_MAX_CPUID 0x80000001
+#define NEED_FEATURES_CX V3_FEATURES_CX
+#define NEED_EXT_FEATURES_CX V3_EXT_FEATURES_CX
+#define NEED_EXT_FEATURES_BX V3_EXT_FEATURES_BX
+#define NEED_OS_SUPPORT_AX V3_OS_SUPPORT_AX
+#endif
+
+#ifdef GOAMD64_v4
+#define NEED_MAX_CPUID 0x80000001
+#define NEED_FEATURES_CX V4_FEATURES_CX
+#define NEED_EXT_FEATURES_CX V4_EXT_FEATURES_CX
+#define NEED_EXT_FEATURES_BX V4_EXT_FEATURES_BX
+
+// Downgrading v4 OS checks on Darwin for now, see CL 285572.
+#ifdef GOOS_darwin
+#define NEED_OS_SUPPORT_AX V3_OS_SUPPORT_AX
+#else
+#define NEED_OS_SUPPORT_AX V4_OS_SUPPORT_AX
+#endif
+
+#endif
+
+#ifdef GOAMD64_v1
+#define SKIP_GOAMD64_CHECK
+#endif
+
+#ifndef GOAMD64_v1
+#ifndef GOAMD64_v2
+#ifndef GOAMD64_v3
+#ifndef GOAMD64_v4
+#define SKIP_GOAMD64_CHECK
+#endif
+#endif
+#endif
+#endif
+
 TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0
        // copy arguments forward on an even stack
        MOVQ    DI, AX          // argc
@@ -99,10 +180,24 @@ TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0
        // find out information about the processor we're on
        MOVL    $0, AX
        CPUID
-       MOVL    AX, SI
        CMPL    AX, $0
+#ifdef SKIP_GOAMD64_CHECK
        JE      nocpuinfo
+#else
+       JNE     has_cpuinfo
 
+bad_cpu: // show that the program requires a certain microarchitecture level.
+       MOVQ    $2, 0(SP)
+       MOVQ    $bad_cpu_msg<>(SB), AX
+       MOVQ    AX, 8(SP)
+       MOVQ    $84, 16(SP)
+       CALL    runtime·write(SB)
+       MOVQ    $1, 0(SP)
+       CALL    runtime·exit(SB)
+       CALL    runtime·abort(SB)
+#endif
+
+has_cpuinfo:
        CMPL    BX, $0x756E6547  // "Genu"
        JNE     notintel
        CMPL    DX, $0x49656E69  // "ineI"
@@ -110,13 +205,51 @@ TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0
        CMPL    CX, $0x6C65746E  // "ntel"
        JNE     notintel
        MOVB    $1, runtime·isIntel(SB)
-notintel:
 
+notintel:
        // Load EAX=1 cpuid flags
        MOVL    $1, AX
        CPUID
        MOVL    AX, runtime·processorVersionInfo(SB)
 
+#ifdef NEED_FEATURES_CX
+       ANDL    $NEED_FEATURES_CX, CX
+       CMPL    CX, $NEED_FEATURES_CX
+       JNE     bad_cpu
+#endif
+
+#ifdef NEED_MAX_CPUID
+       MOVL    $0x80000000, AX
+       CPUID
+       CMPL    AX, $NEED_MAX_CPUID
+       JL      bad_cpu
+#endif
+
+#ifdef NEED_EXT_FEATURES_BX
+       MOVL    $7, AX
+       MOVL    $0, CX
+       CPUID
+       ANDL    $NEED_EXT_FEATURES_BX, BX
+       CMPL    BX, $NEED_EXT_FEATURES_BX
+       JNE     bad_cpu
+#endif
+
+#ifdef NEED_EXT_FEATURES_CX
+       MOVL    $0x80000001, AX
+       CPUID
+       ANDL    $NEED_EXT_FEATURES_CX, CX
+       CMPL    CX, $NEED_EXT_FEATURES_CX
+       JNE     bad_cpu
+#endif
+
+#ifdef NEED_OS_SUPPORT_AX
+       XORL    CX, CX
+       XGETBV
+       ANDL    $NEED_OS_SUPPORT_AX, AX
+       CMPL    AX, $NEED_OS_SUPPORT_AX
+       JNE     bad_cpu
+#endif
+
 nocpuinfo:
        // if there is an _cgo_init, call it.
        MOVQ    _cgo_init(SB), AX