windows: add IsProcessorFeaturePresent and processor feature consts

For golang/go#76791

Change-Id: I1594c4868262c78d40e1ebd883a01a71236e4981
Reviewed-on: https://go-review.googlesource.com/c/sys/+/740500
Reviewed-by: Quim Muntal <quimmuntal@gmail.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/windows/syscall_windows.go b/windows/syscall_windows.go
index 69439df..738a9f2 100644
--- a/windows/syscall_windows.go
+++ b/windows/syscall_windows.go
@@ -900,6 +900,7 @@
 //sys   NotifyRouteChange2(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyRouteChange2
 //sys   NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyUnicastIpAddressChange
 //sys   CancelMibChangeNotify2(notificationHandle Handle) (errcode error) = iphlpapi.CancelMibChangeNotify2
+//sys	IsProcessorFeaturePresent(ProcessorFeature uint32) (ret bool) = kernel32.IsProcessorFeaturePresent
 
 // For testing: clients can set this flag to force
 // creation of IPv6 sockets to return EAFNOSUPPORT.
diff --git a/windows/syscall_windows_test.go b/windows/syscall_windows_test.go
index f81fea0..7611538 100644
--- a/windows/syscall_windows_test.go
+++ b/windows/syscall_windows_test.go
@@ -1493,3 +1493,22 @@
 		}
 	}
 }
+
+func TestIsProcessorFeaturePresent(t *testing.T) {
+	// according to
+	// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent
+	// if PF_PAE_ENABLED returns nonzero value, then
+	// ...
+	// The processor is PAE-enabled. For more information, see Physical Address Extension.
+	// All x64 processors always return a nonzero value for this feature.
+	// ...
+	switch runtime.GOARCH {
+	case "amd64", "386":
+	default:
+		t.Skipf("the test is no supported by %q processor type", runtime.GOARCH)
+	}
+
+	if !windows.IsProcessorFeaturePresent(windows.PF_PAE_ENABLED) {
+		t.Fatal("IsProcessorFeaturePresent failed, but should succeed")
+	}
+}
diff --git a/windows/types_windows.go b/windows/types_windows.go
index 6e4f50e..d5658a1 100644
--- a/windows/types_windows.go
+++ b/windows/types_windows.go
@@ -3938,3 +3938,88 @@
 	MOUSE_EVENT              = 0x0002
 	WINDOW_BUFFER_SIZE_EVENT = 0x0004
 )
+
+// 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
+)
diff --git a/windows/zsyscall_windows.go b/windows/zsyscall_windows.go
index f25b730..fe7a4ea 100644
--- a/windows/zsyscall_windows.go
+++ b/windows/zsyscall_windows.go
@@ -320,6 +320,7 @@
 	procGetVolumePathNamesForVolumeNameW                     = modkernel32.NewProc("GetVolumePathNamesForVolumeNameW")
 	procGetWindowsDirectoryW                                 = modkernel32.NewProc("GetWindowsDirectoryW")
 	procInitializeProcThreadAttributeList                    = modkernel32.NewProc("InitializeProcThreadAttributeList")
+	procIsProcessorFeaturePresent                            = modkernel32.NewProc("IsProcessorFeaturePresent")
 	procIsWow64Process                                       = modkernel32.NewProc("IsWow64Process")
 	procIsWow64Process2                                      = modkernel32.NewProc("IsWow64Process2")
 	procLoadLibraryExW                                       = modkernel32.NewProc("LoadLibraryExW")
@@ -2786,6 +2787,12 @@
 	return
 }
 
+func IsProcessorFeaturePresent(ProcessorFeature uint32) (ret bool) {
+	r0, _, _ := syscall.SyscallN(procIsProcessorFeaturePresent.Addr(), uintptr(ProcessorFeature))
+	ret = r0 != 0
+	return
+}
+
 func IsWow64Process(handle Handle, isWow64 *bool) (err error) {
 	var _p0 uint32
 	if *isWow64 {