1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00

windows/arm64: Implement fallback OS version detection

This commit is contained in:
kd-11 2024-09-08 00:46:12 +00:00 committed by kd-11
parent 31ce32709e
commit d19d0cb70d

View File

@ -68,14 +68,76 @@ namespace Darwin_ProcessInfo
} }
#endif #endif
#if defined(ARCH_ARM64) && defined (_WIN32) && !defined(_MSC_VER) namespace utils
static inline u64 __readx18qword(int offset)
{ {
u64* peb = nullptr; #ifdef _WIN32
__asm__ volatile("mov %0, x18" : "=r"(peb)); // Alternative way to read OS version using the registry.
return peb[offset]; static std::string get_fallback_windows_version()
} {
// Some helpers for sanity
const auto read_reg_dword = [](HKEY hKey, std::string_view value_name) -> std::pair<bool, DWORD>
{
DWORD val;
DWORD len = sizeof(val);
if (ERROR_SUCCESS != RegQueryValueExA(hKey, value_name.data(), nullptr, nullptr, reinterpret_cast<LPBYTE>(&val), &len))
{
return { false, 0 };
}
return { true, val };
};
const auto read_reg_sz = [](HKEY hKey, std::string_view value_name) -> std::pair<bool, std::string>
{
char sz[256];
DWORD sz_len = sizeof(sz);
if (ERROR_SUCCESS != RegQueryValueExA(hKey, value_name.data(), nullptr, nullptr, reinterpret_cast<LPBYTE>(sz), &sz_len))
{
return { false, "" };
}
if (sz_len < sizeof(sz))
{
// Safety, force null terminator
sz[sz_len] = 0;
}
return { true, sz };
};
HKEY hKey;
if (ERROR_SUCCESS != RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &hKey))
{
return "Unknown Windows";
}
// Read ProductName (string), CurrentMajorVersionNumber (dword), CurrentMinorVersionNumber (dword) and CurrentBuildNumber (string) as well as CurrentVersion (string)
const auto [product_valid, product_name] = read_reg_sz(hKey, "ProductName");
if (!product_valid)
{
return "Unknown Windows";
}
const auto [check_major, version_major] = read_reg_dword(hKey, "CurrentMajorVersionNumber");
const auto [check_minor, version_minor] = read_reg_dword(hKey, "CurrentMinorVersionNumber");
const auto [check_build_no, build_no] = read_reg_sz(hKey, "CurrentBuildNumber");
const auto [check_nt_ver, nt_ver] = read_reg_sz(hKey, "CurrentVersion");
// Close the registry key
RegCloseKey(hKey);
std::string version_id = "Unknown";
if (check_major && check_minor && check_build_no)
{
version_id = fmt::format("%u.%u.%s", version_major, version_minor, build_no);
if (check_nt_ver)
{
version_id += " NT" + nt_ver;
}
}
return fmt::format("Operating system: %s, Version %s", product_name, version_id);
}
#endif #endif
}
bool utils::has_ssse3() bool utils::has_ssse3()
{ {
@ -590,14 +652,9 @@ std::string utils::get_OS_version()
#ifdef _WIN32 #ifdef _WIN32
// GetVersionEx is deprecated, RtlGetVersion is kernel-mode only and AnalyticsInfo is UWP only. // GetVersionEx is deprecated, RtlGetVersion is kernel-mode only and AnalyticsInfo is UWP only.
// So we're forced to read PEB instead to get Windows version info. It's ugly but works. // So we're forced to read PEB instead to get Windows version info. It's ugly but works.
const DWORD peb_offset = 0x60;
#if defined(ARCH_X64) #if defined(ARCH_X64)
const DWORD peb_offset = 0x60;
const INT_PTR peb = __readgsqword(peb_offset); const INT_PTR peb = __readgsqword(peb_offset);
#elif defined(_M_ARM64)
const INT_PTR peb = __readx18qword(peb_offset);
#endif
const DWORD version_major = *reinterpret_cast<const DWORD*>(peb + 0x118); const DWORD version_major = *reinterpret_cast<const DWORD*>(peb + 0x118);
const DWORD version_minor = *reinterpret_cast<const DWORD*>(peb + 0x11c); const DWORD version_minor = *reinterpret_cast<const DWORD*>(peb + 0x11c);
const WORD build = *reinterpret_cast<const WORD*>(peb + 0x120); const WORD build = *reinterpret_cast<const WORD*>(peb + 0x120);
@ -615,6 +672,11 @@ std::string utils::get_OS_version()
fmt::append(output, fmt::append(output,
"Operating system: Windows, Major: %lu, Minor: %lu, Build: %u, Service Pack: %s, Compatibility mode: %llu", "Operating system: Windows, Major: %lu, Minor: %lu, Build: %u, Service Pack: %s, Compatibility mode: %llu",
version_major, version_minor, build, has_sp ? holder.data() : "none", compatibility_mode); version_major, version_minor, build, has_sp ? holder.data() : "none", compatibility_mode);
#else
// PEB cannot be easily accessed on ARM64, fall back to registry
static const auto s_windows_version = utils::get_fallback_windows_version();
return s_windows_version;
#endif
#elif defined (__APPLE__) #elif defined (__APPLE__)
const int major_version = Darwin_Version::getNSmajorVersion(); const int major_version = Darwin_Version::getNSmajorVersion();
const int minor_version = Darwin_Version::getNSminorVersion(); const int minor_version = Darwin_Version::getNSminorVersion();