diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2022-11-28 10:41:39 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2022-11-28 17:07:34 +0100 |
| commit | 7fbd2955fae13cdc184dbd648743fb187b3ce33d (patch) | |
| tree | 15459c6f6be6679b2ab454502212822c4e2f9d49 /lib/std | |
| parent | d64d7aaac7650d79a6f5a5c5d0db6730b6a11b2c (diff) | |
| download | zig-7fbd2955fae13cdc184dbd648743fb187b3ce33d.tar.gz zig-7fbd2955fae13cdc184dbd648743fb187b3ce33d.zip | |
windows: pull QWORD and SZ identifiers from registry in one syscall
At the same time, do not assume the values necessarily exist, and
use defaults as markers for the lack of keys in the registry.
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/zig/system/windows.zig | 213 |
1 files changed, 131 insertions, 82 deletions
diff --git a/lib/std/zig/system/windows.zig b/lib/std/zig/system/windows.zig index e1ab002834..0aa1abd941 100644 --- a/lib/std/zig/system/windows.zig +++ b/lib/std/zig/system/windows.zig @@ -93,58 +93,33 @@ const Armv8CpuInfoImpl = struct { } }; -fn getCpuInfoFromRegistry(core: usize, comptime key: []const u8, value_type: std.os.windows.ULONG) ![]const u8 { - const key_name = std.unicode.utf8ToUtf16LeStringLiteral(key); +// Technically, a registry value can be as long as 1MB. However, MS recommends storing +// values larger than 2048 bytes in a file rather than directly in the registry, and since we +// are only accessing a system hive \Registry\Machine, we stick to MS guidelines. +// https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits +const max_value_len = 2048; + +const RegistryPair = struct { + key: []const u8, + value: std.os.windows.ULONG, +}; +fn getCpuInfoFromRegistry( + core: usize, + comptime pairs_num: comptime_int, + comptime pairs: [pairs_num]RegistryPair, + out_buf: *[pairs_num][max_value_len]u8, +) !void { // Originally, I wanted to issue a single call with a more complex table structure such that we // would sequentially visit each CPU#d subkey in the registry and pull the value of interest into // a buffer, however, NT seems to be expecting a single buffer per each table meaning we would // end up pulling only the last CPU core info, overwriting everything else. // If anyone can come up with a solution to this, please do! - const table_size = 2; + const table_size = 1 + pairs.len; var table: [table_size + 1]std.os.windows.RTL_QUERY_REGISTRY_TABLE = undefined; const topkey = std.unicode.utf8ToUtf16LeStringLiteral("\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor"); - // Technically, a registry value can be as long as 1MB. However, MS recommends storing - // values larger than 2048 bytes in a file rather than directly in the registry, and since we - // are only accessing a system hive \Registry\Machine, we stick to MS guidelines. - // https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits - const max_value_len = 2048; - - const ctx: *anyopaque = blk: { - switch (value_type) { - REG.NONE => unreachable, - - REG.SZ, - REG.EXPAND_SZ, - REG.MULTI_SZ, - => { - var buf: [max_value_len / 2]u16 = undefined; - var unicode = std.os.windows.UNICODE_STRING{ - .Length = max_value_len, - .MaximumLength = max_value_len, - .Buffer = &buf, - }; - break :blk &unicode; - }, - - REG.DWORD, - REG.DWORD_BIG_ENDIAN, - => { - var buf: [4]u8 = undefined; - break :blk &buf; - }, - - REG.QWORD => { - var buf: [8]u8 = undefined; - break :blk &buf; - }, - - else => unreachable, - } - }; - const max_cpu_buf = 4; var next_cpu_buf: [max_cpu_buf]u8 = undefined; const next_cpu = try std.fmt.bufPrint(&next_cpu_buf, "{d}", .{core}); @@ -163,15 +138,77 @@ fn getCpuInfoFromRegistry(core: usize, comptime key: []const u8, value_type: std .DefaultLength = 0, }; - table[1] = .{ - .QueryRoutine = null, - .Flags = std.os.windows.RTL_QUERY_REGISTRY_DIRECT | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED, - .Name = @intToPtr([*:0]u16, @ptrToInt(key_name)), - .EntryContext = ctx, - .DefaultType = REG.NONE, - .DefaultData = null, - .DefaultLength = 0, - }; + inline for (pairs) |pair, i| { + const ctx: *anyopaque = blk: { + switch (pair.value) { + REG.SZ, + REG.EXPAND_SZ, + REG.MULTI_SZ, + => { + var buf: [max_value_len / 2]u16 = undefined; + var unicode = std.os.windows.UNICODE_STRING{ + .Length = 0, + .MaximumLength = max_value_len, + .Buffer = &buf, + }; + break :blk &unicode; + }, + + REG.DWORD, + REG.DWORD_BIG_ENDIAN, + => { + var buf: [4]u8 = undefined; + break :blk &buf; + }, + + REG.QWORD => { + var buf: [8]u8 = undefined; + break :blk &buf; + }, + + else => unreachable, + } + }; + const default: struct { ptr: *anyopaque, len: u32 } = blk: { + switch (pair.value) { + REG.SZ, + REG.EXPAND_SZ, + REG.MULTI_SZ, + => { + const def = std.unicode.utf8ToUtf16LeStringLiteral("Unknown"); + var buf: [def.len + 1]u16 = undefined; + mem.copy(u16, &buf, def); + buf[def.len] = 0; + break :blk .{ .ptr = &buf, .len = @intCast(u32, (buf.len + 1) * 2) }; + }, + + REG.DWORD, + REG.DWORD_BIG_ENDIAN, + => { + var buf: [4]u8 = [_]u8{0} ** 4; + break :blk .{ .ptr = &buf, .len = 4 }; + }, + + REG.QWORD => { + var buf: [8]u8 = [_]u8{0} ** 8; + break :blk .{ .ptr = &buf, .len = 8 }; + }, + + else => unreachable, + } + }; + const key_name = std.unicode.utf8ToUtf16LeStringLiteral(pair.key); + + table[i + 1] = .{ + .QueryRoutine = null, + .Flags = std.os.windows.RTL_QUERY_REGISTRY_DIRECT, + .Name = @intToPtr([*:0]u16, @ptrToInt(key_name)), + .EntryContext = ctx, + .DefaultType = pair.value, + .DefaultData = default.ptr, + .DefaultLength = default.len, + }; + } // Table sentinel table[table_size] = .{ @@ -192,32 +229,37 @@ fn getCpuInfoFromRegistry(core: usize, comptime key: []const u8, value_type: std null, ); switch (res) { - .SUCCESS => switch (value_type) { - REG.NONE => unreachable, - - REG.SZ, - REG.EXPAND_SZ, - REG.MULTI_SZ, - => { - const entry = @ptrCast(*align(1) const std.os.windows.UNICODE_STRING, table[1].EntryContext); - var identifier_buf: [max_value_len]u8 = undefined; - const len = try std.unicode.utf16leToUtf8(&identifier_buf, entry.Buffer[0 .. entry.Length / 2]); - return identifier_buf[0..len]; - }, - - REG.DWORD, - REG.DWORD_BIG_ENDIAN, - REG.QWORD, - => { - const entry = @ptrCast([*]align(1) const u8, table[1].EntryContext); - switch (value_type) { - REG.DWORD, REG.DWORD_BIG_ENDIAN => return entry[0..4], - REG.QWORD => return entry[0..8], - else => unreachable, - } - }, - - else => unreachable, + .SUCCESS => { + inline for (pairs) |pair, i| switch (pair.value) { + REG.NONE => unreachable, + + REG.SZ, + REG.EXPAND_SZ, + REG.MULTI_SZ, + => { + const entry = @ptrCast(*align(1) const std.os.windows.UNICODE_STRING, table[i + 1].EntryContext); + const len = try std.unicode.utf16leToUtf8(out_buf[i][0..], entry.Buffer[0 .. entry.Length / 2]); + out_buf[i][len] = 0; + }, + + REG.DWORD, + REG.DWORD_BIG_ENDIAN, + REG.QWORD, + => { + const entry = @ptrCast([*]align(1) const u8, table[i + 1].EntryContext); + switch (pair.value) { + REG.DWORD, REG.DWORD_BIG_ENDIAN => { + mem.copy(u8, out_buf[i][0..4], entry[0..4]); + }, + REG.QWORD => { + mem.copy(u8, out_buf[i][0..8], entry[0..8]); + }, + else => unreachable, + } + }, + + else => unreachable, + }; }, else => return std.os.windows.unexpectedStatus(res), } @@ -234,13 +276,20 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model { // Parse the models from strings var parser = Armv8CpuInfoImpl{}; + var out_buf: [3][max_value_len]u8 = undefined; + var i: usize = 0; while (i < cpu_count) : (i += 1) { - const identifier = try getCpuInfoFromRegistry(i, "Identifier", REG.SZ); - parser.parseOne(identifier); - - const hex = try getCpuInfoFromRegistry(i, "CP 4000", REG.QWORD); - std.log.warn("{d} => {x}", .{ i, std.fmt.fmtSliceHexLower(hex) }); + try getCpuInfoFromRegistry(i, 3, .{ + .{ .key = "CP 4000", .value = REG.QWORD }, + .{ .key = "Identifier", .value = REG.SZ }, + .{ .key = "VendorIdentifier", .value = REG.SZ }, + }, &out_buf); + + const hex = out_buf[0][0..8]; + const identifier = mem.sliceTo(out_buf[1][0..], 0); + const vendor_identifier = mem.sliceTo(out_buf[2][0..], 0); + std.log.warn("{d} => {x}, {s}, {s}", .{ i, std.fmt.fmtSliceHexLower(hex), identifier, vendor_identifier }); } return parser.finalize() orelse Target.Cpu.Model.generic(.aarch64); |
