windows: drive the registry helper with actual value set for reg entries

This commit is contained in:
Jakub Konka 2022-11-27 14:13:28 +01:00
parent 57bda6524b
commit d64d7aaac7
2 changed files with 86 additions and 64 deletions

View File

@ -2981,33 +2981,35 @@ pub const RTL_QUERY_REGISTRY_DELETE = 0x00000040;
/// If the types do not match, the call fails. /// If the types do not match, the call fails.
pub const RTL_QUERY_REGISTRY_TYPECHECK = 0x00000100; pub const RTL_QUERY_REGISTRY_TYPECHECK = 0x00000100;
/// No value type pub const REG = struct {
pub const REG_NONE = 0; /// No value type
/// Unicode nul terminated string pub const NONE: ULONG = 0;
pub const REG_SZ = 1; /// Unicode nul terminated string
/// Unicode nul terminated string (with environment variable references) pub const SZ: ULONG = 1;
pub const REG_EXPAND_SZ = 2; /// Unicode nul terminated string (with environment variable references)
/// Free form binary pub const EXPAND_SZ: ULONG = 2;
pub const REG_BINARY = 3; /// Free form binary
/// 32-bit number pub const BINARY: ULONG = 3;
pub const REG_DWORD = 4; /// 32-bit number
/// 32-bit number (same as REG_DWORD) pub const DWORD: ULONG = 4;
pub const REG_DWORD_LITTLE_ENDIAN = 4; /// 32-bit number (same as REG_DWORD)
/// 32-bit number pub const DWORD_LITTLE_ENDIAN: ULONG = 4;
pub const REG_DWORD_BIG_ENDIAN = 5; /// 32-bit number
/// Symbolic Link (unicode) pub const DWORD_BIG_ENDIAN: ULONG = 5;
pub const REG_LINK = 6; /// Symbolic Link (unicode)
/// Multiple Unicode strings pub const LINK: ULONG = 6;
pub const REG_MULTI_SZ = 7; /// Multiple Unicode strings
/// Resource list in the resource map pub const MULTI_SZ: ULONG = 7;
pub const REG_RESOURCE_LIST = 8; /// Resource list in the resource map
/// Resource list in the hardware description pub const RESOURCE_LIST: ULONG = 8;
pub const REG_FULL_RESOURCE_DESCRIPTOR = 9; /// Resource list in the hardware description
pub const REG_RESOURCE_REQUIREMENTS_LIST = 10; pub const FULL_RESOURCE_DESCRIPTOR: ULONG = 9;
/// 64-bit number pub const RESOURCE_REQUIREMENTS_LIST: ULONG = 10;
pub const REG_QWORD = 11; /// 64-bit number
/// 64-bit number (same as REG_QWORD) pub const QWORD: ULONG = 11;
pub const REG_QWORD_LITTLE_ENDIAN = 11; /// 64-bit number (same as REG_QWORD)
pub const QWORD_LITTLE_ENDIAN: ULONG = 11;
};
pub const FILE_NOTIFY_INFORMATION = extern struct { pub const FILE_NOTIFY_INFORMATION = extern struct {
NextEntryOffset: DWORD, NextEntryOffset: DWORD,

View File

@ -5,6 +5,7 @@ const Target = std.Target;
pub const WindowsVersion = std.Target.Os.WindowsVersion; pub const WindowsVersion = std.Target.Os.WindowsVersion;
pub const PF = std.os.windows.PF; pub const PF = std.os.windows.PF;
pub const REG = std.os.windows.REG;
pub const IsProcessorFeaturePresent = std.os.windows.IsProcessorFeaturePresent; pub const IsProcessorFeaturePresent = std.os.windows.IsProcessorFeaturePresent;
/// Returns the highest known WindowsVersion deduced from reported runtime information. /// Returns the highest known WindowsVersion deduced from reported runtime information.
@ -92,7 +93,7 @@ const Armv8CpuInfoImpl = struct {
} }
}; };
fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u8) !T { fn getCpuInfoFromRegistry(core: usize, comptime key: []const u8, value_type: std.os.windows.ULONG) ![]const u8 {
const key_name = std.unicode.utf8ToUtf16LeStringLiteral(key); const key_name = std.unicode.utf8ToUtf16LeStringLiteral(key);
// Originally, I wanted to issue a single call with a more complex table structure such that we // Originally, I wanted to issue a single call with a more complex table structure such that we
@ -105,37 +106,42 @@ fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u
const topkey = std.unicode.utf8ToUtf16LeStringLiteral("\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor"); const topkey = std.unicode.utf8ToUtf16LeStringLiteral("\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor");
// Technically, a registry value can be as long as 16k u16s. However, MS recommends storing // Technically, a registry value can be as long as 1MB. However, MS recommends storing
// values larger than 2048 in a file rather than directly in the registry, and since we // 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. // 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 // https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits
const max_sz_value = 2048; const max_value_len = 2048;
const ctx: *anyopaque = blk: { const ctx: *anyopaque = blk: {
switch (@typeInfo(T)) { switch (value_type) {
.Int => |int| { REG.NONE => unreachable,
const bits = int.bits;
var buf: [bits * 8]u8 = undefined; 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; 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; REG.QWORD => {
var unicode = std.os.windows.UNICODE_STRING{ var buf: [8]u8 = undefined;
.Length = buf.len * 2, break :blk &buf;
.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"),
else => unreachable,
} }
}; };
@ -152,7 +158,7 @@ fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u
.Flags = std.os.windows.RTL_QUERY_REGISTRY_SUBKEY | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED, .Flags = std.os.windows.RTL_QUERY_REGISTRY_SUBKEY | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED,
.Name = subkey[0..subkey_len :0], .Name = subkey[0..subkey_len :0],
.EntryContext = null, .EntryContext = null,
.DefaultType = std.os.windows.REG_NONE, .DefaultType = REG.NONE,
.DefaultData = null, .DefaultData = null,
.DefaultLength = 0, .DefaultLength = 0,
}; };
@ -162,7 +168,7 @@ fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u
.Flags = std.os.windows.RTL_QUERY_REGISTRY_DIRECT | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED, .Flags = std.os.windows.RTL_QUERY_REGISTRY_DIRECT | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED,
.Name = @intToPtr([*:0]u16, @ptrToInt(key_name)), .Name = @intToPtr([*:0]u16, @ptrToInt(key_name)),
.EntryContext = ctx, .EntryContext = ctx,
.DefaultType = std.os.windows.REG_NONE, .DefaultType = REG.NONE,
.DefaultData = null, .DefaultData = null,
.DefaultLength = 0, .DefaultLength = 0,
}; };
@ -186,17 +192,31 @@ fn getCpuInfoFromRegistry(comptime T: type, core: usize, comptime key: []const u
null, null,
); );
switch (res) { switch (res) {
.SUCCESS => switch (@typeInfo(T)) { .SUCCESS => switch (value_type) {
.Int => { REG.NONE => unreachable,
const entry = @ptrCast(*align(1) const T, table[1].EntryContext);
return entry.*; REG.SZ,
}, REG.EXPAND_SZ,
.Pointer => { REG.MULTI_SZ,
=> {
const entry = @ptrCast(*align(1) const std.os.windows.UNICODE_STRING, table[1].EntryContext); const entry = @ptrCast(*align(1) const std.os.windows.UNICODE_STRING, table[1].EntryContext);
var identifier_buf: [max_sz_value * 2]u8 = undefined; var identifier_buf: [max_value_len]u8 = undefined;
const len = try std.unicode.utf16leToUtf8(&identifier_buf, entry.Buffer[0 .. entry.Length / 2]); const len = try std.unicode.utf16leToUtf8(&identifier_buf, entry.Buffer[0 .. entry.Length / 2]);
return @as(T, identifier_buf[0..len]); 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, else => unreachable,
}, },
else => return std.os.windows.unexpectedStatus(res), else => return std.os.windows.unexpectedStatus(res),
@ -216,11 +236,11 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model {
var i: usize = 0; var i: usize = 0;
while (i < cpu_count) : (i += 1) { while (i < cpu_count) : (i += 1) {
const identifier = try getCpuInfoFromRegistry([]const u8, i, "Identifier"); const identifier = try getCpuInfoFromRegistry(i, "Identifier", REG.SZ);
parser.parseOne(identifier); parser.parseOne(identifier);
const hex = try getCpuInfoFromRegistry(u64, i, "CP 4000"); const hex = try getCpuInfoFromRegistry(i, "CP 4000", REG.QWORD);
std.log.warn("{d} => {x}", .{ i, hex }); std.log.warn("{d} => {x}", .{ i, std.fmt.fmtSliceHexLower(hex) });
} }
return parser.finalize() orelse Target.Cpu.Model.generic(.aarch64); return parser.finalize() orelse Target.Cpu.Model.generic(.aarch64);