mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
windows: use RtlQueryRegistryValues to query reg in a single syscall
This commit is contained in:
parent
153afed877
commit
7ea2c7fbcd
@ -2088,6 +2088,7 @@ pub const LPWSTR = [*:0]WCHAR;
|
|||||||
pub const LPCWSTR = [*:0]const WCHAR;
|
pub const LPCWSTR = [*:0]const WCHAR;
|
||||||
pub const PVOID = *anyopaque;
|
pub const PVOID = *anyopaque;
|
||||||
pub const PWSTR = [*:0]WCHAR;
|
pub const PWSTR = [*:0]WCHAR;
|
||||||
|
pub const PCWSTR = [*:0]const WCHAR;
|
||||||
pub const SIZE_T = usize;
|
pub const SIZE_T = usize;
|
||||||
pub const UINT = c_uint;
|
pub const UINT = c_uint;
|
||||||
pub const ULONG_PTR = usize;
|
pub const ULONG_PTR = usize;
|
||||||
@ -2876,8 +2877,134 @@ pub const ACCESS_MASK = DWORD;
|
|||||||
pub const LSTATUS = LONG;
|
pub const LSTATUS = LONG;
|
||||||
|
|
||||||
pub const HKEY = HANDLE;
|
pub const HKEY = HANDLE;
|
||||||
|
|
||||||
pub const HKEY_LOCAL_MACHINE: HKEY = @intToPtr(HKEY, 0x80000002);
|
pub const HKEY_LOCAL_MACHINE: HKEY = @intToPtr(HKEY, 0x80000002);
|
||||||
|
|
||||||
|
/// Combines the STANDARD_RIGHTS_REQUIRED, KEY_QUERY_VALUE, KEY_SET_VALUE, KEY_CREATE_SUB_KEY,
|
||||||
|
/// KEY_ENUMERATE_SUB_KEYS, KEY_NOTIFY, and KEY_CREATE_LINK access rights.
|
||||||
|
pub const KEY_ALL_ACCESS = 0xF003F;
|
||||||
|
/// Reserved for system use.
|
||||||
|
pub const KEY_CREATE_LINK = 0x0020;
|
||||||
|
/// Required to create a subkey of a registry key.
|
||||||
|
pub const KEY_CREATE_SUB_KEY = 0x0004;
|
||||||
|
/// Required to enumerate the subkeys of a registry key.
|
||||||
|
pub const KEY_ENUMERATE_SUB_KEYS = 0x0008;
|
||||||
|
/// Equivalent to KEY_READ.
|
||||||
|
pub const KEY_EXECUTE = 0x20019;
|
||||||
|
/// Required to request change notifications for a registry key or for subkeys of a registry key.
|
||||||
|
pub const KEY_NOTIFY = 0x0010;
|
||||||
|
/// Required to query the values of a registry key.
|
||||||
|
pub const KEY_QUERY_VALUE = 0x0001;
|
||||||
|
/// Combines the STANDARD_RIGHTS_READ, KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS, and KEY_NOTIFY values.
|
||||||
|
pub const KEY_READ = 0x20019;
|
||||||
|
/// Required to create, delete, or set a registry value.
|
||||||
|
pub const KEY_SET_VALUE = 0x0002;
|
||||||
|
/// Indicates that an application on 64-bit Windows should operate on the 32-bit registry view.
|
||||||
|
/// This flag is ignored by 32-bit Windows.
|
||||||
|
pub const KEY_WOW64_32KEY = 0x0200;
|
||||||
|
/// Indicates that an application on 64-bit Windows should operate on the 64-bit registry view.
|
||||||
|
/// This flag is ignored by 32-bit Windows.
|
||||||
|
pub const KEY_WOW64_64KEY = 0x0100;
|
||||||
|
/// Combines the STANDARD_RIGHTS_WRITE, KEY_SET_VALUE, and KEY_CREATE_SUB_KEY access rights.
|
||||||
|
pub const KEY_WRITE = 0x20006;
|
||||||
|
|
||||||
|
/// Open symbolic link.
|
||||||
|
pub const REG_OPTION_OPEN_LINK: DWORD = 0x8;
|
||||||
|
|
||||||
|
pub const RTL_QUERY_REGISTRY_TABLE = extern struct {
|
||||||
|
QueryRoutine: RTL_QUERY_REGISTRY_ROUTINE,
|
||||||
|
Flags: ULONG,
|
||||||
|
Name: ?PWSTR,
|
||||||
|
EntryContext: ?*anyopaque,
|
||||||
|
DefaultType: ULONG,
|
||||||
|
DefaultData: ?*anyopaque,
|
||||||
|
DefaultLength: ULONG,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const RTL_QUERY_REGISTRY_ROUTINE = ?std.meta.FnPtr(fn (
|
||||||
|
PWSTR,
|
||||||
|
ULONG,
|
||||||
|
?*anyopaque,
|
||||||
|
ULONG,
|
||||||
|
?*anyopaque,
|
||||||
|
?*anyopaque,
|
||||||
|
) callconv(WINAPI) NTSTATUS);
|
||||||
|
|
||||||
|
/// Path is a full path
|
||||||
|
pub const RTL_REGISTRY_ABSOLUTE = 0;
|
||||||
|
/// \Registry\Machine\System\CurrentControlSet\Services
|
||||||
|
pub const RTL_REGISTRY_SERVICES = 1;
|
||||||
|
/// \Registry\Machine\System\CurrentControlSet\Control
|
||||||
|
pub const RTL_REGISTRY_CONTROL = 2;
|
||||||
|
/// \Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion
|
||||||
|
pub const RTL_REGISTRY_WINDOWS_NT = 3;
|
||||||
|
/// \Registry\Machine\Hardware\DeviceMap
|
||||||
|
pub const RTL_REGISTRY_DEVICEMAP = 4;
|
||||||
|
/// \Registry\User\CurrentUser
|
||||||
|
pub const RTL_REGISTRY_USER = 5;
|
||||||
|
pub const RTL_REGISTRY_MAXIMUM = 6;
|
||||||
|
|
||||||
|
/// Low order bits are registry handle
|
||||||
|
pub const RTL_REGISTRY_HANDLE = 0x40000000;
|
||||||
|
/// Indicates the key node is optional
|
||||||
|
pub const RTL_REGISTRY_OPTIONAL = 0x80000000;
|
||||||
|
|
||||||
|
/// Name is a subkey and remainder of table or until next subkey are value
|
||||||
|
/// names for that subkey to look at.
|
||||||
|
pub const RTL_QUERY_REGISTRY_SUBKEY = 0x00000001;
|
||||||
|
|
||||||
|
/// Reset current key to original key for this and all following table entries.
|
||||||
|
pub const RTL_QUERY_REGISTRY_TOPKEY = 0x00000002;
|
||||||
|
|
||||||
|
/// Fail if no match found for this table entry.
|
||||||
|
pub const RTL_QUERY_REGISTRY_REQUIRED = 0x00000004;
|
||||||
|
|
||||||
|
/// Used to mark a table entry that has no value name, just wants a call out, not
|
||||||
|
/// an enumeration of all values.
|
||||||
|
pub const RTL_QUERY_REGISTRY_NOVALUE = 0x00000008;
|
||||||
|
|
||||||
|
/// Used to suppress the expansion of REG_MULTI_SZ into multiple callouts or
|
||||||
|
/// to prevent the expansion of environment variable values in REG_EXPAND_SZ.
|
||||||
|
pub const RTL_QUERY_REGISTRY_NOEXPAND = 0x00000010;
|
||||||
|
|
||||||
|
/// QueryRoutine field ignored. EntryContext field points to location to store value.
|
||||||
|
/// For null terminated strings, EntryContext points to UNICODE_STRING structure that
|
||||||
|
/// that describes maximum size of buffer. If .Buffer field is NULL then a buffer is
|
||||||
|
/// allocated.
|
||||||
|
pub const RTL_QUERY_REGISTRY_DIRECT = 0x00000020;
|
||||||
|
|
||||||
|
/// Used to delete value keys after they are queried.
|
||||||
|
pub const RTL_QUERY_REGISTRY_DELETE = 0x00000040;
|
||||||
|
|
||||||
|
/// Use this flag with the RTL_QUERY_REGISTRY_DIRECT flag to verify that the REG_XXX type
|
||||||
|
/// of the stored registry value matches the type expected by the caller.
|
||||||
|
/// If the types do not match, the call fails.
|
||||||
|
pub const RTL_QUERY_REGISTRY_TYPECHECK = 0x00000100;
|
||||||
|
|
||||||
|
/// No value type
|
||||||
|
pub const REG_NONE = 0;
|
||||||
|
/// Unicode nul terminated string
|
||||||
|
pub const REG_SZ = 1;
|
||||||
|
/// Unicode nul terminated string (with environment variable references)
|
||||||
|
pub const REG_EXPAND_SZ = 2;
|
||||||
|
/// Free form binary
|
||||||
|
pub const REG_BINARY = 3;
|
||||||
|
/// 32-bit number
|
||||||
|
pub const REG_DWORD = 4;
|
||||||
|
/// 32-bit number (same as REG_DWORD)
|
||||||
|
pub const REG_DWORD_LITTLE_ENDIAN = 4;
|
||||||
|
/// 32-bit number
|
||||||
|
pub const REG_DWORD_BIG_ENDIAN = 5;
|
||||||
|
/// Symbolic Link (unicode)
|
||||||
|
pub const REG_LINK = 6;
|
||||||
|
/// Multiple Unicode strings
|
||||||
|
pub const REG_MULTI_SZ = 7;
|
||||||
|
/// Resource list in the resource map
|
||||||
|
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;
|
||||||
|
|
||||||
pub const FILE_NOTIFY_INFORMATION = extern struct {
|
pub const FILE_NOTIFY_INFORMATION = extern struct {
|
||||||
NextEntryOffset: DWORD,
|
NextEntryOffset: DWORD,
|
||||||
Action: DWORD,
|
Action: DWORD,
|
||||||
@ -4020,187 +4147,3 @@ pub fn IsProcessorFeaturePresent(feature: PF) bool {
|
|||||||
if (@enumToInt(feature) >= PROCESSOR_FEATURE_MAX) return false;
|
if (@enumToInt(feature) >= PROCESSOR_FEATURE_MAX) return false;
|
||||||
return SharedUserData.ProcessorFeatures[@enumToInt(feature)] == 1;
|
return SharedUserData.ProcessorFeatures[@enumToInt(feature)] == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const KEY_QUERY_VALUE = 0x0001;
|
|
||||||
|
|
||||||
/// Open symbolic link.
|
|
||||||
pub const REG_OPTION_OPEN_LINK: DWORD = 0x8;
|
|
||||||
|
|
||||||
inline fn IsPredefKey(hkey: HKEY) bool {
|
|
||||||
return @ptrToInt(hkey) & 0xF0000000 == 0x80000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fn GetPredefKeyIndex(hkey: HKEY) usize {
|
|
||||||
return @ptrToInt(hkey) & 0x0FFFFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fn ClosePredefKey(hkey: HKEY) void {
|
|
||||||
if (@ptrToInt(hkey) & 0x1 != 0) {
|
|
||||||
assert(ntdll.NtClose(hkey) == .SUCCESS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const MAX_DEFAULT_HANDLES = 6;
|
|
||||||
pub const REG_MAX_NAME_SIZE = 256;
|
|
||||||
|
|
||||||
pub const RegOpenKeyOpts = struct {
|
|
||||||
ulOptions: DWORD = 0,
|
|
||||||
samDesired: ACCESS_MASK = KEY_QUERY_VALUE,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Pulls existing key from the registry.
|
|
||||||
pub fn RegOpenKey(hkey: HKEY, lpSubKey: []const u16, opts: RegOpenKeyOpts) !HKEY {
|
|
||||||
if (IsPredefKey(hkey) and lpSubKey.len == 0) {
|
|
||||||
return hkey;
|
|
||||||
}
|
|
||||||
|
|
||||||
const key_handle = try MapDefaultKey(hkey);
|
|
||||||
defer ClosePredefKey(key_handle);
|
|
||||||
|
|
||||||
var subkey_string: UNICODE_STRING = undefined;
|
|
||||||
if (lpSubKey.len == 0 or mem.eql(u16, &[_]u16{'\\'}, lpSubKey)) {
|
|
||||||
subkey_string = .{
|
|
||||||
.Length = 0,
|
|
||||||
.MaximumLength = 0,
|
|
||||||
.Buffer = @intToPtr([*]u16, @ptrToInt(&[0]u16{})),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
const len_bytes = math.cast(u16, lpSubKey.len * 2) orelse return error.NameTooLong;
|
|
||||||
subkey_string = .{
|
|
||||||
.Length = len_bytes,
|
|
||||||
.MaximumLength = len_bytes,
|
|
||||||
.Buffer = @intToPtr([*]u16, @ptrToInt(lpSubKey.ptr)),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var attributes: ULONG = OBJ_CASE_INSENSITIVE;
|
|
||||||
if (opts.ulOptions & REG_OPTION_OPEN_LINK != 0) {
|
|
||||||
attributes |= OBJ_OPENLINK;
|
|
||||||
}
|
|
||||||
|
|
||||||
var attr = OBJECT_ATTRIBUTES{
|
|
||||||
.Length = @sizeOf(OBJECT_ATTRIBUTES),
|
|
||||||
.RootDirectory = key_handle,
|
|
||||||
.Attributes = attributes,
|
|
||||||
.ObjectName = &subkey_string,
|
|
||||||
.SecurityDescriptor = null,
|
|
||||||
.SecurityQualityOfService = null,
|
|
||||||
};
|
|
||||||
|
|
||||||
var result: HKEY = undefined;
|
|
||||||
const rc = ntdll.NtOpenKey(
|
|
||||||
&result,
|
|
||||||
opts.samDesired,
|
|
||||||
attr,
|
|
||||||
);
|
|
||||||
switch (rc) {
|
|
||||||
.SUCCESS => return result,
|
|
||||||
else => return unexpectedStatus(rc),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn RegCloseKey(hkey: HKEY) void {
|
|
||||||
if (IsPredefKey(hkey)) return;
|
|
||||||
assert(ntdll.NtClose(hkey) == .SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern var DefaultHandleHKUDisabled: BOOLEAN;
|
|
||||||
extern var DefaultHandlesDisabled: BOOLEAN;
|
|
||||||
extern var DefaultHandleTable: [MAX_DEFAULT_HANDLES]?HANDLE;
|
|
||||||
|
|
||||||
fn MapDefaultKey(key: HKEY) !HANDLE {
|
|
||||||
if (!IsPredefKey(key)) return @intToPtr(HANDLE, @ptrToInt(key) & ~@as(usize, 0x1));
|
|
||||||
|
|
||||||
const index = GetPredefKeyIndex(key);
|
|
||||||
if (index >= MAX_DEFAULT_HANDLES) {
|
|
||||||
return error.InvalidParameter;
|
|
||||||
}
|
|
||||||
|
|
||||||
const def_disabled = if (key == HKEY_LOCAL_MACHINE) DefaultHandleHKUDisabled else DefaultHandlesDisabled;
|
|
||||||
|
|
||||||
var handle: HANDLE = undefined;
|
|
||||||
var do_open: bool = true;
|
|
||||||
|
|
||||||
if (def_disabled != 0) {
|
|
||||||
const tmp = DefaultHandleTable[index];
|
|
||||||
if (tmp) |h| {
|
|
||||||
do_open = false;
|
|
||||||
handle = h;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (do_open) {
|
|
||||||
handle = try OpenPredefinedKey(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (def_disabled == 0) {
|
|
||||||
handle = @intToPtr(HANDLE, @ptrToInt(handle) | 0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn OpenPredefinedKey(index: usize) !HANDLE {
|
|
||||||
switch (index) {
|
|
||||||
0 => {
|
|
||||||
// HKEY_CLASSES_ROOT
|
|
||||||
return error.Unimplemented;
|
|
||||||
},
|
|
||||||
1 => {
|
|
||||||
// HKEY_CURRENT_USER
|
|
||||||
return error.Unimplemented;
|
|
||||||
},
|
|
||||||
2 => {
|
|
||||||
// HKEY_LOCAL_MACHINE
|
|
||||||
return OpenLocalMachineKey();
|
|
||||||
},
|
|
||||||
3 => {
|
|
||||||
// HKEY_USERS
|
|
||||||
return error.Unimplemented;
|
|
||||||
},
|
|
||||||
5 => {
|
|
||||||
// HKEY_CURRENT_CONFIG
|
|
||||||
return error.Unimplemented;
|
|
||||||
},
|
|
||||||
6 => {
|
|
||||||
// HKEY_DYN_DATA
|
|
||||||
return error.Unimplemented;
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
return error.InvalidParameter;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn OpenLocalMachineKey() !HANDLE {
|
|
||||||
const path = "\\Registry\\Machine";
|
|
||||||
var path_u16: [REG_MAX_NAME_SIZE]u16 = undefined;
|
|
||||||
const path_len_u16 = try std.unicode.utf8ToUtf16Le(&path_u16, path);
|
|
||||||
const path_len_bytes = @intCast(u16, path_len_u16 * 2);
|
|
||||||
|
|
||||||
var key_name = UNICODE_STRING{
|
|
||||||
.Length = path_len_bytes,
|
|
||||||
.MaximumLength = path_len_bytes,
|
|
||||||
.Buffer = @intToPtr([*]u16, @ptrToInt(&path_u16)),
|
|
||||||
};
|
|
||||||
|
|
||||||
var attr = OBJECT_ATTRIBUTES{
|
|
||||||
.Length = @sizeOf(OBJECT_ATTRIBUTES),
|
|
||||||
.RootDirectory = null,
|
|
||||||
.Attributes = OBJ_CASE_INSENSITIVE,
|
|
||||||
.ObjectName = &key_name,
|
|
||||||
.SecurityDescriptor = null,
|
|
||||||
.SecurityQualityOfService = null,
|
|
||||||
};
|
|
||||||
|
|
||||||
var result: HKEY = undefined;
|
|
||||||
const rc = ntdll.NtOpenKey(
|
|
||||||
&result,
|
|
||||||
MAXIMUM_ALLOWED,
|
|
||||||
attr,
|
|
||||||
);
|
|
||||||
switch (rc) {
|
|
||||||
.SUCCESS => return result,
|
|
||||||
else => return unexpectedStatus(rc),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ const DWORD = windows.DWORD;
|
|||||||
const FILE_INFO_BY_HANDLE_CLASS = windows.FILE_INFO_BY_HANDLE_CLASS;
|
const FILE_INFO_BY_HANDLE_CLASS = windows.FILE_INFO_BY_HANDLE_CLASS;
|
||||||
const HANDLE = windows.HANDLE;
|
const HANDLE = windows.HANDLE;
|
||||||
const HMODULE = windows.HMODULE;
|
const HMODULE = windows.HMODULE;
|
||||||
|
const HKEY = windows.HKEY;
|
||||||
const HRESULT = windows.HRESULT;
|
const HRESULT = windows.HRESULT;
|
||||||
const LARGE_INTEGER = windows.LARGE_INTEGER;
|
const LARGE_INTEGER = windows.LARGE_INTEGER;
|
||||||
const LPCWSTR = windows.LPCWSTR;
|
const LPCWSTR = windows.LPCWSTR;
|
||||||
@ -57,6 +58,8 @@ const UCHAR = windows.UCHAR;
|
|||||||
const FARPROC = windows.FARPROC;
|
const FARPROC = windows.FARPROC;
|
||||||
const INIT_ONCE_FN = windows.INIT_ONCE_FN;
|
const INIT_ONCE_FN = windows.INIT_ONCE_FN;
|
||||||
const PMEMORY_BASIC_INFORMATION = windows.PMEMORY_BASIC_INFORMATION;
|
const PMEMORY_BASIC_INFORMATION = windows.PMEMORY_BASIC_INFORMATION;
|
||||||
|
const REGSAM = windows.REGSAM;
|
||||||
|
const LSTATUS = windows.LSTATUS;
|
||||||
|
|
||||||
pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(WINAPI) ?*anyopaque;
|
pub extern "kernel32" fn AddVectoredExceptionHandler(First: c_ulong, Handler: ?VECTORED_EXCEPTION_HANDLER) callconv(WINAPI) ?*anyopaque;
|
||||||
pub extern "kernel32" fn RemoveVectoredExceptionHandler(Handle: HANDLE) callconv(WINAPI) c_ulong;
|
pub extern "kernel32" fn RemoveVectoredExceptionHandler(Handle: HANDLE) callconv(WINAPI) c_ulong;
|
||||||
@ -412,3 +415,11 @@ pub extern "kernel32" fn SleepConditionVariableSRW(
|
|||||||
pub extern "kernel32" fn TryAcquireSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) BOOLEAN;
|
pub extern "kernel32" fn TryAcquireSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) BOOLEAN;
|
||||||
pub extern "kernel32" fn AcquireSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) void;
|
pub extern "kernel32" fn AcquireSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) void;
|
||||||
pub extern "kernel32" fn ReleaseSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) void;
|
pub extern "kernel32" fn ReleaseSRWLockExclusive(s: *SRWLOCK) callconv(WINAPI) void;
|
||||||
|
|
||||||
|
pub extern "kernel32" fn RegOpenKeyExW(
|
||||||
|
hkey: HKEY,
|
||||||
|
lpSubKey: LPCWSTR,
|
||||||
|
ulOptions: DWORD,
|
||||||
|
samDesired: REGSAM,
|
||||||
|
phkResult: *HANDLE,
|
||||||
|
) callconv(WINAPI) LSTATUS;
|
||||||
|
|||||||
@ -22,6 +22,8 @@ const RTL_OSVERSIONINFOW = windows.RTL_OSVERSIONINFOW;
|
|||||||
const FILE_BASIC_INFORMATION = windows.FILE_BASIC_INFORMATION;
|
const FILE_BASIC_INFORMATION = windows.FILE_BASIC_INFORMATION;
|
||||||
const SIZE_T = windows.SIZE_T;
|
const SIZE_T = windows.SIZE_T;
|
||||||
const CURDIR = windows.CURDIR;
|
const CURDIR = windows.CURDIR;
|
||||||
|
const PCWSTR = windows.PCWSTR;
|
||||||
|
const RTL_QUERY_REGISTRY_TABLE = windows.RTL_QUERY_REGISTRY_TABLE;
|
||||||
|
|
||||||
pub const THREADINFOCLASS = enum(c_int) {
|
pub const THREADINFOCLASS = enum(c_int) {
|
||||||
ThreadBasicInformation,
|
ThreadBasicInformation,
|
||||||
@ -259,3 +261,11 @@ pub extern "ntdll" fn NtOpenKey(
|
|||||||
DesiredAccess: ACCESS_MASK,
|
DesiredAccess: ACCESS_MASK,
|
||||||
ObjectAttributes: OBJECT_ATTRIBUTES,
|
ObjectAttributes: OBJECT_ATTRIBUTES,
|
||||||
) callconv(WINAPI) NTSTATUS;
|
) callconv(WINAPI) NTSTATUS;
|
||||||
|
|
||||||
|
pub extern "ntdll" fn RtlQueryRegistryValues(
|
||||||
|
RelativeTo: ULONG,
|
||||||
|
Path: PCWSTR,
|
||||||
|
QueryTable: [*]RTL_QUERY_REGISTRY_TABLE,
|
||||||
|
Context: ?*anyopaque,
|
||||||
|
Environment: ?*anyopaque,
|
||||||
|
) callconv(WINAPI) NTSTATUS;
|
||||||
|
|||||||
@ -43,13 +43,124 @@ pub fn detectRuntimeVersion() WindowsVersion {
|
|||||||
return @intToEnum(WindowsVersion, version);
|
return @intToEnum(WindowsVersion, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn detectCpuModelArm64() !*const Target.Cpu.Model {
|
||||||
|
// Pull the CPU identifier from the registry.
|
||||||
|
// Assume max number of cores to be at 128.
|
||||||
|
const max_cpu_count = 128;
|
||||||
|
const cpu_count = getCpuCount();
|
||||||
|
|
||||||
|
if (cpu_count > max_cpu_count) return error.TooManyCpus;
|
||||||
|
|
||||||
|
const table_size = max_cpu_count * 3 + 1;
|
||||||
|
const actual_table_size = cpu_count * 3 + 1;
|
||||||
|
var table: [table_size]std.os.windows.RTL_QUERY_REGISTRY_TABLE = undefined;
|
||||||
|
|
||||||
|
// Table sentinel
|
||||||
|
table[actual_table_size - 1] = .{
|
||||||
|
.QueryRoutine = null,
|
||||||
|
.Flags = 0,
|
||||||
|
.Name = null,
|
||||||
|
.EntryContext = null,
|
||||||
|
.DefaultType = 0,
|
||||||
|
.DefaultData = null,
|
||||||
|
.DefaultLength = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 key_name = std.unicode.utf8ToUtf16LeStringLiteral("Identifier");
|
||||||
|
|
||||||
|
var i: usize = 0;
|
||||||
|
var index: usize = 0;
|
||||||
|
while (i < cpu_count) : (i += 1) {
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
|
var next_cpu_buf: [std.math.log2(max_cpu_count)]u8 = undefined;
|
||||||
|
const next_cpu = try std.fmt.bufPrint(&next_cpu_buf, "{d}", .{i});
|
||||||
|
|
||||||
|
var subkey: [std.math.log2(max_cpu_count) / 2]u16 = undefined;
|
||||||
|
const subkey_len = try std.unicode.utf8ToUtf16Le(&subkey, next_cpu);
|
||||||
|
subkey[subkey_len] = 0;
|
||||||
|
|
||||||
|
table[index] = .{
|
||||||
|
.QueryRoutine = null,
|
||||||
|
.Flags = std.os.windows.RTL_QUERY_REGISTRY_SUBKEY | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED,
|
||||||
|
.Name = subkey[0..subkey_len :0],
|
||||||
|
.EntryContext = null,
|
||||||
|
.DefaultType = std.os.windows.REG_NONE,
|
||||||
|
.DefaultData = null,
|
||||||
|
.DefaultLength = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
table[index + 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 = &buf_uni,
|
||||||
|
.DefaultType = std.os.windows.REG_NONE,
|
||||||
|
.DefaultData = null,
|
||||||
|
.DefaultLength = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
table[index + 2] = .{
|
||||||
|
.QueryRoutine = null,
|
||||||
|
.Flags = std.os.windows.RTL_QUERY_REGISTRY_TOPKEY,
|
||||||
|
.Name = null,
|
||||||
|
.EntryContext = null,
|
||||||
|
.DefaultType = std.os.windows.REG_NONE,
|
||||||
|
.DefaultData = null,
|
||||||
|
.DefaultLength = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
index += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
const topkey = std.unicode.utf8ToUtf16LeStringLiteral("\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor");
|
||||||
|
const res = std.os.windows.ntdll.RtlQueryRegistryValues(
|
||||||
|
std.os.windows.RTL_REGISTRY_ABSOLUTE,
|
||||||
|
topkey,
|
||||||
|
&table,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
switch (res) {
|
||||||
|
.SUCCESS => {},
|
||||||
|
else => return error.QueryRegistryFailed,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the models from strings
|
||||||
|
i = 0;
|
||||||
|
index = 0;
|
||||||
|
while (i < cpu_count) : (i += 1) {
|
||||||
|
const entry = @ptrCast(*align(1) const std.os.windows.UNICODE_STRING, table[index + 1].EntryContext);
|
||||||
|
index += 3;
|
||||||
|
|
||||||
|
var identifier_buf: [max_sz_value * 2]u8 = undefined;
|
||||||
|
const len = try std.unicode.utf16leToUtf8(&identifier_buf, entry.Buffer[0 .. entry.Length / 2]);
|
||||||
|
const identifier = identifier_buf[0..len];
|
||||||
|
_ = identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Target.aarch64.cpu.microsoft_sq3;
|
||||||
|
}
|
||||||
|
|
||||||
fn detectNativeCpuAndFeaturesArm64() Target.Cpu {
|
fn detectNativeCpuAndFeaturesArm64() Target.Cpu {
|
||||||
const Feature = Target.aarch64.Feature;
|
const Feature = Target.aarch64.Feature;
|
||||||
|
|
||||||
|
const model = detectCpuModelArm64() catch Target.Cpu.Model.generic(.aarch64);
|
||||||
|
|
||||||
var cpu = Target.Cpu{
|
var cpu = Target.Cpu{
|
||||||
.arch = .aarch64,
|
.arch = .aarch64,
|
||||||
.model = Target.Cpu.Model.generic(.aarch64),
|
.model = model,
|
||||||
.features = Target.Cpu.Feature.Set.empty,
|
.features = model.features,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (IsProcessorFeaturePresent(PF.ARM_NEON_INSTRUCTIONS_AVAILABLE)) {
|
if (IsProcessorFeaturePresent(PF.ARM_NEON_INSTRUCTIONS_AVAILABLE)) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user