/*
 * Copyright 2024  Veselin Georgiev,
 * anrieffNOSPAM @ mgail_DOT.com (convert to gmail)
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <inttypes.h>
#include "libcpuid.h"
#include "libcpuid_util.h"
#include "libcpuid_internal.h"
#include "recog_arm.h"


struct arm_feature_field_t {
	uint32_t *aarch32_reg;
	uint64_t *aarch64_reg;
	uint8_t highbit, lowbit;
	uint8_t value;
};

#define MAX_IDENTIFY_FIELDS 6
struct arm_feature_map_t {
	cpu_feature_level_t ver_optional, ver_mandatory;
	struct arm_feature_field_t fields[MAX_IDENTIFY_FIELDS];
};

struct arm_arch_feature_t {
	uint8_t optional, mandatory;
};

struct arm_arch_extension_t {
	struct arm_arch_feature_t present[NUM_FEATURE_LEVELS], total[NUM_FEATURE_LEVELS];
};

struct arm_id_part {
	const int id;
	const char* name;
	const char* codename;
	const char* technology;
};

struct arm_hw_impl {
	const int32_t id;
	const cpu_vendor_t vendor;
	const struct arm_id_part *parts;
	const char *name;
};

/* Decoded PartNum for all implementers
   ID taken from lscpu-arm: https://github.com/util-linux/util-linux/blob/master/sys-utils/lscpu-arm.c
*/
/* Part numbers: https://en.wikichip.org/wiki/arm_holdings/cortex#Part_numbers
   Codenames: https://en.wikichip.org/wiki/arm_holdings */
static const struct arm_id_part arm_part[] = {
	{ 0x810, "ARM810",        UNKN_STR,         UNKN_STR   },
	{ 0x920, "ARM920",        UNKN_STR,         UNKN_STR   },
	{ 0x922, "ARM922",        UNKN_STR,         UNKN_STR   },
	{ 0x926, "ARM926",        UNKN_STR,         UNKN_STR   },
	{ 0x940, "ARM940",        UNKN_STR,         UNKN_STR   },
	{ 0x946, "ARM946",        UNKN_STR,         UNKN_STR   },
	{ 0x966, "ARM966",        UNKN_STR,         UNKN_STR   },
	{ 0xa20, "ARM1020",       UNKN_STR,         UNKN_STR   },
	{ 0xa22, "ARM1022",       UNKN_STR,         UNKN_STR   },
	{ 0xa26, "ARM1026",       UNKN_STR,         UNKN_STR   },
	{ 0xb02, "ARM11 MPCore",  UNKN_STR,         UNKN_STR   },
	{ 0xb36, "ARM1136",       UNKN_STR,         UNKN_STR   },
	{ 0xb56, "ARM1156",       UNKN_STR,         UNKN_STR   },
	{ 0xb76, "ARM1176",       UNKN_STR,         UNKN_STR   },
	{ 0xc05, "Cortex-A5",     "Sparrow",        "40-28 nm" },
	{ 0xc07, "Cortex-A7",     "Kingfisher",     "40-28 nm" },
	{ 0xc08, "Cortex-A8",     "Tiger",          "65-45 nm" },
	{ 0xc09, "Cortex-A9",     "Falcon",         "65-28 nm" },
	{ 0xc0d, "Cortex-A17",    "Owl",            "28 nm"    }, /* Originally A12 */
	{ 0xc0f, "Cortex-A15",    "Eagle",          "32-20 nm" },
	{ 0xc0e, "Cortex-A17",    "Owl",            "28 nm"    },
	{ 0xc14, "Cortex-R4",     UNKN_STR,         UNKN_STR   },
	{ 0xc15, "Cortex-R5",     UNKN_STR,         UNKN_STR   },
	{ 0xc17, "Cortex-R7",     UNKN_STR,         UNKN_STR   },
	{ 0xc18, "Cortex-R8",     UNKN_STR,         UNKN_STR   },
	{ 0xc20, "Cortex-M0",     "Swift",          UNKN_STR   },
	{ 0xc21, "Cortex-M1",     "Proteus",        UNKN_STR   },
	{ 0xc23, "Cortex-M3",     "Sandcat",        UNKN_STR   },
	{ 0xc24, "Cortex-M4",     "Merlin",         UNKN_STR   },
	{ 0xc27, "Cortex-M7",     "Pelican",        UNKN_STR   },
	{ 0xc60, "Cortex-M0+",    "Flycatcher",     UNKN_STR   },
	{ 0xd01, "Cortex-A32",    "Minerva",        "28 nm"    },
	{ 0xd02, "Cortex-A34",    "Metis",          UNKN_STR   },
	{ 0xd03, "Cortex-A53",    "Apollo",         "28-10 nm" },
	{ 0xd04, "Cortex-A35",    "Mercury",        "28-10 nm" },
	{ 0xd05, "Cortex-A55",    "Ananke",         "28-5 nm"  },
	{ 0xd06, "Cortex-A65",    "Helios",         UNKN_STR   },
	{ 0xd07, "Cortex-A57",    "Atlas",          "28-14 nm" },
	{ 0xd08, "Cortex-A72",    "Maia",           "28-16 nm" },
	{ 0xd09, "Cortex-A73",    "Artemis",        "28-10 nm" },
	{ 0xd0a, "Cortex-A75",    "Prometheus",     "28-10 nm" },
	{ 0xd0b, "Cortex-A76",    "Enyo",           "10-7 nm"  },
	{ 0xd0c, "Neoverse-N1",   "Ares",           "7 nm"     },
	{ 0xd0d, "Cortex-A77",    "Deimos",         "7 nm"     },
	{ 0xd0e, "Cortex-A76AE",  "Enyo-AE",        UNKN_STR   },
	{ 0xd13, "Cortex-R52",    UNKN_STR,         UNKN_STR   },
	{ 0xd15, "Cortex-R82",    UNKN_STR,         UNKN_STR   },
	{ 0xd16, "Cortex-R52+",   UNKN_STR,         UNKN_STR   },
	{ 0xd20, "Cortex-M23",    "Grebe",          UNKN_STR   },
	{ 0xd21, "Cortex-M33",    "Teal",           UNKN_STR   },
	{ 0xd22, "Cortex-M55",    "Yamin",          UNKN_STR   },
	{ 0xd23, "Cortex-M85",    UNKN_STR,         UNKN_STR   },
	{ 0xd40, "Neoverse-V1",   "Zeus",           "7 nm"     },
	{ 0xd41, "Cortex-A78",    "Hercules",       "5 nm"     },
	{ 0xd42, "Cortex-A78AE",  "Hercules-AE",    UNKN_STR   },
	{ 0xd43, "Cortex-A65AE",  "Helios-AE",      UNKN_STR   },
	{ 0xd44, "Cortex-X1",     "Hera",           "10-5 nm"  },
	{ 0xd46, "Cortex-A510",   "Klein",          "7-5 nm"   },
	{ 0xd47, "Cortex-A710",   "Matterhorn",     "7-5 nm"   },
	{ 0xd48, "Cortex-X2",     "Matterhorn ELP", UNKN_STR   },
	{ 0xd49, "Neoverse-N2",   "Perseus",        "5 nm"     },
	{ 0xd4a, "Neoverse-E1",   "Helios",         UNKN_STR   },
	{ 0xd4b, "Cortex-A78C",   "Hercules-C",     "5 nm"     },
	{ 0xd4c, "Cortex-X1C",    "Hera-C",         UNKN_STR   },
	{ 0xd4d, "Cortex-A715",   "Makalu",         "7-5 nm"   },
	{ 0xd4e, "Cortex-X3",     "Makalu ELP",     UNKN_STR   },
	{ 0xd4f, "Neoverse-V2",   "Demeter",        UNKN_STR   },
	{ 0xd80, "Cortex-A520",   "Hayes",          "3 nm"     },
	{ 0xd81, "Cortex-A720",   "Hunter",         "3 nm"     },
	{ 0xd82, "Cortex-X4",     "Hunter ELP",     UNKN_STR   },
	{ 0xd83, "Neoverse-V3AE", "Autonome",       UNKN_STR   },
	{ 0xd84, "Neoverse-V3",   "Poseidon",       UNKN_STR   },
	{ 0xd85, "Cortex-X925",   "Blackhawk",      "3 nm"     },
	{ 0xd87, "Cortex-A725",   "Chaberton",      "3 nm"     },
	{ 0xd88, "Cortex-A520AE", "Hayes-AE",       "3 nm"     },
	{ 0xd89, "Cortex-A720AE", "Hunter-AE",      "3 nm"     },
	{ 0xd8e, "Neoverse-N3",   "Hermes",         "5 nm"     },
	{ 0xd8f, "Cortex-A320",   "IoT & AI",       UNKN_STR   },
	{ -1,    UNKN_STR,        UNKN_STR,         UNKN_STR   },
};

static const struct arm_id_part brcm_part[] = {
	{ 0x0f,  "Brahma-B15", UNKN_STR, UNKN_STR },
	{ 0x100, "Brahma-B53", UNKN_STR, UNKN_STR },
	{ 0x516, "ThunderX2",  UNKN_STR, UNKN_STR },
	{ -1,    UNKN_STR,     UNKN_STR, UNKN_STR },
};

static const struct arm_id_part dec_part[] = {
	{ 0xa10, "SA110",  UNKN_STR, UNKN_STR },
	{ 0xa11, "SA1100", UNKN_STR, UNKN_STR },
	{ -1,    UNKN_STR, UNKN_STR, UNKN_STR },
};

static const struct arm_id_part cavium_part[] = {
	{ 0x0a0, "ThunderX",         UNKN_STR, UNKN_STR },
	{ 0x0a1, "ThunderX-88XX",    UNKN_STR, UNKN_STR },
	{ 0x0a2, "ThunderX-81XX",    UNKN_STR, UNKN_STR },
	{ 0x0a3, "ThunderX-83XX",    UNKN_STR, UNKN_STR },
	{ 0x0af, "ThunderX2-99xx",   UNKN_STR, UNKN_STR },
	{ 0x0b0, "OcteonTX2",        UNKN_STR, UNKN_STR },
	{ 0x0b1, "OcteonTX2-98XX",   UNKN_STR, UNKN_STR },
	{ 0x0b2, "OcteonTX2-96XX",   UNKN_STR, UNKN_STR },
	{ 0x0b3, "OcteonTX2-95XX",   UNKN_STR, UNKN_STR },
	{ 0x0b4, "OcteonTX2-95XXN",  UNKN_STR, UNKN_STR },
	{ 0x0b5, "OcteonTX2-95XXMM", UNKN_STR, UNKN_STR },
	{ 0x0b6, "OcteonTX2-95XXO",  UNKN_STR, UNKN_STR },
	{ 0x0b8, "ThunderX3-T110",   UNKN_STR, UNKN_STR },
	{ -1,    UNKN_STR,           UNKN_STR, UNKN_STR },
};

static const struct arm_id_part apm_part[] = {
	{ 0x000, "X-Gene", UNKN_STR, UNKN_STR },
	{ -1,    UNKN_STR, UNKN_STR, UNKN_STR },
};

static const struct arm_id_part qcom_part[] = {
	{ 0x001, "Oryon",           UNKN_STR, UNKN_STR   },
	{ 0x00f, "Scorpion",        UNKN_STR, "65-45 nm" },
	{ 0x02d, "Scorpion",        UNKN_STR, "65-45 nm" },
	{ 0x04d, "Krait",           UNKN_STR, "28 nm"    },
	{ 0x06f, "Krait",           UNKN_STR, "28 nm"    },
	{ 0x201, "Kryo",            UNKN_STR, "14 nm"    },
	{ 0x205, "Kryo",            UNKN_STR, "14 nm"    },
	{ 0x211, "Kryo",            UNKN_STR, "14 nm"    },
	{ 0x800, "Falkor-V1/Kryo",  UNKN_STR, UNKN_STR   },
	{ 0x801, "Kryo-V2",         UNKN_STR, "14-6 nm"  },
	{ 0x802, "Kryo-3XX-Gold",   UNKN_STR, "10 nm"    },
	{ 0x803, "Kryo-3XX-Silver", UNKN_STR, "10 nm"    },
	{ 0x804, "Kryo-4XX-Gold",   UNKN_STR, "11-7 nm"  },
	{ 0x805, "Kryo-4XX-Silver", UNKN_STR, "8-7 nm"   },
	{ 0xc00, "Falkor",          UNKN_STR, "10 nm"    },
	{ 0xc01, "Saphira",         UNKN_STR, "8-7 nm"   },
	{ -1,    UNKN_STR,          UNKN_STR, UNKN_STR   },
};

static const struct arm_id_part samsung_part[] = {
	{ 0x001, "Exynos M1", UNKN_STR, "14 nm"  },
	{ 0x002, "Exynos M3", UNKN_STR, "10 nm"  },
	{ 0x003, "Exynos M4", UNKN_STR, "8 nm"   },
	{ 0x004, "Exynos M5", UNKN_STR, "7 nm"   },
	{ -1,    UNKN_STR,    UNKN_STR, UNKN_STR },
};

static const struct arm_id_part nvidia_part[] = {
	{ 0x000, "Denver",   UNKN_STR, "28 nm"  },
	{ 0x003, "Denver 2", UNKN_STR, "16 nm"  },
	{ 0x004, "Carmel",   UNKN_STR, "12 nm"  },
	{ -1,    UNKN_STR,   UNKN_STR, UNKN_STR },
};

static const struct arm_id_part marvell_part[] = {
	{ 0x131, "Feroceon-88FR131", UNKN_STR, UNKN_STR },
	{ 0x581, "PJ4/PJ4b",         UNKN_STR, UNKN_STR },
	{ 0x584, "PJ4B-MP",          UNKN_STR, UNKN_STR },
	{ -1,    UNKN_STR,           UNKN_STR, UNKN_STR },
};

static const struct arm_id_part apple_part[] = {
	{ 0x000, "A6",          "Swift",     "32 nm"    },
	{ 0x001, "A7",          "Cyclone",   "28 nm"    },
	{ 0x002, "A8",          "Typhoon",   "20 nm"    },
	{ 0x003, "A8X",         "Typhoon",   "20 nm"    },
	{ 0x004, "A9",          "Twister",   "16 nm"    },
	{ 0x005, "A9X",         "Twister",   "16 nm"    },
	{ 0x006, "A10 Fusion",  "Zephyr",    "16 nm"    },
	{ 0x007, "A10 Fusion",  "Hurricane", "16 nm"    },
	{ 0x008, "A11 Bionic",  "Monsoon",   "10 nm"    },
	{ 0x009, "A11 Bionic",  "Mistral",   "10 nm"    },
	{ 0x00b, "A12",         "Vortex",    "TSMC N7"  },
	{ 0x00c, "A12",         "Tempest",   "TSMC N7"  },
	{ 0x00f, "M9",          "Tempest",   "TSMC N7"  },
	{ 0x010, "A12X Bionic", "Vortex",    "TSMC N7"  },
	{ 0x011, "A12X Bionic", "Tempest",   "TSMC N7"  },
	{ 0x012, "A13 Bionic",  "Lightning", "TSMC N7P" },
	{ 0x013, "A13 Bionic",  "Thunder",   "TSMC N7P" },
	{ 0x020, "A14",         "Icestorm",  "TSMC N5"  },
	{ 0x021, "A14",         "Firestorm", "TSMC N5"  },
	{ 0x022, "M1",          "Icestorm",  "TSMC N5"  },
	{ 0x023, "M1",          "Firestorm", "TSMC N5"  },
	{ 0x024, "M1 Pro",      "Icestorm",  "TSMC N5"  },
	{ 0x025, "M1 Pro",      "Firestorm", "TSMC N5"  },
	{ 0x026, "M10",         "Thunder",   "TSMC N7P" },
	{ 0x028, "M1 Max",      "Icestorm",  "TSMC N5"  },
	{ 0x029, "M1 Max",      "Firestorm", "TSMC N5"  },
	{ 0x030, "A15",         "Blizzard",  "TSMC N5P" },
	{ 0x031, "A15",         "Avalanche", "TSMC N5P" },
	{ 0x032, "M2",          "Blizzard",  "TSMC N5P" },
	{ 0x033, "M2",          "Avalanche", "TSMC N5P" },
	{ 0x034, "M2 Pro",      "Blizzard",  "TSMC N5P" },
	{ 0x035, "M2 Pro",      "Avalanche", "TSMC N5P" },
	{ 0x036, "A16",         "Sawtooth",  "TSMC N4P" },
	{ 0x037, "A16",         "Everest",   "TSMC N4P" },
	{ 0x038, "M2 Max",      "Blizzard",  "TSMC N5P" },
	{ 0x039, "M2 Max",      "Avalanche", "TSMC N5P" },
	{ -1,    UNKN_STR,      UNKN_STR,    UNKN_STR   },
};

static const struct arm_id_part faraday_part[] = {
	{ 0x526, "FA526",  UNKN_STR, UNKN_STR },
	{ 0x626, "FA626",  UNKN_STR, UNKN_STR },
	{ -1,    UNKN_STR, UNKN_STR, UNKN_STR },
};

static const struct arm_id_part intel_part[] = {
	{ 0x200, "i80200",                UNKN_STR, UNKN_STR },
	{ 0x210, "PXA250A",               UNKN_STR, UNKN_STR },
	{ 0x212, "PXA210A",               UNKN_STR, UNKN_STR },
	{ 0x242, "i80321-400",            UNKN_STR, UNKN_STR },
	{ 0x243, "i80321-600",            UNKN_STR, UNKN_STR },
	{ 0x290, "PXA250B/PXA26x",        UNKN_STR, UNKN_STR },
	{ 0x292, "PXA210B",               UNKN_STR, UNKN_STR },
	{ 0x2c2, "i80321-400-B0",         UNKN_STR, UNKN_STR },
	{ 0x2c3, "i80321-600-B0",         UNKN_STR, UNKN_STR },
	{ 0x2d0, "PXA250C/PXA255/PXA26x", UNKN_STR, UNKN_STR },
	{ 0x2d2, "PXA210C",               UNKN_STR, UNKN_STR },
	{ 0x411, "PXA27x",                UNKN_STR, UNKN_STR },
	{ 0x41c, "IPX425-533",            UNKN_STR, UNKN_STR },
	{ 0x41d, "IPX425-400",            UNKN_STR, UNKN_STR },
	{ 0x41f, "IPX425-266",            UNKN_STR, UNKN_STR },
	{ 0x682, "PXA32x",                UNKN_STR, UNKN_STR },
	{ 0x683, "PXA930/PXA935",         UNKN_STR, UNKN_STR },
	{ 0x688, "PXA30x",                UNKN_STR, UNKN_STR },
	{ 0x689, "PXA31x",                UNKN_STR, UNKN_STR },
	{ 0xb11, "SA1110",                UNKN_STR, UNKN_STR },
	{ 0xc12, "IPX1200",               UNKN_STR, UNKN_STR },
	{ -1,    UNKN_STR,                UNKN_STR, UNKN_STR },
};

static const struct arm_id_part fujitsu_part[] = {
	{ 0x001, "A64FX",  UNKN_STR, "7 nm"   },
	{ 0x003, "MONAKA", UNKN_STR, "2 nm"   },
	{ -1,    UNKN_STR, UNKN_STR, UNKN_STR },
};

static const struct arm_id_part hisi_part[] = {
	{ 0xd01, "TaiShan-v110", UNKN_STR, UNKN_STR }, /* used in Kunpeng-920 SoC */
	{ 0xd02, "TaiShan-v120", UNKN_STR, UNKN_STR }, /* used in Kirin 990A and 9000S SoCs */
	{ 0xd40, "Cortex-A76",   UNKN_STR, UNKN_STR }, /* HiSilicon uses this ID though advertises A76 */
	{ 0xd41, "Cortex-A77",   UNKN_STR, UNKN_STR }, /* HiSilicon uses this ID though advertises A77 */
	{ -1,    UNKN_STR,       UNKN_STR, UNKN_STR },
};

static const struct arm_id_part ampere_part[] = {
	{ 0xac3, "Ampere-1",  UNKN_STR, UNKN_STR },
	{ 0xac4, "Ampere-1a", UNKN_STR, UNKN_STR },
	{ -1,    UNKN_STR,    UNKN_STR, UNKN_STR },
};

static const struct arm_id_part ft_part[] = {
	{ 0x303, "FTC310", UNKN_STR, UNKN_STR },
	{ 0x660, "FTC660", UNKN_STR, UNKN_STR },
	{ 0x661, "FTC661", UNKN_STR, UNKN_STR },
	{ 0x662, "FTC662", UNKN_STR, UNKN_STR },
	{ 0x663, "FTC663", UNKN_STR, UNKN_STR },
	{ 0x664, "FTC664", UNKN_STR, UNKN_STR },
	{ 0x862, "FTC862", UNKN_STR, UNKN_STR },
	{ -1,    UNKN_STR, UNKN_STR, UNKN_STR },
};

static const struct arm_id_part ms_part[] = {
	{ 0xd49, "Azure-Cobalt-100", UNKN_STR, UNKN_STR },
	{ -1,    UNKN_STR,           UNKN_STR, UNKN_STR },
};

static const struct arm_id_part unknown_part[] = {
	{ -1, UNKN_STR, UNKN_STR, UNKN_STR },
};

/* Implementers list */
static const struct arm_hw_impl hw_implementer[] = {
	{ 0x41, VENDOR_ARM,       arm_part,     "ARM"                },
	{ 0x42, VENDOR_BROADCOM,  brcm_part,    "Broadcom"           },
	{ 0x43, VENDOR_CAVIUM,    cavium_part,  "Cavium"             },
	{ 0x44, VENDOR_DEC,       dec_part,     "DEC"                },
	{ 0x46, VENDOR_FUJITSU,   fujitsu_part, "FUJITSU"            },
	{ 0x48, VENDOR_HISILICON, hisi_part,    "HiSilicon"          },
	{ 0x49, VENDOR_INFINEON,  unknown_part, "Infineon"           },
	{ 0x4d, VENDOR_FREESCALE, unknown_part, "Motorola/Freescale" },
	{ 0x4e, VENDOR_NVIDIA,    nvidia_part,  "NVIDIA"             },
	{ 0x50, VENDOR_APM,       apm_part,     "APM"                },
	{ 0x51, VENDOR_QUALCOMM,  qcom_part,    "Qualcomm"           },
	{ 0x53, VENDOR_SAMSUNG,   samsung_part, "Samsung"            },
	{ 0x56, VENDOR_MARVELL,   marvell_part, "Marvell"            },
	{ 0x61, VENDOR_APPLE,     apple_part,   "Apple"              },
	{ 0x66, VENDOR_FARADAY,   faraday_part, "Faraday"            },
	{ 0x69, VENDOR_INTEL,     intel_part,   "Intel"              },
	{ 0x6d, VENDOR_MICROSOFT, ms_part,      "Microsoft"          },
	{ 0x70, VENDOR_PHYTIUM,   ft_part,      "Phytium"            },
	{ 0xc0, VENDOR_AMPERE,    ampere_part,  "Ampere"             },
	{ -1,   VENDOR_UNKNOWN,   unknown_part, UNKN_STR             },
};

static const struct arm_hw_impl* get_cpu_implementer_from_code(uint8_t implementer)
{
	int i;

	for (i = 0; hw_implementer[i].id >= 0; i++) {
		if (hw_implementer[i].id == implementer)
			break;
	}

	/* This function returns an item with VENDOR_UNKNOWN if implementer is not found in the "hw_implementer" array */
	return &hw_implementer[i];
}

static const struct arm_hw_impl* get_cpu_implementer_from_vendor(cpu_vendor_t vendor)
{
	int i;

	for (i = 0; hw_implementer[i].id >= 0; i++) {
		if (hw_implementer[i].vendor == vendor)
			break;
	}

	/* This function returns an item with VENDOR_UNKNOWN if implementer is not found in the "hw_implementer" array */
	return &hw_implementer[i];
}

static const struct arm_id_part* get_cpu_implementer_parts(const struct arm_hw_impl* hw_impl, uint16_t part_num)
{
	int i;

	for (i = 0; hw_impl->parts[i].id >= 0; i++) {
		if (hw_impl->parts[i].id == part_num)
			break;
	}

	/* This function retuns "unknown" if PartNum is not found in the "parts" array */
	return &hw_impl->parts[i];
}

static inline bool is_aarch64_mode(struct cpu_raw_data_t* raw)
{
	return (raw->arm_id_aa64afr[0] != 0) || (raw->arm_id_aa64dfr[0] != 0) || (raw->arm_id_aa64isar[0] != 0) || (raw->arm_id_aa64mmfr[0] != 0) || (raw->arm_id_aa64pfr[0] != 0);
}

static bool decode_arm_architecture_version_by_midr(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
{
	int i;
	const uint8_t architecture = EXTRACTS_BITS(raw->arm_midr, 19, 16);

	const struct { uint8_t raw_value; cpu_feature_level_t enum_value; }
	architecture_matchtable[] = {
		{ 0x00, FEATURE_LEVEL_UNKNOWN },
		{ 0x01, FEATURE_LEVEL_ARM_V4 },
		{ 0x02, FEATURE_LEVEL_ARM_V4T },
		{ 0x03, FEATURE_LEVEL_ARM_V5 },
		{ 0x04, FEATURE_LEVEL_ARM_V5T },
		{ 0x05, FEATURE_LEVEL_ARM_V5TE },
		{ 0x06, FEATURE_LEVEL_ARM_V5TEJ },
		{ 0x07, FEATURE_LEVEL_ARM_V6 },
		{ 0x08, FEATURE_LEVEL_UNKNOWN },
		{ 0x09, FEATURE_LEVEL_UNKNOWN },
		{ 0x0A, FEATURE_LEVEL_UNKNOWN },
		{ 0x0B, FEATURE_LEVEL_UNKNOWN },
		{ 0x0C, FEATURE_LEVEL_ARM_V6_M },
		{ 0x0D, FEATURE_LEVEL_UNKNOWN },
		{ 0x0E, FEATURE_LEVEL_UNKNOWN }
		// 0x0F: defined by CPUID scheme
	};

	/* Check if architecture level is explicit */
	for (i = 0; i < COUNT_OF(architecture_matchtable); i++) {
		if (architecture == architecture_matchtable[i].raw_value) {
			data->feature_level = architecture_matchtable[i].enum_value;
			debugf(2, "ARM architecture version is %s\n", cpu_feature_level_str(data->feature_level));
			return true;
		}
	}

	/* Return false if not found */
	return false;
}

static void decode_arm_architecture_version_by_cpuid(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct arm_arch_extension_t* ext_status)
{
	int i;
	cpu_feature_level_t feature_level = FEATURE_LEVEL_UNKNOWN;
	const cpu_feature_level_t *architecture_arm = NULL;

	/**
	 * Check if CPU is ARMv6 or ARMv7
	 * On ID_DFR0, Coprocessor debug model, bits[3:0]
	*  - 0x02 Support for v6 Debug architecture, with CP14 access.
	*  - 0x03 Support for v6.1 Debug architecture, with CP14 access.
	*  - 0x04 Support for v7 Debug architecture, with CP14 access.
	*  - 0x05 Support for v7.1 Debug architecture, with CP14 access.
	 * The ARMv7-A architecture profile defines a Virtual Memory System Architecture (VMSA). In Armv8-A, the only permitted value is 0x05 for VMSA bits.
	 * The ARMv7-R architecture profile defines a Protected Memory System Architecture (PMSA). In Armv8-A, the only permitted value is 0x00 for PMSA bits.
	 *
	 * If a possible value for a field is shown as Armv7-M reserved it means Armv7-M implementations cannot use that field value.
	*/
	const uint8_t copdbg   = EXTRACTS_BITS(raw->arm_id_dfr[0],   3,  0);
	const uint8_t simd     = EXTRACTS_BITS(raw->arm_id_isar[3],  7,  4);
	const uint8_t psr_m    = EXTRACTS_BITS(raw->arm_id_isar[4], 27, 24);
	const uint8_t vmsa     = EXTRACTS_BITS(raw->arm_id_mmfr[0],  3,  0);
	const uint8_t pmsa     = EXTRACTS_BITS(raw->arm_id_mmfr[0],  7,  4);
	const uint8_t ras      = EXTRACTS_BITS(raw->arm_id_pfr[0],  31, 28);
	const uint8_t mprogmod = EXTRACTS_BITS(raw->arm_id_pfr[1],  11,  8);
	if ((copdbg == 0x02) || (copdbg == 0x03)) {
		/* ARMv6 */
		if (psr_m == 0x01)
			feature_level = FEATURE_LEVEL_ARM_V6_M;
		else
			feature_level = FEATURE_LEVEL_ARM_V6;
	}
	else if ((copdbg == 0x04) || (copdbg == 0x05)) {
		/* ARMv7 */
		if (psr_m == 0x01)
			/* An Armv7-M implementation that includes the DSP extension is called an Armv7E-M implementation */
			feature_level = (simd == 0x03) ? FEATURE_LEVEL_ARM_V7E_M : FEATURE_LEVEL_ARM_V7_M;
		else if (vmsa != 0x00)
			feature_level = FEATURE_LEVEL_ARM_V7_A;
		else if (pmsa != 0x00)
			feature_level = FEATURE_LEVEL_ARM_V7_R;
	}
	else if ((psr_m == 0x01) && (mprogmod == 0x02))
		feature_level = (ras == 0x02) ? FEATURE_LEVEL_ARM_V8_1_M : FEATURE_LEVEL_ARM_V8_0_M;
	else if (pmsa != 0x00)
		feature_level = FEATURE_LEVEL_ARM_V8_0_R;

	if (feature_level != FEATURE_LEVEL_UNKNOWN)
		goto found;

	/**
	 * The Armv8.0 architecture extension
	 *
	 * The original Armv8-A architecture is called Armv8.0. It contains mandatory and optional architectural features.
	 * Some features must be implemented together. An implementation is Armv8.0 compliant if it includes all of the
	 * Armv8.0 architectural features that are mandatory.
	 *
	 * An Armv8.0 compliant implementation can additionally include:
	 * - Armv8.0 features that are optional.
	 * - Any arbitrary subset of the architectural features of Armv8.1, subject only to those constraints that require that certain features be implemented together.
	 */
	const cpu_feature_level_t architecture_arm_v8a[] = {
		FEATURE_LEVEL_ARM_V8_0_A, /*!< ARMv8.0-A */
		FEATURE_LEVEL_ARM_V8_1_A, /*!< ARMv8.1-A */
		FEATURE_LEVEL_ARM_V8_2_A, /*!< ARMv8.2-A */
		FEATURE_LEVEL_ARM_V8_3_A, /*!< ARMv8.3-A */
		FEATURE_LEVEL_ARM_V8_4_A, /*!< ARMv8.4-A */
		FEATURE_LEVEL_ARM_V8_5_A, /*!< ARMv8.5-A */
		FEATURE_LEVEL_ARM_V8_6_A, /*!< ARMv8.6-A */
		FEATURE_LEVEL_ARM_V8_7_A, /*!< ARMv8.7-A */
		FEATURE_LEVEL_ARM_V8_8_A, /*!< ARMv8.8-A */
		FEATURE_LEVEL_ARM_V8_9_A, /*!< ARMv8.9-A */
		FEATURE_LEVEL_UNKNOWN,
	};

	/**
	 * The Armv9.0 architecture extension
	 *
	 * The Armv9.0 architecture extension adds mandatory and optional architectural features. Some features must be
	 * implemented together. An implementation is Armv9.0 compliant if all of the following apply:
	 * - It is Armv8.5 compliant.
	 * - It includes all of the Armv9.0 architectural features that are mandatory.
	 *
	 * An Armv9.0 compliant implementation can additionally include:
	 * - Armv9.0 features that are optional.
	 * - Any arbitrary subset of the architectural features of Armv9.1, subject only to those constraints that require that certain features be implemented together.
	 */
	const cpu_feature_level_t architecture_arm_v9a[] = {
		FEATURE_LEVEL_ARM_V9_0_A, /*!< ARMv9.0-A */
		FEATURE_LEVEL_ARM_V9_1_A, /*!< ARMv9.1-A */
		FEATURE_LEVEL_ARM_V9_2_A, /*!< ARMv9.2-A */
		FEATURE_LEVEL_ARM_V9_3_A, /*!< ARMv9.3-A */
		FEATURE_LEVEL_ARM_V9_4_A, /*!< ARMv9.4-A */
		FEATURE_LEVEL_UNKNOWN,
	};

	if ((ext_status->present[FEATURE_LEVEL_ARM_V9_0_A].optional > 0) || (ext_status->present[FEATURE_LEVEL_ARM_V9_0_A].mandatory > 0))
		architecture_arm = architecture_arm_v9a;
	else if ((ext_status->present[FEATURE_LEVEL_ARM_V8_0_A].optional > 0) || (ext_status->present[FEATURE_LEVEL_ARM_V8_0_A].mandatory > 0))
		architecture_arm = architecture_arm_v8a;
	else
		goto found;

	for (i = 0; architecture_arm[i] != FEATURE_LEVEL_UNKNOWN; i++) {
		debugf(3, "Check if CPU is %s compliant: %2u/%2u optional features detected, %2u/%2u mandatory features required\n",
			cpu_feature_level_str(architecture_arm[i]),
			ext_status->present[ architecture_arm[i] ].optional, ext_status->total[ architecture_arm[i] ].optional,
			ext_status->present[ architecture_arm[i] ].mandatory, ext_status->total[ architecture_arm[i] ].mandatory);
		/* CPU is compliant when it includes all of the architectural features that are mandatory */
		if (ext_status->present[ architecture_arm[i] ].mandatory < ext_status->total[ architecture_arm[i] ].mandatory)
			break;
		/* If there are no mandatory features (like ARMv9.3-A), check that at least one optional feature is implemented */
		else if ((ext_status->total[ architecture_arm[i] ].mandatory == 0) && (ext_status->present[ architecture_arm[i] ].optional == 0))
			break;
		else
			feature_level = architecture_arm[i];
	}

found:
	data->feature_level = feature_level;
	debugf(2, "ARM architecture version is %s\n", cpu_feature_level_str(feature_level));
}

static void set_feature_status(struct cpu_id_t* data, struct arm_arch_extension_t* ext_status, bool is_present, cpu_feature_t feature, cpu_feature_level_t optional_from, cpu_feature_level_t mandatory_from)
{
	if (optional_from >= 0)
		ext_status->total[optional_from].optional++;
	if (mandatory_from >= 0)
		ext_status->total[mandatory_from].mandatory++;

	if (is_present) {
		data->flags[feature] = 1;
		debugf(3, "feature %s is present", cpu_feature_str(feature));
		if (optional_from >= 0) {
			ext_status->present[optional_from].optional++;
			debugf(3, " (optional from %s", cpu_feature_level_str(optional_from));
			if (mandatory_from >= 0) {
				ext_status->present[mandatory_from].mandatory++;
				debugf(3, ", mandatory from %s", cpu_feature_level_str(mandatory_from));
			}
			debugf(3, ")");
		}
		debugf(3, "\n");
	}
}

static void match_arm_features(bool is_aarch64, cpu_feature_t feature, const struct arm_feature_map_t* feature_map, struct cpu_id_t* data, struct arm_arch_extension_t* ext_status)
{
	bool field_is_present, feature_is_present = false;
	unsigned i;
	uint64_t reg_value;
	const struct arm_feature_field_t* field;

	for (i = 0; i < MAX_IDENTIFY_FIELDS; i++) {
		field = &feature_map->fields[i];

		if (!is_aarch64 && field->aarch32_reg != NULL)
			reg_value = *field->aarch32_reg;
		else if (is_aarch64 && field->aarch64_reg != NULL)
			reg_value = *field->aarch64_reg;
		else
			break; // quit on sentinel values

		field_is_present = (EXTRACTS_BITS(reg_value, field->highbit, field->lowbit) == field->value);
		if (field_is_present)
			debugf(3, "match value %u for bits [%2u:%2u] in register 0x%016" PRIX64 ", ", field->value, field->highbit, field->lowbit, reg_value);
		feature_is_present = feature_is_present || field_is_present;
	}

	set_feature_status(data, ext_status, feature_is_present, feature, feature_map->ver_optional, feature_map->ver_mandatory);
}

static void load_arm_feature_pauth(struct cpu_id_t* data, struct arm_arch_extension_t* ext_status)
{
	/* FEAT_PAuth, Pointer authentication
	When FEAT_PAuth is implemented, one of the following must be true:
	- Exactly one of the PAC algorithms is implemented.
	- If the PACGA instruction and other Pointer authentication instructions use different PAC algorithms, exactly two PAC algorithms are implemented.
	The PAC algorithm features are:
	- FEAT_PACQARMA5.
	- FEAT_PACIMP.
	- FEAT_PACQARMA3. */
	set_feature_status(data, ext_status,
		(data->flags[CPU_FEATURE_PACIMP] ||
		 data->flags[CPU_FEATURE_PACQARMA3] ||
		 data->flags[CPU_FEATURE_PACQARMA5]),
		CPU_FEATURE_PAUTH, FEATURE_LEVEL_ARM_V8_2_A, FEATURE_LEVEL_ARM_V8_3_A);
}

static void load_arm_feature_mpam(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct arm_arch_extension_t* ext_status)
{
	/* FEAT_MPAM, Memory Partitioning and Monitoring Extension
	MPAM Extension version: MPAM | MPAM_frac
	Not implemented: 0x00 | 0x00
	v0.1 is implemented: 0x00 | 0x01
	v1.0 is implemented: 0x01 | 0x00
	v1.1 is implemented: 0x01 | 0x01 */
	const uint8_t mpam      = EXTRACTS_BITS(raw->arm_id_aa64pfr[0], 43, 40);
	const uint8_t mpam_frac = EXTRACTS_BITS(raw->arm_id_aa64pfr[1], 19, 16);
	if ((mpam != 0x00) || (mpam_frac != 0x00)) {
		debugf(2, "MPAM Extension version is %u.%u\n", mpam, mpam_frac);
		set_feature_status(data, ext_status, true,                                  CPU_FEATURE_MPAM,     FEATURE_LEVEL_ARM_V8_2_A, -1);
		set_feature_status(data, ext_status, (mpam == 0x00) && (mpam_frac == 0x01), CPU_FEATURE_MPAMV0P1, FEATURE_LEVEL_ARM_V8_5_A, -1);
		set_feature_status(data, ext_status, (mpam == 0x01) && (mpam_frac == 0x01), CPU_FEATURE_MPAMV1P1, FEATURE_LEVEL_ARM_V8_5_A, -1);
	}
}

static void load_arm_feature_mte4(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct arm_arch_extension_t* ext_status)
{
	/* FEAT_MTE4, Enhanced Memory Tagging Extension */
	const uint8_t mte = EXTRACTS_BITS(raw->arm_id_aa64pfr[1], 11,  8);
	if (mte >= 0x02) {
		/* These fields are valid only if ID_AA64PFR1_EL1.MTE >= 0x02 */
		const uint8_t mte_frac = EXTRACTS_BITS(raw->arm_id_aa64pfr[1], 43, 40);
		const uint8_t mtex     = EXTRACTS_BITS(raw->arm_id_aa64pfr[1], 55, 52);
		set_feature_status(data, ext_status, (mte_frac == 0x00), CPU_FEATURE_MTE_ASYNC,           FEATURE_LEVEL_ARM_V8_5_A, -1);
		set_feature_status(data, ext_status, (mtex == 0x01),     CPU_FEATURE_MTE_CANONICAL_TAGS,  FEATURE_LEVEL_ARM_V8_7_A, -1);
		set_feature_status(data, ext_status, (mtex == 0x01),     CPU_FEATURE_MTE_NO_ADDRESS_TAGS, FEATURE_LEVEL_ARM_V8_7_A, -1);
	}
	/* If FEAT_MTE4 is implemented, then FEAT_MTE_CANONICAL_TAGS,
	FEAT_MTE_NO_ADDRESS_TAGS, FEAT_MTE_TAGGED_FAR, and
	FEAT_MTE_STORE_ONLY are implemented. */
	set_feature_status(data, ext_status,
		(data->flags[CPU_FEATURE_MTE_CANONICAL_TAGS] &&
		 data->flags[CPU_FEATURE_MTE_NO_ADDRESS_TAGS] &&
		 data->flags[CPU_FEATURE_MTE_TAGGED_FAR] &&
		 data->flags[CPU_FEATURE_MTE_STORE_ONLY]),
		CPU_FEATURE_MTE4, FEATURE_LEVEL_ARM_V8_7_A, -1);
}

static void load_arm_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct arm_arch_extension_t* ext_status)
{
	cpu_feature_t feature;
	const bool is_aarch64 = is_aarch64_mode(raw);

	/* Thumb */
	set_feature_status(data, ext_status,
		((data->feature_level == FEATURE_LEVEL_ARM_V4T) ||
		 (data->feature_level == FEATURE_LEVEL_ARM_V5T) ||
		 (data->feature_level == FEATURE_LEVEL_ARM_V5TE) ||
		 (data->feature_level == FEATURE_LEVEL_ARM_V5TEJ)
		), CPU_FEATURE_THUMB, -1, -1);

	/* Jazelle */
	set_feature_status(data, ext_status, (data->feature_level == FEATURE_LEVEL_ARM_V5TEJ), CPU_FEATURE_JAZELLE, -1, -1);

	const struct arm_feature_map_t features_map[NUM_CPU_FEATURES] = {
		[CPU_FEATURE_SWAP] = {
			.ver_optional  = -1,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_isar[0], .aarch64_reg = NULL                    , .highbit =  3, .lowbit =  0, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_THUMB] = {
			.ver_optional  = -1,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_pfr[0],  .aarch64_reg = NULL,                     .highbit =  7, .lowbit =  4, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_ADVMULTU] = {
			.ver_optional  = -1,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_isar[2], .aarch64_reg = NULL,                     .highbit = 23, .lowbit = 20, .value = 0x01 }, /* Adds the UMULL and UMLAL instructions */
				{ .aarch32_reg = &raw->arm_id_isar[2], .aarch64_reg = NULL,                     .highbit = 23, .lowbit = 20, .value = 0x02 }, /* As for 0x01, and adds the UMAAL instruction */
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_ADVMULTS] = {
			.ver_optional  = -1,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_isar[2], .aarch64_reg = NULL,                     .highbit = 19, .lowbit = 16, .value = 0x01 }, /* Adds the SMULL and SMLAL instructions */
				{ .aarch32_reg = &raw->arm_id_isar[2], .aarch64_reg = NULL,                     .highbit = 19, .lowbit = 16, .value = 0x02 }, /* As for 0x01, and adds the SMLABB, SMLABT, SMLALBB, SMLALBT, SMLALTB, SMLALTT, SMLATB, SMLATT, SMLAWB, SMLAWT, SMULBB, SMULBT, SMULTB, SMULTT, SMULWB, and SMULWT instructions */
				{ .aarch32_reg = &raw->arm_id_isar[2], .aarch64_reg = NULL,                     .highbit = 19, .lowbit = 16, .value = 0x03 }, /* As for 0x02, and adds the SMLAD, SMLADX, SMLALD, SMLALDX, SMLSD, SMLSDX, SMLSLD, SMLSLDX, SMMLA, SMMLAR, SMMLS, SMMLSR, SMMUL, SMMULR, SMUAD, SMUADX, SMUSD, and SMUSDX instructions */
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_JAZELLE] = {
			.ver_optional  = -1,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_pfr[0],  .aarch64_reg = NULL,                     .highbit = 11, .lowbit =  8, .value = 0x01 }, /* Jazelle extension implemented, without clearing of JOSCR.CV on exception entry */
				{ .aarch32_reg = &raw->arm_id_pfr[0],  .aarch64_reg = NULL,                     .highbit = 11, .lowbit =  8, .value = 0x02 }, /* Jazelle extension implemented, with clearing of JOSCR.CV on exception entry */
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},

		/* Armv6.0 */
		[CPU_FEATURE_DEBUGV6] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V6,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = NULL,                     .highbit =  3, .lowbit =  0, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_DEBUGV6P1] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V6,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = NULL,                     .highbit =  3, .lowbit =  0, .value = 0x03 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_THUMB2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V6,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_pfr[0],  .aarch64_reg = NULL,                     .highbit =  7, .lowbit =  4, .value = 0x03 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},

		/* Armv7.0 */
		[CPU_FEATURE_DEBUGV7] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V7_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = NULL,                     .highbit =  3, .lowbit =  0, .value = 0x04 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_DEBUGV7P1] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V7_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = NULL,                     .highbit =  3, .lowbit =  0, .value = 0x05 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_THUMBEE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V7_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_pfr[0],  .aarch64_reg = NULL,                     .highbit = 15, .lowbit = 12, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_DIVIDE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V7_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_isar[0], .aarch64_reg = NULL,                     .highbit = 27, .lowbit = 24, .value = 0x01 }, /* Thumb instruction set */
				{ .aarch32_reg = &raw->arm_id_isar[0], .aarch64_reg = NULL,                     .highbit = 27, .lowbit = 24, .value = 0x02 }, /* ARM instruction set */
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LPAE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V7_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_mmfr[0], .aarch64_reg = NULL,                     .highbit =  3, .lowbit =  0, .value = 0x05 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PMUV1] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V7_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = NULL                    , .highbit = 31, .lowbit = 28, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PMUV2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V7_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = NULL                    , .highbit = 31, .lowbit = 28, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},

		/* Armv8.0 */
		[CPU_FEATURE_AES] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit =  7, .lowbit =  4, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_ASID16] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[0], .highbit =  7, .lowbit =  4, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_ADVSIMD] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 23, .lowbit = 20, .value = 0x00 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 23, .lowbit = 20, .value = 0x01 }, /* as for 0x00, and also includes support for half-precision floating-point arithmetic */
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_CRC32] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_1_A,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_isar[5], .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 19, .lowbit = 16, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_CSV2_1P1] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[1],  .highbit = 35, .lowbit = 32, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_CSV2_1P2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[1],  .highbit = 35, .lowbit = 32, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_CSV2_2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 59, .lowbit = 56, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_CSV2_3] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 59, .lowbit = 56, .value = 0x03 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_DOUBLELOCK] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 39, .lowbit = 36, .value = 0x00 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_ETS2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_8_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 39, .lowbit = 36, .value = 0x02 },
				{ .aarch32_reg = &raw->arm_id_mmfr[5], .aarch64_reg = NULL,                     .highbit =  3, .lowbit =  0, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FP] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 19, .lowbit = 16, .value = 0x00 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_MIXEDEND] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[0], .highbit = 11, .lowbit =  8, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_MIXEDENDEL0] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[0], .highbit = 19, .lowbit = 16, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PMULL] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit =  7, .lowbit =  4, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PMUV3] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 11, .lowbit =  8, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = NULL,                     .highbit = 27, .lowbit = 24, .value = 0x03 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SHA1] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 11, .lowbit =  8, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SHA256] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 15, .lowbit = 12, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_NTLBPA] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 51, .lowbit = 48, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_mmfr[5], .aarch64_reg = NULL,                     .highbit =  7, .lowbit =  4, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},

		/* Armv8.1 */
		[CPU_FEATURE_HAFDBS] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit =  3, .lowbit =  0, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit =  3, .lowbit =  0, .value = 0x02 }, /* As 0x01, and adds support for hardware update of the Access flag for Block and Page descriptors. Hardware update of dirty state is supported */
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_HPDS] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_1_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 15, .lowbit = 12, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LOR] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_1_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 19, .lowbit = 16, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LSE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_1_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 23, .lowbit = 20, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PAN] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_1_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 23, .lowbit = 20, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_mmfr[3], .aarch64_reg = NULL,                     .highbit = 19, .lowbit = 16, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PMUV3P1] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 11, .lowbit =  8, .value = 0x04 },
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = NULL,                     .highbit = 27, .lowbit = 24, .value = 0x04 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_RDM] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 31, .lowbit = 28, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_isar[5], .aarch64_reg = NULL,                     .highbit = 27, .lowbit = 24, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_VHE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 11, .lowbit =  8, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit =  3, .lowbit =  0, .value = 0x07 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_VMID16] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit =  7, .lowbit =  4, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},

		/* Armv8.2 */
		[CPU_FEATURE_AA32HPD] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_mmfr[4], .aarch64_reg = NULL,                     .highbit = 19, .lowbit = 16, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_AA32I8MM] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_isar[6], .aarch64_reg = NULL,                     .highbit = 27, .lowbit = 24, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_DPB] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_2_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit =  3, .lowbit =  0, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_DEBUGV8P2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_2_A,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit =  3, .lowbit =  0, .value = 0x08 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_F32MM] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64zfr[0],  .highbit = 55, .lowbit = 52, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_F64MM] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64zfr[0],  .highbit = 59, .lowbit = 56, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FP16] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 23, .lowbit = 20, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 19, .lowbit = 16, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_HPDS2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 15, .lowbit = 12, .value = 0x02 },
				{ .aarch32_reg = &raw->arm_id_mmfr[4], .aarch64_reg = NULL,                     .highbit = 19, .lowbit = 16, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_I8MM] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_6_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 55, .lowbit = 52, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64zfr[0],  .highbit = 47, .lowbit = 44, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_IESB] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit = 15, .lowbit = 12, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LPA] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[0], .highbit =  3, .lowbit =  0, .value = 0x06 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LSMAOC] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit = 11, .lowbit =  8, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_mmfr[4], .aarch64_reg = NULL,                     .highbit = 23, .lowbit = 20, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LVA] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit = 19, .lowbit = 16, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PAN2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_2_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 23, .lowbit = 20, .value = 0x02 },
				{ .aarch32_reg = &raw->arm_id_mmfr[3], .aarch64_reg = NULL,                     .highbit = 19, .lowbit = 16, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_RAS] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_2_A,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_pfr[0],  .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 31, .lowbit = 28, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SHA3] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 35, .lowbit = 32, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SHA512] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 15, .lowbit = 12, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SM3] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 39, .lowbit = 36, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SM4] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 43, .lowbit = 40, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SPE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 35, .lowbit = 32, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SVE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 35, .lowbit = 32, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_TTCNP] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_2_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit =  3, .lowbit =  0, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_mmfr[4], .aarch64_reg = NULL,                     .highbit = 15, .lowbit = 12, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_UAO] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_2_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit =  7, .lowbit =  4, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_XNX] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 31, .lowbit = 28, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_mmfr[4], .aarch64_reg = NULL,                     .highbit = 11, .lowbit =  8, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},

		/* Armv8.3 */
		[CPU_FEATURE_CCIDX] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit = 23, .lowbit = 20, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_mmfr[4], .aarch64_reg = NULL,                     .highbit = 27, .lowbit = 24, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_CONSTPACFIELD] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 27, .lowbit = 24, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_EPAC] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 11, .lowbit =  8, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit =  7, .lowbit =  4, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 15, .lowbit = 12, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FCMA] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 19, .lowbit = 16, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_isar[5], .aarch64_reg = NULL,                     .highbit = 31, .lowbit = 28, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FPAC] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 11, .lowbit =  8, .value = 0x04 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit =  7, .lowbit =  4, .value = 0x04 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 15, .lowbit = 12, .value = 0x04 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FPACCOMBINE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 11, .lowbit =  8, .value = 0x05 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit =  7, .lowbit =  4, .value = 0x05 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 15, .lowbit = 12, .value = 0x05 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_JSCVT] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 15, .lowbit = 12, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_isar[6], .aarch64_reg = NULL,                     .highbit =  3, .lowbit =  0, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LRCPC] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_3_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 23, .lowbit = 20, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PACIMP] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 31, .lowbit = 28, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PACQARMA3] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 11, .lowbit =  8, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PACQARMA5] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 27, .lowbit = 24, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PAUTH] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_3_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 11, .lowbit =  8, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit =  7, .lowbit =  4, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 15, .lowbit = 12, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SPEV1P1] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 35, .lowbit = 32, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},

		/* Armv8.4 */
		[CPU_FEATURE_AMUV1] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 47, .lowbit = 44, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_pfr[0],  .aarch64_reg = NULL,                     .highbit = 23, .lowbit = 20, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_BBM] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_3_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_4_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit = 55, .lowbit = 52, .value = 0x00 }, /* Level 0 support for changing block size is supported */
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit = 55, .lowbit = 52, .value = 0x01 }, /* Level 1 support for changing block size is supported */
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit = 55, .lowbit = 52, .value = 0x02 }, /* Level 2 support for changing block size is supported */
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_DIT] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_3_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_4_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 51, .lowbit = 48, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_pfr[0],  .aarch64_reg = NULL,                     .highbit = 27, .lowbit = 24, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_DEBUGV8P4] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_3_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_4_A,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit =  3, .lowbit =  0, .value = 0x09 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_DOTPROD] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 47, .lowbit = 44, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_isar[6], .aarch64_reg = NULL,                     .highbit =  7, .lowbit =  4, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_DOUBLEFAULT] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 31, .lowbit = 28, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FHM] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 51, .lowbit = 48, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_isar[6], .aarch64_reg = NULL,                     .highbit = 11, .lowbit =  8, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FLAGM] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_4_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 55, .lowbit = 52, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_IDST] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_3_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_4_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit = 39, .lowbit = 36, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LRCPC2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_4_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 23, .lowbit = 20, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LSE2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_4_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit = 35, .lowbit = 32, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PMUV3P4] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 11, .lowbit =  8, .value = 0x05 },
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = NULL,                     .highbit = 27, .lowbit = 24, .value = 0x05 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_RASV1P1] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_pfr[0],  .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 31, .lowbit = 28, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_S2FWB] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit = 43, .lowbit = 40, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SEL2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 39, .lowbit = 36, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_TLBIOS] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_3_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_4_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 59, .lowbit = 56, .value = 0x01 }, /* Outer Shareable and TLB range maintenance instructions are not implemented */
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 59, .lowbit = 56, .value = 0x02 }, /* Outer Shareable TLB maintenance instructions are implemented */
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_TLBIRANGE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_3_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_4_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 59, .lowbit = 56, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_TRF] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 43, .lowbit = 40, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = NULL,                     .highbit = 31, .lowbit = 28, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_TTL] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_3_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_4_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit = 51, .lowbit = 48, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_TTST] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit = 31, .lowbit = 28, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},

		/* Armv8.5 */
		[CPU_FEATURE_BTI] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_4_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_5_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[1],  .highbit =  3, .lowbit =  0, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_CSV2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_5_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 59, .lowbit = 56, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_pfr[0],  .aarch64_reg = NULL,                     .highbit = 19, .lowbit = 16, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_CSV3] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_5_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 63, .lowbit = 60, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_DPB2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_1_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_5_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit =  3, .lowbit =  0, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_E0PD] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_4_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_5_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit = 63, .lowbit = 60, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_EVT] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit = 59, .lowbit = 56, .value = 0x01 }, /* HCR_EL2.{TOCU, TICAB, TID4} traps are supported. HCR_EL2.{TTLBOS,TTLBIS} traps are not supported */
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit = 59, .lowbit = 56, .value = 0x02 }, /* HCR_EL2.{TTLBOS, TTLBIS, TOCU, TICAB, TID4} traps are supported */
				{ .aarch32_reg = &raw->arm_id_mmfr[4], .aarch64_reg = NULL,                     .highbit = 31, .lowbit = 28, .value = 0x01 }, /* HCR2.{TOCU, TICAB, TID4} traps are supported. HCR2.TTLBIS trap is not supported */
				{ .aarch32_reg = &raw->arm_id_mmfr[4], .aarch64_reg = NULL,                     .highbit = 31, .lowbit = 28, .value = 0x02 }, /* HCR2.{TTLBIS, TOCU, TICAB, TID4} traps are supported */
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_EXS] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[0], .highbit = 47, .lowbit = 44, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FRINTTS] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 35, .lowbit = 32, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FLAGM2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 55, .lowbit = 52, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_MTE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[1],  .highbit = 11, .lowbit =  8, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_MTE2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[1],  .highbit = 11, .lowbit =  8, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PMUV3P5] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 11, .lowbit =  8, .value = 0x06 },
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = NULL,                     .highbit = 27, .lowbit = 24, .value = 0x06 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_RNG] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 63, .lowbit = 60, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_RNG_TRAP] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[1],  .highbit = 31, .lowbit = 28, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SB] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_5_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 39, .lowbit = 36, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_isar[6], .aarch64_reg = NULL,                     .highbit = 15, .lowbit = 12, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SPECRES] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_5_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 43, .lowbit = 40, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_isar[6], .aarch64_reg = NULL,                     .highbit = 19, .lowbit = 16, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SSBS] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg =  &raw->arm_id_pfr[2], .aarch64_reg = &raw->arm_id_aa64pfr[1],  .highbit =  7, .lowbit =  4, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SSBS2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[1],  .highbit =  7, .lowbit =  4, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},

		/* Armv8.6 */
		[CPU_FEATURE_AA32BF16] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_isar[6], .aarch64_reg = NULL,                     .highbit = 23, .lowbit = 20, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_AMUV1P1] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_5_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 47, .lowbit = 44, .value = 0x02 },
				{ .aarch32_reg = &raw->arm_id_pfr[0],  .aarch64_reg = NULL,                     .highbit = 23, .lowbit = 20, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_BF16] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_6_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 47, .lowbit = 44, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64zfr[0],  .highbit = 23, .lowbit = 20, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_DGH] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 51, .lowbit = 48, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_ECV] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_5_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_6_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[0], .highbit = 63, .lowbit = 60, .value = 0x01 }, /* Enhanced Counter Virtualization is implemented. Supports CNTHCTL_EL2.{EL1TVT, EL1TVCT, EL1NVPCT, EL1NVVCT, EVNTIS}, CNTKCTL_EL1.EVNTIS, CNTPCTSS_EL0 counter views, and CNTVCTSS_EL0 counter views. Extends the PMSCR_EL1.PCT, PMSCR_EL2.PCT, TRFCR_EL1.TS, and TRFCR_EL2.TS fields */
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[0], .highbit = 63, .lowbit = 60, .value = 0x02 }, /* As 0x01, and also includes support for CNTHCTL_EL2.ECV and CNTPOFF_EL2 */
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FGT] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_5_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[0], .highbit = 59, .lowbit = 56, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_HPMN0] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_5_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 63, .lowbit = 60, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = NULL,                     .highbit =  7, .lowbit =  4, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_MTPMU] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_5_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 51, .lowbit = 48, .value = 0x01 },
				{ .aarch32_reg = &raw->arm_id_dfr[1],  .aarch64_reg = NULL,                     .highbit =  3, .lowbit =  0, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PAUTH2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_6_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 11, .lowbit =  8, .value = 0x03 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit =  7, .lowbit =  4, .value = 0x03 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 15, .lowbit = 12, .value = 0x03 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_TWED] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_5_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 35, .lowbit = 32, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},

		/* Armv8.7 */
		[CPU_FEATURE_AFP] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_6_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 47, .lowbit = 44, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_EBF16] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 47, .lowbit = 44, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64zfr[0],  .highbit = 23, .lowbit = 20, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_HCX] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_6_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 43, .lowbit = 40, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LPA2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_6_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[0], .highbit = 31, .lowbit = 28, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[0], .highbit = 23, .lowbit = 20, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LS64] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_6_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 63, .lowbit = 60, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LS64_ACCDATA] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_6_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 63, .lowbit = 60, .value = 0x03 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LS64_V] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_6_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 63, .lowbit = 60, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_MTE3] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_5_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[1],  .highbit = 11, .lowbit =  8, .value = 0x03 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_MTE_ASYM_FAULT] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_7_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[1],  .highbit = 11, .lowbit =  8, .value = 0x03 }, /* As 0x02, except that support for FEAT_MTE_ASYNC is mandatory, and adds support for Asymmetric Tag Check Fault handling, identified as FEAT_MTE_ASYM_FAULT */
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PAN3] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_7_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 23, .lowbit = 20, .value = 0x03 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PMUV3P7] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_6_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 11, .lowbit =  8, .value = 0x07 },
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = NULL,                     .highbit = 27, .lowbit = 24, .value = 0x07 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_RPRES] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_6_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit =  7, .lowbit =  4, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SPEV1P2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_6_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 35, .lowbit = 32, .value = 0x03 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_WFXT] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_6_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_7_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit =  3, .lowbit =  0, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_XS] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_6_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_7_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 59, .lowbit = 56, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},

		/* Armv8.8 */
		[CPU_FEATURE_CMOW] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_7_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_8_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 59, .lowbit = 56, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_DEBUGV8P8] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_7_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_8_A,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit =  3, .lowbit =  0, .value = 0x0A },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_HBC] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_7_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_8_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 23, .lowbit = 20, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_MOPS] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_7_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_8_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 19, .lowbit = 16, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_NMI] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_7_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_8_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[1],  .highbit = 39, .lowbit = 36, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PMUV3P8] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_7_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 11, .lowbit =  8, .value = 0x08 },
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = NULL,                     .highbit = 27, .lowbit = 24, .value = 0x08 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SCTLR2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_9_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[3], .highbit =  7, .lowbit =  4, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SPEV1P3] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_7_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 35, .lowbit = 32, .value = 0x04 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_TCR2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_9_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[3], .highbit =  3, .lowbit =  0, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_TIDCP1] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_7_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_8_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 55, .lowbit = 52, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},

		/* Armv8.9 */
		[CPU_FEATURE_ADERR] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[3], .highbit = 59, .lowbit = 56, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[3], .highbit = 55, .lowbit = 52, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_AIE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[3], .highbit = 27, .lowbit = 24, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_ANERR] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[3], .highbit = 47, .lowbit = 44, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[3], .highbit = 43, .lowbit = 40, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_ATS1A] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 63, .lowbit = 60, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_CLRBHB] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_9_A,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_isar[6], .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 31, .lowbit = 28, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_CSSC] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_7_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 55, .lowbit = 52, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_DEBUGV8P9] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_9_A,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit =  3, .lowbit =  0, .value = 0x0B },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_DOUBLEFAULT2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[1],  .highbit = 59, .lowbit = 56, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_ECBHB] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_9_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 63, .lowbit = 60, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FGT2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[0], .highbit = 59, .lowbit = 56, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_HAFT] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_7_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit =  3, .lowbit =  0, .value = 0x03 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LRCPC3] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 23, .lowbit = 20, .value = 0x03 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_MTE_PERM] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_7_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[2],  .highbit =  3, .lowbit =  0, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_MTE_STORE_ONLY] = { /* sub-feature of FEAT_MTE4 */
			.ver_optional  = FEATURE_LEVEL_ARM_V8_7_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[2],  .highbit =  7, .lowbit =  4, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_MTE_TAGGED_FAR] = { /* sub-feature of FEAT_MTE4 */
			.ver_optional  = FEATURE_LEVEL_ARM_V8_7_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[2],  .highbit = 11, .lowbit =  8, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PFAR] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[1],  .highbit = 63, .lowbit = 60, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PMUV3_ICNTR] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[1],  .highbit = 39, .lowbit = 36, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PMUV3_SS] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 19, .lowbit = 16, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PMUV3P9] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 11, .lowbit =  8, .value = 0x09 },
				{ .aarch32_reg = &raw->arm_id_dfr[0],  .aarch64_reg = NULL,                     .highbit = 27, .lowbit = 24, .value = 0x09 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PRFMSLC] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 43, .lowbit = 40, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_RASV2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = &raw->arm_id_pfr[0],  .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 31, .lowbit = 28, .value = 0x03 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_RPRFM] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 51, .lowbit = 48, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_S1PIE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[3], .highbit = 11, .lowbit =  8, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_S1POE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[3], .highbit = 19, .lowbit = 16, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_S2PIE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[3], .highbit = 15, .lowbit = 12, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_S2POE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[3], .highbit = 23, .lowbit = 20, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SPECRES2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V8_9_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 43, .lowbit = 40, .value = 0x02 },
				{ .aarch32_reg = &raw->arm_id_isar[6], .aarch64_reg = NULL,                     .highbit = 19, .lowbit = 16, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SPE_DPFZS] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_6_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[1],  .highbit = 55, .lowbit = 52, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SPEV1P4] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 35, .lowbit = 32, .value = 0x05 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SPMU] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[1],  .highbit = 35, .lowbit = 32, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_THE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_8_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[1],  .highbit = 51, .lowbit = 48, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},

		/* Armv9.0 */
		[CPU_FEATURE_SVE2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64zfr[0],  .highbit =  3, .lowbit =  0, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SVE_AES] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64zfr[0],  .highbit =  7, .lowbit =  4, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SVE_BITPERM] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64zfr[0],  .highbit = 19, .lowbit = 16, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SVE_PMULL128] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64zfr[0],  .highbit =  7, .lowbit =  4, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SVE_SHA3] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64zfr[0],  .highbit = 35, .lowbit = 32, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SVE_SM4] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64zfr[0],  .highbit = 43, .lowbit = 40, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_TME] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[0], .highbit = 27, .lowbit = 24, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_TRBE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 47, .lowbit = 44, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},

		/* Armv9.2 */
		[CPU_FEATURE_BRBE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 55, .lowbit = 52, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_RME] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_1_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 55, .lowbit = 52, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SME] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[1],  .highbit = 27, .lowbit = 24, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SME_F64F64] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64smfr[0], .highbit = 48, .lowbit = 48, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SME_FA64] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64smfr[0], .highbit = 63, .lowbit = 63, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SME_I16I64] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64smfr[0], .highbit = 55, .lowbit = 52, .value = 0x0F },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},

		/* Armv9.3 */
		[CPU_FEATURE_BRBEV1P1] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 55, .lowbit = 52, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_MEC] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[3], .highbit = 31, .lowbit = 28, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SME2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64smfr[0], .highbit = 59, .lowbit = 56, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[1],  .highbit = 27, .lowbit = 24, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},

		/* Armv9.4 */
		[CPU_FEATURE_ABLE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[1],  .highbit = 43, .lowbit = 40, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_BWE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[1],  .highbit = 43, .lowbit = 40, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_D128] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[3], .highbit = 35, .lowbit = 32, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_EBEP] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[1],  .highbit = 51, .lowbit = 48, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_GCS] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[1],  .highbit = 47, .lowbit = 44, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_ITE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[1],  .highbit = 47, .lowbit = 44, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LSE128] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[1],  .highbit = 23, .lowbit = 20, .value = 0x03 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LVA3] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[2], .highbit = 19, .lowbit = 16, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SEBEP] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 27, .lowbit = 24, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SME2P1] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64smfr[0], .highbit = 59, .lowbit = 56, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SME_F16F16] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64smfr[0], .highbit = 42, .lowbit = 42, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SVE2P1] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64zfr[0],  .highbit =  3, .lowbit =  0, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SVE_B16B16] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64smfr[0], .highbit = 43, .lowbit = 43, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64zfr[0],  .highbit = 27, .lowbit = 24, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SYSINSTR128] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 39, .lowbit = 36, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SYSREG128] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 35, .lowbit = 32, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_TRBE_EXT] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_3_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[0],  .highbit = 59, .lowbit = 56, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_ASID2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_4_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V9_5_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[4], .highbit = 11, .lowbit =  8, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_BWE2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[2],  .highbit =  7, .lowbit =  4, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_CPA] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_4_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V9_5_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[3], .highbit =  3, .lowbit =  0, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_CPA2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[3], .highbit =  3, .lowbit =  0, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_E2H0] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V8_0_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[4], .highbit = 27, .lowbit = 24, .value = 0x00 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_E3DSE] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[4], .highbit = 39, .lowbit = 36, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_ETS3] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_4_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V9_5_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit = 39, .lowbit = 36, .value = 0x03 },
				{ .aarch32_reg = &raw->arm_id_mmfr[5], .aarch64_reg = NULL,                     .highbit =  3, .lowbit =  0, .value = 0x03 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FAMINMAX] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[3], .highbit =  7, .lowbit =  4, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FGWTE3] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[4], .highbit = 19, .lowbit = 16, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FP8] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64fpfr[0], .highbit = 31, .lowbit = 31, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64fpfr[0], .highbit =  1, .lowbit =  1, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64fpfr[0], .highbit =  0, .lowbit =  0, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FP8DOT2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64fpfr[0], .highbit = 28, .lowbit = 28, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FP8DOT4] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64fpfr[0], .highbit = 29, .lowbit = 29, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FP8FMA] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64fpfr[0], .highbit = 30, .lowbit = 30, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_FPMR] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[2],  .highbit = 35, .lowbit = 32, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_HACDBS] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[4], .highbit = 15, .lowbit = 12, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_HDBSS] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64mmfr[1], .highbit =  3, .lowbit =  0, .value = 0x04 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_LUT] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 59, .lowbit = 56, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_PAUTH_LR] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit =  7, .lowbit =  3, .value = 0x06 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[1], .highbit = 11, .lowbit =  8, .value = 0x06 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[2], .highbit = 15, .lowbit = 12, .value = 0x06 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_RME_GPC2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64pfr[0],  .highbit = 55, .lowbit = 52, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SME_F8F16] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64smfr[0], .highbit = 41, .lowbit = 41, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SME_F8F32] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64smfr[0], .highbit = 40, .lowbit = 40, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SME_LUTV2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64smfr[0], .highbit = 60, .lowbit = 60, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SPMU2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[1],  .highbit = 35, .lowbit = 32, .value = 0x02 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SSVE_FP8DOT2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64smfr[0], .highbit = 28, .lowbit = 28, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SSVE_FP8DOT4] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64smfr[0], .highbit = 29, .lowbit = 29, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_SSVE_FP8FMA] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_2_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64smfr[0], .highbit = 30, .lowbit = 30, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_STEP2] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_4_A,
			.ver_mandatory = FEATURE_LEVEL_ARM_V9_5_A,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64dfr[2],  .highbit =  3, .lowbit =  0, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
		[CPU_FEATURE_TLBIW] = {
			.ver_optional  = FEATURE_LEVEL_ARM_V9_4_A,
			.ver_mandatory = -1,
			.fields        = {
				{ .aarch32_reg = NULL,                 .aarch64_reg = &raw->arm_id_aa64isar[3], .highbit = 11, .lowbit =  8, .value = 0x01 },
				{ .aarch32_reg = NULL,                 .aarch64_reg = NULL,                     .highbit =  0, .lowbit =  0, .value = 0    }
			}
		},
	};

	for (feature = 0; feature < NUM_CPU_FEATURES; feature++)
		if (features_map[feature].ver_optional)
			match_arm_features(is_aarch64, feature, &features_map[feature], data, ext_status);

	/* Some fields do not follow the standard ID scheme */
	load_arm_feature_pauth(data, ext_status);
	load_arm_feature_mpam(raw, data, ext_status);
	load_arm_feature_mte4(raw, data, ext_status);
}

int cpuid_identify_arm(struct cpu_raw_data_t* raw, struct cpu_id_t* data)
{
	bool use_cpuid_scheme;
	struct arm_arch_extension_t ext_status;
	memset(&ext_status, 0, sizeof(struct arm_arch_extension_t));

	/* Basic values extraction
	   Based on "Arm Architecture Reference Manual for A-profile architecture", section D23.2.122 "MIDR_EL1, Main ID Register"
	*/
	data->arm.implementer = EXTRACTS_BITS(raw->arm_midr, 31, 24);
	data->arm.variant     = EXTRACTS_BITS(raw->arm_midr, 23, 20);
	data->arm.part_num    = EXTRACTS_BITS(raw->arm_midr, 15,  4);
	data->arm.revision    = EXTRACTS_BITS(raw->arm_midr,  3,  0);
	data->purpose         = cpuid_identify_purpose_arm(raw);

	/* Values decoding */
	const struct arm_hw_impl* hw_impl = get_cpu_implementer_from_code(data->arm.implementer);
	const struct arm_id_part* id_part = get_cpu_implementer_parts(hw_impl, data->arm.part_num);
	data->vendor = hw_impl->vendor;
	strncpy(data->vendor_str,      hw_impl->name,       VENDOR_STR_MAX);
	strncpy(data->brand_str,       id_part->name,       BRAND_STR_MAX);
	strncpy(data->cpu_codename,    id_part->codename,   CODENAME_STR_MAX);
	strncpy(data->technology_node, id_part->technology, TECHNOLOGY_STR_MAX);
	use_cpuid_scheme = (decode_arm_architecture_version_by_midr(raw, data) == false);
	load_arm_features(raw, data, &ext_status);
	if (use_cpuid_scheme)
		decode_arm_architecture_version_by_cpuid(raw, data, &ext_status);

	return 0;
}

void cpuid_get_list_arm(cpu_vendor_t vendor, struct cpu_list_t* list)
{
	int i, j, n, good, sub_count, total_count;
	char **tmp_names = NULL;
	const struct arm_hw_impl* hw_impl = get_cpu_implementer_from_vendor(vendor);

	/* Get item count in hw_impl->parts */
	sub_count = 0;
	for (i = 0; hw_impl->parts[i].id >= 0; i++)
		sub_count++;
	total_count = list->num_entries + sub_count;
	if (sub_count == 0)
		return;

	/* Grow current list */
	n = list->num_entries;
	tmp_names = (char**) realloc(list->names, sizeof(char*) * total_count);
	if (!tmp_names) { /* Memory allocation failure */
		cpuid_set_error(ERR_NO_MEM);
		return;
	}
	list->names = tmp_names;

	/* Append item to list */
	for (i = 0; i < sub_count; i++) {
		if (strstr(hw_impl->parts[i].name, "Unknown")) continue;
		good = 1;
		for (j = n - 1; j >= 0; j--)
			if (!strcmp(list->names[j], hw_impl->parts[i].name)) {
				good = 0;
				break;
			}
		if (!good) continue;
#if defined(_MSC_VER)
		list->names[n] = _strdup(hw_impl->parts[i].name);
#else
		list->names[n] = strdup(hw_impl->parts[i].name);
#endif
		if (!list->names[n]) { /* Memory allocation failure */
			cpuid_set_error(ERR_NO_MEM);
			list->num_entries = 0;
			for (j = 0; j < n; j++) {
				free(list->names[j]);
			}
			free(list->names);
			list->names = NULL;
			return;
		}
		n++;
	}
	list->num_entries = n;
}

cpu_purpose_t cpuid_identify_purpose_arm(struct cpu_raw_data_t* raw)
{
	const uint8_t implementer         = EXTRACTS_BITS(raw->arm_midr, 31, 24);
	const uint16_t part_num           = EXTRACTS_BITS(raw->arm_midr, 15,  4);
	const struct arm_hw_impl* hw_impl = get_cpu_implementer_from_code(implementer);
	const struct arm_id_part* id_part = get_cpu_implementer_parts(hw_impl, part_num);

	/* ARM big.LITTLE Typical Processor Combinations: https://www.arm.com/technologies/big-little */
	if (match_pattern(id_part->name, "Cortex-X[012356789]"))
		return PURPOSE_U_PERFORMANCE;
	else if (match_pattern(id_part->name, "Cortex-A[67][012356789]") || match_pattern(id_part->name, "Cortex-A[5][6789]"))
		return PURPOSE_PERFORMANCE;
	else if (match_pattern(id_part->name, "Cortex-A[5][012345]") || match_pattern(id_part->name, "Cortex-A[3][0123456789]"))
		return PURPOSE_EFFICIENCY;

	return PURPOSE_GENERAL;
}
