mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
windows: map CP 40xx registry values to system ID registers
This commit is contained in:
parent
152202da77
commit
988fff260e
@ -51,23 +51,22 @@ pub fn detectRuntimeVersion() WindowsVersion {
|
||||
// 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, args: anytype) !void {
|
||||
const ArgsType = @TypeOf(args);
|
||||
const args_type_info = @typeInfo(ArgsType);
|
||||
|
||||
if (args_type_info != .Struct) {
|
||||
@compileError("expected tuple or struct argument, found " ++ @typeName(ArgsType));
|
||||
}
|
||||
|
||||
const fields_info = args_type_info.Struct.fields;
|
||||
|
||||
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 = 1 + pairs.len;
|
||||
const table_size = 1 + fields_info.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");
|
||||
@ -90,9 +89,9 @@ fn getCpuInfoFromRegistry(
|
||||
.DefaultLength = 0,
|
||||
};
|
||||
|
||||
inline for (pairs) |pair, i| {
|
||||
inline for (fields_info) |field, i| {
|
||||
const ctx: *anyopaque = blk: {
|
||||
switch (pair.value) {
|
||||
switch (@field(args, field.name).value_type) {
|
||||
REG.SZ,
|
||||
REG.EXPAND_SZ,
|
||||
REG.MULTI_SZ,
|
||||
@ -121,12 +120,15 @@ fn getCpuInfoFromRegistry(
|
||||
else => unreachable,
|
||||
}
|
||||
};
|
||||
const key_name = std.unicode.utf8ToUtf16LeStringLiteral(pair.key);
|
||||
|
||||
var key_buf: [max_value_len / 2 + 1]u16 = undefined;
|
||||
const key_len = try std.unicode.utf8ToUtf16Le(&key_buf, @field(args, field.name).key);
|
||||
key_buf[key_len] = 0;
|
||||
|
||||
table[i + 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)),
|
||||
.Name = key_buf[0..key_len :0],
|
||||
.EntryContext = ctx,
|
||||
.DefaultType = REG.NONE,
|
||||
.DefaultData = null,
|
||||
@ -154,14 +156,15 @@ fn getCpuInfoFromRegistry(
|
||||
);
|
||||
switch (res) {
|
||||
.SUCCESS => {
|
||||
inline for (pairs) |pair, i| switch (pair.value) {
|
||||
inline for (fields_info) |field, i| switch (@field(args, field.name).value_type) {
|
||||
REG.SZ,
|
||||
REG.EXPAND_SZ,
|
||||
REG.MULTI_SZ,
|
||||
=> {
|
||||
var buf = @field(args, field.name).value_buf;
|
||||
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;
|
||||
const len = try std.unicode.utf16leToUtf8(buf, entry.Buffer[0 .. entry.Length / 2]);
|
||||
buf[len] = 0;
|
||||
},
|
||||
|
||||
REG.DWORD,
|
||||
@ -169,12 +172,12 @@ fn getCpuInfoFromRegistry(
|
||||
REG.QWORD,
|
||||
=> {
|
||||
const entry = @ptrCast([*]align(1) const u8, table[i + 1].EntryContext);
|
||||
switch (pair.value) {
|
||||
switch (@field(args, field.name).value_type) {
|
||||
REG.DWORD, REG.DWORD_BIG_ENDIAN => {
|
||||
mem.copy(u8, out_buf[i][0..4], entry[0..4]);
|
||||
mem.copy(u8, @field(args, field.name).value_buf[0..4], entry[0..4]);
|
||||
},
|
||||
REG.QWORD => {
|
||||
mem.copy(u8, out_buf[i][0..8], entry[0..8]);
|
||||
mem.copy(u8, @field(args, field.name).value_buf[0..8], entry[0..8]);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
@ -197,7 +200,7 @@ fn getCpuCount() usize {
|
||||
return std.os.windows.peb().NumberOfProcessors;
|
||||
}
|
||||
|
||||
const ArmCpuInfoImpl = struct {
|
||||
const ArmCpuInfoParser = struct {
|
||||
cores: [4]CoreInfo = undefined,
|
||||
core_no: usize = 0,
|
||||
have_fields: usize = 0,
|
||||
@ -205,38 +208,26 @@ const ArmCpuInfoImpl = struct {
|
||||
const CoreInfo = @import("arm.zig").CoreInfo;
|
||||
const cpu_models = @import("arm.zig").cpu_models;
|
||||
|
||||
const Data = struct {
|
||||
cp_4000: []const u8,
|
||||
identifier: []const u8,
|
||||
};
|
||||
|
||||
fn parseDataHook(self: *ArmCpuInfoImpl, data: Data) !void {
|
||||
fn parseFeaturesFromRegisters(self: *ArmCpuInfoParser, registers: [12]u64) !void {
|
||||
const info = &self.cores[self.core_no];
|
||||
info.* = .{};
|
||||
|
||||
// CPU part
|
||||
info.part = mem.readIntLittle(u16, data.cp_4000[0..2]) >> 4;
|
||||
self.have_fields += 1;
|
||||
for (registers) |register| {
|
||||
std.log.warn("{x}", .{register});
|
||||
}
|
||||
|
||||
// CPU implementer
|
||||
info.implementer = data.cp_4000[3];
|
||||
self.have_fields += 1;
|
||||
// // CPU part
|
||||
// info.part = mem.readIntLittle(u16, data.cp_4000[0..2]) >> 4;
|
||||
// self.have_fields += 1;
|
||||
|
||||
var tokens = mem.tokenize(u8, data.identifier, " ");
|
||||
while (tokens.next()) |token| {
|
||||
if (mem.eql(u8, "Family", token)) {
|
||||
// CPU architecture
|
||||
const family = tokens.next() orelse continue;
|
||||
info.architecture = try std.fmt.parseInt(u8, family, 10);
|
||||
self.have_fields += 1;
|
||||
break;
|
||||
}
|
||||
} else return;
|
||||
// // CPU implementer
|
||||
// info.implementer = data.cp_4000[3];
|
||||
// self.have_fields += 1;
|
||||
|
||||
self.addOne();
|
||||
// self.addOne();
|
||||
}
|
||||
|
||||
fn addOne(self: *ArmCpuInfoImpl) void {
|
||||
fn addOne(self: *ArmCpuInfoParser) void {
|
||||
if (self.have_fields == 3 and self.core_no < self.cores.len) {
|
||||
if (self.core_no > 0) {
|
||||
// Deduplicate the core info.
|
||||
@ -249,7 +240,7 @@ const ArmCpuInfoImpl = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn finalize(self: ArmCpuInfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {
|
||||
fn finalize(self: ArmCpuInfoParser, arch: Target.Cpu.Arch) ?Target.Cpu {
|
||||
if (self.core_no == 0) return null;
|
||||
|
||||
const is_64bit = switch (arch) {
|
||||
@ -271,36 +262,49 @@ const ArmCpuInfoImpl = struct {
|
||||
.features = model.features,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const ArmCpuInfoParser = CpuInfoParser(ArmCpuInfoImpl);
|
||||
fn parse(arch: Target.Cpu.Arch) !?Target.Cpu {
|
||||
var obj: ArmCpuInfoParser = .{};
|
||||
|
||||
fn CpuInfoParser(comptime impl: anytype) type {
|
||||
return struct {
|
||||
fn parse(arch: Target.Cpu.Arch) !?Target.Cpu {
|
||||
var obj: impl = .{};
|
||||
var out_buf: [2][max_value_len]u8 = undefined;
|
||||
// Backing datastore
|
||||
var registers: [12]u64 = undefined;
|
||||
|
||||
var i: usize = 0;
|
||||
while (i < getCpuCount()) : (i += 1) {
|
||||
try getCpuInfoFromRegistry(i, 2, .{
|
||||
.{ .key = "CP 4000", .value = REG.QWORD },
|
||||
.{ .key = "Identifier", .value = REG.SZ },
|
||||
}, &out_buf);
|
||||
var i: usize = 0;
|
||||
while (i < getCpuCount()) : (i += 1) {
|
||||
// Registry key to system ID register mapping
|
||||
// CP 4000 -> MIDR_EL1
|
||||
// CP 4020 -> ID_AA64PFR0_EL1
|
||||
// CP 4021 -> ID_AA64PFR1_EL1
|
||||
// CP 4028 -> ID_AA64DFR0_EL1
|
||||
// CP 4029 -> ID_AA64DFR1_EL1
|
||||
// CP 402C -> ID_AA64AFR0_EL1
|
||||
// CP 402D -> ID_AA64AFR1_EL1
|
||||
// CP 4030 -> ID_AA64ISAR0_EL1
|
||||
// CP 4031 -> ID_AA64ISAR1_EL1
|
||||
// CP 4038 -> ID_AA64MMFR0_EL1
|
||||
// CP 4039 -> ID_AA64MMFR1_EL1
|
||||
// CP 403A -> ID_AA64MMFR2_EL1
|
||||
try getCpuInfoFromRegistry(i, .{
|
||||
.{ .key = "CP 4000", .value_type = REG.QWORD, .value_buf = @ptrCast(*[8]u8, ®isters[0]) },
|
||||
.{ .key = "CP 4020", .value_type = REG.QWORD, .value_buf = @ptrCast(*[8]u8, ®isters[1]) },
|
||||
.{ .key = "CP 4021", .value_type = REG.QWORD, .value_buf = @ptrCast(*[8]u8, ®isters[2]) },
|
||||
.{ .key = "CP 4028", .value_type = REG.QWORD, .value_buf = @ptrCast(*[8]u8, ®isters[3]) },
|
||||
.{ .key = "CP 4029", .value_type = REG.QWORD, .value_buf = @ptrCast(*[8]u8, ®isters[4]) },
|
||||
.{ .key = "CP 402C", .value_type = REG.QWORD, .value_buf = @ptrCast(*[8]u8, ®isters[5]) },
|
||||
.{ .key = "CP 402D", .value_type = REG.QWORD, .value_buf = @ptrCast(*[8]u8, ®isters[6]) },
|
||||
.{ .key = "CP 4030", .value_type = REG.QWORD, .value_buf = @ptrCast(*[8]u8, ®isters[7]) },
|
||||
.{ .key = "CP 4031", .value_type = REG.QWORD, .value_buf = @ptrCast(*[8]u8, ®isters[8]) },
|
||||
.{ .key = "CP 4038", .value_type = REG.QWORD, .value_buf = @ptrCast(*[8]u8, ®isters[9]) },
|
||||
.{ .key = "CP 4039", .value_type = REG.QWORD, .value_buf = @ptrCast(*[8]u8, ®isters[10]) },
|
||||
.{ .key = "CP 403A", .value_type = REG.QWORD, .value_buf = @ptrCast(*[8]u8, ®isters[11]) },
|
||||
});
|
||||
|
||||
const cp_4000 = out_buf[0][0..8];
|
||||
const identifier = mem.sliceTo(out_buf[1][0..], 0);
|
||||
|
||||
try obj.parseDataHook(.{
|
||||
.cp_4000 = cp_4000,
|
||||
.identifier = identifier,
|
||||
});
|
||||
}
|
||||
|
||||
return obj.finalize(arch);
|
||||
try obj.parseFeaturesFromRegisters(registers);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return obj.finalize(arch);
|
||||
}
|
||||
};
|
||||
|
||||
/// If the fine-grained detection of CPU features via Win registry fails,
|
||||
/// we fallback to a generic CPU model but we override the feature set
|
||||
@ -333,10 +337,9 @@ fn genericCpuAndNativeFeatures(arch: Target.Cpu.Arch) Target.Cpu {
|
||||
|
||||
pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
|
||||
const current_arch = builtin.cpu.arch;
|
||||
switch (current_arch) {
|
||||
.aarch64, .aarch64_be, .aarch64_32 => {
|
||||
return ArmCpuInfoParser.parse(current_arch) catch genericCpuAndNativeFeatures(current_arch);
|
||||
},
|
||||
else => return null,
|
||||
}
|
||||
const cpu: ?Target.Cpu = switch (current_arch) {
|
||||
.aarch64, .aarch64_be, .aarch64_32 => ArmCpuInfoParser.parse(current_arch) catch null,
|
||||
else => null,
|
||||
};
|
||||
return cpu orelse genericCpuAndNativeFeatures(current_arch);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user