summaryrefslogtreecommitdiff
path: root/vendor/github.com/tetratelabs/wazero/internal/platform/cpuid_arm64.go
blob: 5430353fdbfec3de54ca62a4128dd267188d0bcf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
//go:build gc

package platform

import "runtime"

// CpuFeatures exposes the capabilities for this CPU, queried via the Has, HasExtra methods.
var CpuFeatures = loadCpuFeatureFlags()

// cpuFeatureFlags implements CpuFeatureFlags interface.
type cpuFeatureFlags struct {
	isar0 uint64
	isar1 uint64
}

// implemented in cpuid_arm64.s
func getisar0() uint64

// implemented in cpuid_arm64.s
func getisar1() uint64

func loadCpuFeatureFlags() CpuFeatureFlags {
	switch runtime.GOOS {
	case "darwin", "windows":
		// These OSes do not allow userland to read the instruction set attribute registers,
		// but basically require atomic instructions:
		// - "darwin" is the desktop version (mobile version is "ios"),
		//   and the M1 is a ARMv8.4.
		// - "windows" requires them from Windows 11, see page 12
		//   https://download.microsoft.com/download/7/8/8/788bf5ab-0751-4928-a22c-dffdc23c27f2/Minimum%20Hardware%20Requirements%20for%20Windows%2011.pdf
		return &cpuFeatureFlags{
			isar0: uint64(CpuFeatureArm64Atomic),
			isar1: 0,
		}
	case "linux", "freebsd":
		// These OSes allow userland to read the instruction set attribute registers,
		// which is otherwise restricted to EL0:
		// https://kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt
		// See these for contents of the registers:
		// https://developer.arm.com/documentation/ddi0601/latest/AArch64-Registers/ID-AA64ISAR0-EL1--AArch64-Instruction-Set-Attribute-Register-0
		// https://developer.arm.com/documentation/ddi0601/latest/AArch64-Registers/ID-AA64ISAR1-EL1--AArch64-Instruction-Set-Attribute-Register-1
		return &cpuFeatureFlags{
			isar0: getisar0(),
			isar1: getisar1(),
		}
	default:
		return &cpuFeatureFlags{}
	}
}

// Has implements the same method on the CpuFeatureFlags interface.
func (f *cpuFeatureFlags) Has(cpuFeature CpuFeature) bool {
	return (f.isar0 & uint64(cpuFeature)) != 0
}

// HasExtra implements the same method on the CpuFeatureFlags interface.
func (f *cpuFeatureFlags) HasExtra(cpuFeature CpuFeature) bool {
	return (f.isar1 & uint64(cpuFeature)) != 0
}

// Raw implements the same method on the CpuFeatureFlags interface.
func (f *cpuFeatureFlags) Raw() uint64 {
	// Below, we only set bits for the features we care about,
	// instead of setting all the unnecessary bits obtained from the
	// instruction set attribute registers.
	var ret uint64
	if f.Has(CpuFeatureArm64Atomic) {
		ret = 1 << 0
	}
	return ret
}