| ... | ... | @@ -92,12 +92,7 @@ const Armv8CpuInfoImpl = struct { |
| 92 | 92 | } |
| 93 | 93 | }; |
| 94 | 94 | |
| 95 | | fn getCpuInfoFromRegistry(core: usize, comptime key: []const u8) ![]const u8 { |
| 96 | | // Technically, a registry value can be as long as 16k u16s. However, MS recommends storing |
| 97 | | // values larger than 2048 in a file rather than directly in the registry, and since we |
| 98 | | // are only accessing a system hive \Registry\Machine, we stick to MS guidelines. |
| 99 | | // https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits |
| 100 | | const max_sz_value = 2048; |
| 95 | fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u8) !T { |
| 101 | 96 | const key_name = std.unicode.utf8ToUtf16LeStringLiteral(key); |
| 102 | 97 | |
| 103 | 98 | // Originally, I wanted to issue a single call with a more complex table structure such that we |
| ... | ... | @@ -110,11 +105,38 @@ fn getCpuInfoFromRegistry(core: usize, comptime key: []const u8) ![]const u8 { |
| 110 | 105 | |
| 111 | 106 | const topkey = std.unicode.utf8ToUtf16LeStringLiteral("\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor"); |
| 112 | 107 | |
| 113 | | var buf: [max_sz_value]u16 = undefined; |
| 114 | | var buf_uni = std.os.windows.UNICODE_STRING{ |
| 115 | | .Length = buf.len * 2, |
| 116 | | .MaximumLength = buf.len * 2, |
| 117 | | .Buffer = &buf, |
| 108 | // Technically, a registry value can be as long as 16k u16s. However, MS recommends storing |
| 109 | // values larger than 2048 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 | // https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits |
| 112 | const max_sz_value = 2048; |
| 113 | |
| 114 | const ctx: *anyopaque = blk: { |
| 115 | switch (@typeInfo(T)) { |
| 116 | .Int => |int| { |
| 117 | const bits = int.bits; |
| 118 | var buf: [bits * 8]u8 = undefined; |
| 119 | break :blk &buf; |
| 120 | }, |
| 121 | .Pointer => |ptr| switch (ptr.size) { |
| 122 | .Slice => { |
| 123 | const child = @typeInfo(ptr.child); |
| 124 | if (child != .Int and child.Int.bits != 8) { |
| 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 | }, |
| 138 | else => @compileError("Unsupported type " ++ @typeName(T) ++ " as registry value"), |
| 139 | } |
| 118 | 140 | }; |
| 119 | 141 | |
| 120 | 142 | const max_cpu_buf = 4; |
| ... | ... | @@ -139,7 +161,7 @@ fn getCpuInfoFromRegistry(core: usize, comptime key: []const u8) ![]const u8 { |
| 139 | 161 | .QueryRoutine = null, |
| 140 | 162 | .Flags = std.os.windows.RTL_QUERY_REGISTRY_DIRECT | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED, |
| 141 | 163 | .Name = @intToPtr([*:0]u16, @ptrToInt(key_name)), |
| 142 | | .EntryContext = &buf_uni, |
| 164 | .EntryContext = ctx, |
| 143 | 165 | .DefaultType = std.os.windows.REG_NONE, |
| 144 | 166 | .DefaultData = null, |
| 145 | 167 | .DefaultLength = 0, |
| ... | ... | @@ -164,10 +186,18 @@ fn getCpuInfoFromRegistry(core: usize, comptime key: []const u8) ![]const u8 { |
| 164 | 186 | null, |
| 165 | 187 | ); |
| 166 | 188 | switch (res) { |
| 167 | | .SUCCESS => { |
| 168 | | var identifier_buf: [max_sz_value * 2]u8 = undefined; |
| 169 | | const len = try std.unicode.utf16leToUtf8(&identifier_buf, buf_uni.Buffer[0 .. buf_uni.Length / 2]); |
| 170 | | return identifier_buf[0..len]; |
| 189 | .SUCCESS => switch (@typeInfo(T)) { |
| 190 | .Int => { |
| 191 | const entry = @ptrCast(*align(1) const T, table[1].EntryContext); |
| 192 | return entry.*; |
| 193 | }, |
| 194 | .Pointer => { |
| 195 | const entry = @ptrCast(*align(1) const std.os.windows.UNICODE_STRING, table[1].EntryContext); |
| 196 | var identifier_buf: [max_sz_value * 2]u8 = undefined; |
| 197 | const len = try std.unicode.utf16leToUtf8(&identifier_buf, entry.Buffer[0 .. entry.Length / 2]); |
| 198 | return @as(T, identifier_buf[0..len]); |
| 199 | }, |
| 200 | else => unreachable, |
| 171 | 201 | }, |
| 172 | 202 | else => return std.os.windows.unexpectedStatus(res), |
| 173 | 203 | } |
| ... | ... | @@ -186,8 +216,11 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model { |
| 186 | 216 | |
| 187 | 217 | var i: usize = 0; |
| 188 | 218 | while (i < cpu_count) : (i += 1) { |
| 189 | | const identifier = try getCpuInfoFromRegistry(i, "Identifier"); |
| 219 | const identifier = try getCpuInfoFromRegistry([]const u8, i, "Identifier"); |
| 190 | 220 | parser.parseOne(identifier); |
| 221 | |
| 222 | const hex = try getCpuInfoFromRegistry(u64, i, "CP 4000"); |
| 223 | std.log.warn("{d} => {x}", .{ i, hex }); |
| 191 | 224 | } |
| 192 | 225 | |
| 193 | 226 | return parser.finalize() orelse Target.Cpu.Model.generic(.aarch64); |