aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2022-11-28 10:41:39 +0100
committerJakub Konka <kubkon@jakubkonka.com>2022-11-28 17:07:34 +0100
commit7fbd2955fae13cdc184dbd648743fb187b3ce33d (patch)
tree15459c6f6be6679b2ab454502212822c4e2f9d49
parentd64d7aaac7650d79a6f5a5c5d0db6730b6a11b2c (diff)
downloadzig-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.
-rw-r--r--lib/std/zig/system/windows.zig213
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);