| ... | @@ -5,6 +5,7 @@ const Target = std.Target; | ... | @@ -5,6 +5,7 @@ const Target = std.Target; |
| 5 | | 5 | |
| 6 | pub const WindowsVersion = std.Target.Os.WindowsVersion; | 6 | pub const WindowsVersion = std.Target.Os.WindowsVersion; |
| 7 | pub const PF = std.os.windows.PF; | 7 | pub const PF = std.os.windows.PF; |
| | 8 | pub const REG = std.os.windows.REG; |
| 8 | pub const IsProcessorFeaturePresent = std.os.windows.IsProcessorFeaturePresent; | 9 | pub const IsProcessorFeaturePresent = std.os.windows.IsProcessorFeaturePresent; |
| 9 | | 10 | |
| 10 | /// Returns the highest known WindowsVersion deduced from reported runtime information. | 11 | /// Returns the highest known WindowsVersion deduced from reported runtime information. |
| ... | @@ -92,7 +93,7 @@ const Armv8CpuInfoImpl = struct { | ... | @@ -92,7 +93,7 @@ const Armv8CpuInfoImpl = struct { |
| 92 | } | 93 | } |
| 93 | }; | 94 | }; |
| 94 | | 95 | |
| 95 | fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u8) !T { | 96 | fn getCpuInfoFromRegistry(core: usize, comptime key: []const u8, value_type: std.os.windows.ULONG) ![]const u8 { |
| 96 | const key_name = std.unicode.utf8ToUtf16LeStringLiteral(key); | 97 | const key_name = std.unicode.utf8ToUtf16LeStringLiteral(key); |
| 97 | | 98 | |
| 98 | // Originally, I wanted to issue a single call with a more complex table structure such that we | 99 | // Originally, I wanted to issue a single call with a more complex table structure such that we |
| ... | @@ -105,37 +106,42 @@ fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u | ... | @@ -105,37 +106,42 @@ fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u |
| 105 | | 106 | |
| 106 | const topkey = std.unicode.utf8ToUtf16LeStringLiteral("\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor"); | 107 | const topkey = std.unicode.utf8ToUtf16LeStringLiteral("\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor"); |
| 107 | | 108 | |
| 108 | // Technically, a registry value can be as long as 16k u16s. However, MS recommends storing | 109 | // Technically, a registry value can be as long as 1MB. However, MS recommends storing |
| 109 | // values larger than 2048 in a file rather than directly in the registry, and since we | 110 | // values larger than 2048 bytes in a file rather than directly in the registry, and since we |
| 110 | // are only accessing a system hive \Registry\Machine, we stick to MS guidelines. | 111 | // are only accessing a system hive \Registry\Machine, we stick to MS guidelines. |
| 111 | // https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits | 112 | // https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits |
| 112 | const max_sz_value = 2048; | 113 | const max_value_len = 2048; |
| 113 | | 114 | |
| 114 | const ctx: *anyopaque = blk: { | 115 | const ctx: *anyopaque = blk: { |
| 115 | switch (@typeInfo(T)) { | 116 | switch (value_type) { |
| 116 | .Int => |int| { | 117 | REG.NONE => unreachable, |
| 117 | const bits = int.bits; | 118 | |
| 118 | var buf: [bits * 8]u8 = undefined; | 119 | REG.SZ, |
| | 120 | REG.EXPAND_SZ, |
| | 121 | REG.MULTI_SZ, |
| | 122 | => { |
| | 123 | var buf: [max_value_len / 2]u16 = undefined; |
| | 124 | var unicode = std.os.windows.UNICODE_STRING{ |
| | 125 | .Length = max_value_len, |
| | 126 | .MaximumLength = max_value_len, |
| | 127 | .Buffer = &buf, |
| | 128 | }; |
| | 129 | break :blk &unicode; |
| | 130 | }, |
| | 131 | |
| | 132 | REG.DWORD, |
| | 133 | REG.DWORD_BIG_ENDIAN, |
| | 134 | => { |
| | 135 | var buf: [4]u8 = undefined; |
| 119 | break :blk &buf; | 136 | break :blk &buf; |
| 120 | }, | 137 | }, |
| 121 | .Pointer => |ptr| switch (ptr.size) { | 138 | |
| 122 | .Slice => { | 139 | REG.QWORD => { |
| 123 | const child = @typeInfo(ptr.child); | 140 | var buf: [8]u8 = undefined; |
| 124 | if (child != .Int and child.Int.bits != 8) { | 141 | break :blk &buf; |
| 125 | @compileError("Unsupported type " ++ @typeName(T) ++ " as registry value"); | | |
| 126 | } | | |
| 127 | | | |
| 128 | var buf: [max_sz_value]u16 = undefined; | | |
| 129 | var unicode = std.os.windows.UNICODE_STRING{ | | |
| 130 | .Length = buf.len * 2, | | |
| 131 | .MaximumLength = buf.len * 2, | | |
| 132 | .Buffer = &buf, | | |
| 133 | }; | | |
| 134 | break :blk &unicode; | | |
| 135 | }, | | |
| 136 | else => @compileError("Unsupported type " ++ @typeName(T) ++ " as registry value"), | | |
| 137 | }, | 142 | }, |
| 138 | else => @compileError("Unsupported type " ++ @typeName(T) ++ " as registry value"), | 143 | |
| | 144 | else => unreachable, |
| 139 | } | 145 | } |
| 140 | }; | 146 | }; |
| 141 | | 147 | |
| ... | @@ -152,7 +158,7 @@ fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u | ... | @@ -152,7 +158,7 @@ fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u |
| 152 | .Flags = std.os.windows.RTL_QUERY_REGISTRY_SUBKEY | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED, | 158 | .Flags = std.os.windows.RTL_QUERY_REGISTRY_SUBKEY | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED, |
| 153 | .Name = subkey[0..subkey_len :0], | 159 | .Name = subkey[0..subkey_len :0], |
| 154 | .EntryContext = null, | 160 | .EntryContext = null, |
| 155 | .DefaultType = std.os.windows.REG_NONE, | 161 | .DefaultType = REG.NONE, |
| 156 | .DefaultData = null, | 162 | .DefaultData = null, |
| 157 | .DefaultLength = 0, | 163 | .DefaultLength = 0, |
| 158 | }; | 164 | }; |
| ... | @@ -162,7 +168,7 @@ fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u | ... | @@ -162,7 +168,7 @@ fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u |
| 162 | .Flags = std.os.windows.RTL_QUERY_REGISTRY_DIRECT | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED, | 168 | .Flags = std.os.windows.RTL_QUERY_REGISTRY_DIRECT | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED, |
| 163 | .Name = @intToPtr([*:0]u16, @ptrToInt(key_name)), | 169 | .Name = @intToPtr([*:0]u16, @ptrToInt(key_name)), |
| 164 | .EntryContext = ctx, | 170 | .EntryContext = ctx, |
| 165 | .DefaultType = std.os.windows.REG_NONE, | 171 | .DefaultType = REG.NONE, |
| 166 | .DefaultData = null, | 172 | .DefaultData = null, |
| 167 | .DefaultLength = 0, | 173 | .DefaultLength = 0, |
| 168 | }; | 174 | }; |
| ... | @@ -186,17 +192,31 @@ fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u | ... | @@ -186,17 +192,31 @@ fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u |
| 186 | null, | 192 | null, |
| 187 | ); | 193 | ); |
| 188 | switch (res) { | 194 | switch (res) { |
| 189 | .SUCCESS => switch (@typeInfo(T)) { | 195 | .SUCCESS => switch (value_type) { |
| 190 | .Int => { | 196 | REG.NONE => unreachable, |
| 191 | const entry = @ptrCast(*align(1) const T, table[1].EntryContext); | 197 | |
| 192 | return entry.*; | 198 | REG.SZ, |
| 193 | }, | 199 | REG.EXPAND_SZ, |
| 194 | .Pointer => { | 200 | REG.MULTI_SZ, |
| | 201 | => { |
| 195 | const entry = @ptrCast(*align(1) const std.os.windows.UNICODE_STRING, table[1].EntryContext); | 202 | const entry = @ptrCast(*align(1) const std.os.windows.UNICODE_STRING, table[1].EntryContext); |
| 196 | var identifier_buf: [max_sz_value * 2]u8 = undefined; | 203 | var identifier_buf: [max_value_len]u8 = undefined; |
| 197 | const len = try std.unicode.utf16leToUtf8(&identifier_buf, entry.Buffer[0 .. entry.Length / 2]); | 204 | const len = try std.unicode.utf16leToUtf8(&identifier_buf, entry.Buffer[0 .. entry.Length / 2]); |
| 198 | return @as(T, identifier_buf[0..len]); | 205 | return identifier_buf[0..len]; |
| 199 | }, | 206 | }, |
| | 207 | |
| | 208 | REG.DWORD, |
| | 209 | REG.DWORD_BIG_ENDIAN, |
| | 210 | REG.QWORD, |
| | 211 | => { |
| | 212 | const entry = @ptrCast([*]align(1) const u8, table[1].EntryContext); |
| | 213 | switch (value_type) { |
| | 214 | REG.DWORD, REG.DWORD_BIG_ENDIAN => return entry[0..4], |
| | 215 | REG.QWORD => return entry[0..8], |
| | 216 | else => unreachable, |
| | 217 | } |
| | 218 | }, |
| | 219 | |
| 200 | else => unreachable, | 220 | else => unreachable, |
| 201 | }, | 221 | }, |
| 202 | else => return std.os.windows.unexpectedStatus(res), | 222 | else => return std.os.windows.unexpectedStatus(res), |
| ... | @@ -216,11 +236,11 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model { | ... | @@ -216,11 +236,11 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model { |
| 216 | | 236 | |
| 217 | var i: usize = 0; | 237 | var i: usize = 0; |
| 218 | while (i < cpu_count) : (i += 1) { | 238 | while (i < cpu_count) : (i += 1) { |
| 219 | const identifier = try getCpuInfoFromRegistry([]const u8, i, "Identifier"); | 239 | const identifier = try getCpuInfoFromRegistry(i, "Identifier", REG.SZ); |
| 220 | parser.parseOne(identifier); | 240 | parser.parseOne(identifier); |
| 221 | | 241 | |
| 222 | const hex = try getCpuInfoFromRegistry(u64, i, "CP 4000"); | 242 | const hex = try getCpuInfoFromRegistry(i, "CP 4000", REG.QWORD); |
| 223 | std.log.warn("{d} => {x}", .{ i, hex }); | 243 | std.log.warn("{d} => {x}", .{ i, std.fmt.fmtSliceHexLower(hex) }); |
| 224 | } | 244 | } |
| 225 | | 245 | |
| 226 | return parser.finalize() orelse Target.Cpu.Model.generic(.aarch64); | 246 | return parser.finalize() orelse Target.Cpu.Model.generic(.aarch64); |