mirror of
https://github.com/golang/go.git
synced 2026-04-03 01:40:30 +09:00
internal/cpu: use IsProcessorFeaturePresent to calculate ARM64 on windows
This CL also adds internal/syscall/windows.IsProcessorFeaturePresent and all processor feature consts to test internal/cpu changes. For #76791 Change-Id: Iba9cc812f676b700e767a1ed7f194fcb4a67f61b Cq-Include-Trybots: luci.golang.try:gotip-windows-arm64 Reviewed-on: https://go-review.googlesource.com/c/go/+/745560 Reviewed-by: Quim Muntal <quimmuntal@gmail.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Mark Freeman <markfreeman@google.com> Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build arm64 && !linux && !freebsd && !android && (!darwin || ios) && !openbsd
|
||||
//go:build arm64 && !linux && !freebsd && !android && (!darwin || ios) && !openbsd && !windows
|
||||
|
||||
package cpu
|
||||
|
||||
|
||||
26
src/internal/cpu/cpu_arm64_windows.go
Normal file
26
src/internal/cpu/cpu_arm64_windows.go
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build arm64
|
||||
|
||||
package cpu
|
||||
|
||||
func osInit() {
|
||||
// TODO(brainman): we don't know how to retrieve those bits form user space - leaving them as false for now
|
||||
// https://github.com/golang/go/issues/76791#issuecomment-3877873959
|
||||
ARM64.HasCPUID = false
|
||||
ARM64.HasDIT = false
|
||||
ARM64.IsNeoverse = false
|
||||
|
||||
if isProcessorFeaturePresent(_PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) {
|
||||
ARM64.HasAES = true
|
||||
ARM64.HasPMULL = true
|
||||
ARM64.HasSHA1 = true
|
||||
ARM64.HasSHA2 = true
|
||||
}
|
||||
ARM64.HasSHA3 = isProcessorFeaturePresent(_PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasCRC32 = isProcessorFeaturePresent(_PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasSHA512 = isProcessorFeaturePresent(_PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE)
|
||||
ARM64.HasATOMICS = isProcessorFeaturePresent(_PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)
|
||||
}
|
||||
20
src/internal/cpu/cpu_windows.go
Normal file
20
src/internal/cpu/cpu_windows.go
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cpu
|
||||
|
||||
import _ "unsafe" // for linkname
|
||||
|
||||
const (
|
||||
_PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE = 30
|
||||
_PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE = 31
|
||||
_PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE = 34
|
||||
_PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE = 64
|
||||
_PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE = 65
|
||||
)
|
||||
|
||||
// isProcessorFeaturePresent calls windows IsProcessorFeaturePresent API.
|
||||
//
|
||||
//go:linkname isProcessorFeaturePresent
|
||||
func isProcessorFeaturePresent(processorFeature uint32) bool // Implemented in runtime package.
|
||||
54
src/internal/cpu/cpu_windows_test.go
Normal file
54
src/internal/cpu/cpu_windows_test.go
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright 2026 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cpu_test
|
||||
|
||||
import (
|
||||
"internal/cpu"
|
||||
"internal/syscall/windows"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestARM64WindowsFeatures(t *testing.T) {
|
||||
if runtime.GOARCH != "amd64" {
|
||||
return
|
||||
}
|
||||
|
||||
if cpu.ARM64.HasCPUID {
|
||||
t.Fatal("HasCPUID expected false, got true")
|
||||
}
|
||||
if cpu.ARM64.HasDIT {
|
||||
t.Fatal("HasDIT expected false, got true")
|
||||
}
|
||||
if cpu.ARM64.IsNeoverse {
|
||||
t.Fatal("IsNeoverse expected false, got true")
|
||||
}
|
||||
|
||||
if got, want := cpu.ARM64.HasAES, windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); got != want {
|
||||
t.Fatalf("HasAES expected %v, got %v", want, got)
|
||||
}
|
||||
if got, want := cpu.ARM64.HasPMULL, windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); got != want {
|
||||
t.Fatalf("HasPMULL expected %v, got %v", want, got)
|
||||
}
|
||||
if got, want := cpu.ARM64.HasSHA1, windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); got != want {
|
||||
t.Fatalf("HasSHA1 expected %v, got %v", want, got)
|
||||
}
|
||||
if got, want := cpu.ARM64.HasSHA2, windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); got != want {
|
||||
t.Fatalf("HasSHA2 expected %v, got %v", want, got)
|
||||
}
|
||||
|
||||
if got, want := cpu.ARM64.HasSHA3, windows.IsProcessorFeaturePresent(windows.PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE); got != want {
|
||||
t.Fatalf("HasSHA3 expected %v, got %v", want, got)
|
||||
}
|
||||
if got, want := cpu.ARM64.HasCRC32, windows.IsProcessorFeaturePresent(windows.PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE); got != want {
|
||||
t.Fatalf("HasCRC32 expected %v, got %v", want, got)
|
||||
}
|
||||
if got, want := cpu.ARM64.HasSHA512, windows.IsProcessorFeaturePresent(windows.PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE); got != want {
|
||||
t.Fatalf("HasSHA512 expected %v, got %v", want, got)
|
||||
}
|
||||
if got, want := cpu.ARM64.HasATOMICS, windows.IsProcessorFeaturePresent(windows.PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE); got != want {
|
||||
t.Fatalf("HasATOMICS expected %v, got %v", want, got)
|
||||
}
|
||||
}
|
||||
@@ -573,6 +573,8 @@ type FILE_MODE_INFORMATION struct {
|
||||
Mode uint32
|
||||
}
|
||||
|
||||
//sys IsProcessorFeaturePresent(ProcessorFeature uint32) (ret bool) = kernel32.IsProcessorFeaturePresent
|
||||
|
||||
// NT Native APIs
|
||||
//sys NtCreateFile(handle *syscall.Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, allocationSize *int64, attributes uint32, share uint32, disposition uint32, options uint32, eabuffer unsafe.Pointer, ealength uint32) (ntstatus error) = ntdll.NtCreateFile
|
||||
//sys NtOpenFile(handle *syscall.Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, share uint32, options uint32) (ntstatus error) = ntdll.NtOpenFile
|
||||
|
||||
@@ -383,3 +383,88 @@ const (
|
||||
PROCESS_TRUST_LABEL_SECURITY_INFORMATION = 0x00000080
|
||||
BACKUP_SECURITY_INFORMATION = 0x00010000
|
||||
)
|
||||
|
||||
// The processor features to be tested for IsProcessorFeaturePresent, see
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent
|
||||
const (
|
||||
PF_ARM_64BIT_LOADSTORE_ATOMIC = 25
|
||||
PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE = 24
|
||||
PF_ARM_EXTERNAL_CACHE_AVAILABLE = 26
|
||||
PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE = 27
|
||||
PF_ARM_VFP_32_REGISTERS_AVAILABLE = 18
|
||||
PF_3DNOW_INSTRUCTIONS_AVAILABLE = 7
|
||||
PF_CHANNELS_ENABLED = 16
|
||||
PF_COMPARE_EXCHANGE_DOUBLE = 2
|
||||
PF_COMPARE_EXCHANGE128 = 14
|
||||
PF_COMPARE64_EXCHANGE128 = 15
|
||||
PF_FASTFAIL_AVAILABLE = 23
|
||||
PF_FLOATING_POINT_EMULATED = 1
|
||||
PF_FLOATING_POINT_PRECISION_ERRATA = 0
|
||||
PF_MMX_INSTRUCTIONS_AVAILABLE = 3
|
||||
PF_NX_ENABLED = 12
|
||||
PF_PAE_ENABLED = 9
|
||||
PF_RDTSC_INSTRUCTION_AVAILABLE = 8
|
||||
PF_RDWRFSGSBASE_AVAILABLE = 22
|
||||
PF_SECOND_LEVEL_ADDRESS_TRANSLATION = 20
|
||||
PF_SSE3_INSTRUCTIONS_AVAILABLE = 13
|
||||
PF_SSSE3_INSTRUCTIONS_AVAILABLE = 36
|
||||
PF_SSE4_1_INSTRUCTIONS_AVAILABLE = 37
|
||||
PF_SSE4_2_INSTRUCTIONS_AVAILABLE = 38
|
||||
PF_AVX_INSTRUCTIONS_AVAILABLE = 39
|
||||
PF_AVX2_INSTRUCTIONS_AVAILABLE = 40
|
||||
PF_AVX512F_INSTRUCTIONS_AVAILABLE = 41
|
||||
PF_VIRT_FIRMWARE_ENABLED = 21
|
||||
PF_XMMI_INSTRUCTIONS_AVAILABLE = 6
|
||||
PF_XMMI64_INSTRUCTIONS_AVAILABLE = 10
|
||||
PF_XSAVE_ENABLED = 17
|
||||
PF_ARM_V8_INSTRUCTIONS_AVAILABLE = 29
|
||||
PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE = 30
|
||||
PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE = 31
|
||||
PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE = 34
|
||||
PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE = 43
|
||||
PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE = 44
|
||||
PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE = 45
|
||||
PF_ARM_SVE_INSTRUCTIONS_AVAILABLE = 46
|
||||
PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE = 47
|
||||
PF_ARM_SVE2_1_INSTRUCTIONS_AVAILABLE = 48
|
||||
PF_ARM_SVE_AES_INSTRUCTIONS_AVAILABLE = 49
|
||||
PF_ARM_SVE_PMULL128_INSTRUCTIONS_AVAILABLE = 50
|
||||
PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE = 51
|
||||
PF_ARM_SVE_BF16_INSTRUCTIONS_AVAILABLE = 52
|
||||
PF_ARM_SVE_EBF16_INSTRUCTIONS_AVAILABLE = 53
|
||||
PF_ARM_SVE_B16B16_INSTRUCTIONS_AVAILABLE = 54
|
||||
PF_ARM_SVE_SHA3_INSTRUCTIONS_AVAILABLE = 55
|
||||
PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE = 56
|
||||
PF_ARM_SVE_I8MM_INSTRUCTIONS_AVAILABLE = 57
|
||||
PF_ARM_SVE_F32MM_INSTRUCTIONS_AVAILABLE = 58
|
||||
PF_ARM_SVE_F64MM_INSTRUCTIONS_AVAILABLE = 59
|
||||
PF_BMI2_INSTRUCTIONS_AVAILABLE = 60
|
||||
PF_MOVDIR64B_INSTRUCTION_AVAILABLE = 61
|
||||
PF_ARM_LSE2_AVAILABLE = 62
|
||||
PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE = 64
|
||||
PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE = 65
|
||||
PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE = 66
|
||||
PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE = 67
|
||||
PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE = 68
|
||||
PF_ARM_V86_EBF16_INSTRUCTIONS_AVAILABLE = 69
|
||||
PF_ARM_SME_INSTRUCTIONS_AVAILABLE = 70
|
||||
PF_ARM_SME2_INSTRUCTIONS_AVAILABLE = 71
|
||||
PF_ARM_SME2_1_INSTRUCTIONS_AVAILABLE = 72
|
||||
PF_ARM_SME2_2_INSTRUCTIONS_AVAILABLE = 73
|
||||
PF_ARM_SME_AES_INSTRUCTIONS_AVAILABLE = 74
|
||||
PF_ARM_SME_SBITPERM_INSTRUCTIONS_AVAILABLE = 75
|
||||
PF_ARM_SME_SF8MM4_INSTRUCTIONS_AVAILABLE = 76
|
||||
PF_ARM_SME_SF8MM8_INSTRUCTIONS_AVAILABLE = 77
|
||||
PF_ARM_SME_SF8DP2_INSTRUCTIONS_AVAILABLE = 78
|
||||
PF_ARM_SME_SF8DP4_INSTRUCTIONS_AVAILABLE = 79
|
||||
PF_ARM_SME_SF8FMA_INSTRUCTIONS_AVAILABLE = 80
|
||||
PF_ARM_SME_F8F32_INSTRUCTIONS_AVAILABLE = 81
|
||||
PF_ARM_SME_F8F16_INSTRUCTIONS_AVAILABLE = 82
|
||||
PF_ARM_SME_F16F16_INSTRUCTIONS_AVAILABLE = 83
|
||||
PF_ARM_SME_B16B16_INSTRUCTIONS_AVAILABLE = 84
|
||||
PF_ARM_SME_F64F64_INSTRUCTIONS_AVAILABLE = 85
|
||||
PF_ARM_SME_I16I64_INSTRUCTIONS_AVAILABLE = 86
|
||||
PF_ARM_SME_LUTv2_INSTRUCTIONS_AVAILABLE = 87
|
||||
PF_ARM_SME_FA64_INSTRUCTIONS_AVAILABLE = 88
|
||||
PF_UMONITOR_INSTRUCTION_AVAILABLE = 89
|
||||
)
|
||||
|
||||
@@ -83,6 +83,7 @@ var (
|
||||
procGetTempPath2W = modkernel32.NewProc("GetTempPath2W")
|
||||
procGetVolumeInformationByHandleW = modkernel32.NewProc("GetVolumeInformationByHandleW")
|
||||
procGetVolumeNameForVolumeMountPointW = modkernel32.NewProc("GetVolumeNameForVolumeMountPointW")
|
||||
procIsProcessorFeaturePresent = modkernel32.NewProc("IsProcessorFeaturePresent")
|
||||
procLockFileEx = modkernel32.NewProc("LockFileEx")
|
||||
procModule32FirstW = modkernel32.NewProc("Module32FirstW")
|
||||
procModule32NextW = modkernel32.NewProc("Module32NextW")
|
||||
@@ -427,6 +428,12 @@ func GetVolumeNameForVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint
|
||||
return
|
||||
}
|
||||
|
||||
func IsProcessorFeaturePresent(ProcessorFeature uint32) (ret bool) {
|
||||
r0, _, _ := syscall.SyscallN(procIsProcessorFeaturePresent.Addr(), uintptr(ProcessorFeature))
|
||||
ret = r0 != 0
|
||||
return
|
||||
}
|
||||
|
||||
func LockFileEx(file syscall.Handle, flags uint32, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) {
|
||||
r1, _, e1 := syscall.SyscallN(procLockFileEx.Addr(), uintptr(file), uintptr(flags), uintptr(reserved), uintptr(bytesLow), uintptr(bytesHigh), uintptr(unsafe.Pointer(overlapped)))
|
||||
if r1 == 0 {
|
||||
|
||||
@@ -39,6 +39,7 @@ const (
|
||||
//go:cgo_import_dynamic runtime._GetSystemDirectoryA GetSystemDirectoryA%2 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo%1 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext%2 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._IsProcessorFeaturePresent IsProcessorFeaturePresent%1 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._SetThreadContext SetThreadContext%2 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._LoadLibraryExW LoadLibraryExW%3 "kernel32.dll"
|
||||
//go:cgo_import_dynamic runtime._PostQueuedCompletionStatus PostQueuedCompletionStatus%4 "kernel32.dll"
|
||||
@@ -96,6 +97,7 @@ var (
|
||||
_GetSystemDirectoryA,
|
||||
_GetSystemInfo,
|
||||
_GetThreadContext,
|
||||
_IsProcessorFeaturePresent,
|
||||
_SetThreadContext,
|
||||
_LoadLibraryExW,
|
||||
_PostQueuedCompletionStatus,
|
||||
@@ -261,6 +263,12 @@ func windows_QueryPerformanceFrequency() int64 {
|
||||
return frequency
|
||||
}
|
||||
|
||||
//go:linkname cpu_isProcessorFeaturePresent internal/cpu.isProcessorFeaturePresent
|
||||
func cpu_isProcessorFeaturePresent(processorFeature uint32) bool {
|
||||
ret := stdcall(_IsProcessorFeaturePresent, uintptr(processorFeature))
|
||||
return ret != 0
|
||||
}
|
||||
|
||||
func loadOptionalSyscalls() {
|
||||
bcryptPrimitives := windowsLoadSystemLib(bcryptprimitivesdll[:])
|
||||
if bcryptPrimitives == 0 {
|
||||
|
||||
Reference in New Issue
Block a user