windows: make registry helper generic over value types

This commit is contained in:
Jakub Konka 2022-11-27 13:51:27 +01:00
parent 49ce86bddf
commit 57bda6524b
2 changed files with 54 additions and 17 deletions

View File

@ -3004,6 +3004,10 @@ pub const REG_RESOURCE_LIST = 8;
/// Resource list in the hardware description
pub const REG_FULL_RESOURCE_DESCRIPTOR = 9;
pub const REG_RESOURCE_REQUIREMENTS_LIST = 10;
/// 64-bit number
pub const REG_QWORD = 11;
/// 64-bit number (same as REG_QWORD)
pub const REG_QWORD_LITTLE_ENDIAN = 11;
pub const FILE_NOTIFY_INFORMATION = extern struct {
NextEntryOffset: DWORD,

View File

@ -92,12 +92,7 @@ const Armv8CpuInfoImpl = struct {
}
};
fn getCpuInfoFromRegistry(core: usize, comptime key: []const u8) ![]const u8 {
// Technically, a registry value can be as long as 16k u16s. However, MS recommends storing
// values larger than 2048 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_sz_value = 2048;
fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u8) !T {
const key_name = std.unicode.utf8ToUtf16LeStringLiteral(key);
// 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 {
const topkey = std.unicode.utf8ToUtf16LeStringLiteral("\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor");
var buf: [max_sz_value]u16 = undefined;
var buf_uni = std.os.windows.UNICODE_STRING{
.Length = buf.len * 2,
.MaximumLength = buf.len * 2,
.Buffer = &buf,
// Technically, a registry value can be as long as 16k u16s. However, MS recommends storing
// values larger than 2048 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_sz_value = 2048;
const ctx: *anyopaque = blk: {
switch (@typeInfo(T)) {
.Int => |int| {
const bits = int.bits;
var buf: [bits * 8]u8 = undefined;
break :blk &buf;
},
.Pointer => |ptr| switch (ptr.size) {
.Slice => {
const child = @typeInfo(ptr.child);
if (child != .Int and child.Int.bits != 8) {
@compileError("Unsupported type " ++ @typeName(T) ++ " as registry value");
}
var buf: [max_sz_value]u16 = undefined;
var unicode = std.os.windows.UNICODE_STRING{
.Length = buf.len * 2,
.MaximumLength = buf.len * 2,
.Buffer = &buf,
};
break :blk &unicode;
},
else => @compileError("Unsupported type " ++ @typeName(T) ++ " as registry value"),
},
else => @compileError("Unsupported type " ++ @typeName(T) ++ " as registry value"),
}
};
const max_cpu_buf = 4;
@ -139,7 +161,7 @@ fn getCpuInfoFromRegistry(core: usize, comptime key: []const u8) ![]const u8 {
.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 = &buf_uni,
.EntryContext = ctx,
.DefaultType = std.os.windows.REG_NONE,
.DefaultData = null,
.DefaultLength = 0,
@ -164,10 +186,18 @@ fn getCpuInfoFromRegistry(core: usize, comptime key: []const u8) ![]const u8 {
null,
);
switch (res) {
.SUCCESS => {
var identifier_buf: [max_sz_value * 2]u8 = undefined;
const len = try std.unicode.utf16leToUtf8(&identifier_buf, buf_uni.Buffer[0 .. buf_uni.Length / 2]);
return identifier_buf[0..len];
.SUCCESS => switch (@typeInfo(T)) {
.Int => {
const entry = @ptrCast(*align(1) const T, table[1].EntryContext);
return entry.*;
},
.Pointer => {
const entry = @ptrCast(*align(1) const std.os.windows.UNICODE_STRING, table[1].EntryContext);
var identifier_buf: [max_sz_value * 2]u8 = undefined;
const len = try std.unicode.utf16leToUtf8(&identifier_buf, entry.Buffer[0 .. entry.Length / 2]);
return @as(T, identifier_buf[0..len]);
},
else => unreachable,
},
else => return std.os.windows.unexpectedStatus(res),
}
@ -186,8 +216,11 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model {
var i: usize = 0;
while (i < cpu_count) : (i += 1) {
const identifier = try getCpuInfoFromRegistry(i, "Identifier");
const identifier = try getCpuInfoFromRegistry([]const u8, i, "Identifier");
parser.parseOne(identifier);
const hex = try getCpuInfoFromRegistry(u64, i, "CP 4000");
std.log.warn("{d} => {x}", .{ i, hex });
}
return parser.finalize() orelse Target.Cpu.Model.generic(.aarch64);