authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-11-28 21:36:56+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-11-28 21:36:56+01:00
logd3b1cdf508242cbef9b107aaf5ede627e63c9e7b
treee36ee941bad6ebf4753a3571633d9f0d2a625381
parenta660df4900520c505a0865707552dcc777f4b791
parent25281891013619aa767b02418d08d84d111fd7f1
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #13659 from ziglang/arm-win-cpu-features

windows: add native CPU and features detection for Armv8 chips

7 files changed, 931 insertions(+), 125 deletions(-)

lib/std/os/windows.zig+440-1
......@@ -2089,6 +2089,7 @@ pub const LPWSTR = [*:0]WCHAR;
20892089pub const LPCWSTR = [*:0]const WCHAR;
20902090pub const PVOID = *anyopaque;
20912091pub const PWSTR = [*:0]WCHAR;
2092pub const PCWSTR = [*:0]const WCHAR;
20922093pub const SIZE_T = usize;
20932094pub const UINT = c_uint;
20942095pub const ULONG_PTR = usize;
......@@ -2104,6 +2105,7 @@ pub const USHORT = u16;
21042105pub const SHORT = i16;
21052106pub const ULONG = u32;
21062107pub const LONG = i32;
2108pub const ULONG64 = u64;
21072109pub const ULONGLONG = u64;
21082110pub const LONGLONG = i64;
21092111pub const HLOCAL = HANDLE;
......@@ -2504,6 +2506,7 @@ pub const STANDARD_RIGHTS_READ = READ_CONTROL;
25042506pub const STANDARD_RIGHTS_WRITE = READ_CONTROL;
25052507pub const STANDARD_RIGHTS_EXECUTE = READ_CONTROL;
25062508pub const STANDARD_RIGHTS_REQUIRED = DELETE | READ_CONTROL | WRITE_DAC | WRITE_OWNER;
2509pub const MAXIMUM_ALLOWED = 0x02000000;
25072510
25082511// disposition for NtCreateFile
25092512pub const FILE_SUPERSEDE = 0;
......@@ -2872,9 +2875,143 @@ pub const PROV_RSA_FULL = 1;
28722875
28732876pub const REGSAM = ACCESS_MASK;
28742877pub const ACCESS_MASK = DWORD;
2875pub const HKEY = *opaque {};
28762878pub const LSTATUS = LONG;
28772879
2880pub const HKEY = *opaque {};
2881
2882pub const HKEY_LOCAL_MACHINE: HKEY = @intToPtr(HKEY, 0x80000002);
2883
2884/// Combines the STANDARD_RIGHTS_REQUIRED, KEY_QUERY_VALUE, KEY_SET_VALUE, KEY_CREATE_SUB_KEY,
2885/// KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, and KEY_CREATE_LINK access rights.
2886pub const KEY_ALL_ACCESS = 0xF003F;
2887/// Reserved for system use.
2888pub const KEY_CREATE_LINK = 0x0020;
2889/// Required to create a subkey of a registry key.
2890pub const KEY_CREATE_SUB_KEY = 0x0004;
2891/// Required to enumerate the subkeys of a registry key.
2892pub const KEY_ENUMERATE_SUB_KEYS = 0x0008;
2893/// Equivalent to KEY_READ.
2894pub const KEY_EXECUTE = 0x20019;
2895/// Required to request change notifications for a registry key or for subkeys of a registry key.
2896pub const KEY_NOTIFY = 0x0010;
2897/// Required to query the values of a registry key.
2898pub const KEY_QUERY_VALUE = 0x0001;
2899/// Combines the STANDARD_RIGHTS_READ, KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY values.
2900pub const KEY_READ = 0x20019;
2901/// Required to create, delete, or set a registry value.
2902pub const KEY_SET_VALUE = 0x0002;
2903/// Indicates that an application on 64-bit Windows should operate on the 32-bit registry view.
2904/// This flag is ignored by 32-bit Windows.
2905pub const KEY_WOW64_32KEY = 0x0200;
2906/// Indicates that an application on 64-bit Windows should operate on the 64-bit registry view.
2907/// This flag is ignored by 32-bit Windows.
2908pub const KEY_WOW64_64KEY = 0x0100;
2909/// Combines the STANDARD_RIGHTS_WRITE, KEY_SET_VALUE, and KEY_CREATE_SUB_KEY access rights.
2910pub const KEY_WRITE = 0x20006;
2911
2912/// Open symbolic link.
2913pub const REG_OPTION_OPEN_LINK: DWORD = 0x8;
2914
2915pub const RTL_QUERY_REGISTRY_TABLE = extern struct {
2916 QueryRoutine: RTL_QUERY_REGISTRY_ROUTINE,
2917 Flags: ULONG,
2918 Name: ?PWSTR,
2919 EntryContext: ?*anyopaque,
2920 DefaultType: ULONG,
2921 DefaultData: ?*anyopaque,
2922 DefaultLength: ULONG,
2923};
2924
2925pub const RTL_QUERY_REGISTRY_ROUTINE = ?std.meta.FnPtr(fn (
2926 PWSTR,
2927 ULONG,
2928 ?*anyopaque,
2929 ULONG,
2930 ?*anyopaque,
2931 ?*anyopaque,
2932) callconv(WINAPI) NTSTATUS);
2933
2934/// Path is a full path
2935pub const RTL_REGISTRY_ABSOLUTE = 0;
2936/// \Registry\Machine\System\CurrentControlSet\Services
2937pub const RTL_REGISTRY_SERVICES = 1;
2938/// \Registry\Machine\System\CurrentControlSet\Control
2939pub const RTL_REGISTRY_CONTROL = 2;
2940/// \Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion
2941pub const RTL_REGISTRY_WINDOWS_NT = 3;
2942/// \Registry\Machine\Hardware\DeviceMap
2943pub const RTL_REGISTRY_DEVICEMAP = 4;
2944/// \Registry\User\CurrentUser
2945pub const RTL_REGISTRY_USER = 5;
2946pub const RTL_REGISTRY_MAXIMUM = 6;
2947
2948/// Low order bits are registry handle
2949pub const RTL_REGISTRY_HANDLE = 0x40000000;
2950/// Indicates the key node is optional
2951pub const RTL_REGISTRY_OPTIONAL = 0x80000000;
2952
2953/// Name is a subkey and remainder of table or until next subkey are value
2954/// names for that subkey to look at.
2955pub const RTL_QUERY_REGISTRY_SUBKEY = 0x00000001;
2956
2957/// Reset current key to original key for this and all following table entries.
2958pub const RTL_QUERY_REGISTRY_TOPKEY = 0x00000002;
2959
2960/// Fail if no match found for this table entry.
2961pub const RTL_QUERY_REGISTRY_REQUIRED = 0x00000004;
2962
2963/// Used to mark a table entry that has no value name, just wants a call out, not
2964/// an enumeration of all values.
2965pub const RTL_QUERY_REGISTRY_NOVALUE = 0x00000008;
2966
2967/// Used to suppress the expansion of REG_MULTI_SZ into multiple callouts or
2968/// to prevent the expansion of environment variable values in REG_EXPAND_SZ.
2969pub const RTL_QUERY_REGISTRY_NOEXPAND = 0x00000010;
2970
2971/// QueryRoutine field ignored. EntryContext field points to location to store value.
2972/// For null terminated strings, EntryContext points to UNICODE_STRING structure that
2973/// that describes maximum size of buffer. If .Buffer field is NULL then a buffer is
2974/// allocated.
2975pub const RTL_QUERY_REGISTRY_DIRECT = 0x00000020;
2976
2977/// Used to delete value keys after they are queried.
2978pub const RTL_QUERY_REGISTRY_DELETE = 0x00000040;
2979
2980/// Use this flag with the RTL_QUERY_REGISTRY_DIRECT flag to verify that the REG_XXX type
2981/// of the stored registry value matches the type expected by the caller.
2982/// If the types do not match, the call fails.
2983pub const RTL_QUERY_REGISTRY_TYPECHECK = 0x00000100;
2984
2985pub const REG = struct {
2986 /// No value type
2987 pub const NONE: ULONG = 0;
2988 /// Unicode nul terminated string
2989 pub const SZ: ULONG = 1;
2990 /// Unicode nul terminated string (with environment variable references)
2991 pub const EXPAND_SZ: ULONG = 2;
2992 /// Free form binary
2993 pub const BINARY: ULONG = 3;
2994 /// 32-bit number
2995 pub const DWORD: ULONG = 4;
2996 /// 32-bit number (same as REG_DWORD)
2997 pub const DWORD_LITTLE_ENDIAN: ULONG = 4;
2998 /// 32-bit number
2999 pub const DWORD_BIG_ENDIAN: ULONG = 5;
3000 /// Symbolic Link (unicode)
3001 pub const LINK: ULONG = 6;
3002 /// Multiple Unicode strings
3003 pub const MULTI_SZ: ULONG = 7;
3004 /// Resource list in the resource map
3005 pub const RESOURCE_LIST: ULONG = 8;
3006 /// Resource list in the hardware description
3007 pub const FULL_RESOURCE_DESCRIPTOR: ULONG = 9;
3008 pub const RESOURCE_REQUIREMENTS_LIST: ULONG = 10;
3009 /// 64-bit number
3010 pub const QWORD: ULONG = 11;
3011 /// 64-bit number (same as REG_QWORD)
3012 pub const QWORD_LITTLE_ENDIAN: ULONG = 11;
3013};
3014
28783015pub const FILE_NOTIFY_INFORMATION = extern struct {
28793016 NextEntryOffset: DWORD,
28803017 Action: DWORD,
......@@ -3715,3 +3852,305 @@ pub const CTRL_LOGOFF_EVENT: DWORD = 5;
37153852pub const CTRL_SHUTDOWN_EVENT: DWORD = 6;
37163853
37173854pub const HANDLER_ROUTINE = std.meta.FnPtr(fn (dwCtrlType: DWORD) callconv(WINAPI) BOOL);
3855
3856/// Processor feature enumeration.
3857pub const PF = enum(DWORD) {
3858 /// On a Pentium, a floating-point precision error can occur in rare circumstances.
3859 FLOATING_POINT_PRECISION_ERRATA = 0,
3860
3861 /// Floating-point operations are emulated using software emulator.
3862 /// This function returns a nonzero value if floating-point operations are emulated; otherwise, it returns zero.
3863 FLOATING_POINT_EMULATED = 1,
3864
3865 /// The atomic compare and exchange operation (cmpxchg) is available.
3866 COMPARE_EXCHANGE_DOUBLE = 2,
3867
3868 /// The MMX instruction set is available.
3869 MMX_INSTRUCTIONS_AVAILABLE = 3,
3870
3871 PPC_MOVEMEM_64BIT_OK = 4,
3872 ALPHA_BYTE_INSTRUCTIONS = 5,
3873
3874 /// The SSE instruction set is available.
3875 XMMI_INSTRUCTIONS_AVAILABLE = 6,
3876
3877 /// The 3D-Now instruction is available.
3878 @"3DNOW_INSTRUCTIONS_AVAILABLE" = 7,
3879
3880 /// The RDTSC instruction is available.
3881 RDTSC_INSTRUCTION_AVAILABLE = 8,
3882
3883 /// The processor is PAE-enabled.
3884 PAE_ENABLED = 9,
3885
3886 /// The SSE2 instruction set is available.
3887 XMMI64_INSTRUCTIONS_AVAILABLE = 10,
3888
3889 SSE_DAZ_MODE_AVAILABLE = 11,
3890
3891 /// Data execution prevention is enabled.
3892 NX_ENABLED = 12,
3893
3894 /// The SSE3 instruction set is available.
3895 SSE3_INSTRUCTIONS_AVAILABLE = 13,
3896
3897 /// The atomic compare and exchange 128-bit operation (cmpxchg16b) is available.
3898 COMPARE_EXCHANGE128 = 14,
3899
3900 /// The atomic compare 64 and exchange 128-bit operation (cmp8xchg16) is available.
3901 COMPARE64_EXCHANGE128 = 15,
3902
3903 /// The processor channels are enabled.
3904 CHANNELS_ENABLED = 16,
3905
3906 /// The processor implements the XSAVI and XRSTOR instructions.
3907 XSAVE_ENABLED = 17,
3908
3909 /// The VFP/Neon: 32 x 64bit register bank is present.
3910 /// This flag has the same meaning as PF_ARM_VFP_EXTENDED_REGISTERS.
3911 ARM_VFP_32_REGISTERS_AVAILABLE = 18,
3912
3913 /// This ARM processor implements the ARM v8 NEON instruction set.
3914 ARM_NEON_INSTRUCTIONS_AVAILABLE = 19,
3915
3916 /// Second Level Address Translation is supported by the hardware.
3917 SECOND_LEVEL_ADDRESS_TRANSLATION = 20,
3918
3919 /// Virtualization is enabled in the firmware and made available by the operating system.
3920 VIRT_FIRMWARE_ENABLED = 21,
3921
3922 /// RDFSBASE, RDGSBASE, WRFSBASE, and WRGSBASE instructions are available.
3923 RDWRFSGBASE_AVAILABLE = 22,
3924
3925 /// _fastfail() is available.
3926 FASTFAIL_AVAILABLE = 23,
3927
3928 /// The divide instruction_available.
3929 ARM_DIVIDE_INSTRUCTION_AVAILABLE = 24,
3930
3931 /// The 64-bit load/store atomic instructions are available.
3932 ARM_64BIT_LOADSTORE_ATOMIC = 25,
3933
3934 /// The external cache is available.
3935 ARM_EXTERNAL_CACHE_AVAILABLE = 26,
3936
3937 /// The floating-point multiply-accumulate instruction is available.
3938 ARM_FMAC_INSTRUCTIONS_AVAILABLE = 27,
3939
3940 RDRAND_INSTRUCTION_AVAILABLE = 28,
3941
3942 /// This ARM processor implements the ARM v8 instructions set.
3943 ARM_V8_INSTRUCTIONS_AVAILABLE = 29,
3944
3945 /// This ARM processor implements the ARM v8 extra cryptographic instructions (i.e., AES, SHA1 and SHA2).
3946 ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE = 30,
3947
3948 /// This ARM processor implements the ARM v8 extra CRC32 instructions.
3949 ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE = 31,
3950
3951 RDTSCP_INSTRUCTION_AVAILABLE = 32,
3952 RDPID_INSTRUCTION_AVAILABLE = 33,
3953
3954 /// This ARM processor implements the ARM v8.1 atomic instructions (e.g., CAS, SWP).
3955 ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE = 34,
3956
3957 MONITORX_INSTRUCTION_AVAILABLE = 35,
3958
3959 /// The SSSE3 instruction set is available.
3960 SSSE3_INSTRUCTIONS_AVAILABLE = 36,
3961
3962 /// The SSE4_1 instruction set is available.
3963 SSE4_1_INSTRUCTIONS_AVAILABLE = 37,
3964
3965 /// The SSE4_2 instruction set is available.
3966 SSE4_2_INSTRUCTIONS_AVAILABLE = 38,
3967
3968 /// The AVX instruction set is available.
3969 AVX_INSTRUCTIONS_AVAILABLE = 39,
3970
3971 /// The AVX2 instruction set is available.
3972 AVX2_INSTRUCTIONS_AVAILABLE = 40,
3973
3974 /// The AVX512F instruction set is available.
3975 AVX512F_INSTRUCTIONS_AVAILABLE = 41,
3976
3977 ERMS_AVAILABLE = 42,
3978
3979 /// This ARM processor implements the ARM v8.2 Dot Product (DP) instructions.
3980 ARM_V82_DP_INSTRUCTIONS_AVAILABLE = 43,
3981
3982 /// This ARM processor implements the ARM v8.3 JavaScript conversion (JSCVT) instructions.
3983 ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE = 44,
3984};
3985
3986pub const MAX_WOW64_SHARED_ENTRIES = 16;
3987pub const PROCESSOR_FEATURE_MAX = 64;
3988pub const MAXIMUM_XSTATE_FEATURES = 64;
3989
3990pub const KSYSTEM_TIME = extern struct {
3991 LowPart: ULONG,
3992 High1Time: LONG,
3993 High2Time: LONG,
3994};
3995
3996pub const NT_PRODUCT_TYPE = enum(INT) {
3997 NtProductWinNt = 1,
3998 NtProductLanManNt,
3999 NtProductServer,
4000};
4001
4002pub const ALTERNATIVE_ARCHITECTURE_TYPE = enum(INT) {
4003 StandardDesign,
4004 NEC98x86,
4005 EndAlternatives,
4006};
4007
4008pub const XSTATE_FEATURE = extern struct {
4009 Offset: ULONG,
4010 Size: ULONG,
4011};
4012
4013pub const XSTATE_CONFIGURATION = extern struct {
4014 EnabledFeatures: ULONG64,
4015 Size: ULONG,
4016 OptimizedSave: ULONG,
4017 Features: [MAXIMUM_XSTATE_FEATURES]XSTATE_FEATURE,
4018};
4019
4020/// Shared Kernel User Data
4021pub const KUSER_SHARED_DATA = extern struct {
4022 TickCountLowDeprecated: ULONG,
4023 TickCountMultiplier: ULONG,
4024 InterruptTime: KSYSTEM_TIME,
4025 SystemTime: KSYSTEM_TIME,
4026 TimeZoneBias: KSYSTEM_TIME,
4027 ImageNumberLow: USHORT,
4028 ImageNumberHigh: USHORT,
4029 NtSystemRoot: [260]WCHAR,
4030 MaxStackTraceDepth: ULONG,
4031 CryptoExponent: ULONG,
4032 TimeZoneId: ULONG,
4033 LargePageMinimum: ULONG,
4034 AitSamplingValue: ULONG,
4035 AppCompatFlag: ULONG,
4036 RNGSeedVersion: ULONGLONG,
4037 GlobalValidationRunlevel: ULONG,
4038 TimeZoneBiasStamp: LONG,
4039 NtBuildNumber: ULONG,
4040 NtProductType: NT_PRODUCT_TYPE,
4041 ProductTypeIsValid: BOOLEAN,
4042 Reserved0: [1]BOOLEAN,
4043 NativeProcessorArchitecture: USHORT,
4044 NtMajorVersion: ULONG,
4045 NtMinorVersion: ULONG,
4046 ProcessorFeatures: [PROCESSOR_FEATURE_MAX]BOOLEAN,
4047 Reserved1: ULONG,
4048 Reserved3: ULONG,
4049 TimeSlip: ULONG,
4050 AlternativeArchitecture: ALTERNATIVE_ARCHITECTURE_TYPE,
4051 BootId: ULONG,
4052 SystemExpirationDate: LARGE_INTEGER,
4053 SuiteMaskY: ULONG,
4054 KdDebuggerEnabled: BOOLEAN,
4055 DummyUnion1: extern union {
4056 MitigationPolicies: UCHAR,
4057 Alt: packed struct {
4058 NXSupportPolicy: u2,
4059 SEHValidationPolicy: u2,
4060 CurDirDevicesSkippedForDlls: u2,
4061 Reserved: u2,
4062 },
4063 },
4064 CyclesPerYield: USHORT,
4065 ActiveConsoleId: ULONG,
4066 DismountCount: ULONG,
4067 ComPlusPackage: ULONG,
4068 LastSystemRITEventTickCount: ULONG,
4069 NumberOfPhysicalPages: ULONG,
4070 SafeBootMode: BOOLEAN,
4071 DummyUnion2: extern union {
4072 VirtualizationFlags: UCHAR,
4073 Alt: packed struct {
4074 ArchStartedInEl2: u1,
4075 QcSlIsSupported: u1,
4076 SpareBits: u6,
4077 },
4078 },
4079 Reserved12: [2]UCHAR,
4080 DummyUnion3: extern union {
4081 SharedDataFlags: ULONG,
4082 Alt: packed struct {
4083 DbgErrorPortPresent: u1,
4084 DbgElevationEnabled: u1,
4085 DbgVirtEnabled: u1,
4086 DbgInstallerDetectEnabled: u1,
4087 DbgLkgEnabled: u1,
4088 DbgDynProcessorEnabled: u1,
4089 DbgConsoleBrokerEnabled: u1,
4090 DbgSecureBootEnabled: u1,
4091 DbgMultiSessionSku: u1,
4092 DbgMultiUsersInSessionSku: u1,
4093 DbgStateSeparationEnabled: u1,
4094 SpareBits: u21,
4095 },
4096 },
4097 DataFlagsPad: [1]ULONG,
4098 TestRetInstruction: ULONGLONG,
4099 QpcFrequency: LONGLONG,
4100 SystemCall: ULONG,
4101 Reserved2: ULONG,
4102 SystemCallPad: [2]ULONGLONG,
4103 DummyUnion4: extern union {
4104 TickCount: KSYSTEM_TIME,
4105 TickCountQuad: ULONG64,
4106 Alt: extern struct {
4107 ReservedTickCountOverlay: [3]ULONG,
4108 TickCountPad: [1]ULONG,
4109 },
4110 },
4111 Cookie: ULONG,
4112 CookiePad: [1]ULONG,
4113 ConsoleSessionForegroundProcessId: LONGLONG,
4114 TimeUpdateLock: ULONGLONG,
4115 BaselineSystemTimeQpc: ULONGLONG,
4116 BaselineInterruptTimeQpc: ULONGLONG,
4117 QpcSystemTimeIncrement: ULONGLONG,
4118 QpcInterruptTimeIncrement: ULONGLONG,
4119 QpcSystemTimeIncrementShift: UCHAR,
4120 QpcInterruptTimeIncrementShift: UCHAR,
4121 UnparkedProcessorCount: USHORT,
4122 EnclaveFeatureMask: [4]ULONG,
4123 TelemetryCoverageRound: ULONG,
4124 UserModeGlobalLogger: [16]USHORT,
4125 ImageFileExecutionOptions: ULONG,
4126 LangGenerationCount: ULONG,
4127 Reserved4: ULONGLONG,
4128 InterruptTimeBias: ULONGLONG,
4129 QpcBias: ULONGLONG,
4130 ActiveProcessorCount: ULONG,
4131 ActiveGroupCount: UCHAR,
4132 Reserved9: UCHAR,
4133 DummyUnion5: extern union {
4134 QpcData: USHORT,
4135 Alt: extern struct {
4136 QpcBypassEnabled: UCHAR,
4137 QpcShift: UCHAR,
4138 },
4139 },
4140 TimeZoneBiasEffectiveStart: LARGE_INTEGER,
4141 TimeZoneBiasEffectiveEnd: LARGE_INTEGER,
4142 XState: XSTATE_CONFIGURATION,
4143 FeatureConfigurationChangeStamp: KSYSTEM_TIME,
4144 Spare: ULONG,
4145 UserPointerAuthMask: ULONG64,
4146};
4147
4148/// Read-only user-mode address for the shared data.
4149/// https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm
4150/// https://msrc-blog.microsoft.com/2022/04/05/randomizing-the-kuser_shared_data-structure-on-windows/
4151pub const SharedUserData: *const KUSER_SHARED_DATA = @intToPtr(*const KUSER_SHARED_DATA, 0x7FFE0000);
4152
4153pub fn IsProcessorFeaturePresent(feature: PF) bool {
4154 if (@enumToInt(feature) >= PROCESSOR_FEATURE_MAX) return false;
4155 return SharedUserData.ProcessorFeatures[@enumToInt(feature)] == 1;
4156}
lib/std/os/windows/kernel32.zig+12
......@@ -10,6 +10,7 @@ const DWORD = windows.DWORD;
1010const FILE_INFO_BY_HANDLE_CLASS = windows.FILE_INFO_BY_HANDLE_CLASS;
1111const HANDLE = windows.HANDLE;
1212const HMODULE = windows.HMODULE;
13const HKEY = windows.HKEY;
1314const HRESULT = windows.HRESULT;
1415const LARGE_INTEGER = windows.LARGE_INTEGER;
1516const LPCWSTR = windows.LPCWSTR;
......@@ -57,6 +58,8 @@ const UCHAR = windows.UCHAR;
5758const FARPROC = windows.FARPROC;
5859const INIT_ONCE_FN = windows.INIT_ONCE_FN;
5960const PMEMORY_BASIC_INFORMATION = windows.PMEMORY_BASIC_INFORMATION;
61const REGSAM = windows.REGSAM;
62const LSTATUS = windows.LSTATUS;
6063
6164pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(WINAPI) ?*anyopaque;
6265pub extern "kernel32" fn RemoveVectoredExceptionHandler(Handle: HANDLE) callconv(WINAPI) c_ulong;
......@@ -231,6 +234,7 @@ pub extern "kernel32" fn GetQueuedCompletionStatusEx(
231234
232235pub extern "kernel32" fn GetSystemInfo(lpSystemInfo: *SYSTEM_INFO) callconv(WINAPI) void;
233236pub extern "kernel32" fn GetSystemTimeAsFileTime(*FILETIME) callconv(WINAPI) void;
237pub extern "kernel32" fn IsProcessorFeaturePresent(ProcessorFeature: DWORD) BOOL;
234238
235239pub extern "kernel32" fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) callconv(WINAPI) ?HANDLE;
236240pub extern "kernel32" fn HeapDestroy(hHeap: HANDLE) callconv(WINAPI) BOOL;
......@@ -411,3 +415,11 @@ pub extern "kernel32" fn SleepConditionVariableSRW(
411415pub extern "kernel32" fn TryAcquireSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) BOOLEAN;
412416pub extern "kernel32" fn AcquireSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) void;
413417pub extern "kernel32" fn ReleaseSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) void;
418
419pub extern "kernel32" fn RegOpenKeyExW(
420 hkey: HKEY,
421 lpSubKey: LPCWSTR,
422 ulOptions: DWORD,
423 samDesired: REGSAM,
424 phkResult: *HKEY,
425) callconv(WINAPI) LSTATUS;
lib/std/os/windows/ntdll.zig+16
......@@ -22,6 +22,8 @@ const RTL_OSVERSIONINFOW = windows.RTL_OSVERSIONINFOW;
2222const FILE_BASIC_INFORMATION = windows.FILE_BASIC_INFORMATION;
2323const SIZE_T = windows.SIZE_T;
2424const CURDIR = windows.CURDIR;
25const PCWSTR = windows.PCWSTR;
26const RTL_QUERY_REGISTRY_TABLE = windows.RTL_QUERY_REGISTRY_TABLE;
2527
2628pub const THREADINFOCLASS = enum(c_int) {
2729 ThreadBasicInformation,
......@@ -253,3 +255,17 @@ pub extern "ntdll" fn NtUnlockFile(
253255 Length: *const LARGE_INTEGER,
254256 Key: ?*ULONG,
255257) callconv(WINAPI) NTSTATUS;
258
259pub extern "ntdll" fn NtOpenKey(
260 KeyHandle: *HANDLE,
261 DesiredAccess: ACCESS_MASK,
262 ObjectAttributes: OBJECT_ATTRIBUTES,
263) callconv(WINAPI) NTSTATUS;
264
265pub extern "ntdll" fn RtlQueryRegistryValues(
266 RelativeTo: ULONG,
267 Path: PCWSTR,
268 QueryTable: [*]RTL_QUERY_REGISTRY_TABLE,
269 Context: ?*anyopaque,
270 Environment: ?*anyopaque,
271) callconv(WINAPI) NTSTATUS;
lib/std/zig/system/NativeTargetInfo.zig+1
......@@ -978,6 +978,7 @@ fn detectNativeCpuAndFeatures(cpu_arch: Target.Cpu.Arch, os: Target.Os, cross_ta
978978 switch (builtin.os.tag) {
979979 .linux => return linux.detectNativeCpuAndFeatures(),
980980 .macos => return darwin.macos.detectNativeCpuAndFeatures(),
981 .windows => return windows.detectNativeCpuAndFeatures(),
981982 else => {},
982983 }
983984
lib/std/zig/system/arm.zig created+134
......@@ -0,0 +1,134 @@
1const std = @import("std");
2
3pub const CoreInfo = struct {
4 architecture: u8 = 0,
5 implementer: u8 = 0,
6 variant: u8 = 0,
7 part: u16 = 0,
8};
9
10pub const cpu_models = struct {
11 // Shorthands to simplify the tables below.
12 const A32 = std.Target.arm.cpu;
13 const A64 = std.Target.aarch64.cpu;
14
15 const E = struct {
16 part: u16,
17 variant: ?u8 = null, // null if matches any variant
18 m32: ?*const std.Target.Cpu.Model = null,
19 m64: ?*const std.Target.Cpu.Model = null,
20 };
21
22 // implementer = 0x41
23 const ARM = [_]E{
24 E{ .part = 0x926, .m32 = &A32.arm926ej_s, .m64 = null },
25 E{ .part = 0xb02, .m32 = &A32.mpcore, .m64 = null },
26 E{ .part = 0xb36, .m32 = &A32.arm1136j_s, .m64 = null },
27 E{ .part = 0xb56, .m32 = &A32.arm1156t2_s, .m64 = null },
28 E{ .part = 0xb76, .m32 = &A32.arm1176jz_s, .m64 = null },
29 E{ .part = 0xc05, .m32 = &A32.cortex_a5, .m64 = null },
30 E{ .part = 0xc07, .m32 = &A32.cortex_a7, .m64 = null },
31 E{ .part = 0xc08, .m32 = &A32.cortex_a8, .m64 = null },
32 E{ .part = 0xc09, .m32 = &A32.cortex_a9, .m64 = null },
33 E{ .part = 0xc0d, .m32 = &A32.cortex_a17, .m64 = null },
34 E{ .part = 0xc0f, .m32 = &A32.cortex_a15, .m64 = null },
35 E{ .part = 0xc0e, .m32 = &A32.cortex_a17, .m64 = null },
36 E{ .part = 0xc14, .m32 = &A32.cortex_r4, .m64 = null },
37 E{ .part = 0xc15, .m32 = &A32.cortex_r5, .m64 = null },
38 E{ .part = 0xc17, .m32 = &A32.cortex_r7, .m64 = null },
39 E{ .part = 0xc18, .m32 = &A32.cortex_r8, .m64 = null },
40 E{ .part = 0xc20, .m32 = &A32.cortex_m0, .m64 = null },
41 E{ .part = 0xc21, .m32 = &A32.cortex_m1, .m64 = null },
42 E{ .part = 0xc23, .m32 = &A32.cortex_m3, .m64 = null },
43 E{ .part = 0xc24, .m32 = &A32.cortex_m4, .m64 = null },
44 E{ .part = 0xc27, .m32 = &A32.cortex_m7, .m64 = null },
45 E{ .part = 0xc60, .m32 = &A32.cortex_m0plus, .m64 = null },
46 E{ .part = 0xd01, .m32 = &A32.cortex_a32, .m64 = null },
47 E{ .part = 0xd03, .m32 = &A32.cortex_a53, .m64 = &A64.cortex_a53 },
48 E{ .part = 0xd04, .m32 = &A32.cortex_a35, .m64 = &A64.cortex_a35 },
49 E{ .part = 0xd05, .m32 = &A32.cortex_a55, .m64 = &A64.cortex_a55 },
50 E{ .part = 0xd07, .m32 = &A32.cortex_a57, .m64 = &A64.cortex_a57 },
51 E{ .part = 0xd08, .m32 = &A32.cortex_a72, .m64 = &A64.cortex_a72 },
52 E{ .part = 0xd09, .m32 = &A32.cortex_a73, .m64 = &A64.cortex_a73 },
53 E{ .part = 0xd0a, .m32 = &A32.cortex_a75, .m64 = &A64.cortex_a75 },
54 E{ .part = 0xd0b, .m32 = &A32.cortex_a76, .m64 = &A64.cortex_a76 },
55 E{ .part = 0xd0c, .m32 = &A32.neoverse_n1, .m64 = &A64.neoverse_n1 },
56 E{ .part = 0xd0d, .m32 = &A32.cortex_a77, .m64 = &A64.cortex_a77 },
57 E{ .part = 0xd13, .m32 = &A32.cortex_r52, .m64 = null },
58 E{ .part = 0xd20, .m32 = &A32.cortex_m23, .m64 = null },
59 E{ .part = 0xd21, .m32 = &A32.cortex_m33, .m64 = null },
60 E{ .part = 0xd41, .m32 = &A32.cortex_a78, .m64 = &A64.cortex_a78 },
61 E{ .part = 0xd4b, .m32 = &A32.cortex_a78c, .m64 = &A64.cortex_a78c },
62 // This is a guess based on https://www.notebookcheck.net/Qualcomm-Snapdragon-8cx-Gen-3-Processor-Benchmarks-and-Specs.652916.0.html
63 E{ .part = 0xd4c, .m32 = &A32.cortex_x1c, .m64 = &A64.cortex_x1c },
64 E{ .part = 0xd44, .m32 = &A32.cortex_x1, .m64 = &A64.cortex_x1 },
65 E{ .part = 0xd02, .m64 = &A64.cortex_a34 },
66 E{ .part = 0xd06, .m64 = &A64.cortex_a65 },
67 E{ .part = 0xd43, .m64 = &A64.cortex_a65ae },
68 };
69 // implementer = 0x42
70 const Broadcom = [_]E{
71 E{ .part = 0x516, .m64 = &A64.thunderx2t99 },
72 };
73 // implementer = 0x43
74 const Cavium = [_]E{
75 E{ .part = 0x0a0, .m64 = &A64.thunderx },
76 E{ .part = 0x0a2, .m64 = &A64.thunderxt81 },
77 E{ .part = 0x0a3, .m64 = &A64.thunderxt83 },
78 E{ .part = 0x0a1, .m64 = &A64.thunderxt88 },
79 E{ .part = 0x0af, .m64 = &A64.thunderx2t99 },
80 };
81 // implementer = 0x46
82 const Fujitsu = [_]E{
83 E{ .part = 0x001, .m64 = &A64.a64fx },
84 };
85 // implementer = 0x48
86 const HiSilicon = [_]E{
87 E{ .part = 0xd01, .m64 = &A64.tsv110 },
88 };
89 // implementer = 0x4e
90 const Nvidia = [_]E{
91 E{ .part = 0x004, .m64 = &A64.carmel },
92 };
93 // implementer = 0x50
94 const Ampere = [_]E{
95 E{ .part = 0x000, .variant = 3, .m64 = &A64.emag },
96 E{ .part = 0x000, .m64 = &A64.xgene1 },
97 };
98 // implementer = 0x51
99 const Qualcomm = [_]E{
100 E{ .part = 0x06f, .m32 = &A32.krait },
101 E{ .part = 0x201, .m64 = &A64.kryo, .m32 = &A64.kryo },
102 E{ .part = 0x205, .m64 = &A64.kryo, .m32 = &A64.kryo },
103 E{ .part = 0x211, .m64 = &A64.kryo, .m32 = &A64.kryo },
104 E{ .part = 0x800, .m64 = &A64.cortex_a73, .m32 = &A64.cortex_a73 },
105 E{ .part = 0x801, .m64 = &A64.cortex_a73, .m32 = &A64.cortex_a73 },
106 E{ .part = 0x802, .m64 = &A64.cortex_a75, .m32 = &A64.cortex_a75 },
107 E{ .part = 0x803, .m64 = &A64.cortex_a75, .m32 = &A64.cortex_a75 },
108 E{ .part = 0x804, .m64 = &A64.cortex_a76, .m32 = &A64.cortex_a76 },
109 E{ .part = 0x805, .m64 = &A64.cortex_a76, .m32 = &A64.cortex_a76 },
110 E{ .part = 0xc00, .m64 = &A64.falkor },
111 E{ .part = 0xc01, .m64 = &A64.saphira },
112 };
113
114 pub fn isKnown(core: CoreInfo, is_64bit: bool) ?*const std.Target.Cpu.Model {
115 const models = switch (core.implementer) {
116 0x41 => &ARM,
117 0x42 => &Broadcom,
118 0x43 => &Cavium,
119 0x46 => &Fujitsu,
120 0x48 => &HiSilicon,
121 0x50 => &Ampere,
122 0x51 => &Qualcomm,
123 else => return null,
124 };
125
126 for (models) |model| {
127 if (model.part == core.part and
128 (model.variant == null or model.variant.? == core.variant))
129 return if (is_64bit) model.m64 else model.m32;
130 }
131
132 return null;
133 }
134};
lib/std/zig/system/linux.zig+7-124
......@@ -159,129 +159,7 @@ const ArmCpuinfoImpl = struct {
159159 is_really_v6: bool = false,
160160 };
161161
162 const cpu_models = struct {
163 // Shorthands to simplify the tables below.
164 const A32 = Target.arm.cpu;
165 const A64 = Target.aarch64.cpu;
166
167 const E = struct {
168 part: u16,
169 variant: ?u8 = null, // null if matches any variant
170 m32: ?*const Target.Cpu.Model = null,
171 m64: ?*const Target.Cpu.Model = null,
172 };
173
174 // implementer = 0x41
175 const ARM = [_]E{
176 E{ .part = 0x926, .m32 = &A32.arm926ej_s, .m64 = null },
177 E{ .part = 0xb02, .m32 = &A32.mpcore, .m64 = null },
178 E{ .part = 0xb36, .m32 = &A32.arm1136j_s, .m64 = null },
179 E{ .part = 0xb56, .m32 = &A32.arm1156t2_s, .m64 = null },
180 E{ .part = 0xb76, .m32 = &A32.arm1176jz_s, .m64 = null },
181 E{ .part = 0xc05, .m32 = &A32.cortex_a5, .m64 = null },
182 E{ .part = 0xc07, .m32 = &A32.cortex_a7, .m64 = null },
183 E{ .part = 0xc08, .m32 = &A32.cortex_a8, .m64 = null },
184 E{ .part = 0xc09, .m32 = &A32.cortex_a9, .m64 = null },
185 E{ .part = 0xc0d, .m32 = &A32.cortex_a17, .m64 = null },
186 E{ .part = 0xc0f, .m32 = &A32.cortex_a15, .m64 = null },
187 E{ .part = 0xc0e, .m32 = &A32.cortex_a17, .m64 = null },
188 E{ .part = 0xc14, .m32 = &A32.cortex_r4, .m64 = null },
189 E{ .part = 0xc15, .m32 = &A32.cortex_r5, .m64 = null },
190 E{ .part = 0xc17, .m32 = &A32.cortex_r7, .m64 = null },
191 E{ .part = 0xc18, .m32 = &A32.cortex_r8, .m64 = null },
192 E{ .part = 0xc20, .m32 = &A32.cortex_m0, .m64 = null },
193 E{ .part = 0xc21, .m32 = &A32.cortex_m1, .m64 = null },
194 E{ .part = 0xc23, .m32 = &A32.cortex_m3, .m64 = null },
195 E{ .part = 0xc24, .m32 = &A32.cortex_m4, .m64 = null },
196 E{ .part = 0xc27, .m32 = &A32.cortex_m7, .m64 = null },
197 E{ .part = 0xc60, .m32 = &A32.cortex_m0plus, .m64 = null },
198 E{ .part = 0xd01, .m32 = &A32.cortex_a32, .m64 = null },
199 E{ .part = 0xd03, .m32 = &A32.cortex_a53, .m64 = &A64.cortex_a53 },
200 E{ .part = 0xd04, .m32 = &A32.cortex_a35, .m64 = &A64.cortex_a35 },
201 E{ .part = 0xd05, .m32 = &A32.cortex_a55, .m64 = &A64.cortex_a55 },
202 E{ .part = 0xd07, .m32 = &A32.cortex_a57, .m64 = &A64.cortex_a57 },
203 E{ .part = 0xd08, .m32 = &A32.cortex_a72, .m64 = &A64.cortex_a72 },
204 E{ .part = 0xd09, .m32 = &A32.cortex_a73, .m64 = &A64.cortex_a73 },
205 E{ .part = 0xd0a, .m32 = &A32.cortex_a75, .m64 = &A64.cortex_a75 },
206 E{ .part = 0xd0b, .m32 = &A32.cortex_a76, .m64 = &A64.cortex_a76 },
207 E{ .part = 0xd0c, .m32 = &A32.neoverse_n1, .m64 = &A64.neoverse_n1 },
208 E{ .part = 0xd0d, .m32 = &A32.cortex_a77, .m64 = &A64.cortex_a77 },
209 E{ .part = 0xd13, .m32 = &A32.cortex_r52, .m64 = null },
210 E{ .part = 0xd20, .m32 = &A32.cortex_m23, .m64 = null },
211 E{ .part = 0xd21, .m32 = &A32.cortex_m33, .m64 = null },
212 E{ .part = 0xd41, .m32 = &A32.cortex_a78, .m64 = &A64.cortex_a78 },
213 E{ .part = 0xd4b, .m32 = &A32.cortex_a78c, .m64 = &A64.cortex_a78c },
214 E{ .part = 0xd44, .m32 = &A32.cortex_x1, .m64 = &A64.cortex_x1 },
215 E{ .part = 0xd02, .m64 = &A64.cortex_a34 },
216 E{ .part = 0xd06, .m64 = &A64.cortex_a65 },
217 E{ .part = 0xd43, .m64 = &A64.cortex_a65ae },
218 };
219 // implementer = 0x42
220 const Broadcom = [_]E{
221 E{ .part = 0x516, .m64 = &A64.thunderx2t99 },
222 };
223 // implementer = 0x43
224 const Cavium = [_]E{
225 E{ .part = 0x0a0, .m64 = &A64.thunderx },
226 E{ .part = 0x0a2, .m64 = &A64.thunderxt81 },
227 E{ .part = 0x0a3, .m64 = &A64.thunderxt83 },
228 E{ .part = 0x0a1, .m64 = &A64.thunderxt88 },
229 E{ .part = 0x0af, .m64 = &A64.thunderx2t99 },
230 };
231 // implementer = 0x46
232 const Fujitsu = [_]E{
233 E{ .part = 0x001, .m64 = &A64.a64fx },
234 };
235 // implementer = 0x48
236 const HiSilicon = [_]E{
237 E{ .part = 0xd01, .m64 = &A64.tsv110 },
238 };
239 // implementer = 0x4e
240 const Nvidia = [_]E{
241 E{ .part = 0x004, .m64 = &A64.carmel },
242 };
243 // implementer = 0x50
244 const Ampere = [_]E{
245 E{ .part = 0x000, .variant = 3, .m64 = &A64.emag },
246 E{ .part = 0x000, .m64 = &A64.xgene1 },
247 };
248 // implementer = 0x51
249 const Qualcomm = [_]E{
250 E{ .part = 0x06f, .m32 = &A32.krait },
251 E{ .part = 0x201, .m64 = &A64.kryo, .m32 = &A64.kryo },
252 E{ .part = 0x205, .m64 = &A64.kryo, .m32 = &A64.kryo },
253 E{ .part = 0x211, .m64 = &A64.kryo, .m32 = &A64.kryo },
254 E{ .part = 0x800, .m64 = &A64.cortex_a73, .m32 = &A64.cortex_a73 },
255 E{ .part = 0x801, .m64 = &A64.cortex_a73, .m32 = &A64.cortex_a73 },
256 E{ .part = 0x802, .m64 = &A64.cortex_a75, .m32 = &A64.cortex_a75 },
257 E{ .part = 0x803, .m64 = &A64.cortex_a75, .m32 = &A64.cortex_a75 },
258 E{ .part = 0x804, .m64 = &A64.cortex_a76, .m32 = &A64.cortex_a76 },
259 E{ .part = 0x805, .m64 = &A64.cortex_a76, .m32 = &A64.cortex_a76 },
260 E{ .part = 0xc00, .m64 = &A64.falkor },
261 E{ .part = 0xc01, .m64 = &A64.saphira },
262 };
263
264 fn isKnown(core: CoreInfo, is_64bit: bool) ?*const Target.Cpu.Model {
265 const models = switch (core.implementer) {
266 0x41 => &ARM,
267 0x42 => &Broadcom,
268 0x43 => &Cavium,
269 0x46 => &Fujitsu,
270 0x48 => &HiSilicon,
271 0x50 => &Ampere,
272 0x51 => &Qualcomm,
273 else => return null,
274 };
275
276 for (models) |model| {
277 if (model.part == core.part and
278 (model.variant == null or model.variant.? == core.variant))
279 return if (is_64bit) model.m64 else model.m32;
280 }
281
282 return null;
283 }
284 };
162 const cpu_models = @import("arm.zig").cpu_models;
285163
286164 fn addOne(self: *ArmCpuinfoImpl) void {
287165 if (self.have_fields == 4 and self.core_no < self.cores.len) {
......@@ -346,7 +224,12 @@ const ArmCpuinfoImpl = struct {
346224
347225 var known_models: [self.cores.len]?*const Target.Cpu.Model = undefined;
348226 for (self.cores[0..self.core_no]) |core, i| {
349 known_models[i] = cpu_models.isKnown(core, is_64bit);
227 known_models[i] = cpu_models.isKnown(.{
228 .architecture = core.architecture,
229 .implementer = core.implementer,
230 .variant = core.variant,
231 .part = core.part,
232 }, is_64bit);
350233 }
351234
352235 // XXX We pick the first core on big.LITTLE systems, hopefully the
lib/std/zig/system/windows.zig+321
......@@ -1,6 +1,12 @@
11const std = @import("std");
2const builtin = @import("builtin");
3const mem = std.mem;
4const Target = std.Target;
25
36pub const WindowsVersion = std.Target.Os.WindowsVersion;
7pub const PF = std.os.windows.PF;
8pub const REG = std.os.windows.REG;
9pub const IsProcessorFeaturePresent = std.os.windows.IsProcessorFeaturePresent;
410
511/// Returns the highest known WindowsVersion deduced from reported runtime information.
612/// Discards information about in-between versions we don't differentiate.
......@@ -38,3 +44,318 @@ pub fn detectRuntimeVersion() WindowsVersion {
3844
3945 return @intToEnum(WindowsVersion, version);
4046}
47
48// Technically, a registry value can be as long as 1MB. However, MS recommends storing
49// values larger than 2048 bytes in a file rather than directly in the registry, and since we
50// are only accessing a system hive \Registry\Machine, we stick to MS guidelines.
51// https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits
52const max_value_len = 2048;
53
54const RegistryPair = struct {
55 key: []const u8,
56 value: std.os.windows.ULONG,
57};
58
59fn getCpuInfoFromRegistry(
60 core: usize,
61 comptime pairs_num: comptime_int,
62 comptime pairs: [pairs_num]RegistryPair,
63 out_buf: *[pairs_num][max_value_len]u8,
64) !void {
65 // Originally, I wanted to issue a single call with a more complex table structure such that we
66 // would sequentially visit each CPU#d subkey in the registry and pull the value of interest into
67 // a buffer, however, NT seems to be expecting a single buffer per each table meaning we would
68 // end up pulling only the last CPU core info, overwriting everything else.
69 // If anyone can come up with a solution to this, please do!
70 const table_size = 1 + pairs.len;
71 var table: [table_size + 1]std.os.windows.RTL_QUERY_REGISTRY_TABLE = undefined;
72
73 const topkey = std.unicode.utf8ToUtf16LeStringLiteral("\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor");
74
75 const max_cpu_buf = 4;
76 var next_cpu_buf: [max_cpu_buf]u8 = undefined;
77 const next_cpu = try std.fmt.bufPrint(&next_cpu_buf, "{d}", .{core});
78
79 var subkey: [max_cpu_buf + 1]u16 = undefined;
80 const subkey_len = try std.unicode.utf8ToUtf16Le(&subkey, next_cpu);
81 subkey[subkey_len] = 0;
82
83 table[0] = .{
84 .QueryRoutine = null,
85 .Flags = std.os.windows.RTL_QUERY_REGISTRY_SUBKEY | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED,
86 .Name = subkey[0..subkey_len :0],
87 .EntryContext = null,
88 .DefaultType = REG.NONE,
89 .DefaultData = null,
90 .DefaultLength = 0,
91 };
92
93 inline for (pairs) |pair, i| {
94 const ctx: *anyopaque = blk: {
95 switch (pair.value) {
96 REG.SZ,
97 REG.EXPAND_SZ,
98 REG.MULTI_SZ,
99 => {
100 var buf: [max_value_len / 2]u16 = undefined;
101 var unicode = std.os.windows.UNICODE_STRING{
102 .Length = 0,
103 .MaximumLength = max_value_len,
104 .Buffer = &buf,
105 };
106 break :blk &unicode;
107 },
108
109 REG.DWORD,
110 REG.DWORD_BIG_ENDIAN,
111 => {
112 var buf: [4]u8 = undefined;
113 break :blk &buf;
114 },
115
116 REG.QWORD => {
117 var buf: [8]u8 = undefined;
118 break :blk &buf;
119 },
120
121 else => unreachable,
122 }
123 };
124 const key_namee = std.unicode.utf8ToUtf16LeStringLiteral(pair.key);
125
126 table[i + 1] = .{
127 .QueryRoutine = null,
128 .Flags = std.os.windows.RTL_QUERY_REGISTRY_DIRECT | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED,
129 .Name = @intToPtr([*:0]u16, @ptrToInt(key_namee)),
130 .EntryContext = ctx,
131 .DefaultType = REG.NONE,
132 .DefaultData = null,
133 .DefaultLength = 0,
134 };
135 }
136
137 // Table sentinel
138 table[table_size] = .{
139 .QueryRoutine = null,
140 .Flags = 0,
141 .Name = null,
142 .EntryContext = null,
143 .DefaultType = 0,
144 .DefaultData = null,
145 .DefaultLength = 0,
146 };
147
148 const res = std.os.windows.ntdll.RtlQueryRegistryValues(
149 std.os.windows.RTL_REGISTRY_ABSOLUTE,
150 topkey,
151 &table,
152 null,
153 null,
154 );
155 switch (res) {
156 .SUCCESS => {
157 inline for (pairs) |pair, i| switch (pair.value) {
158 REG.NONE => unreachable,
159
160 REG.SZ,
161 REG.EXPAND_SZ,
162 REG.MULTI_SZ,
163 => {
164 const entry = @ptrCast(*align(1) const std.os.windows.UNICODE_STRING, table[i + 1].EntryContext);
165 const len = try std.unicode.utf16leToUtf8(out_buf[i][0..], entry.Buffer[0 .. entry.Length / 2]);
166 out_buf[i][len] = 0;
167 },
168
169 REG.DWORD,
170 REG.DWORD_BIG_ENDIAN,
171 REG.QWORD,
172 => {
173 const entry = @ptrCast([*]align(1) const u8, table[i + 1].EntryContext);
174 switch (pair.value) {
175 REG.DWORD, REG.DWORD_BIG_ENDIAN => {
176 mem.copy(u8, out_buf[i][0..4], entry[0..4]);
177 },
178 REG.QWORD => {
179 mem.copy(u8, out_buf[i][0..8], entry[0..8]);
180 },
181 else => unreachable,
182 }
183 },
184
185 else => unreachable,
186 };
187 },
188 else => return error.Unexpected,
189 }
190}
191
192fn getCpuCount() usize {
193 return std.os.windows.peb().NumberOfProcessors;
194}
195
196const ArmCpuInfoImpl = struct {
197 cores: [4]CoreInfo = undefined,
198 core_no: usize = 0,
199 have_fields: usize = 0,
200
201 const CoreInfo = @import("arm.zig").CoreInfo;
202 const cpu_models = @import("arm.zig").cpu_models;
203
204 const Data = struct {
205 cp_4000: []const u8,
206 identifier: []const u8,
207 };
208
209 fn parseDataHook(self: *ArmCpuInfoImpl, data: Data) !void {
210 const info = &self.cores[self.core_no];
211 info.* = .{};
212
213 // CPU part
214 info.part = mem.readIntLittle(u16, data.cp_4000[0..2]) >> 4;
215 self.have_fields += 1;
216
217 // CPU implementer
218 info.implementer = data.cp_4000[3];
219 self.have_fields += 1;
220
221 var tokens = mem.tokenize(u8, data.identifier, " ");
222 while (tokens.next()) |token| {
223 if (mem.eql(u8, "Family", token)) {
224 // CPU architecture
225 const family = tokens.next() orelse continue;
226 info.architecture = try std.fmt.parseInt(u8, family, 10);
227 self.have_fields += 1;
228 break;
229 }
230 } else return;
231
232 self.addOne();
233 }
234
235 fn addOne(self: *ArmCpuInfoImpl) void {
236 if (self.have_fields == 3 and self.core_no < self.cores.len) {
237 if (self.core_no > 0) {
238 // Deduplicate the core info.
239 for (self.cores[0..self.core_no]) |it| {
240 if (std.meta.eql(it, self.cores[self.core_no]))
241 return;
242 }
243 }
244 self.core_no += 1;
245 }
246 }
247
248 fn finalize(self: ArmCpuInfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {
249 if (self.core_no == 0) return null;
250
251 const is_64bit = switch (arch) {
252 .aarch64, .aarch64_be, .aarch64_32 => true,
253 else => false,
254 };
255
256 var known_models: [self.cores.len]?*const Target.Cpu.Model = undefined;
257 for (self.cores[0..self.core_no]) |core, i| {
258 known_models[i] = cpu_models.isKnown(core, is_64bit);
259 }
260
261 // XXX We pick the first core on big.LITTLE systems, hopefully the
262 // LITTLE one.
263 const model = known_models[0] orelse return null;
264 return Target.Cpu{
265 .arch = arch,
266 .model = model,
267 .features = model.features,
268 };
269 }
270};
271
272const ArmCpuInfoParser = CpuInfoParser(ArmCpuInfoImpl);
273
274fn CpuInfoParser(comptime impl: anytype) type {
275 return struct {
276 fn parse(arch: Target.Cpu.Arch) !?Target.Cpu {
277 var obj: impl = .{};
278 var out_buf: [2][max_value_len]u8 = undefined;
279
280 var i: usize = 0;
281 while (i < getCpuCount()) : (i += 1) {
282 try getCpuInfoFromRegistry(i, 2, .{
283 .{ .key = "CP 4000", .value = REG.QWORD },
284 .{ .key = "Identifier", .value = REG.SZ },
285 }, &out_buf);
286
287 const cp_4000 = out_buf[0][0..8];
288 const identifier = mem.sliceTo(out_buf[1][0..], 0);
289
290 try obj.parseDataHook(.{
291 .cp_4000 = cp_4000,
292 .identifier = identifier,
293 });
294 }
295
296 return obj.finalize(arch);
297 }
298 };
299}
300
301fn genericCpu(comptime arch: Target.Cpu.Arch) Target.Cpu {
302 return .{
303 .arch = arch,
304 .model = Target.Cpu.Model.generic(arch),
305 .features = Target.Cpu.Feature.Set.empty,
306 };
307}
308
309pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
310 const current_arch = builtin.cpu.arch;
311 switch (current_arch) {
312 .aarch64, .aarch64_be, .aarch64_32 => {
313 var cpu = cpu: {
314 var maybe_cpu = ArmCpuInfoParser.parse(current_arch) catch break :cpu genericCpu(current_arch);
315 break :cpu maybe_cpu orelse genericCpu(current_arch);
316 };
317
318 const Feature = Target.aarch64.Feature;
319
320 // Override any features that are either present or absent
321 if (IsProcessorFeaturePresent(PF.ARM_NEON_INSTRUCTIONS_AVAILABLE)) {
322 cpu.features.addFeature(@enumToInt(Feature.neon));
323 } else {
324 cpu.features.removeFeature(@enumToInt(Feature.neon));
325 }
326
327 if (IsProcessorFeaturePresent(PF.ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)) {
328 cpu.features.addFeature(@enumToInt(Feature.crc));
329 } else {
330 cpu.features.removeFeature(@enumToInt(Feature.crc));
331 }
332
333 if (IsProcessorFeaturePresent(PF.ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE)) {
334 cpu.features.addFeature(@enumToInt(Feature.crypto));
335 } else {
336 cpu.features.removeFeature(@enumToInt(Feature.crypto));
337 }
338
339 if (IsProcessorFeaturePresent(PF.ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)) {
340 cpu.features.addFeature(@enumToInt(Feature.lse));
341 } else {
342 cpu.features.removeFeature(@enumToInt(Feature.lse));
343 }
344
345 if (IsProcessorFeaturePresent(PF.ARM_V82_DP_INSTRUCTIONS_AVAILABLE)) {
346 cpu.features.addFeature(@enumToInt(Feature.dotprod));
347 } else {
348 cpu.features.removeFeature(@enumToInt(Feature.dotprod));
349 }
350
351 if (IsProcessorFeaturePresent(PF.ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE)) {
352 cpu.features.addFeature(@enumToInt(Feature.jsconv));
353 } else {
354 cpu.features.removeFeature(@enumToInt(Feature.jsconv));
355 }
356
357 return cpu;
358 },
359 else => {},
360 }
361}