|
#include <stdio.h> |
|
#include <stdint.h> |
|
#include <stdlib.h> |
|
#include <errno.h> |
|
|
|
#include <cpuinfo.h> |
|
#include <cpuinfo/internal-api.h> |
|
#include <cpuinfo/log.h> |
|
|
|
#include "windows-arm-init.h" |
|
|
|
|
|
#define MAX_WOA_VALID_EFFICIENCY_CLASSES 2 |
|
|
|
struct cpuinfo_arm_isa cpuinfo_isa; |
|
|
|
static void set_cpuinfo_isa_fields(void); |
|
static bool get_system_info_from_registry( |
|
struct woa_chip_info** chip_info); |
|
|
|
static struct woa_chip_info woa_chip_unknown = { |
|
L"Unknown", |
|
woa_chip_name_unknown, |
|
{ |
|
{ |
|
cpuinfo_vendor_unknown, |
|
cpuinfo_uarch_unknown, |
|
0 |
|
} |
|
} |
|
}; |
|
|
|
|
|
static struct woa_chip_info woa_chips[] = { |
|
|
|
{ |
|
L"Microsoft SQ1", |
|
woa_chip_name_microsoft_sq_1, |
|
{ |
|
{ |
|
cpuinfo_vendor_arm, |
|
cpuinfo_uarch_cortex_a55, |
|
1800000000, |
|
}, |
|
{ |
|
cpuinfo_vendor_arm, |
|
cpuinfo_uarch_cortex_a76, |
|
3000000000, |
|
} |
|
} |
|
}, |
|
|
|
{ |
|
L"Microsoft SQ2", |
|
woa_chip_name_microsoft_sq_2, |
|
{ |
|
{ |
|
cpuinfo_vendor_arm, |
|
cpuinfo_uarch_cortex_a55, |
|
2420000000, |
|
}, |
|
{ |
|
cpuinfo_vendor_arm, |
|
cpuinfo_uarch_cortex_a76, |
|
3150000000 |
|
} |
|
} |
|
}, |
|
|
|
{ |
|
L"Snapdragon (TM) 8cx Gen 3 @ 3.0 GHz", |
|
woa_chip_name_microsoft_sq_3, |
|
{ |
|
{ |
|
cpuinfo_vendor_arm, |
|
cpuinfo_uarch_cortex_a78, |
|
2420000000, |
|
}, |
|
{ |
|
cpuinfo_vendor_arm, |
|
cpuinfo_uarch_cortex_x1, |
|
3000000000 |
|
} |
|
} |
|
}, |
|
|
|
{ |
|
L"Ampere(R) Altra(R) Processor", |
|
woa_chip_name_ampere_altra, |
|
{ |
|
{ |
|
cpuinfo_vendor_arm, |
|
cpuinfo_uarch_neoverse_n1, |
|
3000000000 |
|
} |
|
} |
|
} |
|
}; |
|
|
|
BOOL CALLBACK cpuinfo_arm_windows_init( |
|
PINIT_ONCE init_once, PVOID parameter, PVOID* context) |
|
{ |
|
struct woa_chip_info *chip_info = NULL; |
|
enum cpuinfo_vendor vendor = cpuinfo_vendor_unknown; |
|
|
|
set_cpuinfo_isa_fields(); |
|
|
|
const bool system_result = get_system_info_from_registry(&chip_info); |
|
if (!system_result) { |
|
chip_info = &woa_chip_unknown; |
|
} |
|
|
|
cpuinfo_is_initialized = cpu_info_init_by_logical_sys_info(chip_info, chip_info->uarchs[0].vendor); |
|
|
|
return (system_result && cpuinfo_is_initialized ? TRUE : FALSE); |
|
} |
|
|
|
bool get_core_uarch_for_efficiency( |
|
enum woa_chip_name chip, BYTE EfficiencyClass, |
|
enum cpuinfo_uarch* uarch, uint64_t* frequency) |
|
{ |
|
|
|
|
|
|
|
|
|
if (uarch && frequency && chip < woa_chip_name_last && |
|
EfficiencyClass < MAX_WOA_VALID_EFFICIENCY_CLASSES) { |
|
*uarch = woa_chips[chip].uarchs[EfficiencyClass].uarch; |
|
*frequency = woa_chips[chip].uarchs[EfficiencyClass].frequency; |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
|
|
|
|
static bool read_registry( |
|
LPCWSTR subkey, |
|
LPCWSTR value, |
|
char** text_buffer) |
|
{ |
|
DWORD key_type = 0; |
|
DWORD data_size = 0; |
|
const DWORD flags = RRF_RT_REG_SZ; |
|
LSTATUS result = 0; |
|
HANDLE heap = GetProcessHeap(); |
|
|
|
result = RegGetValueW( |
|
HKEY_LOCAL_MACHINE, |
|
subkey, |
|
value, |
|
flags, |
|
&key_type, |
|
NULL, |
|
&data_size); |
|
if (result != 0 || data_size == 0) { |
|
cpuinfo_log_error("Registry entry size read error"); |
|
return false; |
|
} |
|
|
|
if (*text_buffer) { |
|
HeapFree(heap, 0, *text_buffer); |
|
} |
|
*text_buffer = HeapAlloc(heap, HEAP_ZERO_MEMORY, data_size * sizeof(wchar_t)); |
|
if (*text_buffer == NULL) { |
|
cpuinfo_log_error("Registry textbuffer allocation error"); |
|
return false; |
|
} |
|
|
|
result = RegGetValueW( |
|
HKEY_LOCAL_MACHINE, |
|
subkey, |
|
value, |
|
flags, |
|
NULL, |
|
*text_buffer, |
|
&data_size); |
|
if (result != 0) { |
|
cpuinfo_log_error("Registry read error"); |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
static bool get_system_info_from_registry( |
|
struct woa_chip_info** chip_info) |
|
{ |
|
bool result = false; |
|
char* text_buffer = NULL; |
|
LPCWSTR cpu0_subkey = L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"; |
|
LPCWSTR chip_name_value = L"ProcessorNameString"; |
|
|
|
*chip_info = NULL; |
|
HANDLE heap = GetProcessHeap(); |
|
|
|
|
|
if (!read_registry(cpu0_subkey, chip_name_value, &text_buffer)) { |
|
cpuinfo_log_error("Registry read error"); |
|
goto cleanup; |
|
} |
|
for (uint32_t i = 0; i < (uint32_t) woa_chip_name_last; i++) { |
|
size_t compare_length = wcsnlen(woa_chips[i].chip_name_string, CPUINFO_PACKAGE_NAME_MAX); |
|
int compare_result = wcsncmp(text_buffer, woa_chips[i].chip_name_string, compare_length); |
|
if (compare_result == 0) { |
|
*chip_info = woa_chips+i; |
|
break; |
|
} |
|
} |
|
if (*chip_info == NULL) { |
|
|
|
cpuinfo_log_error("Unknown chip model name '%ls'.\nPlease add new Windows on Arm SoC/chip support to arm/windows/init.c!", text_buffer); |
|
goto cleanup; |
|
} |
|
cpuinfo_log_debug("detected chip model name: %s", (**chip_info).chip_name_string); |
|
|
|
cleanup: |
|
HeapFree(heap, 0, text_buffer); |
|
text_buffer = NULL; |
|
return result; |
|
} |
|
|
|
static void set_cpuinfo_isa_fields(void) |
|
{ |
|
bool armv8 = IsProcessorFeaturePresent(PF_ARM_V8_INSTRUCTIONS_AVAILABLE); |
|
bool crypto = IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE); |
|
bool load_store_atomic = IsProcessorFeaturePresent(PF_ARM_64BIT_LOADSTORE_ATOMIC); |
|
bool float_multiply_accumulate = IsProcessorFeaturePresent(PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE); |
|
bool crc32 = IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE); |
|
bool float_emulated = IsProcessorFeaturePresent(PF_FLOATING_POINT_EMULATED); |
|
|
|
|
|
|
|
|
|
#if CPUINFO_LOG_DEBUG_PARSERS |
|
bool divide = IsProcessorFeaturePresent(PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE); |
|
bool ext_cache = IsProcessorFeaturePresent(PF_ARM_EXTERNAL_CACHE_AVAILABLE); |
|
bool vfp_registers = IsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE); |
|
bool arm_v81 = IsProcessorFeaturePresent(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE); |
|
|
|
cpuinfo_log_debug("divide present: %d", divide); |
|
cpuinfo_log_debug("ext_cache present: %d", ext_cache); |
|
cpuinfo_log_debug("vfp_registers present: %d", vfp_registers); |
|
cpuinfo_log_debug("arm_v81 present: %d", arm_v81); |
|
#endif |
|
|
|
cpuinfo_log_debug("armv8 present: %d", armv8); |
|
cpuinfo_log_debug("crypto present: %d", crypto); |
|
cpuinfo_log_debug("load_store_atomic present: %d", load_store_atomic); |
|
cpuinfo_log_debug("float_multiply_accumulate present: %d", float_multiply_accumulate); |
|
cpuinfo_log_debug("crc32 present: %d", crc32); |
|
cpuinfo_log_debug("float_emulated: %d", float_emulated); |
|
|
|
#if CPUINFO_ARCH_ARM |
|
cpuinfo_isa.armv8 = armv8; |
|
#endif |
|
#if CPUINFO_ARCH_ARM64 |
|
cpuinfo_isa.atomics = load_store_atomic; |
|
#endif |
|
cpuinfo_isa.crc32 = crc32; |
|
|
|
cpuinfo_isa.aes = crypto; |
|
cpuinfo_isa.sha1 = crypto; |
|
cpuinfo_isa.sha2 = crypto; |
|
cpuinfo_isa.pmull = crypto; |
|
cpuinfo_isa.fp16arith = !float_emulated && float_multiply_accumulate; |
|
} |
|
|