aboutsummaryrefslogtreecommitdiff
path: root/src/arm/windows/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/arm/windows/init.c')
-rw-r--r--src/arm/windows/init.c253
1 files changed, 253 insertions, 0 deletions
diff --git a/src/arm/windows/init.c b/src/arm/windows/init.c
new file mode 100644
index 0000000..8effc15
--- /dev/null
+++ b/src/arm/windows/init.c
@@ -0,0 +1,253 @@
+#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"
+
+/* Efficiency class = 0 means little core, while 1 means big core for now */
+#define MAX_WOA_VALID_EFFICIENCY_CLASSES 2
+#define VENDOR_NAME_MAX CPUINFO_PACKAGE_NAME_MAX
+
+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,
+ enum cpuinfo_vendor* vendor);
+
+struct vendor_info {
+ char vendor_name[VENDOR_NAME_MAX];
+ enum cpuinfo_vendor vendor;
+};
+
+/* Please add new vendor here! */
+static struct vendor_info vendors[] = {
+ {
+ "Qualcomm",
+ cpuinfo_vendor_qualcomm
+ }
+};
+
+/* Please add new SoC/chip info here! */
+static struct woa_chip_info woa_chips[] = {
+ /* Microsoft SQ1 Kryo 495 4 + 4 cores (3 GHz + 1.80 GHz) */
+ {
+ "Microsoft SQ1",
+ woa_chip_name_microsoft_sq_1,
+ {
+ {
+ cpuinfo_uarch_cortex_a55,
+ 1800000000,
+ },
+ {
+ cpuinfo_uarch_cortex_a76,
+ 3000000000,
+ }
+ }
+ },
+ /* Microsoft SQ2 Kryo 495 4 + 4 cores (3.15 GHz + 2.42 GHz) */
+ {
+ "Microsoft SQ2",
+ woa_chip_name_microsoft_sq_2,
+ {
+ {
+ cpuinfo_uarch_cortex_a55,
+ 2420000000,
+ },
+ {
+ cpuinfo_uarch_cortex_a76,
+ 3150000000
+ }
+ }
+ }
+};
+
+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;
+ bool result = false;
+
+ set_cpuinfo_isa_fields();
+ result = get_system_info_from_registry(&chip_info, &vendor);
+ result &= cpu_info_init_by_logical_sys_info(chip_info, vendor);
+ cpuinfo_is_initialized = result;
+ return ((result == true) ? TRUE : FALSE);
+}
+
+bool get_core_uarch_for_efficiency(
+ enum woa_chip_name chip, BYTE EfficiencyClass,
+ enum cpuinfo_uarch* uarch, uint64_t* frequency)
+{
+ /* For currently supported WoA chips, the Efficiency class selects
+ * the pre-defined little and big core.
+ * Any further supported SoC's logic should be implemented here.
+ */
+ 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 helper functions */
+
+static bool read_registry(
+ LPCTSTR subkey,
+ LPCTSTR value,
+ char** textBuffer)
+{
+ DWORD keyType = 0;
+ DWORD dataSize = 0;
+ const DWORD flags = RRF_RT_REG_SZ; /* Only read strings (REG_SZ) */
+ LSTATUS result = 0;
+ HANDLE heap = GetProcessHeap();
+
+ result = RegGetValue(
+ HKEY_LOCAL_MACHINE,
+ subkey,
+ value,
+ flags,
+ &keyType,
+ NULL, /* Request buffer size */
+ &dataSize);
+ if (result != 0 || dataSize == 0) {
+ cpuinfo_log_error("Registry entry size read error");
+ return false;
+ }
+
+ if (*textBuffer) {
+ HeapFree(heap, 0, *textBuffer);
+ }
+ *textBuffer = HeapAlloc(heap, HEAP_ZERO_MEMORY, dataSize);
+ if (*textBuffer == NULL) {
+ cpuinfo_log_error("Registry textbuffer allocation error");
+ return false;
+ }
+
+ result = RegGetValue(
+ HKEY_LOCAL_MACHINE,
+ subkey,
+ value,
+ flags,
+ NULL,
+ *textBuffer, /* Write string in this destination buffer */
+ &dataSize);
+ 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,
+ enum cpuinfo_vendor* vendor)
+{
+ bool result = false;
+ char* textBuffer = NULL;
+ LPCTSTR cpu0_subkey =
+ (LPCTSTR)"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
+ LPCTSTR chip_name_value = (LPCTSTR)"ProcessorNameString";
+ LPCTSTR vendor_name_value = (LPCTSTR)"VendorIdentifier";
+
+ *chip_info = NULL;
+ *vendor = cpuinfo_vendor_unknown;
+ HANDLE heap = GetProcessHeap();
+
+ /* 1. Read processor model name from registry and find in the hard-coded list. */
+ if (!read_registry(cpu0_subkey, chip_name_value, &textBuffer)) {
+ 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 = strnlen(woa_chips[i].chip_name_string, CPUINFO_PACKAGE_NAME_MAX);
+ int compare_result = strncmp(textBuffer, 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.\n Please add new Windows on Arm SoC/chip support!");
+ goto cleanup;
+ }
+ cpuinfo_log_debug("detected chip model name: %s", (**chip_info).chip_name_string);
+
+ /* 2. Read vendor/manufacturer name from registry. */
+ if (!read_registry(cpu0_subkey, vendor_name_value, &textBuffer)) {
+ cpuinfo_log_error("Registry read error");
+ goto cleanup;
+ }
+
+ for (uint32_t i = 0; i < (sizeof(vendors) / sizeof(struct vendor_info)); i++) {
+ if (strncmp(textBuffer, vendors[i].vendor_name,
+ strlen(vendors[i].vendor_name)) == 0) {
+ *vendor = vendors[i].vendor;
+ result = true;
+ break;
+ }
+ }
+ if (*vendor == cpuinfo_vendor_unknown) {
+ cpuinfo_log_error("Unexpected vendor: %s", textBuffer);
+ }
+
+cleanup:
+ HeapFree(heap, 0, textBuffer);
+ textBuffer = 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);
+
+ /* Read all Arm related Windows features for debug purposes, even if we can't
+ * pair Arm ISA feature to that now.
+ */
+#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;
+ /* Windows API reports all or nothing for cryptographic instructions. */
+ cpuinfo_isa.aes = crypto;
+ cpuinfo_isa.sha1 = crypto;
+ cpuinfo_isa.sha2 = crypto;
+ cpuinfo_isa.pmull = crypto;
+ cpuinfo_isa.fp16arith = !float_emulated && float_multiply_accumulate;
+}