cpuid_arm64.go

 1//go:build gc
 2
 3package platform
 4
 5import "runtime"
 6
 7// CpuFeatures exposes the capabilities for this CPU, queried via the Has, HasExtra methods.
 8var CpuFeatures = loadCpuFeatureFlags()
 9
10// cpuFeatureFlags implements CpuFeatureFlags interface.
11type cpuFeatureFlags struct {
12	isar0 uint64
13	isar1 uint64
14}
15
16// implemented in cpuid_arm64.s
17func getisar0() uint64
18
19// implemented in cpuid_arm64.s
20func getisar1() uint64
21
22func loadCpuFeatureFlags() CpuFeatureFlags {
23	switch runtime.GOOS {
24	case "darwin", "windows":
25		// These OSes do not allow userland to read the instruction set attribute registers,
26		// but basically require atomic instructions:
27		// - "darwin" is the desktop version (mobile version is "ios"),
28		//   and the M1 is a ARMv8.4.
29		// - "windows" requires them from Windows 11, see page 12
30		//   https://download.microsoft.com/download/7/8/8/788bf5ab-0751-4928-a22c-dffdc23c27f2/Minimum%20Hardware%20Requirements%20for%20Windows%2011.pdf
31		return &cpuFeatureFlags{
32			isar0: uint64(CpuFeatureArm64Atomic),
33			isar1: 0,
34		}
35	case "linux", "freebsd":
36		// These OSes allow userland to read the instruction set attribute registers,
37		// which is otherwise restricted to EL0:
38		// https://kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt
39		// See these for contents of the registers:
40		// https://developer.arm.com/documentation/ddi0601/latest/AArch64-Registers/ID-AA64ISAR0-EL1--AArch64-Instruction-Set-Attribute-Register-0
41		// https://developer.arm.com/documentation/ddi0601/latest/AArch64-Registers/ID-AA64ISAR1-EL1--AArch64-Instruction-Set-Attribute-Register-1
42		return &cpuFeatureFlags{
43			isar0: getisar0(),
44			isar1: getisar1(),
45		}
46	default:
47		return &cpuFeatureFlags{}
48	}
49}
50
51// Has implements the same method on the CpuFeatureFlags interface.
52func (f *cpuFeatureFlags) Has(cpuFeature CpuFeature) bool {
53	return (f.isar0 & uint64(cpuFeature)) != 0
54}
55
56// HasExtra implements the same method on the CpuFeatureFlags interface.
57func (f *cpuFeatureFlags) HasExtra(cpuFeature CpuFeature) bool {
58	return (f.isar1 & uint64(cpuFeature)) != 0
59}
60
61// Raw implements the same method on the CpuFeatureFlags interface.
62func (f *cpuFeatureFlags) Raw() uint64 {
63	// Below, we only set bits for the features we care about,
64	// instead of setting all the unnecessary bits obtained from the
65	// instruction set attribute registers.
66	var ret uint64
67	if f.Has(CpuFeatureArm64Atomic) {
68		ret = 1 << 0
69	}
70	return ret
71}