From 8f0adf1186b1da18446dda9b893f01e8ca0a50e2 Mon Sep 17 00:00:00 2001 From: Vyacheslav Pachkov Date: Fri, 24 Sep 2021 12:02:41 +0300 Subject: [PATCH] runtime: check amd64 microarchitecture level at startup Make Go runtime throw if it's been compiled to assume instruction set extensions that aren't available on the CPU. Updates #485064 --- src/runtime/asm_amd64.s | 78 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s index 3ab6060ec0c608..bc5ed40db5b2a6 100644 --- a/src/runtime/asm_amd64.s +++ b/src/runtime/asm_amd64.s @@ -78,6 +78,30 @@ 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_proc_msg<>+0x00(SB)/78, $"This program can only be run on processors with v2 microarchitecture support.\n" +#endif + +#ifdef GOAMD64_v3 +DATA bad_proc_msg<>+0x00(SB)/78, $"This program can only be run on processors with v3 microarchitecture support.\n" +#endif + +GLOBL bad_proc_msg<>(SB), RODATA, $78 + +// 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) + TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 // copy arguments forward on an even stack MOVQ DI, AX // argc @@ -101,8 +125,23 @@ TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0 CPUID MOVL AX, SI CMPL AX, $0 - JE nocpuinfo +#ifdef GOAMD64_v1 + JE nocpuinfo +#else + JNE has_cpuinfo + +bad_proc: // show that the program requires a certain microarchitecture level. + MOVQ $2, 0(SP) + MOVQ $bad_proc_msg<>(SB), AX + MOVQ AX, 8(SP) + MOVQ $78, 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 +149,48 @@ 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 GOAMD64_v2 + ANDL $V2_FEATURES_CX, CX + CMPL CX, $V2_FEATURES_CX + JNZ bad_proc + MOVL $0x80000000, AX + CPUID + CMPL AX, $0x80000001 + JL bad_proc + MOVL $0x80000001, AX + CPUID + TESTL $V2_EXT_FEATURES_CX, CX + JZ bad_proc +#endif + +#ifdef GOAMD64_v3 + ANDL $V3_FEATURES_CX, CX + CMPL CX, $V3_FEATURES_CX + JNZ bad_proc + MOVL $7, AX + MOVL $0, CX + CPUID + ANDL $V3_EXT_FEATURES_BX, BX + CMPL BX, $V3_EXT_FEATURES_BX + JNZ bad_proc + MOVL $0x80000000, AX + CPUID + CMPL AX, $0x80000001 + JL bad_proc + MOVL $0x80000001, AX + CPUID + ANDL $V3_EXT_FEATURES_CX, CX + CMPL CX, $V3_EXT_FEATURES_CX + JNZ bad_proc +#endif + nocpuinfo: // if there is an _cgo_init, call it. MOVQ _cgo_init(SB), AX