Skip to content

runtime: check amd64 microarchitecture level at startup #48514

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 135 additions & 2 deletions src/runtime/asm_amd64.s
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -99,24 +180,76 @@ 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"
JNE notintel
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
Expand Down