authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-11-27 13:51:27+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-11-28 17:07:34+01:00
log57bda6524b2dbe69c20f25e99c9b136dd0859297
tree76209fb7e7b42a4a81c8c119029eb252d65f12af
parent49ce86bddf49efcd1de8768d728d77ea1c8849f8

windows: make registry helper generic over value types


2 files changed, 54 insertions(+), 17 deletions(-)

lib/std/os/windows.zig+4
......@@ -3004,6 +3004,10 @@ pub const REG_RESOURCE_LIST = 8;
30043004/// Resource list in the hardware description
30053005pub const REG_FULL_RESOURCE_DESCRIPTOR = 9;
30063006pub const REG_RESOURCE_REQUIREMENTS_LIST = 10;
3007/// 64-bit number
3008pub const REG_QWORD = 11;
3009/// 64-bit number (same as REG_QWORD)
3010pub const REG_QWORD_LITTLE_ENDIAN = 11;
30073011
30083012pub const FILE_NOTIFY_INFORMATION = extern struct {
30093013 NextEntryOffset: DWORD,
lib/std/zig/system/windows.zig+50-17
......@@ -92,12 +92,7 @@ const Armv8CpuInfoImpl = struct {
9292 }
9393};
9494
95fn 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;
95fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u8) !T {
10196 const key_name = std.unicode.utf8ToUtf16LeStringLiteral(key);
10297
10398 // 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 {
110105
111106 const topkey = std.unicode.utf8ToUtf16LeStringLiteral("\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor");
112107
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 }
118140 };
119141
120142 const max_cpu_buf = 4;
......@@ -139,7 +161,7 @@ fn getCpuInfoFromRegistry(core: usize, comptime key: []const u8) ![]const u8 {
139161 .QueryRoutine = null,
140162 .Flags = std.os.windows.RTL_QUERY_REGISTRY_DIRECT | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED,
141163 .Name = @intToPtr([*:0]u16, @ptrToInt(key_name)),
142 .EntryContext = &buf_uni,
164 .EntryContext = ctx,
143165 .DefaultType = std.os.windows.REG_NONE,
144166 .DefaultData = null,
145167 .DefaultLength = 0,
......@@ -164,10 +186,18 @@ fn getCpuInfoFromRegistry(core: usize, comptime key: []const u8) ![]const u8 {
164186 null,
165187 );
166188 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,
171201 },
172202 else => return std.os.windows.unexpectedStatus(res),
173203 }
......@@ -186,8 +216,11 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model {
186216
187217 var i: usize = 0;
188218 while (i < cpu_count) : (i += 1) {
189 const identifier = try getCpuInfoFromRegistry(i, "Identifier");
219 const identifier = try getCpuInfoFromRegistry([]const u8, i, "Identifier");
190220 parser.parseOne(identifier);
221
222 const hex = try getCpuInfoFromRegistry(u64, i, "CP 4000");
223 std.log.warn("{d} => {x}", .{ i, hex });
191224 }
192225
193226 return parser.finalize() orelse Target.Cpu.Model.generic(.aarch64);