[edk2-devel] [PATCH v3] add ArmCpuInfo EFI application

Marcin Juszkiewicz posted 1 patch 1 year ago
Failed in applying to current master (apply log)
There is a newer version of this series
ArmPkg/ArmPkg.dsc                            |    1 +
ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf |   38 +
ArmPkg/Application/ArmCpuInfo/readargs.h     |   12 +
ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c   | 2317 ++++++++++++++++++++
ArmPkg/Application/ArmCpuInfo/readregs.s     |   49 +
5 files changed, 2417 insertions(+)
[edk2-devel] [PATCH v3] add ArmCpuInfo EFI application
Posted by Marcin Juszkiewicz 1 year ago
App goes through ID_AA64*_EL1 system registers and decode their values.

Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
---
 ArmPkg/ArmPkg.dsc                            |    1 +
 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf |   38 +
 ArmPkg/Application/ArmCpuInfo/readargs.h     |   12 +
 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c   | 2317 ++++++++++++++++++++
 ArmPkg/Application/ArmCpuInfo/readregs.s     |   49 +
 5 files changed, 2417 insertions(+)

diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
index 3fb95d1951a9..6b938ce8b671 100644
--- a/ArmPkg/ArmPkg.dsc
+++ b/ArmPkg/ArmPkg.dsc
@@ -166,6 +166,7 @@ [Components.AARCH64]
   ArmPkg/Drivers/ArmPsciMpServicesDxe/ArmPsciMpServicesDxe.inf
   ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.inf
   ArmPkg/Library/ArmMmuLib/ArmMmuPeiLib.inf
+  ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
 
 [Components.AARCH64, Components.ARM]
   ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStandaloneMmLib.inf
diff --git a/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
new file mode 100644
index 000000000000..158f86a4740c
--- /dev/null
+++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
@@ -0,0 +1,38 @@
+## @file
+#
+#  Attempt to have AArch64 cpu information.
+#
+#  Based on HelloWorld:
+#  Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.
+#  Copyright (c) 2023 Marcin Juszkiewicz
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010019
+  BASE_NAME                      = ArmCpuInfo
+  FILE_GUID                      = b3134491-6502-4faf-a9da-007184e32163
+  MODULE_TYPE                    = UEFI_APPLICATION
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = UefiMain
+
+#
+#  This flag specifies whether HII resource section is generated into PE image.
+#
+  UEFI_HII_RESOURCE_SECTION      = TRUE
+
+[Sources]
+  ArmCpuInfo.c
+  readregs.s
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  UefiApplicationEntryPoint
+  UefiLib
diff --git a/ArmPkg/Application/ArmCpuInfo/readargs.h b/ArmPkg/Application/ArmCpuInfo/readargs.h
new file mode 100644
index 000000000000..eaa52cf16145
--- /dev/null
+++ b/ArmPkg/Application/ArmCpuInfo/readargs.h
@@ -0,0 +1,12 @@
+UINT64 read_aa64pfr0_el1(void);
+UINT64 read_aa64pfr1_el1(void);
+UINT64 read_aa64dfr0_el1(void);
+UINT64 read_aa64dfr1_el1(void);
+UINT64 read_aa64isar0_el1(void);
+UINT64 read_aa64isar1_el1(void);
+UINT64 read_aa64isar2_el1(void);
+UINT64 read_aa64mmfr0_el1(void);
+UINT64 read_aa64mmfr1_el1(void);
+UINT64 read_aa64mmfr2_el1(void);
+UINT64 read_aa64smfr0_el1(void);
+UINT64 read_aa64zfr0_el1(void);
diff --git a/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
new file mode 100644
index 000000000000..6c31ad4dbcb9
--- /dev/null
+++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
@@ -0,0 +1,2317 @@
+/** @file
+
+  Copyright  (c) 2023 Marcin Juszkiewicz
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ **/
+
+#include <Library/UefiLib.h>
+#include "readargs.h"
+
+void
+print_text (
+  const char  *field,
+  const char  *bits,
+  const char  *value,
+  const char  *description
+  )
+{
+  AsciiPrint (" %-16a | %5a | %5a | %a\n", field, bits, value, description);
+}
+
+void
+print_values (
+  const char  *field,
+  const char  *bits,
+  const int   value,
+  const char  *description
+  )
+{
+  STATIC CONST CHAR8  binaries[][5] = {
+    "0000", "0001", "0010", "0011",
+    "0100", "0101", "0110", "0111","1000",  "1001", "1010", "1011",
+    "1100", "1101", "1110", "1111"
+  };
+
+  AsciiPrint (" %-16a | %5a | %5a | %a\n", field, bits, binaries[value & 0xf], description);
+}
+
+void
+print_spacer (
+  void
+  )
+{
+  AsciiPrint ("------------------|-------|-------|----------------------------------------------\n");
+}
+
+void
+handle_aa64mmfr0_el1 (
+  const UINT64  aa64mmfr0_el1
+  )
+{
+  UINT64              value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR0_EL1";
+  char                *description;
+  char                *bits;
+
+  bits  = "3:0 ";
+  value = aa64mmfr0_el1 & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "32 bits  (4GB) of physical address range supported.";
+      break;
+    case 0b0001:
+      description = "36 bits  (64GB) of physical address range supported.";
+      break;
+    case 0b0010:
+      description = "40 bits  (1TB) of physical address range supported.";
+      break;
+    case 0b0011:
+      description = "42 bits  (4TB) of physical address range supported.";
+      break;
+    case 0b0100:
+      description = "44 bits  (16TB) of physical address range supported.";
+      break;
+    case 0b0101:
+      description = "48 bits  (256TB) of physical address range supported.";
+      break;
+    case 0b0110:
+      description = "52 bits  (4PB) of physical address range supported.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+  if (value == 0b0110) {
+    print_text ("", "", "", "FEAT_LPA implemented.");
+  }
+
+  bits  = "7:4 ";
+  value = (aa64mmfr0_el1 >>  4) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "ASID: 8 bits";
+      break;
+    case 0b0010:
+      description = "ASID: 16 bits";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "11:8 ";
+  value = (aa64mmfr0_el1 >>  8) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "No mixed-endian support.";
+      break;
+    case 0b0001:
+      description = "Mixed-endian support.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  // only valid for BigEnd != 0b0000
+  if (((aa64mmfr0_el1 >>  8) & 0xf) != 0b0000 ) {
+    if (((aa64mmfr0_el1 >> 16) & 0xf) == 0b0000 ) {
+      print_values ("ID_AA64MMFR0_EL1", "19:16", 0b0000, "No mixed-endian support at EL0.");
+    }
+
+    if (((aa64mmfr0_el1 >> 16) & 0xf) == 0b0001 ) {
+      print_values ("ID_AA64MMFR0_EL1", "19:16", 0b0001, "Mixed-endian support at EL0.");
+    }
+  }
+
+  bits  = "15:12";
+  value = (aa64mmfr0_el1 >> 12) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "No support for a distinction between Secure and Non-Secure Memory.";
+      break;
+    case 0b0001:
+      description = "Supports a distinction between Secure and Non-Secure Memory.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "31:28";
+  value = (aa64mmfr0_el1 >> 28) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = " 4KB granule supported.";
+      break;
+    case 0b1111:
+      description = " 4KB granule not supported.";
+      break;
+    case 0b0001:             // add FEAT_LPA2 check
+      description = " 4KB granule supported for 52-bit address.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "43:40";
+  value = (aa64mmfr0_el1 >> 40) & 0xf;
+  switch (value) {
+    case 0b0001:
+      description = " 4KB granule not supported at stage 2.";
+      break;
+    case 0b0010:
+      description = " 4KB granule supported at stage 2.";
+      break;
+    case 0b0011:
+      description = " 4KB granule supported at stage 2 for 52-bit address.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "23:20";
+  value = (aa64mmfr0_el1 >> 20) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "16KB granule not supported.";
+      break;
+    case 0b0001:
+      description = "16KB granule supported.";
+      break;
+    case 0b0010:             // add FEAT_LPA2 check
+      description = "16KB granule supported for 52-bit address.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "35:32";
+  value = (aa64mmfr0_el1 >> 32) & 0xf;
+  switch (value) {
+    case 0b0001:
+      description = "16KB granule not supported at stage 2.";
+      break;
+    case 0b0010:
+      description = "16KB granule supported at stage 2.";
+      break;
+    case 0b0011:
+      description = "16KB granule supported at stage 2 for 52-bit address.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "27:24";
+  value = (aa64mmfr0_el1 >> 24) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "64KB granule supported.";
+      break;
+    case 0b1111:
+      description = "64KB granule not supported.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "39:36";
+  value = (aa64mmfr0_el1 >> 36) & 0xf;
+  switch (value) {
+    case 0b0001:
+      description = "64KB granule not supported at stage 2.";
+      break;
+    case 0b0010:
+      description = "64KB granule supported at stage 2.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "47:44";
+  value = (aa64mmfr0_el1 >> 44) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_ExS not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_ExS implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  // 55:48 reserved
+
+  bits  = "59:56";
+  value = (aa64mmfr0_el1 >> 56) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_FGT not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_FGT implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "63:60";
+  value = (aa64mmfr0_el1 >> 60) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_ECV not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_ECV implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_ECV implemented with extras.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+}
+
+void
+handle_aa64mmfr1_el1 (
+  const UINT64  aa64mmfr1_el1,
+  const UINT64  aa64pfr0_el1
+  )
+{
+  UINT64              value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR1_EL1";
+  char                *description;
+  char                *bits;
+
+  bits  = "3:0 ";
+  value = aa64mmfr1_el1 & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_HAFDBS not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_HAFDBS implemented without dirty status support.";
+      break;
+    case 0b0010:
+      description = "FEAT_HAFDBS implemented with dirty status support.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "7:4 ";
+  value = (aa64mmfr1_el1 >>  4) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_VMID16 not implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_VMID16 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "11:8 ";
+  value = (aa64mmfr1_el1 >>  8) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_VHE not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_VHE implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "15:12";
+  value = (aa64mmfr1_el1 >> 12) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_HPDS not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_HPDS implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_HPDS2 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "19:16";
+  value = (aa64mmfr1_el1 >> 16) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_LOR not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_LOR implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "23:20";
+  value = (aa64mmfr1_el1 >> 20) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_PAN not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_PAN implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_PAN2 implemented.";
+      break;
+    case 0b0011:
+      description = "FEAT_PAN3 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  // when FEAT_RAS implemented
+  if ((((aa64pfr0_el1 >> 28) & 0xf) == 0b0001) ||
+      (((aa64pfr0_el1 >> 28) & 0xf) == 0b0010))
+  {
+    if (((aa64mmfr1_el1 >> 24) & 0xf) == 0b0000 ) {
+      print_values ("ID_AA64MMFR1_EL1", "27:24", 0b0000, "The PE never generates an SError interrupt due to");
+      print_text ("", "", "", "an External abort on a speculative read.");
+    }
+
+    if (((aa64mmfr1_el1 >> 24) & 0xf) == 0b0001 ) {
+      print_values ("ID_AA64MMFR1_EL1", "27:24", 0b0001, "The PE might generate an SError interrupt due to");
+      print_text ("", "", "", "an External abort on a speculative read.");
+    }
+  }
+
+  bits  = "31:28";
+  value = (aa64mmfr1_el1 >> 28) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_XNX not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_XNX implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "35:32";
+  value = (aa64mmfr1_el1 >> 32) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_TWED not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_TWED implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "39:36";
+  value = (aa64mmfr1_el1 >> 36) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_ETS not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_ETS implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "43:40";
+  value = (aa64mmfr1_el1 >> 40) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_HCX not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_HCX implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "47:44";
+  value = (aa64mmfr1_el1 >> 44) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_AFP not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_AFP implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "51:48";
+  value = (aa64mmfr1_el1 >> 48) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_nTLBPA not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_nTLBPA implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "55:52";
+  value = (aa64mmfr1_el1 >> 52) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_TIDCP1 not implemented";
+      break;
+    case 0b0001:
+      description = "FEAT_TIDCP1 implemented";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "59:56";
+  value = (aa64mmfr1_el1 >> 56) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_CMOW not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_CMOW implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  // 63:60 reserved
+}
+
+void
+handle_aa64mmfr2_el1 (
+  const UINT64  aa64mmfr2_el1
+  )
+{
+  UINT64              value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR2_EL1";
+  char                *description;
+  char                *bits;
+
+  bits  = "3:0 ";
+  value = (aa64mmfr2_el1)       & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_TTCNP not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_TTCNP implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "7:4 ";
+  value = (aa64mmfr2_el1 >>  4) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_UAO not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_UAO implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "11:8 ";
+  value = (aa64mmfr2_el1 >>  8) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_LSMAOC not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_LSMAOC implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "15:12";
+  value = (aa64mmfr2_el1 >> 12) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_IESB not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_IESB implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "19:16";
+  value = (aa64mmfr2_el1 >> 16) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_LVA not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_LVA implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "23:20";
+  value = (aa64mmfr2_el1 >> 20) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_CCIDX not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_CCIDX implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "27:24";
+  value = (aa64mmfr2_el1 >> 24) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_NV not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_NV implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_NV2 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "31:28";
+  value = (aa64mmfr2_el1 >> 28) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_TTST not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_TTST implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "35:32";
+  value = (aa64mmfr2_el1 >> 32) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_LSE2 not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_LSE2 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "39:36";
+  value = (aa64mmfr2_el1 >> 36) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_IDST not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_IDST implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "43:40";
+  value = (aa64mmfr2_el1 >> 40) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_S2FWB not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_S2FWB implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  // 47:44 reserved
+
+  bits  = "51:48";
+  value = (aa64mmfr2_el1 >> 48) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_TTL not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_TTL implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "55:52";
+  value = (aa64mmfr2_el1 >> 52) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_BBM: Level 0 support for changing block size is supported.";
+      break;
+    case 0b0001:
+      description = "FEAT_BBM: Level 1 support for changing block size is supported.";
+      break;
+    case 0b0010:
+      description = "FEAT_BBM: Level 2 support for changing block size is supported.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "59:56";
+  value = (aa64mmfr2_el1 >> 56) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_EVT not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_EVT: HCR_EL2.{TOCU, TICAB, TID4} traps are supported.";
+      break;
+    case 0b0010:
+      description = "FEAT_EVT: HCR_EL2.{TTLBOS, TTLSBIS, TOCU, TICAB, TID4} traps are supported.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "63:60";
+  value = (aa64mmfr2_el1 >> 60) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_E0PD not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_E0PD implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+}
+
+void
+handle_aa64pfr0_el1 (
+  const UINT64  aa64pfr0_el1,
+  const UINT64  aa64pfr1_el1
+  )
+{
+  UINT64              value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR0_EL1";
+  char                *description;
+  char                *bits;
+
+  bits  = "3:0 ";
+  value = (aa64pfr0_el1)       & 0xf;
+  switch (value) {
+    case 0b0001:
+      description = "EL0 in AArch64 only";
+      break;
+    case 0b0010:
+      description = "EL0 in AArch64 and AArch32";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "7:4 ";
+  value = (aa64pfr0_el1 >>  4) & 0xf;
+  switch (value) {
+    case 0b0001:
+      description = "EL1 in AArch64 only";
+      break;
+    case 0b0010:
+      description = "EL1 in AArch64 and AArch32";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "11:8 ";
+  value = (aa64pfr0_el1 >>  8) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "EL2 not implemented.";
+      break;
+    case 0b0001:
+      description = "EL2 in AArch64 only";
+      break;
+    case 0b0010:
+      description = "EL2 in AArch64 and AArch32";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "15:12";
+  value = (aa64pfr0_el1 >> 12) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "EL3 not implemented.";
+      break;
+    case 0b0001:
+      description = "EL3 in AArch64 only";
+      break;
+    case 0b0010:
+      description = "EL3 in AArch64 and AArch32";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "19:16";
+  value = (aa64pfr0_el1 >> 16) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "Floating-point implemented.";
+      break;
+    case 0b0001:
+      description = "Floating-point with half-precision support  (FEAT_FP16).";
+      break;
+    case 0b1111:
+      description = "Floating-point not implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "23:20";
+  value = (aa64pfr0_el1 >> 20) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "Advanced SIMD implemented.";
+      break;
+    case 0b0001:
+      description = "Advanced SIMD with half precision support  (FEAT_FP16).";
+      break;
+    case 0b1111:
+      description = "Advanced SIMD not implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "27:24";
+  value = (aa64pfr0_el1 >> 24) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "System registers of GIC CPU not implemented.";
+      break;
+    case 0b0001:
+      description = "System registers to versions 3.0/4.0 of GIC CPU implemented.";
+      break;
+    case 0b0011:
+      description = "System registers to versions 4.1 of GIC CPU implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "31:28";
+  value = (aa64pfr0_el1 >> 28) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_RAS not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_RAS implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_RASv1p1 implemented.";
+      // 0b0010 FEAT_RASv1p1 implemented and, if EL3 is implemented, FEAT_DoubleFault implemented.
+      if ((((aa64pfr0_el1 >> 12) & 0xf) == 0b0001) ||
+          (((aa64pfr0_el1 >> 12) & 0xf) == 0b0010))
+      {
+        description = "FEAT_RASv1p1 implemented. FEAT_DoubleFault implemented.";
+      }
+
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "35:32";
+  value = (aa64pfr0_el1 >> 32) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_SVE not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_SVE implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "39:36";
+  value = (aa64pfr0_el1 >> 36) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "Secure EL2 not implemented.";
+      break;
+    case 0b0001:
+      description = "Secure EL2 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "43:40";
+  value = (aa64pfr0_el1 >> 40) & 0xf;
+  switch (value) {
+    case 0b0000:
+      if (((aa64pfr1_el1 >> 16) & 0xf) == 0b0000 ) {
+        description = "FEAT_MPAM not implemented.";
+      }
+
+      if (((aa64pfr1_el1 >> 16) & 0xf) == 0b0001 ) {
+        description = "FEAT_MPAM v0.1 implemented.";
+      }
+
+      break;
+    case 0b0001:
+      if (((aa64pfr1_el1 >> 16) & 0xf) == 0b0000 ) {
+        description = "FEAT_MPAM v1.0 implemented.";
+      }
+
+      if (((aa64pfr1_el1 >> 16) & 0xf) == 0b0001 ) {
+        description = "FEAT_MPAM v1.1 implemented.";
+      }
+
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "47:44";
+  value = (aa64pfr0_el1 >> 44) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_AMU not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_AMUv1 implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_AMUv1p1 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "51:48";
+  value = (aa64pfr0_el1 >> 48) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_DIT not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_DIT implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "55:52";
+  value = (aa64pfr0_el1 >> 52) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_RME not implemented";
+      break;
+    case 0b0001:
+      description = "FEAT_RME implemented";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "59:56";
+  value = (aa64pfr0_el1 >> 56) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "no info is FEAT_CSV2 implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_CSV2 implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_CSV2_2 implemented.";
+      break;
+    case 0b0011:
+      description = "FEAT_CSV2_3 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+  if (value == 0b0001) {
+    if (((aa64pfr1_el1 >> 32) & 0xf) == 0b0001 ) {
+      print_values ("ID_AA64PRF1_EL1", "35:32", 0b0001, "FEAT_CSV2_1p1 implemented.");
+    }
+
+    if (((aa64pfr1_el1 >> 32) & 0xf) == 0b0010 ) {
+      print_values ("ID_AA64PRF1_EL1", "35:32", 0b0010, "FEAT_CSV2_1p2 implemented.");
+    }
+  }
+
+  bits  = "63:60";
+  value = (aa64pfr0_el1 >> 60) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_CSV3 not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_CSV3 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+}
+
+void
+handle_aa64pfr1_el1 (
+  const UINT64  aa64pfr1_el1
+  )
+{
+  UINT64              value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR1_EL1";
+  char                *description;
+  char                *bits;
+
+  bits  = "3:0 ";
+  value = aa64pfr1_el1 & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_BTI not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_BTI implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "7:4 ";
+  value = (aa64pfr1_el1 >>  4) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_SSBS not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_SSBS implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_SSBS2 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "11:8 ";
+  value = (aa64pfr1_el1 >>  8) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_MTE not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_MTE implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_MTE2 implemented.";
+      break;
+    case 0b0011:
+      description = "FEAT_MTE3 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  // 15:12 is RAS_frac
+  // 19:16 is MPAM_frac
+  // 23:20 is reserved
+
+  bits  = "27:24";
+  value = (aa64pfr1_el1 >> 24) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_SME not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_SME implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "31:28";
+  value = (aa64pfr1_el1 >> 28) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_RNG_TRAP not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_RNG_TRAP implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  // 35:32 is CSV2_frac
+
+  bits  = "39:36";
+  value = (aa64pfr1_el1 >> 36) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_NMI not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_NMI implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  // 63:40 are reserved
+}
+
+void
+handle_aa64isar0_el1 (
+  const UINT64  aa64isar0_el1
+  )
+{
+  UINT64              value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR0_EL1";
+  char                *description;
+  char                *bits;
+
+  // 3:0 reserved
+
+  bits  = "7:4 ";
+  value = (aa64isar0_el1 >>  4) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_AES, FEAT_PMULL not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_AES implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_AES and FEAT_PMULL implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "11:8 ";
+  value = (aa64isar0_el1 >>  8) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_SHA1 not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_SHA1 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "15:12";
+  value = (aa64isar0_el1 >> 12) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_SHA256, FEAT_SHA512 not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_SHA256 implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_SHA512 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "19:16";
+  value = (aa64isar0_el1 >> 16) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "CRC32 not implemented.";
+      break;
+    case 0b0001:
+      description = "CRC32 instructions implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "23:20";
+  value = (aa64isar0_el1 >> 20) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_LSE not implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_LSE implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "27:24";
+  value = (aa64isar0_el1 >> 24) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "TME instructions not implemented.";
+      break;
+    case 0b0001:
+      description = "TME instructions implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "31:28";
+  value = (aa64isar0_el1 >> 28) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_RDM not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_RDM implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "35:32";
+  value = (aa64isar0_el1 >> 32) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_SHA3 not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_SHA3 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "39:36";
+  value = (aa64isar0_el1 >> 36) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_SM3 not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_SM3 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "43:40";
+  value = (aa64isar0_el1 >> 40) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_SM4 not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_SM4 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "47:44";
+  value = (aa64isar0_el1 >> 44) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_DotProd not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_DotProd implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "51:48";
+  value = (aa64isar0_el1 >> 48) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_FHM not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_FHM implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "55:52";
+  value = (aa64isar0_el1 >> 52) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_FlagM/FEAT_FlagM2 not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_FlagM implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_FlagM2 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "59:56";
+  value = (aa64isar0_el1 >> 56) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_TLBIOS/FEAT_TLBIRANGE not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_TLBIOS implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_TLBIRANGE implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "63:60";
+  value = (aa64isar0_el1 >> 60) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_RNG not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_RNG implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+}
+
+void
+handle_aa64isar1_el1 (
+  const UINT64  aa64isar1_el1
+  )
+{
+  UINT64              value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR1_EL1";
+  char                *description;
+  char                *bits;
+
+  bits  = "3:0 ";
+  value = (aa64isar1_el1 >>  4) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "DC CVAP not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_DPB implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_DPB2 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "7:4 ";
+  value = (aa64isar1_el1 >>  4) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "Address Authentication  (APA) not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_PAuth implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_EPAC implemented.";
+      break;
+    case 0b0011:
+      description = "FEAT_PAuth2 implemented.";
+      break;
+    case 0b0100:
+      description = "FEAT_FPAC implemented.";
+      break;
+    case 0b0101:
+      description = "FEAT_FPACCOMBINE implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+  if (value > 0) {
+    print_text ("", "", "", "FEAT_PACQARMA5 implemented.");
+  }
+
+  bits  = "11:8 ";
+  value = (aa64isar1_el1 >>  8) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "Address Authentication  (API) not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_PAuth implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_EPAC implemented.";
+      break;
+    case 0b0011:
+      description = "FEAT_PAuth2 implemented.";
+      break;
+    case 0b0100:
+      description = "FEAT_FPAC implemented.";
+      break;
+    case 0b0101:
+      description = "FEAT_FPACCOMBINE implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+  if (value > 0) {
+    print_text ("", "", "", "FEAT_PACIMP implemented.");
+  }
+
+  bits  = "15:12";
+  value = (aa64isar1_el1 >> 12) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_JSCVT not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_JSCVT implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "19:16";
+  value = (aa64isar1_el1 >> 16) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_FCMA not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_FCMA implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "23:20";
+  value = (aa64isar1_el1 >> 20) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_LRCPC (2) not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_LRCPC implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_LRCPC2 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "27:24";
+  value = (aa64isar1_el1 >> 24) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_PACQARMA5 not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_PACQARMA5 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "31:28";
+  value = (aa64isar1_el1 >> 28) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_PACIMP not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_PACIMP implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "35:32";
+  value = (aa64isar1_el1 >> 32) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_FRINTTS not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_FRINTTS implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "39:36";
+  value = (aa64isar1_el1 >> 36) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_SB not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_SB implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "43:40";
+  value = (aa64isar1_el1 >> 40) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_SPECRES not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_SPECRES implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "47:44";
+  value = (aa64isar1_el1 >> 44) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_BF16 not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_BF16 implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_EBF16 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "51:48";
+  value = (aa64isar1_el1 >> 48) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_DGH not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_DGH implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "55:52";
+  value = (aa64isar1_el1 >> 52) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_I8MM not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_I8MM implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "59:56";
+  value = (aa64isar1_el1 >> 56) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_XS not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_XS implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "63:60";
+  value = (aa64isar1_el1 >> 60) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_LS64 not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_LS64 implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_LS64_V implemented.";
+      break;
+    case 0b0011:
+      description = "FEAT_LS64_ACCDATA implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+}
+
+void
+handle_aa64isar2_el1 (
+  const UINT64  aa64isar2_el1
+  )
+{
+  UINT64              value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR2_EL1";
+  char                *description;
+  char                *bits;
+
+  bits  = "3:0 ";
+  value = (aa64isar2_el1 >>  4) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_WFxT not implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_WFxT implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "7:4 ";
+  value = (aa64isar2_el1 >>  4) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_RPRES not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_RPRES implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "11:8 ";
+  value = (aa64isar2_el1 >>  8) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_PACQARMA3 not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_PACQARMA3 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "15:12";
+  value = (aa64isar2_el1 >> 12) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "Address Authentication  (APA3) not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_PAuth implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_EPAC implemented.";
+      break;
+    case 0b0011:
+      description = "FEAT_PAuth2 implemented.";
+      break;
+    case 0b0100:
+      description = "FEAT_FPAC implemented.";
+      break;
+    case 0b0101:
+      description = "FEAT_FPACCOMBINE implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "19:16";
+  value = (aa64isar2_el1 >> 16) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_MOPS not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_MOPS implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "23:20";
+  value = (aa64isar2_el1 >> 20) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_HBC not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_HBC implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "27:24";
+  value = (aa64isar2_el1 >> 24) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_CONSTPACFIELD not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_CONSTPACFIELD implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  // 63:28 reserved
+}
+
+void
+handle_aa64dfr0_el1 (
+  const UINT64  aa64dfr0_el1
+  )
+{
+  UINT64              value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64DFR0_EL1";
+  char                *description;
+  char                *bits;
+
+  bits  = "3:0 ";
+  value = (aa64dfr0_el1 >>  4) & 0xf;
+  switch (value) {
+    case 0b0110:
+      description = "Armv8 debug architecture";
+      break;
+    case 0b0111:
+      description = "Armv8 debug architecture with VHE";
+      break;
+    case 0b1000:
+      description = "FEAT_Debugv8p2 implemented.";
+      break;
+    case 0b1001:
+      description = "FEAT_Debugv8p4 implemented.";
+      break;
+    case 0b1010:
+      description = "FEAT_Debugv8p8 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "7:4 ";
+  value = (aa64dfr0_el1 >>  4) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "Trace unit System registers not implemented.";
+      break;
+    case 0b0001:
+      description = "Trace unit System registers implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "11:8 ";
+  value = (aa64dfr0_el1 >>  8) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "Performance Monitors Extension not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_PMUv3 implemented.";
+      break;
+    case 0b0100:
+      description = "FEAT_PMUv3p1 implemented.";
+      break;
+    case 0b0101:
+      description = "FEAT_PMUv3p4 implemented.";
+      break;
+    case 0b0110:
+      description = "FEAT_PMUv3p5 implemented.";
+      break;
+    case 0b0111:
+      description = "FEAT_PMUv3p7 implemented.";
+      break;
+    case 0b1000:
+      description = "FEAT_PMUv3p8 implemented.";
+      break;
+    case 0b1111:
+      description = "IMPLEMENTATION DEFINED form of performance monitors supported.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "15:12";
+  value = (aa64dfr0_el1 >> 12) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "reserved";
+      break;
+    default:
+      description = "Number of breakpoints, minus 1.";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  // 19:16 reserved
+
+  bits  = "23:20";
+  value = (aa64dfr0_el1 >> 20) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "reserved";
+      break;
+    default:
+      description = "Number of watchpoints, minus 1.";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  // 27:24 reserved
+
+  bits  = "31:28";
+  value = (aa64dfr0_el1 >> 28) & 0xf;
+  switch (value) {
+    default:
+      description = "Number of breakpoints that are context-aware, minus 1.";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "35:32";
+  value = (aa64dfr0_el1 >> 32) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_SPE not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_SPE implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_SPEv1p1 implemented.";
+      break;
+    case 0b0011:
+      description = "FEAT_SPEv1p2 implemented.";
+      break;
+    case 0b0100:
+      description = "FEAT_SPEv1p3 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "39:36";
+  value = (aa64dfr0_el1 >> 36) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_DoubleLock implemented.";
+      break;
+    case 0b1111:
+      description = "FEAT_DoubleLock not implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "43:40";
+  value = (aa64dfr0_el1 >> 40) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_TRF not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_TRF implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "47:44";
+  value = (aa64dfr0_el1 >> 44) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_TRBE not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_TRBE implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "51:48";
+  value = (aa64dfr0_el1 >> 48) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_MTPMU not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_MTPMU and FEAT_PMUv3 implemented.";
+      break;
+    case 0b1111:
+      description = "FEAT_MTPMU not implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  bits  = "55:52";
+  value = (aa64dfr0_el1 >> 52) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "FEAT_BRBE not implemented.";
+      break;
+    case 0b0001:
+      description = "FEAT_BRBE implemented.";
+      break;
+    case 0b0010:
+      description = "FEAT_BRBEv1p1 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+
+  // 59:56 reserved
+
+  bits  = "63:60";
+  value = (aa64dfr0_el1 >> 60) & 0xf;
+  switch (value) {
+    case 0b0000:
+      description = "Setting MDCR_EL2.HPMN to zero has CONSTRAINED UNPREDICTABLE behavior.";
+      break;
+    case 0b0001:
+      description = "FEAT_HPMN0 implemented.";
+      break;
+    default:
+      description = "unknown";
+      break;
+  }
+
+  print_values (RegName, bits, value, description);
+}
+
+EFI_STATUS
+EFIAPI
+UefiMain  (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  UINT64  aa64dfr0_el1  = read_aa64dfr0_el1 ();
+  UINT64  aa64dfr1_el1  = read_aa64dfr1_el1 ();
+  UINT64  aa64isar0_el1 = read_aa64isar0_el1 ();
+  UINT64  aa64isar1_el1 = read_aa64isar1_el1 ();
+  UINT64  aa64isar2_el1 = read_aa64isar2_el1 ();
+  UINT64  aa64mmfr0_el1 = read_aa64mmfr0_el1 ();
+  UINT64  aa64mmfr1_el1 = read_aa64mmfr1_el1 ();
+  UINT64  aa64mmfr2_el1 = read_aa64mmfr2_el1 ();
+  UINT64  aa64pfr0_el1  = read_aa64pfr0_el1 ();
+  UINT64  aa64pfr1_el1  = read_aa64pfr1_el1 ();
+
+  /*    UINT64 aa64smfr0_el1 = read_aa64smfr0_el1 ();*/
+  /*    UINT64 aa64zfr0_el1 = read_aa64zfr0_el1 ();*/
+
+  AsciiPrint ("ID_AA64MMFR0_EL1 = 0x%016lx\n", aa64mmfr0_el1);
+  AsciiPrint ("ID_AA64MMFR1_EL1 = 0x%016lx\n", aa64mmfr1_el1);
+  AsciiPrint ("ID_AA64MMFR2_EL1 = 0x%016lx\n", aa64mmfr2_el1);
+  AsciiPrint ("ID_AA64PFR0_EL1  = 0x%016lx\n", aa64pfr0_el1);
+  AsciiPrint ("ID_AA64PFR1_EL1  = 0x%016lx\n", aa64pfr1_el1);
+  AsciiPrint ("ID_AA64ISAR0_EL1 = 0x%016lx\n", aa64isar0_el1);
+  AsciiPrint ("ID_AA64ISAR1_EL1 = 0x%016lx\n", aa64isar1_el1);
+  AsciiPrint ("ID_AA64ISAR2_EL1 = 0x%016lx\n", aa64isar2_el1);
+  AsciiPrint ("ID_AA64DFR0_EL1  = 0x%016lx\n", aa64dfr0_el1);
+  AsciiPrint ("ID_AA64DFR1_EL1  = 0x%016lx\n", aa64dfr1_el1);            // ignore
+  /*    AsciiPrint ("ID_AA64SMFR0_EL1 = 0x%016lx\n", aa64smfr0_el1);*/
+  /*    AsciiPrint ("ID_AA64ZFR0_EL1 = 0x%016lx\n", aa64zfr0_el1);*/
+
+  AsciiPrint ("\n");
+  print_text ("Register", "Bits", "Value", "Feature");
+  print_spacer ();
+
+  handle_aa64mmfr0_el1 (aa64mmfr0_el1);
+  print_spacer ();
+  handle_aa64mmfr1_el1 (aa64mmfr1_el1, aa64pfr0_el1);
+  print_spacer ();
+  handle_aa64mmfr2_el1 (aa64mmfr2_el1);
+
+  print_spacer ();
+  handle_aa64pfr0_el1 (aa64pfr0_el1, aa64pfr1_el1);
+  print_spacer ();
+  handle_aa64pfr1_el1 (aa64pfr1_el1);
+
+  print_spacer ();
+  handle_aa64isar0_el1 (aa64isar0_el1);
+  print_spacer ();
+  handle_aa64isar1_el1 (aa64isar1_el1);
+  print_spacer ();
+  handle_aa64isar2_el1 (aa64isar2_el1);
+
+  print_spacer ();
+  handle_aa64dfr0_el1 (aa64dfr0_el1);
+
+  return EFI_SUCCESS;
+}
diff --git a/ArmPkg/Application/ArmCpuInfo/readregs.s b/ArmPkg/Application/ArmCpuInfo/readregs.s
new file mode 100644
index 000000000000..052834b3c3f2
--- /dev/null
+++ b/ArmPkg/Application/ArmCpuInfo/readregs.s
@@ -0,0 +1,49 @@
+#include <AsmMacroIoLibV8.h>
+
+ASM_FUNC(read_aa64pfr0_el1)
+        mrs x0, ID_AA64PFR0_EL1;
+        ret;
+
+ASM_FUNC(read_aa64pfr1_el1)
+        mrs x0, ID_AA64PFR1_EL1;
+        ret;
+
+ASM_FUNC(read_aa64dfr0_el1)
+        mrs x0, ID_AA64DFR0_EL1;
+        ret;
+
+ASM_FUNC(read_aa64dfr1_el1)
+        mrs x0, ID_AA64DFR1_EL1;
+        ret;
+
+ASM_FUNC(read_aa64isar0_el1)
+        mrs x0, ID_AA64ISAR0_EL1;
+        ret;
+
+ASM_FUNC(read_aa64isar1_el1)
+        mrs x0, ID_AA64ISAR1_EL1;
+        ret;
+
+ASM_FUNC(read_aa64isar2_el1)
+        mrs x0, ID_AA64ISAR2_EL1;
+        ret;
+
+ASM_FUNC(read_aa64mmfr0_el1)
+        mrs x0, ID_AA64MMFR0_EL1;
+        ret;
+
+ASM_FUNC(read_aa64mmfr1_el1)
+        mrs x0, ID_AA64MMFR1_EL1;
+        ret;
+
+ASM_FUNC(read_aa64mmfr2_el1)
+        mrs x0, ID_AA64MMFR2_EL1;
+        ret;
+
+# ASM_FUNC(read_aa64zfr0_el1)
+#     mrs x0, ID_AA64ZFR0_EL1;
+#     ret;
+
+# ASM_FUNC(read_aa64smfr0_el1)
+#     mrs x0, ID_AA64SMFR0_EL1;
+#     ret;
-- 
2.40.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#102694): https://edk2.groups.io/g/devel/message/102694
Mute This Topic: https://groups.io/mt/98123579/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH v3] add ArmCpuInfo EFI application
Posted by Pedro Falcato 1 year ago
On Fri, Apr 7, 2023 at 1:47 PM Marcin Juszkiewicz
<marcin.juszkiewicz@linaro.org> wrote:
>
> App goes through ID_AA64*_EL1 system registers and decode their values.
>
> Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
> ---
>  ArmPkg/ArmPkg.dsc                            |    1 +
>  ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf |   38 +
>  ArmPkg/Application/ArmCpuInfo/readargs.h     |   12 +
>  ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c   | 2317 ++++++++++++++++++++
>  ArmPkg/Application/ArmCpuInfo/readregs.s     |   49 +
>  5 files changed, 2417 insertions(+)
>
> diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
> index 3fb95d1951a9..6b938ce8b671 100644
> --- a/ArmPkg/ArmPkg.dsc
> +++ b/ArmPkg/ArmPkg.dsc
> @@ -166,6 +166,7 @@ [Components.AARCH64]
>    ArmPkg/Drivers/ArmPsciMpServicesDxe/ArmPsciMpServicesDxe.inf
>    ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.inf
>    ArmPkg/Library/ArmMmuLib/ArmMmuPeiLib.inf
> +  ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
>
>  [Components.AARCH64, Components.ARM]
>    ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStandaloneMmLib.inf
> diff --git a/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
> new file mode 100644
> index 000000000000..158f86a4740c
> --- /dev/null
> +++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
> @@ -0,0 +1,38 @@
> +## @file
> +#
> +#  Attempt to have AArch64 cpu information.
> +#
> +#  Based on HelloWorld:
> +#  Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.
> +#  Copyright (c) 2023 Marcin Juszkiewicz
> +#
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x00010019
> +  BASE_NAME                      = ArmCpuInfo
> +  FILE_GUID                      = b3134491-6502-4faf-a9da-007184e32163
> +  MODULE_TYPE                    = UEFI_APPLICATION
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = UefiMain
> +
> +#
> +#  This flag specifies whether HII resource section is generated into PE image.
> +#
> +  UEFI_HII_RESOURCE_SECTION      = TRUE
> +
> +[Sources]
> +  ArmCpuInfo.c
> +  readregs.s
> +
> +[Packages]
> +  ArmPkg/ArmPkg.dec
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +
> +[LibraryClasses]
> +  UefiApplicationEntryPoint
> +  UefiLib
> diff --git a/ArmPkg/Application/ArmCpuInfo/readargs.h b/ArmPkg/Application/ArmCpuInfo/readargs.h
> new file mode 100644
> index 000000000000..eaa52cf16145
> --- /dev/null
> +++ b/ArmPkg/Application/ArmCpuInfo/readargs.h
> @@ -0,0 +1,12 @@
> +UINT64 read_aa64pfr0_el1(void);
> +UINT64 read_aa64pfr1_el1(void);
> +UINT64 read_aa64dfr0_el1(void);
> +UINT64 read_aa64dfr1_el1(void);
> +UINT64 read_aa64isar0_el1(void);
> +UINT64 read_aa64isar1_el1(void);
> +UINT64 read_aa64isar2_el1(void);
> +UINT64 read_aa64mmfr0_el1(void);
> +UINT64 read_aa64mmfr1_el1(void);
> +UINT64 read_aa64mmfr2_el1(void);
> +UINT64 read_aa64smfr0_el1(void);
> +UINT64 read_aa64zfr0_el1(void);
> diff --git a/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
> new file mode 100644
> index 000000000000..6c31ad4dbcb9
> --- /dev/null
> +++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
> @@ -0,0 +1,2317 @@
> +/** @file
> +
> +  Copyright  (c) 2023 Marcin Juszkiewicz
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + **/
> +
> +#include <Library/UefiLib.h>
> +#include "readargs.h"
> +
> +void
> +print_text (
> +  const char  *field,
> +  const char  *bits,
> +  const char  *value,
> +  const char  *description
> +  )
> +{
> +  AsciiPrint (" %-16a | %5a | %5a | %a\n", field, bits, value, description);
> +}
> +
> +void
> +print_values (
> +  const char  *field,
> +  const char  *bits,
> +  const int   value,
> +  const char  *description
> +  )
> +{
> +  STATIC CONST CHAR8  binaries[][5] = {
> +    "0000", "0001", "0010", "0011",
> +    "0100", "0101", "0110", "0111","1000",  "1001", "1010", "1011",
> +    "1100", "1101", "1110", "1111"
> +  };
> +
> +  AsciiPrint (" %-16a | %5a | %5a | %a\n", field, bits, binaries[value & 0xf], description);
> +}
> +
> +void
> +print_spacer (
> +  void
> +  )
> +{
> +  AsciiPrint ("------------------|-------|-------|----------------------------------------------\n");
> +}
> +
> +void
> +handle_aa64mmfr0_el1 (
> +  const UINT64  aa64mmfr0_el1
> +  )
> +{
> +  UINT64              value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR0_EL1";
> +  char                *description;
> +  char                *bits;
> +
> +  bits  = "3:0 ";
> +  value = aa64mmfr0_el1 & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "32 bits  (4GB) of physical address range supported.";
> +      break;
> +    case 0b0001:
> +      description = "36 bits  (64GB) of physical address range supported.";
> +      break;
> +    case 0b0010:
> +      description = "40 bits  (1TB) of physical address range supported.";
> +      break;
> +    case 0b0011:
> +      description = "42 bits  (4TB) of physical address range supported.";
> +      break;
> +    case 0b0100:
> +      description = "44 bits  (16TB) of physical address range supported.";
> +      break;
> +    case 0b0101:
> +      description = "48 bits  (256TB) of physical address range supported.";
> +      break;
> +    case 0b0110:
> +      description = "52 bits  (4PB) of physical address range supported.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +  if (value == 0b0110) {
> +    print_text ("", "", "", "FEAT_LPA implemented.");
> +  }
> +
> +  bits  = "7:4 ";
> +  value = (aa64mmfr0_el1 >>  4) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "ASID: 8 bits";
> +      break;
> +    case 0b0010:
> +      description = "ASID: 16 bits";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "11:8 ";
> +  value = (aa64mmfr0_el1 >>  8) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "No mixed-endian support.";
> +      break;
> +    case 0b0001:
> +      description = "Mixed-endian support.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  // only valid for BigEnd != 0b0000
> +  if (((aa64mmfr0_el1 >>  8) & 0xf) != 0b0000 ) {
> +    if (((aa64mmfr0_el1 >> 16) & 0xf) == 0b0000 ) {
> +      print_values ("ID_AA64MMFR0_EL1", "19:16", 0b0000, "No mixed-endian support at EL0.");
> +    }
> +
> +    if (((aa64mmfr0_el1 >> 16) & 0xf) == 0b0001 ) {
> +      print_values ("ID_AA64MMFR0_EL1", "19:16", 0b0001, "Mixed-endian support at EL0.");
> +    }
> +  }
> +
> +  bits  = "15:12";
> +  value = (aa64mmfr0_el1 >> 12) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "No support for a distinction between Secure and Non-Secure Memory.";
> +      break;
> +    case 0b0001:
> +      description = "Supports a distinction between Secure and Non-Secure Memory.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "31:28";
> +  value = (aa64mmfr0_el1 >> 28) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = " 4KB granule supported.";
> +      break;
> +    case 0b1111:
> +      description = " 4KB granule not supported.";
> +      break;
> +    case 0b0001:             // add FEAT_LPA2 check
> +      description = " 4KB granule supported for 52-bit address.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "43:40";
> +  value = (aa64mmfr0_el1 >> 40) & 0xf;
> +  switch (value) {
> +    case 0b0001:
> +      description = " 4KB granule not supported at stage 2.";
> +      break;
> +    case 0b0010:
> +      description = " 4KB granule supported at stage 2.";
> +      break;
> +    case 0b0011:
> +      description = " 4KB granule supported at stage 2 for 52-bit address.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "23:20";
> +  value = (aa64mmfr0_el1 >> 20) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "16KB granule not supported.";
> +      break;
> +    case 0b0001:
> +      description = "16KB granule supported.";
> +      break;
> +    case 0b0010:             // add FEAT_LPA2 check
> +      description = "16KB granule supported for 52-bit address.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "35:32";
> +  value = (aa64mmfr0_el1 >> 32) & 0xf;
> +  switch (value) {
> +    case 0b0001:
> +      description = "16KB granule not supported at stage 2.";
> +      break;
> +    case 0b0010:
> +      description = "16KB granule supported at stage 2.";
> +      break;
> +    case 0b0011:
> +      description = "16KB granule supported at stage 2 for 52-bit address.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "27:24";
> +  value = (aa64mmfr0_el1 >> 24) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "64KB granule supported.";
> +      break;
> +    case 0b1111:
> +      description = "64KB granule not supported.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "39:36";
> +  value = (aa64mmfr0_el1 >> 36) & 0xf;
> +  switch (value) {
> +    case 0b0001:
> +      description = "64KB granule not supported at stage 2.";
> +      break;
> +    case 0b0010:
> +      description = "64KB granule supported at stage 2.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "47:44";
> +  value = (aa64mmfr0_el1 >> 44) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_ExS not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_ExS implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  // 55:48 reserved
> +
> +  bits  = "59:56";
> +  value = (aa64mmfr0_el1 >> 56) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_FGT not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_FGT implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "63:60";
> +  value = (aa64mmfr0_el1 >> 60) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_ECV not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_ECV implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_ECV implemented with extras.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +}
> +
> +void
> +handle_aa64mmfr1_el1 (
> +  const UINT64  aa64mmfr1_el1,
> +  const UINT64  aa64pfr0_el1
> +  )
> +{
> +  UINT64              value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR1_EL1";
> +  char                *description;
> +  char                *bits;
> +
> +  bits  = "3:0 ";
> +  value = aa64mmfr1_el1 & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_HAFDBS not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_HAFDBS implemented without dirty status support.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_HAFDBS implemented with dirty status support.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "7:4 ";
> +  value = (aa64mmfr1_el1 >>  4) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_VMID16 not implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_VMID16 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "11:8 ";
> +  value = (aa64mmfr1_el1 >>  8) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_VHE not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_VHE implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "15:12";
> +  value = (aa64mmfr1_el1 >> 12) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_HPDS not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_HPDS implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_HPDS2 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "19:16";
> +  value = (aa64mmfr1_el1 >> 16) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_LOR not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_LOR implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "23:20";
> +  value = (aa64mmfr1_el1 >> 20) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_PAN not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_PAN implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_PAN2 implemented.";
> +      break;
> +    case 0b0011:
> +      description = "FEAT_PAN3 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  // when FEAT_RAS implemented
> +  if ((((aa64pfr0_el1 >> 28) & 0xf) == 0b0001) ||
> +      (((aa64pfr0_el1 >> 28) & 0xf) == 0b0010))
> +  {
> +    if (((aa64mmfr1_el1 >> 24) & 0xf) == 0b0000 ) {
> +      print_values ("ID_AA64MMFR1_EL1", "27:24", 0b0000, "The PE never generates an SError interrupt due to");
> +      print_text ("", "", "", "an External abort on a speculative read.");
> +    }
> +
> +    if (((aa64mmfr1_el1 >> 24) & 0xf) == 0b0001 ) {
> +      print_values ("ID_AA64MMFR1_EL1", "27:24", 0b0001, "The PE might generate an SError interrupt due to");
> +      print_text ("", "", "", "an External abort on a speculative read.");
> +    }
> +  }
> +
> +  bits  = "31:28";
> +  value = (aa64mmfr1_el1 >> 28) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_XNX not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_XNX implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "35:32";
> +  value = (aa64mmfr1_el1 >> 32) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_TWED not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_TWED implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "39:36";
> +  value = (aa64mmfr1_el1 >> 36) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_ETS not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_ETS implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "43:40";
> +  value = (aa64mmfr1_el1 >> 40) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_HCX not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_HCX implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "47:44";
> +  value = (aa64mmfr1_el1 >> 44) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_AFP not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_AFP implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "51:48";
> +  value = (aa64mmfr1_el1 >> 48) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_nTLBPA not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_nTLBPA implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "55:52";
> +  value = (aa64mmfr1_el1 >> 52) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_TIDCP1 not implemented";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_TIDCP1 implemented";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "59:56";
> +  value = (aa64mmfr1_el1 >> 56) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_CMOW not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_CMOW implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  // 63:60 reserved
> +}
> +
> +void
> +handle_aa64mmfr2_el1 (
> +  const UINT64  aa64mmfr2_el1
> +  )
> +{
> +  UINT64              value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR2_EL1";
> +  char                *description;
> +  char                *bits;
> +
> +  bits  = "3:0 ";
> +  value = (aa64mmfr2_el1)       & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_TTCNP not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_TTCNP implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "7:4 ";
> +  value = (aa64mmfr2_el1 >>  4) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_UAO not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_UAO implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "11:8 ";
> +  value = (aa64mmfr2_el1 >>  8) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_LSMAOC not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_LSMAOC implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "15:12";
> +  value = (aa64mmfr2_el1 >> 12) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_IESB not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_IESB implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "19:16";
> +  value = (aa64mmfr2_el1 >> 16) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_LVA not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_LVA implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "23:20";
> +  value = (aa64mmfr2_el1 >> 20) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_CCIDX not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_CCIDX implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "27:24";
> +  value = (aa64mmfr2_el1 >> 24) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_NV not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_NV implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_NV2 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "31:28";
> +  value = (aa64mmfr2_el1 >> 28) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_TTST not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_TTST implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "35:32";
> +  value = (aa64mmfr2_el1 >> 32) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_LSE2 not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_LSE2 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "39:36";
> +  value = (aa64mmfr2_el1 >> 36) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_IDST not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_IDST implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "43:40";
> +  value = (aa64mmfr2_el1 >> 40) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_S2FWB not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_S2FWB implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  // 47:44 reserved
> +
> +  bits  = "51:48";
> +  value = (aa64mmfr2_el1 >> 48) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_TTL not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_TTL implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "55:52";
> +  value = (aa64mmfr2_el1 >> 52) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_BBM: Level 0 support for changing block size is supported.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_BBM: Level 1 support for changing block size is supported.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_BBM: Level 2 support for changing block size is supported.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "59:56";
> +  value = (aa64mmfr2_el1 >> 56) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_EVT not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_EVT: HCR_EL2.{TOCU, TICAB, TID4} traps are supported.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_EVT: HCR_EL2.{TTLBOS, TTLSBIS, TOCU, TICAB, TID4} traps are supported.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "63:60";
> +  value = (aa64mmfr2_el1 >> 60) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_E0PD not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_E0PD implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +}
> +
> +void
> +handle_aa64pfr0_el1 (
> +  const UINT64  aa64pfr0_el1,
> +  const UINT64  aa64pfr1_el1
> +  )
> +{
> +  UINT64              value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR0_EL1";
> +  char                *description;
> +  char                *bits;
> +
> +  bits  = "3:0 ";
> +  value = (aa64pfr0_el1)       & 0xf;
> +  switch (value) {
> +    case 0b0001:
> +      description = "EL0 in AArch64 only";
> +      break;
> +    case 0b0010:
> +      description = "EL0 in AArch64 and AArch32";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "7:4 ";
> +  value = (aa64pfr0_el1 >>  4) & 0xf;
> +  switch (value) {
> +    case 0b0001:
> +      description = "EL1 in AArch64 only";
> +      break;
> +    case 0b0010:
> +      description = "EL1 in AArch64 and AArch32";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "11:8 ";
> +  value = (aa64pfr0_el1 >>  8) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "EL2 not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "EL2 in AArch64 only";
> +      break;
> +    case 0b0010:
> +      description = "EL2 in AArch64 and AArch32";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "15:12";
> +  value = (aa64pfr0_el1 >> 12) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "EL3 not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "EL3 in AArch64 only";
> +      break;
> +    case 0b0010:
> +      description = "EL3 in AArch64 and AArch32";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "19:16";
> +  value = (aa64pfr0_el1 >> 16) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "Floating-point implemented.";
> +      break;
> +    case 0b0001:
> +      description = "Floating-point with half-precision support  (FEAT_FP16).";
> +      break;
> +    case 0b1111:
> +      description = "Floating-point not implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "23:20";
> +  value = (aa64pfr0_el1 >> 20) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "Advanced SIMD implemented.";
> +      break;
> +    case 0b0001:
> +      description = "Advanced SIMD with half precision support  (FEAT_FP16).";
> +      break;
> +    case 0b1111:
> +      description = "Advanced SIMD not implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "27:24";
> +  value = (aa64pfr0_el1 >> 24) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "System registers of GIC CPU not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "System registers to versions 3.0/4.0 of GIC CPU implemented.";
> +      break;
> +    case 0b0011:
> +      description = "System registers to versions 4.1 of GIC CPU implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "31:28";
> +  value = (aa64pfr0_el1 >> 28) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_RAS not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_RAS implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_RASv1p1 implemented.";
> +      // 0b0010 FEAT_RASv1p1 implemented and, if EL3 is implemented, FEAT_DoubleFault implemented.
> +      if ((((aa64pfr0_el1 >> 12) & 0xf) == 0b0001) ||
> +          (((aa64pfr0_el1 >> 12) & 0xf) == 0b0010))
> +      {
> +        description = "FEAT_RASv1p1 implemented. FEAT_DoubleFault implemented.";
> +      }
> +
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "35:32";
> +  value = (aa64pfr0_el1 >> 32) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_SVE not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_SVE implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "39:36";
> +  value = (aa64pfr0_el1 >> 36) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "Secure EL2 not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "Secure EL2 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "43:40";
> +  value = (aa64pfr0_el1 >> 40) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      if (((aa64pfr1_el1 >> 16) & 0xf) == 0b0000 ) {
> +        description = "FEAT_MPAM not implemented.";
> +      }
> +
> +      if (((aa64pfr1_el1 >> 16) & 0xf) == 0b0001 ) {
> +        description = "FEAT_MPAM v0.1 implemented.";
> +      }
> +
> +      break;
> +    case 0b0001:
> +      if (((aa64pfr1_el1 >> 16) & 0xf) == 0b0000 ) {
> +        description = "FEAT_MPAM v1.0 implemented.";
> +      }
> +
> +      if (((aa64pfr1_el1 >> 16) & 0xf) == 0b0001 ) {
> +        description = "FEAT_MPAM v1.1 implemented.";
> +      }
> +
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "47:44";
> +  value = (aa64pfr0_el1 >> 44) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_AMU not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_AMUv1 implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_AMUv1p1 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "51:48";
> +  value = (aa64pfr0_el1 >> 48) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_DIT not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_DIT implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "55:52";
> +  value = (aa64pfr0_el1 >> 52) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_RME not implemented";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_RME implemented";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "59:56";
> +  value = (aa64pfr0_el1 >> 56) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "no info is FEAT_CSV2 implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_CSV2 implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_CSV2_2 implemented.";
> +      break;
> +    case 0b0011:
> +      description = "FEAT_CSV2_3 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +  if (value == 0b0001) {
> +    if (((aa64pfr1_el1 >> 32) & 0xf) == 0b0001 ) {
> +      print_values ("ID_AA64PRF1_EL1", "35:32", 0b0001, "FEAT_CSV2_1p1 implemented.");
> +    }
> +
> +    if (((aa64pfr1_el1 >> 32) & 0xf) == 0b0010 ) {
> +      print_values ("ID_AA64PRF1_EL1", "35:32", 0b0010, "FEAT_CSV2_1p2 implemented.");
> +    }
> +  }
> +
> +  bits  = "63:60";
> +  value = (aa64pfr0_el1 >> 60) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_CSV3 not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_CSV3 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +}
> +
> +void
> +handle_aa64pfr1_el1 (
> +  const UINT64  aa64pfr1_el1
> +  )
> +{
> +  UINT64              value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR1_EL1";
> +  char                *description;
> +  char                *bits;
> +
> +  bits  = "3:0 ";
> +  value = aa64pfr1_el1 & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_BTI not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_BTI implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "7:4 ";
> +  value = (aa64pfr1_el1 >>  4) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_SSBS not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_SSBS implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_SSBS2 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "11:8 ";
> +  value = (aa64pfr1_el1 >>  8) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_MTE not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_MTE implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_MTE2 implemented.";
> +      break;
> +    case 0b0011:
> +      description = "FEAT_MTE3 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  // 15:12 is RAS_frac
> +  // 19:16 is MPAM_frac
> +  // 23:20 is reserved
> +
> +  bits  = "27:24";
> +  value = (aa64pfr1_el1 >> 24) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_SME not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_SME implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "31:28";
> +  value = (aa64pfr1_el1 >> 28) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_RNG_TRAP not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_RNG_TRAP implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  // 35:32 is CSV2_frac
> +
> +  bits  = "39:36";
> +  value = (aa64pfr1_el1 >> 36) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_NMI not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_NMI implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  // 63:40 are reserved
> +}
> +
> +void
> +handle_aa64isar0_el1 (
> +  const UINT64  aa64isar0_el1
> +  )
> +{
> +  UINT64              value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR0_EL1";
> +  char                *description;
> +  char                *bits;
> +
> +  // 3:0 reserved
> +
> +  bits  = "7:4 ";
> +  value = (aa64isar0_el1 >>  4) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_AES, FEAT_PMULL not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_AES implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_AES and FEAT_PMULL implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "11:8 ";
> +  value = (aa64isar0_el1 >>  8) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_SHA1 not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_SHA1 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "15:12";
> +  value = (aa64isar0_el1 >> 12) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_SHA256, FEAT_SHA512 not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_SHA256 implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_SHA512 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "19:16";
> +  value = (aa64isar0_el1 >> 16) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "CRC32 not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "CRC32 instructions implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "23:20";
> +  value = (aa64isar0_el1 >> 20) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_LSE not implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_LSE implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "27:24";
> +  value = (aa64isar0_el1 >> 24) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "TME instructions not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "TME instructions implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "31:28";
> +  value = (aa64isar0_el1 >> 28) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_RDM not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_RDM implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "35:32";
> +  value = (aa64isar0_el1 >> 32) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_SHA3 not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_SHA3 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "39:36";
> +  value = (aa64isar0_el1 >> 36) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_SM3 not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_SM3 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "43:40";
> +  value = (aa64isar0_el1 >> 40) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_SM4 not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_SM4 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "47:44";
> +  value = (aa64isar0_el1 >> 44) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_DotProd not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_DotProd implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "51:48";
> +  value = (aa64isar0_el1 >> 48) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_FHM not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_FHM implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "55:52";
> +  value = (aa64isar0_el1 >> 52) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_FlagM/FEAT_FlagM2 not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_FlagM implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_FlagM2 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "59:56";
> +  value = (aa64isar0_el1 >> 56) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_TLBIOS/FEAT_TLBIRANGE not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_TLBIOS implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_TLBIRANGE implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "63:60";
> +  value = (aa64isar0_el1 >> 60) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_RNG not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_RNG implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +}
> +
> +void
> +handle_aa64isar1_el1 (
> +  const UINT64  aa64isar1_el1
> +  )
> +{
> +  UINT64              value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR1_EL1";
> +  char                *description;
> +  char                *bits;
> +
> +  bits  = "3:0 ";
> +  value = (aa64isar1_el1 >>  4) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "DC CVAP not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_DPB implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_DPB2 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "7:4 ";
> +  value = (aa64isar1_el1 >>  4) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "Address Authentication  (APA) not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_PAuth implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_EPAC implemented.";
> +      break;
> +    case 0b0011:
> +      description = "FEAT_PAuth2 implemented.";
> +      break;
> +    case 0b0100:
> +      description = "FEAT_FPAC implemented.";
> +      break;
> +    case 0b0101:
> +      description = "FEAT_FPACCOMBINE implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +  if (value > 0) {
> +    print_text ("", "", "", "FEAT_PACQARMA5 implemented.");
> +  }
> +
> +  bits  = "11:8 ";
> +  value = (aa64isar1_el1 >>  8) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "Address Authentication  (API) not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_PAuth implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_EPAC implemented.";
> +      break;
> +    case 0b0011:
> +      description = "FEAT_PAuth2 implemented.";
> +      break;
> +    case 0b0100:
> +      description = "FEAT_FPAC implemented.";
> +      break;
> +    case 0b0101:
> +      description = "FEAT_FPACCOMBINE implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +  if (value > 0) {
> +    print_text ("", "", "", "FEAT_PACIMP implemented.");
> +  }
> +
> +  bits  = "15:12";
> +  value = (aa64isar1_el1 >> 12) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_JSCVT not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_JSCVT implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "19:16";
> +  value = (aa64isar1_el1 >> 16) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_FCMA not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_FCMA implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "23:20";
> +  value = (aa64isar1_el1 >> 20) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_LRCPC (2) not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_LRCPC implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_LRCPC2 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "27:24";
> +  value = (aa64isar1_el1 >> 24) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_PACQARMA5 not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_PACQARMA5 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "31:28";
> +  value = (aa64isar1_el1 >> 28) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_PACIMP not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_PACIMP implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "35:32";
> +  value = (aa64isar1_el1 >> 32) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_FRINTTS not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_FRINTTS implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "39:36";
> +  value = (aa64isar1_el1 >> 36) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_SB not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_SB implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "43:40";
> +  value = (aa64isar1_el1 >> 40) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_SPECRES not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_SPECRES implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "47:44";
> +  value = (aa64isar1_el1 >> 44) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_BF16 not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_BF16 implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_EBF16 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "51:48";
> +  value = (aa64isar1_el1 >> 48) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_DGH not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_DGH implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "55:52";
> +  value = (aa64isar1_el1 >> 52) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_I8MM not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_I8MM implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "59:56";
> +  value = (aa64isar1_el1 >> 56) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_XS not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_XS implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "63:60";
> +  value = (aa64isar1_el1 >> 60) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_LS64 not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_LS64 implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_LS64_V implemented.";
> +      break;
> +    case 0b0011:
> +      description = "FEAT_LS64_ACCDATA implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +}
> +
> +void
> +handle_aa64isar2_el1 (
> +  const UINT64  aa64isar2_el1
> +  )
> +{
> +  UINT64              value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR2_EL1";
> +  char                *description;
> +  char                *bits;
> +
> +  bits  = "3:0 ";
> +  value = (aa64isar2_el1 >>  4) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_WFxT not implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_WFxT implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "7:4 ";
> +  value = (aa64isar2_el1 >>  4) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_RPRES not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_RPRES implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "11:8 ";
> +  value = (aa64isar2_el1 >>  8) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_PACQARMA3 not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_PACQARMA3 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "15:12";
> +  value = (aa64isar2_el1 >> 12) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "Address Authentication  (APA3) not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_PAuth implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_EPAC implemented.";
> +      break;
> +    case 0b0011:
> +      description = "FEAT_PAuth2 implemented.";
> +      break;
> +    case 0b0100:
> +      description = "FEAT_FPAC implemented.";
> +      break;
> +    case 0b0101:
> +      description = "FEAT_FPACCOMBINE implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "19:16";
> +  value = (aa64isar2_el1 >> 16) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_MOPS not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_MOPS implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "23:20";
> +  value = (aa64isar2_el1 >> 20) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_HBC not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_HBC implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "27:24";
> +  value = (aa64isar2_el1 >> 24) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_CONSTPACFIELD not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_CONSTPACFIELD implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  // 63:28 reserved
> +}
> +
> +void
> +handle_aa64dfr0_el1 (
> +  const UINT64  aa64dfr0_el1
> +  )
> +{
> +  UINT64              value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64DFR0_EL1";
> +  char                *description;
> +  char                *bits;
> +
> +  bits  = "3:0 ";
> +  value = (aa64dfr0_el1 >>  4) & 0xf;
> +  switch (value) {
> +    case 0b0110:
> +      description = "Armv8 debug architecture";
> +      break;
> +    case 0b0111:
> +      description = "Armv8 debug architecture with VHE";
> +      break;
> +    case 0b1000:
> +      description = "FEAT_Debugv8p2 implemented.";
> +      break;
> +    case 0b1001:
> +      description = "FEAT_Debugv8p4 implemented.";
> +      break;
> +    case 0b1010:
> +      description = "FEAT_Debugv8p8 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "7:4 ";
> +  value = (aa64dfr0_el1 >>  4) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "Trace unit System registers not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "Trace unit System registers implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "11:8 ";
> +  value = (aa64dfr0_el1 >>  8) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "Performance Monitors Extension not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_PMUv3 implemented.";
> +      break;
> +    case 0b0100:
> +      description = "FEAT_PMUv3p1 implemented.";
> +      break;
> +    case 0b0101:
> +      description = "FEAT_PMUv3p4 implemented.";
> +      break;
> +    case 0b0110:
> +      description = "FEAT_PMUv3p5 implemented.";
> +      break;
> +    case 0b0111:
> +      description = "FEAT_PMUv3p7 implemented.";
> +      break;
> +    case 0b1000:
> +      description = "FEAT_PMUv3p8 implemented.";
> +      break;
> +    case 0b1111:
> +      description = "IMPLEMENTATION DEFINED form of performance monitors supported.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "15:12";
> +  value = (aa64dfr0_el1 >> 12) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "reserved";
> +      break;
> +    default:
> +      description = "Number of breakpoints, minus 1.";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  // 19:16 reserved
> +
> +  bits  = "23:20";
> +  value = (aa64dfr0_el1 >> 20) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "reserved";
> +      break;
> +    default:
> +      description = "Number of watchpoints, minus 1.";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  // 27:24 reserved
> +
> +  bits  = "31:28";
> +  value = (aa64dfr0_el1 >> 28) & 0xf;
> +  switch (value) {
> +    default:
> +      description = "Number of breakpoints that are context-aware, minus 1.";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "35:32";
> +  value = (aa64dfr0_el1 >> 32) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_SPE not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_SPE implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_SPEv1p1 implemented.";
> +      break;
> +    case 0b0011:
> +      description = "FEAT_SPEv1p2 implemented.";
> +      break;
> +    case 0b0100:
> +      description = "FEAT_SPEv1p3 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "39:36";
> +  value = (aa64dfr0_el1 >> 36) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_DoubleLock implemented.";
> +      break;
> +    case 0b1111:
> +      description = "FEAT_DoubleLock not implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "43:40";
> +  value = (aa64dfr0_el1 >> 40) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_TRF not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_TRF implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "47:44";
> +  value = (aa64dfr0_el1 >> 44) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_TRBE not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_TRBE implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "51:48";
> +  value = (aa64dfr0_el1 >> 48) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_MTPMU not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_MTPMU and FEAT_PMUv3 implemented.";
> +      break;
> +    case 0b1111:
> +      description = "FEAT_MTPMU not implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  bits  = "55:52";
> +  value = (aa64dfr0_el1 >> 52) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "FEAT_BRBE not implemented.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_BRBE implemented.";
> +      break;
> +    case 0b0010:
> +      description = "FEAT_BRBEv1p1 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +
> +  // 59:56 reserved
> +
> +  bits  = "63:60";
> +  value = (aa64dfr0_el1 >> 60) & 0xf;
> +  switch (value) {
> +    case 0b0000:
> +      description = "Setting MDCR_EL2.HPMN to zero has CONSTRAINED UNPREDICTABLE behavior.";
> +      break;
> +    case 0b0001:
> +      description = "FEAT_HPMN0 implemented.";
> +      break;
> +    default:
> +      description = "unknown";
> +      break;
> +  }
> +
> +  print_values (RegName, bits, value, description);
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +UefiMain  (
> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +  UINT64  aa64dfr0_el1  = read_aa64dfr0_el1 ();
> +  UINT64  aa64dfr1_el1  = read_aa64dfr1_el1 ();
> +  UINT64  aa64isar0_el1 = read_aa64isar0_el1 ();
> +  UINT64  aa64isar1_el1 = read_aa64isar1_el1 ();
> +  UINT64  aa64isar2_el1 = read_aa64isar2_el1 ();
> +  UINT64  aa64mmfr0_el1 = read_aa64mmfr0_el1 ();
> +  UINT64  aa64mmfr1_el1 = read_aa64mmfr1_el1 ();
> +  UINT64  aa64mmfr2_el1 = read_aa64mmfr2_el1 ();
> +  UINT64  aa64pfr0_el1  = read_aa64pfr0_el1 ();
> +  UINT64  aa64pfr1_el1  = read_aa64pfr1_el1 ();

EDK2 requires separation between declarations and code (something
alike old C89 semantics, but stricter). so:
    UINT64 aa64pfr1_el1;
    <...>
    aa64pfr1_el1 = read_aa64pfr1_el1 ();

> +
> +  /*    UINT64 aa64smfr0_el1 = read_aa64smfr0_el1 ();*/
> +  /*    UINT64 aa64zfr0_el1 = read_aa64zfr0_el1 ();*/

Dead Code?
> +
> +  AsciiPrint ("ID_AA64MMFR0_EL1 = 0x%016lx\n", aa64mmfr0_el1);
> +  AsciiPrint ("ID_AA64MMFR1_EL1 = 0x%016lx\n", aa64mmfr1_el1);
> +  AsciiPrint ("ID_AA64MMFR2_EL1 = 0x%016lx\n", aa64mmfr2_el1);
> +  AsciiPrint ("ID_AA64PFR0_EL1  = 0x%016lx\n", aa64pfr0_el1);
> +  AsciiPrint ("ID_AA64PFR1_EL1  = 0x%016lx\n", aa64pfr1_el1);
> +  AsciiPrint ("ID_AA64ISAR0_EL1 = 0x%016lx\n", aa64isar0_el1);
> +  AsciiPrint ("ID_AA64ISAR1_EL1 = 0x%016lx\n", aa64isar1_el1);
> +  AsciiPrint ("ID_AA64ISAR2_EL1 = 0x%016lx\n", aa64isar2_el1);
> +  AsciiPrint ("ID_AA64DFR0_EL1  = 0x%016lx\n", aa64dfr0_el1);
> +  AsciiPrint ("ID_AA64DFR1_EL1  = 0x%016lx\n", aa64dfr1_el1);            // ignore

Why ignore?

> +  /*    AsciiPrint ("ID_AA64SMFR0_EL1 = 0x%016lx\n", aa64smfr0_el1);*/
> +  /*    AsciiPrint ("ID_AA64ZFR0_EL1 = 0x%016lx\n", aa64zfr0_el1);*/

dead?
> +
> +  AsciiPrint ("\n");
> +  print_text ("Register", "Bits", "Value", "Feature");
> +  print_spacer ();
> +
> +  handle_aa64mmfr0_el1 (aa64mmfr0_el1);
> +  print_spacer ();
> +  handle_aa64mmfr1_el1 (aa64mmfr1_el1, aa64pfr0_el1);
> +  print_spacer ();
> +  handle_aa64mmfr2_el1 (aa64mmfr2_el1);
> +
> +  print_spacer ();
> +  handle_aa64pfr0_el1 (aa64pfr0_el1, aa64pfr1_el1);
> +  print_spacer ();
> +  handle_aa64pfr1_el1 (aa64pfr1_el1);
> +
> +  print_spacer ();
> +  handle_aa64isar0_el1 (aa64isar0_el1);
> +  print_spacer ();
> +  handle_aa64isar1_el1 (aa64isar1_el1);
> +  print_spacer ();
> +  handle_aa64isar2_el1 (aa64isar2_el1);
> +
> +  print_spacer ();
> +  handle_aa64dfr0_el1 (aa64dfr0_el1);
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/ArmPkg/Application/ArmCpuInfo/readregs.s b/ArmPkg/Application/ArmCpuInfo/readregs.s

ASM files that require preprocessing should have a capital S here (.S vs .s)

> new file mode 100644
> index 000000000000..052834b3c3f2
> --- /dev/null
> +++ b/ArmPkg/Application/ArmCpuInfo/readregs.s
> @@ -0,0 +1,49 @@
> +#include <AsmMacroIoLibV8.h>
> +
> +ASM_FUNC(read_aa64pfr0_el1)
> +        mrs x0, ID_AA64PFR0_EL1;
> +        ret;

ASM lines (for GAS at least) don't usually end in semicolons. so
   +ASM_FUNC(read_aa64pfr0_el1)
   +        mrs x0, ID_AA64PFR0_EL1
   +        ret

You'd only need the semicolons if you had multiple instructions in one
line (like mrs x0, ID_AA...; ret)

> +
> +ASM_FUNC(read_aa64pfr1_el1)
> +        mrs x0, ID_AA64PFR1_EL1;
> +        ret;
> +
> +ASM_FUNC(read_aa64dfr0_el1)
> +        mrs x0, ID_AA64DFR0_EL1;
> +        ret;
> +
> +ASM_FUNC(read_aa64dfr1_el1)
> +        mrs x0, ID_AA64DFR1_EL1;
> +        ret;
> +
> +ASM_FUNC(read_aa64isar0_el1)
> +        mrs x0, ID_AA64ISAR0_EL1;
> +        ret;
> +
> +ASM_FUNC(read_aa64isar1_el1)
> +        mrs x0, ID_AA64ISAR1_EL1;
> +        ret;
> +
> +ASM_FUNC(read_aa64isar2_el1)
> +        mrs x0, ID_AA64ISAR2_EL1;
> +        ret;
> +
> +ASM_FUNC(read_aa64mmfr0_el1)
> +        mrs x0, ID_AA64MMFR0_EL1;
> +        ret;
> +
> +ASM_FUNC(read_aa64mmfr1_el1)
> +        mrs x0, ID_AA64MMFR1_EL1;
> +        ret;
> +
> +ASM_FUNC(read_aa64mmfr2_el1)
> +        mrs x0, ID_AA64MMFR2_EL1;
> +        ret;
> +
> +# ASM_FUNC(read_aa64zfr0_el1)
> +#     mrs x0, ID_AA64ZFR0_EL1;
> +#     ret;
> +
> +# ASM_FUNC(read_aa64smfr0_el1)
> +#     mrs x0, ID_AA64SMFR0_EL1;
> +#     ret;

Dead code?

> --
> 2.40.0

Marcin,

Brief comments in general:
1) You use binary literals extensively, which are not portable (GNU C
extension, AFAIK not in MSVC)

2) Naming of identifiers (vars, functions, etc) needs to follow the
EDK2 style. eg:
    description vs Description
    read_aa64mmfr1_el1 vs ReadAa64MmfrEl1
    etc...

-- 
Pedro


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#102695): https://edk2.groups.io/g/devel/message/102695
Mute This Topic: https://groups.io/mt/98123579/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH v3] add ArmCpuInfo EFI application
Posted by Marcin Juszkiewicz 1 year ago
W dniu 7.04.2023 o 15:02, Pedro Falcato pisze:

>> +EFI_STATUS
>> +EFIAPI
>> +UefiMain  (
>> +  IN EFI_HANDLE        ImageHandle,
>> +  IN EFI_SYSTEM_TABLE  *SystemTable
>> +  )
>> +{
>> +  UINT64  aa64dfr0_el1  = read_aa64dfr0_el1 ();
>> +  UINT64  aa64dfr1_el1  = read_aa64dfr1_el1 ();
>> +  UINT64  aa64isar0_el1 = read_aa64isar0_el1 ();
>> +  UINT64  aa64isar1_el1 = read_aa64isar1_el1 ();
>> +  UINT64  aa64isar2_el1 = read_aa64isar2_el1 ();
>> +  UINT64  aa64mmfr0_el1 = read_aa64mmfr0_el1 ();
>> +  UINT64  aa64mmfr1_el1 = read_aa64mmfr1_el1 ();
>> +  UINT64  aa64mmfr2_el1 = read_aa64mmfr2_el1 ();
>> +  UINT64  aa64pfr0_el1  = read_aa64pfr0_el1 ();
>> +  UINT64  aa64pfr1_el1  = read_aa64pfr1_el1 ();
> 
> EDK2 requires separation between declarations and code (something
> alike old C89 semantics, but stricter). so:
>      UINT64 aa64pfr1_el1;
>      <...>
>      aa64pfr1_el1 = read_aa64pfr1_el1 ();

done

>> +
>> +  /*    UINT64 aa64smfr0_el1 = read_aa64smfr0_el1 ();*/
>> +  /*    UINT64 aa64zfr0_el1 = read_aa64zfr0_el1 ();*/
> 
> Dead Code?

I ignore SVE/SME registers for now. Dropped code.

>> +
>> +  AsciiPrint ("ID_AA64MMFR0_EL1 = 0x%016lx\n", aa64mmfr0_el1);
>> +  AsciiPrint ("ID_AA64MMFR1_EL1 = 0x%016lx\n", aa64mmfr1_el1);
>> +  AsciiPrint ("ID_AA64MMFR2_EL1 = 0x%016lx\n", aa64mmfr2_el1);
>> +  AsciiPrint ("ID_AA64PFR0_EL1  = 0x%016lx\n", aa64pfr0_el1);
>> +  AsciiPrint ("ID_AA64PFR1_EL1  = 0x%016lx\n", aa64pfr1_el1);
>> +  AsciiPrint ("ID_AA64ISAR0_EL1 = 0x%016lx\n", aa64isar0_el1);
>> +  AsciiPrint ("ID_AA64ISAR1_EL1 = 0x%016lx\n", aa64isar1_el1);
>> +  AsciiPrint ("ID_AA64ISAR2_EL1 = 0x%016lx\n", aa64isar2_el1);
>> +  AsciiPrint ("ID_AA64DFR0_EL1  = 0x%016lx\n", aa64dfr0_el1);
>> +  AsciiPrint ("ID_AA64DFR1_EL1  = 0x%016lx\n", aa64dfr1_el1);            // ignore
> 
> Why ignore?

Was 0 on systems I checked. Dropped.

>> +  /*    AsciiPrint ("ID_AA64SMFR0_EL1 = 0x%016lx\n", aa64smfr0_el1);*/
>> +  /*    AsciiPrint ("ID_AA64ZFR0_EL1 = 0x%016lx\n", aa64zfr0_el1);*/
> 
> dead?

Dropped.

>> diff --git a/ArmPkg/Application/ArmCpuInfo/readregs.s b/ArmPkg/Application/ArmCpuInfo/readregs.s
> 
> ASM files that require preprocessing should have a capital S here (.S vs .s)

After renaming it to readregs.S (and changing in ArmCpuInfo.inf) I get:

build.py...
/home/marcin/devel/linaro/sbsa-qemu/code/edk2/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf(29): 
error 000E: File/directory not found in workspace
         readregs.S is not found in packages path:

>> new file mode 100644
>> index 000000000000..052834b3c3f2
>> --- /dev/null
>> +++ b/ArmPkg/Application/ArmCpuInfo/readregs.s
>> @@ -0,0 +1,49 @@
>> +#include <AsmMacroIoLibV8.h>
>> +
>> +ASM_FUNC(read_aa64pfr0_el1)
>> +        mrs x0, ID_AA64PFR0_EL1;
>> +        ret;
> 
> ASM lines (for GAS at least) don't usually end in semicolons. so
>     +ASM_FUNC(read_aa64pfr0_el1)
>     +        mrs x0, ID_AA64PFR0_EL1
>     +        ret
> 
> You'd only need the semicolons if you had multiple instructions in one
> line (like mrs x0, ID_AA...; ret)

thanks, dropped semicolons

>> +# ASM_FUNC(read_aa64zfr0_el1)
>> +#     mrs x0, ID_AA64ZFR0_EL1;
>> +#     ret;
>> +
>> +# ASM_FUNC(read_aa64smfr0_el1)
>> +#     mrs x0, ID_AA64SMFR0_EL1;
>> +#     ret;
> 
> Dead code?

Those two registers names were missing so got disabled. Dropped.


> Brief comments in general:
> 1) You use binary literals extensively, which are not portable (GNU C
> extension, AFAIK not in MSVC)

My C skills are rusty and the last time I used compiler other than GCC 
was in Borland Turbo C 3 times.

> 2) Naming of identifiers (vars, functions, etc) needs to follow the
> EDK2 style. eg:
>      description vs Description
>      read_aa64mmfr1_el1 vs ReadAa64MmfrEl1
>      etc...

ok

 > Forgot mentioning: STATIC vs static, CONST vs const,
 > VOID vs void, CHAR8 vs char, etc.
 > All fun microsoftisms you need to use here.

Will be fun.



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#102699): https://edk2.groups.io/g/devel/message/102699
Mute This Topic: https://groups.io/mt/98123579/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-


Re: [edk2-devel] [PATCH v3] add ArmCpuInfo EFI application
Posted by Pedro Falcato 1 year ago
(+cc old CCs)

(Marcin, you're dropping CC's on your replies)

On Fri, Apr 7, 2023 at 2:29 PM Marcin Juszkiewicz
<marcin.juszkiewicz@linaro.org> wrote:
>
> W dniu 7.04.2023 o 15:02, Pedro Falcato pisze:
>
> >> diff --git a/ArmPkg/Application/ArmCpuInfo/readregs.s b/ArmPkg/Application/ArmCpuInfo/readregs.s
> >
> > ASM files that require preprocessing should have a capital S here (.S vs .s)
>
> After renaming it to readregs.S (and changing in ArmCpuInfo.inf) I get:
>
> build.py...
> /home/marcin/devel/linaro/sbsa-qemu/code/edk2/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf(29):
> error 000E: File/directory not found in workspace
>          readregs.S is not found in packages path:
>

Odd. Other packages (e.g ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf)
use .S just fine.

Leif, Ard, any ideas?

-- 
Pedro


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#102700): https://edk2.groups.io/g/devel/message/102700
Mute This Topic: https://groups.io/mt/98123579/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH v3] add ArmCpuInfo EFI application
Posted by Pedro Falcato 1 year ago
Oops, now I screwed up the CC's, apologies.

On Fri, Apr 7, 2023 at 2:40 PM Pedro Falcato <pedro.falcato@gmail.com> wrote:
>
> (+cc old CCs)
>
> (Marcin, you're dropping CC's on your replies)
>
> On Fri, Apr 7, 2023 at 2:29 PM Marcin Juszkiewicz
> <marcin.juszkiewicz@linaro.org> wrote:
> >
> > W dniu 7.04.2023 o 15:02, Pedro Falcato pisze:
> >
> > >> diff --git a/ArmPkg/Application/ArmCpuInfo/readregs.s b/ArmPkg/Application/ArmCpuInfo/readregs.s
> > >
> > > ASM files that require preprocessing should have a capital S here (.S vs .s)
> >
> > After renaming it to readregs.S (and changing in ArmCpuInfo.inf) I get:
> >
> > build.py...
> > /home/marcin/devel/linaro/sbsa-qemu/code/edk2/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf(29):
> > error 000E: File/directory not found in workspace
> >          readregs.S is not found in packages path:
> >
>
> Odd. Other packages (e.g ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf)
> use .S just fine.
>
> Leif, Ard, any ideas?
>
> --
> Pedro



-- 
Pedro


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#102701): https://edk2.groups.io/g/devel/message/102701
Mute This Topic: https://groups.io/mt/98123579/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
Re: [edk2-devel] [PATCH v3] add ArmCpuInfo EFI application
Posted by Marcin Juszkiewicz 1 year ago
W dniu 7.04.2023 o 15:40, Pedro Falcato pisze:
> (+cc old CCs)
> 
> (Marcin, you're dropping CC's on your replies)

Oops, sorry.

>>> ASM files that require preprocessing should have a capital S here (.S vs .s)
>>
>> After renaming it to readregs.S (and changing in ArmCpuInfo.inf) I get:
>>
>> build.py...
>> /home/marcin/devel/linaro/sbsa-qemu/code/edk2/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf(29):
>> error 000E: File/directory not found in workspace
>>           readregs.S is not found in packages path:
>>
> 
> Odd. Other packages (e.g ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf)
> use .S just fine.

Sorted out. Will send v4 later.



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#102702): https://edk2.groups.io/g/devel/message/102702
Mute This Topic: https://groups.io/mt/98123579/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-


Re: [edk2-devel] [PATCH v3] add ArmCpuInfo EFI application
Posted by Pedro Falcato 1 year ago
Forgot mentioning: STATIC vs static, CONST vs const, VOID vs void,
CHAR8 vs char, etc. All fun microsoftisms you need to use here.

On Fri, Apr 7, 2023 at 2:02 PM Pedro Falcato <pedro.falcato@gmail.com> wrote:
>
> On Fri, Apr 7, 2023 at 1:47 PM Marcin Juszkiewicz
> <marcin.juszkiewicz@linaro.org> wrote:
> >
> > App goes through ID_AA64*_EL1 system registers and decode their values.
> >
> > Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
> > ---
> >  ArmPkg/ArmPkg.dsc                            |    1 +
> >  ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf |   38 +
> >  ArmPkg/Application/ArmCpuInfo/readargs.h     |   12 +
> >  ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c   | 2317 ++++++++++++++++++++
> >  ArmPkg/Application/ArmCpuInfo/readregs.s     |   49 +
> >  5 files changed, 2417 insertions(+)
> >
> > diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
> > index 3fb95d1951a9..6b938ce8b671 100644
> > --- a/ArmPkg/ArmPkg.dsc
> > +++ b/ArmPkg/ArmPkg.dsc
> > @@ -166,6 +166,7 @@ [Components.AARCH64]
> >    ArmPkg/Drivers/ArmPsciMpServicesDxe/ArmPsciMpServicesDxe.inf
> >    ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.inf
> >    ArmPkg/Library/ArmMmuLib/ArmMmuPeiLib.inf
> > +  ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
> >
> >  [Components.AARCH64, Components.ARM]
> >    ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStandaloneMmLib.inf
> > diff --git a/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
> > new file mode 100644
> > index 000000000000..158f86a4740c
> > --- /dev/null
> > +++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
> > @@ -0,0 +1,38 @@
> > +## @file
> > +#
> > +#  Attempt to have AArch64 cpu information.
> > +#
> > +#  Based on HelloWorld:
> > +#  Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.
> > +#  Copyright (c) 2023 Marcin Juszkiewicz
> > +#
> > +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +#
> > +#
> > +##
> > +
> > +[Defines]
> > +  INF_VERSION                    = 0x00010019
> > +  BASE_NAME                      = ArmCpuInfo
> > +  FILE_GUID                      = b3134491-6502-4faf-a9da-007184e32163
> > +  MODULE_TYPE                    = UEFI_APPLICATION
> > +  VERSION_STRING                 = 1.0
> > +  ENTRY_POINT                    = UefiMain
> > +
> > +#
> > +#  This flag specifies whether HII resource section is generated into PE image.
> > +#
> > +  UEFI_HII_RESOURCE_SECTION      = TRUE
> > +
> > +[Sources]
> > +  ArmCpuInfo.c
> > +  readregs.s
> > +
> > +[Packages]
> > +  ArmPkg/ArmPkg.dec
> > +  MdePkg/MdePkg.dec
> > +  MdeModulePkg/MdeModulePkg.dec
> > +
> > +[LibraryClasses]
> > +  UefiApplicationEntryPoint
> > +  UefiLib
> > diff --git a/ArmPkg/Application/ArmCpuInfo/readargs.h b/ArmPkg/Application/ArmCpuInfo/readargs.h
> > new file mode 100644
> > index 000000000000..eaa52cf16145
> > --- /dev/null
> > +++ b/ArmPkg/Application/ArmCpuInfo/readargs.h
> > @@ -0,0 +1,12 @@
> > +UINT64 read_aa64pfr0_el1(void);
> > +UINT64 read_aa64pfr1_el1(void);
> > +UINT64 read_aa64dfr0_el1(void);
> > +UINT64 read_aa64dfr1_el1(void);
> > +UINT64 read_aa64isar0_el1(void);
> > +UINT64 read_aa64isar1_el1(void);
> > +UINT64 read_aa64isar2_el1(void);
> > +UINT64 read_aa64mmfr0_el1(void);
> > +UINT64 read_aa64mmfr1_el1(void);
> > +UINT64 read_aa64mmfr2_el1(void);
> > +UINT64 read_aa64smfr0_el1(void);
> > +UINT64 read_aa64zfr0_el1(void);
> > diff --git a/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
> > new file mode 100644
> > index 000000000000..6c31ad4dbcb9
> > --- /dev/null
> > +++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
> > @@ -0,0 +1,2317 @@
> > +/** @file
> > +
> > +  Copyright  (c) 2023 Marcin Juszkiewicz
> > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > + **/
> > +
> > +#include <Library/UefiLib.h>
> > +#include "readargs.h"
> > +
> > +void
> > +print_text (
> > +  const char  *field,
> > +  const char  *bits,
> > +  const char  *value,
> > +  const char  *description
> > +  )
> > +{
> > +  AsciiPrint (" %-16a | %5a | %5a | %a\n", field, bits, value, description);
> > +}
> > +
> > +void
> > +print_values (
> > +  const char  *field,
> > +  const char  *bits,
> > +  const int   value,
> > +  const char  *description
> > +  )
> > +{
> > +  STATIC CONST CHAR8  binaries[][5] = {
> > +    "0000", "0001", "0010", "0011",
> > +    "0100", "0101", "0110", "0111","1000",  "1001", "1010", "1011",
> > +    "1100", "1101", "1110", "1111"
> > +  };
> > +
> > +  AsciiPrint (" %-16a | %5a | %5a | %a\n", field, bits, binaries[value & 0xf], description);
> > +}
> > +
> > +void
> > +print_spacer (
> > +  void
> > +  )
> > +{
> > +  AsciiPrint ("------------------|-------|-------|----------------------------------------------\n");
> > +}
> > +
> > +void
> > +handle_aa64mmfr0_el1 (
> > +  const UINT64  aa64mmfr0_el1
> > +  )
> > +{
> > +  UINT64              value;
> > +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR0_EL1";
> > +  char                *description;
> > +  char                *bits;
> > +
> > +  bits  = "3:0 ";
> > +  value = aa64mmfr0_el1 & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "32 bits  (4GB) of physical address range supported.";
> > +      break;
> > +    case 0b0001:
> > +      description = "36 bits  (64GB) of physical address range supported.";
> > +      break;
> > +    case 0b0010:
> > +      description = "40 bits  (1TB) of physical address range supported.";
> > +      break;
> > +    case 0b0011:
> > +      description = "42 bits  (4TB) of physical address range supported.";
> > +      break;
> > +    case 0b0100:
> > +      description = "44 bits  (16TB) of physical address range supported.";
> > +      break;
> > +    case 0b0101:
> > +      description = "48 bits  (256TB) of physical address range supported.";
> > +      break;
> > +    case 0b0110:
> > +      description = "52 bits  (4PB) of physical address range supported.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +  if (value == 0b0110) {
> > +    print_text ("", "", "", "FEAT_LPA implemented.");
> > +  }
> > +
> > +  bits  = "7:4 ";
> > +  value = (aa64mmfr0_el1 >>  4) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "ASID: 8 bits";
> > +      break;
> > +    case 0b0010:
> > +      description = "ASID: 16 bits";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "11:8 ";
> > +  value = (aa64mmfr0_el1 >>  8) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "No mixed-endian support.";
> > +      break;
> > +    case 0b0001:
> > +      description = "Mixed-endian support.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  // only valid for BigEnd != 0b0000
> > +  if (((aa64mmfr0_el1 >>  8) & 0xf) != 0b0000 ) {
> > +    if (((aa64mmfr0_el1 >> 16) & 0xf) == 0b0000 ) {
> > +      print_values ("ID_AA64MMFR0_EL1", "19:16", 0b0000, "No mixed-endian support at EL0.");
> > +    }
> > +
> > +    if (((aa64mmfr0_el1 >> 16) & 0xf) == 0b0001 ) {
> > +      print_values ("ID_AA64MMFR0_EL1", "19:16", 0b0001, "Mixed-endian support at EL0.");
> > +    }
> > +  }
> > +
> > +  bits  = "15:12";
> > +  value = (aa64mmfr0_el1 >> 12) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "No support for a distinction between Secure and Non-Secure Memory.";
> > +      break;
> > +    case 0b0001:
> > +      description = "Supports a distinction between Secure and Non-Secure Memory.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "31:28";
> > +  value = (aa64mmfr0_el1 >> 28) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = " 4KB granule supported.";
> > +      break;
> > +    case 0b1111:
> > +      description = " 4KB granule not supported.";
> > +      break;
> > +    case 0b0001:             // add FEAT_LPA2 check
> > +      description = " 4KB granule supported for 52-bit address.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "43:40";
> > +  value = (aa64mmfr0_el1 >> 40) & 0xf;
> > +  switch (value) {
> > +    case 0b0001:
> > +      description = " 4KB granule not supported at stage 2.";
> > +      break;
> > +    case 0b0010:
> > +      description = " 4KB granule supported at stage 2.";
> > +      break;
> > +    case 0b0011:
> > +      description = " 4KB granule supported at stage 2 for 52-bit address.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "23:20";
> > +  value = (aa64mmfr0_el1 >> 20) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "16KB granule not supported.";
> > +      break;
> > +    case 0b0001:
> > +      description = "16KB granule supported.";
> > +      break;
> > +    case 0b0010:             // add FEAT_LPA2 check
> > +      description = "16KB granule supported for 52-bit address.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "35:32";
> > +  value = (aa64mmfr0_el1 >> 32) & 0xf;
> > +  switch (value) {
> > +    case 0b0001:
> > +      description = "16KB granule not supported at stage 2.";
> > +      break;
> > +    case 0b0010:
> > +      description = "16KB granule supported at stage 2.";
> > +      break;
> > +    case 0b0011:
> > +      description = "16KB granule supported at stage 2 for 52-bit address.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "27:24";
> > +  value = (aa64mmfr0_el1 >> 24) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "64KB granule supported.";
> > +      break;
> > +    case 0b1111:
> > +      description = "64KB granule not supported.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "39:36";
> > +  value = (aa64mmfr0_el1 >> 36) & 0xf;
> > +  switch (value) {
> > +    case 0b0001:
> > +      description = "64KB granule not supported at stage 2.";
> > +      break;
> > +    case 0b0010:
> > +      description = "64KB granule supported at stage 2.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "47:44";
> > +  value = (aa64mmfr0_el1 >> 44) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_ExS not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_ExS implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  // 55:48 reserved
> > +
> > +  bits  = "59:56";
> > +  value = (aa64mmfr0_el1 >> 56) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_FGT not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_FGT implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "63:60";
> > +  value = (aa64mmfr0_el1 >> 60) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_ECV not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_ECV implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_ECV implemented with extras.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +}
> > +
> > +void
> > +handle_aa64mmfr1_el1 (
> > +  const UINT64  aa64mmfr1_el1,
> > +  const UINT64  aa64pfr0_el1
> > +  )
> > +{
> > +  UINT64              value;
> > +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR1_EL1";
> > +  char                *description;
> > +  char                *bits;
> > +
> > +  bits  = "3:0 ";
> > +  value = aa64mmfr1_el1 & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_HAFDBS not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_HAFDBS implemented without dirty status support.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_HAFDBS implemented with dirty status support.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "7:4 ";
> > +  value = (aa64mmfr1_el1 >>  4) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_VMID16 not implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_VMID16 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "11:8 ";
> > +  value = (aa64mmfr1_el1 >>  8) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_VHE not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_VHE implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "15:12";
> > +  value = (aa64mmfr1_el1 >> 12) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_HPDS not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_HPDS implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_HPDS2 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "19:16";
> > +  value = (aa64mmfr1_el1 >> 16) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_LOR not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_LOR implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "23:20";
> > +  value = (aa64mmfr1_el1 >> 20) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_PAN not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_PAN implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_PAN2 implemented.";
> > +      break;
> > +    case 0b0011:
> > +      description = "FEAT_PAN3 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  // when FEAT_RAS implemented
> > +  if ((((aa64pfr0_el1 >> 28) & 0xf) == 0b0001) ||
> > +      (((aa64pfr0_el1 >> 28) & 0xf) == 0b0010))
> > +  {
> > +    if (((aa64mmfr1_el1 >> 24) & 0xf) == 0b0000 ) {
> > +      print_values ("ID_AA64MMFR1_EL1", "27:24", 0b0000, "The PE never generates an SError interrupt due to");
> > +      print_text ("", "", "", "an External abort on a speculative read.");
> > +    }
> > +
> > +    if (((aa64mmfr1_el1 >> 24) & 0xf) == 0b0001 ) {
> > +      print_values ("ID_AA64MMFR1_EL1", "27:24", 0b0001, "The PE might generate an SError interrupt due to");
> > +      print_text ("", "", "", "an External abort on a speculative read.");
> > +    }
> > +  }
> > +
> > +  bits  = "31:28";
> > +  value = (aa64mmfr1_el1 >> 28) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_XNX not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_XNX implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "35:32";
> > +  value = (aa64mmfr1_el1 >> 32) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_TWED not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_TWED implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "39:36";
> > +  value = (aa64mmfr1_el1 >> 36) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_ETS not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_ETS implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "43:40";
> > +  value = (aa64mmfr1_el1 >> 40) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_HCX not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_HCX implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "47:44";
> > +  value = (aa64mmfr1_el1 >> 44) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_AFP not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_AFP implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "51:48";
> > +  value = (aa64mmfr1_el1 >> 48) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_nTLBPA not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_nTLBPA implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "55:52";
> > +  value = (aa64mmfr1_el1 >> 52) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_TIDCP1 not implemented";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_TIDCP1 implemented";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "59:56";
> > +  value = (aa64mmfr1_el1 >> 56) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_CMOW not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_CMOW implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  // 63:60 reserved
> > +}
> > +
> > +void
> > +handle_aa64mmfr2_el1 (
> > +  const UINT64  aa64mmfr2_el1
> > +  )
> > +{
> > +  UINT64              value;
> > +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR2_EL1";
> > +  char                *description;
> > +  char                *bits;
> > +
> > +  bits  = "3:0 ";
> > +  value = (aa64mmfr2_el1)       & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_TTCNP not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_TTCNP implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "7:4 ";
> > +  value = (aa64mmfr2_el1 >>  4) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_UAO not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_UAO implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "11:8 ";
> > +  value = (aa64mmfr2_el1 >>  8) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_LSMAOC not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_LSMAOC implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "15:12";
> > +  value = (aa64mmfr2_el1 >> 12) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_IESB not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_IESB implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "19:16";
> > +  value = (aa64mmfr2_el1 >> 16) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_LVA not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_LVA implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "23:20";
> > +  value = (aa64mmfr2_el1 >> 20) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_CCIDX not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_CCIDX implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "27:24";
> > +  value = (aa64mmfr2_el1 >> 24) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_NV not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_NV implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_NV2 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "31:28";
> > +  value = (aa64mmfr2_el1 >> 28) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_TTST not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_TTST implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "35:32";
> > +  value = (aa64mmfr2_el1 >> 32) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_LSE2 not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_LSE2 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "39:36";
> > +  value = (aa64mmfr2_el1 >> 36) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_IDST not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_IDST implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "43:40";
> > +  value = (aa64mmfr2_el1 >> 40) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_S2FWB not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_S2FWB implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  // 47:44 reserved
> > +
> > +  bits  = "51:48";
> > +  value = (aa64mmfr2_el1 >> 48) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_TTL not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_TTL implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "55:52";
> > +  value = (aa64mmfr2_el1 >> 52) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_BBM: Level 0 support for changing block size is supported.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_BBM: Level 1 support for changing block size is supported.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_BBM: Level 2 support for changing block size is supported.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "59:56";
> > +  value = (aa64mmfr2_el1 >> 56) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_EVT not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_EVT: HCR_EL2.{TOCU, TICAB, TID4} traps are supported.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_EVT: HCR_EL2.{TTLBOS, TTLSBIS, TOCU, TICAB, TID4} traps are supported.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "63:60";
> > +  value = (aa64mmfr2_el1 >> 60) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_E0PD not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_E0PD implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +}
> > +
> > +void
> > +handle_aa64pfr0_el1 (
> > +  const UINT64  aa64pfr0_el1,
> > +  const UINT64  aa64pfr1_el1
> > +  )
> > +{
> > +  UINT64              value;
> > +  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR0_EL1";
> > +  char                *description;
> > +  char                *bits;
> > +
> > +  bits  = "3:0 ";
> > +  value = (aa64pfr0_el1)       & 0xf;
> > +  switch (value) {
> > +    case 0b0001:
> > +      description = "EL0 in AArch64 only";
> > +      break;
> > +    case 0b0010:
> > +      description = "EL0 in AArch64 and AArch32";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "7:4 ";
> > +  value = (aa64pfr0_el1 >>  4) & 0xf;
> > +  switch (value) {
> > +    case 0b0001:
> > +      description = "EL1 in AArch64 only";
> > +      break;
> > +    case 0b0010:
> > +      description = "EL1 in AArch64 and AArch32";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "11:8 ";
> > +  value = (aa64pfr0_el1 >>  8) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "EL2 not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "EL2 in AArch64 only";
> > +      break;
> > +    case 0b0010:
> > +      description = "EL2 in AArch64 and AArch32";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "15:12";
> > +  value = (aa64pfr0_el1 >> 12) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "EL3 not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "EL3 in AArch64 only";
> > +      break;
> > +    case 0b0010:
> > +      description = "EL3 in AArch64 and AArch32";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "19:16";
> > +  value = (aa64pfr0_el1 >> 16) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "Floating-point implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "Floating-point with half-precision support  (FEAT_FP16).";
> > +      break;
> > +    case 0b1111:
> > +      description = "Floating-point not implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "23:20";
> > +  value = (aa64pfr0_el1 >> 20) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "Advanced SIMD implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "Advanced SIMD with half precision support  (FEAT_FP16).";
> > +      break;
> > +    case 0b1111:
> > +      description = "Advanced SIMD not implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "27:24";
> > +  value = (aa64pfr0_el1 >> 24) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "System registers of GIC CPU not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "System registers to versions 3.0/4.0 of GIC CPU implemented.";
> > +      break;
> > +    case 0b0011:
> > +      description = "System registers to versions 4.1 of GIC CPU implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "31:28";
> > +  value = (aa64pfr0_el1 >> 28) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_RAS not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_RAS implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_RASv1p1 implemented.";
> > +      // 0b0010 FEAT_RASv1p1 implemented and, if EL3 is implemented, FEAT_DoubleFault implemented.
> > +      if ((((aa64pfr0_el1 >> 12) & 0xf) == 0b0001) ||
> > +          (((aa64pfr0_el1 >> 12) & 0xf) == 0b0010))
> > +      {
> > +        description = "FEAT_RASv1p1 implemented. FEAT_DoubleFault implemented.";
> > +      }
> > +
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "35:32";
> > +  value = (aa64pfr0_el1 >> 32) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_SVE not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_SVE implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "39:36";
> > +  value = (aa64pfr0_el1 >> 36) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "Secure EL2 not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "Secure EL2 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "43:40";
> > +  value = (aa64pfr0_el1 >> 40) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      if (((aa64pfr1_el1 >> 16) & 0xf) == 0b0000 ) {
> > +        description = "FEAT_MPAM not implemented.";
> > +      }
> > +
> > +      if (((aa64pfr1_el1 >> 16) & 0xf) == 0b0001 ) {
> > +        description = "FEAT_MPAM v0.1 implemented.";
> > +      }
> > +
> > +      break;
> > +    case 0b0001:
> > +      if (((aa64pfr1_el1 >> 16) & 0xf) == 0b0000 ) {
> > +        description = "FEAT_MPAM v1.0 implemented.";
> > +      }
> > +
> > +      if (((aa64pfr1_el1 >> 16) & 0xf) == 0b0001 ) {
> > +        description = "FEAT_MPAM v1.1 implemented.";
> > +      }
> > +
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "47:44";
> > +  value = (aa64pfr0_el1 >> 44) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_AMU not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_AMUv1 implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_AMUv1p1 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "51:48";
> > +  value = (aa64pfr0_el1 >> 48) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_DIT not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_DIT implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "55:52";
> > +  value = (aa64pfr0_el1 >> 52) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_RME not implemented";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_RME implemented";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "59:56";
> > +  value = (aa64pfr0_el1 >> 56) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "no info is FEAT_CSV2 implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_CSV2 implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_CSV2_2 implemented.";
> > +      break;
> > +    case 0b0011:
> > +      description = "FEAT_CSV2_3 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +  if (value == 0b0001) {
> > +    if (((aa64pfr1_el1 >> 32) & 0xf) == 0b0001 ) {
> > +      print_values ("ID_AA64PRF1_EL1", "35:32", 0b0001, "FEAT_CSV2_1p1 implemented.");
> > +    }
> > +
> > +    if (((aa64pfr1_el1 >> 32) & 0xf) == 0b0010 ) {
> > +      print_values ("ID_AA64PRF1_EL1", "35:32", 0b0010, "FEAT_CSV2_1p2 implemented.");
> > +    }
> > +  }
> > +
> > +  bits  = "63:60";
> > +  value = (aa64pfr0_el1 >> 60) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_CSV3 not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_CSV3 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +}
> > +
> > +void
> > +handle_aa64pfr1_el1 (
> > +  const UINT64  aa64pfr1_el1
> > +  )
> > +{
> > +  UINT64              value;
> > +  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR1_EL1";
> > +  char                *description;
> > +  char                *bits;
> > +
> > +  bits  = "3:0 ";
> > +  value = aa64pfr1_el1 & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_BTI not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_BTI implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "7:4 ";
> > +  value = (aa64pfr1_el1 >>  4) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_SSBS not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_SSBS implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_SSBS2 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "11:8 ";
> > +  value = (aa64pfr1_el1 >>  8) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_MTE not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_MTE implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_MTE2 implemented.";
> > +      break;
> > +    case 0b0011:
> > +      description = "FEAT_MTE3 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  // 15:12 is RAS_frac
> > +  // 19:16 is MPAM_frac
> > +  // 23:20 is reserved
> > +
> > +  bits  = "27:24";
> > +  value = (aa64pfr1_el1 >> 24) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_SME not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_SME implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "31:28";
> > +  value = (aa64pfr1_el1 >> 28) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_RNG_TRAP not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_RNG_TRAP implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  // 35:32 is CSV2_frac
> > +
> > +  bits  = "39:36";
> > +  value = (aa64pfr1_el1 >> 36) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_NMI not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_NMI implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  // 63:40 are reserved
> > +}
> > +
> > +void
> > +handle_aa64isar0_el1 (
> > +  const UINT64  aa64isar0_el1
> > +  )
> > +{
> > +  UINT64              value;
> > +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR0_EL1";
> > +  char                *description;
> > +  char                *bits;
> > +
> > +  // 3:0 reserved
> > +
> > +  bits  = "7:4 ";
> > +  value = (aa64isar0_el1 >>  4) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_AES, FEAT_PMULL not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_AES implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_AES and FEAT_PMULL implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "11:8 ";
> > +  value = (aa64isar0_el1 >>  8) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_SHA1 not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_SHA1 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "15:12";
> > +  value = (aa64isar0_el1 >> 12) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_SHA256, FEAT_SHA512 not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_SHA256 implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_SHA512 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "19:16";
> > +  value = (aa64isar0_el1 >> 16) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "CRC32 not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "CRC32 instructions implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "23:20";
> > +  value = (aa64isar0_el1 >> 20) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_LSE not implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_LSE implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "27:24";
> > +  value = (aa64isar0_el1 >> 24) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "TME instructions not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "TME instructions implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "31:28";
> > +  value = (aa64isar0_el1 >> 28) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_RDM not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_RDM implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "35:32";
> > +  value = (aa64isar0_el1 >> 32) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_SHA3 not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_SHA3 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "39:36";
> > +  value = (aa64isar0_el1 >> 36) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_SM3 not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_SM3 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "43:40";
> > +  value = (aa64isar0_el1 >> 40) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_SM4 not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_SM4 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "47:44";
> > +  value = (aa64isar0_el1 >> 44) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_DotProd not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_DotProd implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "51:48";
> > +  value = (aa64isar0_el1 >> 48) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_FHM not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_FHM implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "55:52";
> > +  value = (aa64isar0_el1 >> 52) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_FlagM/FEAT_FlagM2 not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_FlagM implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_FlagM2 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "59:56";
> > +  value = (aa64isar0_el1 >> 56) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_TLBIOS/FEAT_TLBIRANGE not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_TLBIOS implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_TLBIRANGE implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "63:60";
> > +  value = (aa64isar0_el1 >> 60) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_RNG not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_RNG implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +}
> > +
> > +void
> > +handle_aa64isar1_el1 (
> > +  const UINT64  aa64isar1_el1
> > +  )
> > +{
> > +  UINT64              value;
> > +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR1_EL1";
> > +  char                *description;
> > +  char                *bits;
> > +
> > +  bits  = "3:0 ";
> > +  value = (aa64isar1_el1 >>  4) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "DC CVAP not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_DPB implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_DPB2 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "7:4 ";
> > +  value = (aa64isar1_el1 >>  4) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "Address Authentication  (APA) not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_PAuth implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_EPAC implemented.";
> > +      break;
> > +    case 0b0011:
> > +      description = "FEAT_PAuth2 implemented.";
> > +      break;
> > +    case 0b0100:
> > +      description = "FEAT_FPAC implemented.";
> > +      break;
> > +    case 0b0101:
> > +      description = "FEAT_FPACCOMBINE implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +  if (value > 0) {
> > +    print_text ("", "", "", "FEAT_PACQARMA5 implemented.");
> > +  }
> > +
> > +  bits  = "11:8 ";
> > +  value = (aa64isar1_el1 >>  8) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "Address Authentication  (API) not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_PAuth implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_EPAC implemented.";
> > +      break;
> > +    case 0b0011:
> > +      description = "FEAT_PAuth2 implemented.";
> > +      break;
> > +    case 0b0100:
> > +      description = "FEAT_FPAC implemented.";
> > +      break;
> > +    case 0b0101:
> > +      description = "FEAT_FPACCOMBINE implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +  if (value > 0) {
> > +    print_text ("", "", "", "FEAT_PACIMP implemented.");
> > +  }
> > +
> > +  bits  = "15:12";
> > +  value = (aa64isar1_el1 >> 12) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_JSCVT not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_JSCVT implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "19:16";
> > +  value = (aa64isar1_el1 >> 16) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_FCMA not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_FCMA implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "23:20";
> > +  value = (aa64isar1_el1 >> 20) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_LRCPC (2) not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_LRCPC implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_LRCPC2 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "27:24";
> > +  value = (aa64isar1_el1 >> 24) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_PACQARMA5 not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_PACQARMA5 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "31:28";
> > +  value = (aa64isar1_el1 >> 28) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_PACIMP not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_PACIMP implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "35:32";
> > +  value = (aa64isar1_el1 >> 32) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_FRINTTS not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_FRINTTS implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "39:36";
> > +  value = (aa64isar1_el1 >> 36) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_SB not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_SB implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "43:40";
> > +  value = (aa64isar1_el1 >> 40) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_SPECRES not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_SPECRES implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "47:44";
> > +  value = (aa64isar1_el1 >> 44) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_BF16 not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_BF16 implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_EBF16 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "51:48";
> > +  value = (aa64isar1_el1 >> 48) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_DGH not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_DGH implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "55:52";
> > +  value = (aa64isar1_el1 >> 52) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_I8MM not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_I8MM implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "59:56";
> > +  value = (aa64isar1_el1 >> 56) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_XS not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_XS implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "63:60";
> > +  value = (aa64isar1_el1 >> 60) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_LS64 not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_LS64 implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_LS64_V implemented.";
> > +      break;
> > +    case 0b0011:
> > +      description = "FEAT_LS64_ACCDATA implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +}
> > +
> > +void
> > +handle_aa64isar2_el1 (
> > +  const UINT64  aa64isar2_el1
> > +  )
> > +{
> > +  UINT64              value;
> > +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR2_EL1";
> > +  char                *description;
> > +  char                *bits;
> > +
> > +  bits  = "3:0 ";
> > +  value = (aa64isar2_el1 >>  4) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_WFxT not implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_WFxT implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "7:4 ";
> > +  value = (aa64isar2_el1 >>  4) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_RPRES not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_RPRES implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "11:8 ";
> > +  value = (aa64isar2_el1 >>  8) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_PACQARMA3 not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_PACQARMA3 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "15:12";
> > +  value = (aa64isar2_el1 >> 12) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "Address Authentication  (APA3) not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_PAuth implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_EPAC implemented.";
> > +      break;
> > +    case 0b0011:
> > +      description = "FEAT_PAuth2 implemented.";
> > +      break;
> > +    case 0b0100:
> > +      description = "FEAT_FPAC implemented.";
> > +      break;
> > +    case 0b0101:
> > +      description = "FEAT_FPACCOMBINE implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "19:16";
> > +  value = (aa64isar2_el1 >> 16) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_MOPS not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_MOPS implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "23:20";
> > +  value = (aa64isar2_el1 >> 20) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_HBC not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_HBC implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "27:24";
> > +  value = (aa64isar2_el1 >> 24) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_CONSTPACFIELD not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_CONSTPACFIELD implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  // 63:28 reserved
> > +}
> > +
> > +void
> > +handle_aa64dfr0_el1 (
> > +  const UINT64  aa64dfr0_el1
> > +  )
> > +{
> > +  UINT64              value;
> > +  STATIC CONST CHAR8  RegName[] = "ID_AA64DFR0_EL1";
> > +  char                *description;
> > +  char                *bits;
> > +
> > +  bits  = "3:0 ";
> > +  value = (aa64dfr0_el1 >>  4) & 0xf;
> > +  switch (value) {
> > +    case 0b0110:
> > +      description = "Armv8 debug architecture";
> > +      break;
> > +    case 0b0111:
> > +      description = "Armv8 debug architecture with VHE";
> > +      break;
> > +    case 0b1000:
> > +      description = "FEAT_Debugv8p2 implemented.";
> > +      break;
> > +    case 0b1001:
> > +      description = "FEAT_Debugv8p4 implemented.";
> > +      break;
> > +    case 0b1010:
> > +      description = "FEAT_Debugv8p8 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "7:4 ";
> > +  value = (aa64dfr0_el1 >>  4) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "Trace unit System registers not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "Trace unit System registers implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "11:8 ";
> > +  value = (aa64dfr0_el1 >>  8) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "Performance Monitors Extension not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_PMUv3 implemented.";
> > +      break;
> > +    case 0b0100:
> > +      description = "FEAT_PMUv3p1 implemented.";
> > +      break;
> > +    case 0b0101:
> > +      description = "FEAT_PMUv3p4 implemented.";
> > +      break;
> > +    case 0b0110:
> > +      description = "FEAT_PMUv3p5 implemented.";
> > +      break;
> > +    case 0b0111:
> > +      description = "FEAT_PMUv3p7 implemented.";
> > +      break;
> > +    case 0b1000:
> > +      description = "FEAT_PMUv3p8 implemented.";
> > +      break;
> > +    case 0b1111:
> > +      description = "IMPLEMENTATION DEFINED form of performance monitors supported.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "15:12";
> > +  value = (aa64dfr0_el1 >> 12) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "reserved";
> > +      break;
> > +    default:
> > +      description = "Number of breakpoints, minus 1.";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  // 19:16 reserved
> > +
> > +  bits  = "23:20";
> > +  value = (aa64dfr0_el1 >> 20) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "reserved";
> > +      break;
> > +    default:
> > +      description = "Number of watchpoints, minus 1.";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  // 27:24 reserved
> > +
> > +  bits  = "31:28";
> > +  value = (aa64dfr0_el1 >> 28) & 0xf;
> > +  switch (value) {
> > +    default:
> > +      description = "Number of breakpoints that are context-aware, minus 1.";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "35:32";
> > +  value = (aa64dfr0_el1 >> 32) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_SPE not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_SPE implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_SPEv1p1 implemented.";
> > +      break;
> > +    case 0b0011:
> > +      description = "FEAT_SPEv1p2 implemented.";
> > +      break;
> > +    case 0b0100:
> > +      description = "FEAT_SPEv1p3 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "39:36";
> > +  value = (aa64dfr0_el1 >> 36) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_DoubleLock implemented.";
> > +      break;
> > +    case 0b1111:
> > +      description = "FEAT_DoubleLock not implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "43:40";
> > +  value = (aa64dfr0_el1 >> 40) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_TRF not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_TRF implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "47:44";
> > +  value = (aa64dfr0_el1 >> 44) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_TRBE not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_TRBE implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "51:48";
> > +  value = (aa64dfr0_el1 >> 48) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_MTPMU not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_MTPMU and FEAT_PMUv3 implemented.";
> > +      break;
> > +    case 0b1111:
> > +      description = "FEAT_MTPMU not implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  bits  = "55:52";
> > +  value = (aa64dfr0_el1 >> 52) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "FEAT_BRBE not implemented.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_BRBE implemented.";
> > +      break;
> > +    case 0b0010:
> > +      description = "FEAT_BRBEv1p1 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +
> > +  // 59:56 reserved
> > +
> > +  bits  = "63:60";
> > +  value = (aa64dfr0_el1 >> 60) & 0xf;
> > +  switch (value) {
> > +    case 0b0000:
> > +      description = "Setting MDCR_EL2.HPMN to zero has CONSTRAINED UNPREDICTABLE behavior.";
> > +      break;
> > +    case 0b0001:
> > +      description = "FEAT_HPMN0 implemented.";
> > +      break;
> > +    default:
> > +      description = "unknown";
> > +      break;
> > +  }
> > +
> > +  print_values (RegName, bits, value, description);
> > +}
> > +
> > +EFI_STATUS
> > +EFIAPI
> > +UefiMain  (
> > +  IN EFI_HANDLE        ImageHandle,
> > +  IN EFI_SYSTEM_TABLE  *SystemTable
> > +  )
> > +{
> > +  UINT64  aa64dfr0_el1  = read_aa64dfr0_el1 ();
> > +  UINT64  aa64dfr1_el1  = read_aa64dfr1_el1 ();
> > +  UINT64  aa64isar0_el1 = read_aa64isar0_el1 ();
> > +  UINT64  aa64isar1_el1 = read_aa64isar1_el1 ();
> > +  UINT64  aa64isar2_el1 = read_aa64isar2_el1 ();
> > +  UINT64  aa64mmfr0_el1 = read_aa64mmfr0_el1 ();
> > +  UINT64  aa64mmfr1_el1 = read_aa64mmfr1_el1 ();
> > +  UINT64  aa64mmfr2_el1 = read_aa64mmfr2_el1 ();
> > +  UINT64  aa64pfr0_el1  = read_aa64pfr0_el1 ();
> > +  UINT64  aa64pfr1_el1  = read_aa64pfr1_el1 ();
>
> EDK2 requires separation between declarations and code (something
> alike old C89 semantics, but stricter). so:
>     UINT64 aa64pfr1_el1;
>     <...>
>     aa64pfr1_el1 = read_aa64pfr1_el1 ();
>
> > +
> > +  /*    UINT64 aa64smfr0_el1 = read_aa64smfr0_el1 ();*/
> > +  /*    UINT64 aa64zfr0_el1 = read_aa64zfr0_el1 ();*/
>
> Dead Code?
> > +
> > +  AsciiPrint ("ID_AA64MMFR0_EL1 = 0x%016lx\n", aa64mmfr0_el1);
> > +  AsciiPrint ("ID_AA64MMFR1_EL1 = 0x%016lx\n", aa64mmfr1_el1);
> > +  AsciiPrint ("ID_AA64MMFR2_EL1 = 0x%016lx\n", aa64mmfr2_el1);
> > +  AsciiPrint ("ID_AA64PFR0_EL1  = 0x%016lx\n", aa64pfr0_el1);
> > +  AsciiPrint ("ID_AA64PFR1_EL1  = 0x%016lx\n", aa64pfr1_el1);
> > +  AsciiPrint ("ID_AA64ISAR0_EL1 = 0x%016lx\n", aa64isar0_el1);
> > +  AsciiPrint ("ID_AA64ISAR1_EL1 = 0x%016lx\n", aa64isar1_el1);
> > +  AsciiPrint ("ID_AA64ISAR2_EL1 = 0x%016lx\n", aa64isar2_el1);
> > +  AsciiPrint ("ID_AA64DFR0_EL1  = 0x%016lx\n", aa64dfr0_el1);
> > +  AsciiPrint ("ID_AA64DFR1_EL1  = 0x%016lx\n", aa64dfr1_el1);            // ignore
>
> Why ignore?
>
> > +  /*    AsciiPrint ("ID_AA64SMFR0_EL1 = 0x%016lx\n", aa64smfr0_el1);*/
> > +  /*    AsciiPrint ("ID_AA64ZFR0_EL1 = 0x%016lx\n", aa64zfr0_el1);*/
>
> dead?
> > +
> > +  AsciiPrint ("\n");
> > +  print_text ("Register", "Bits", "Value", "Feature");
> > +  print_spacer ();
> > +
> > +  handle_aa64mmfr0_el1 (aa64mmfr0_el1);
> > +  print_spacer ();
> > +  handle_aa64mmfr1_el1 (aa64mmfr1_el1, aa64pfr0_el1);
> > +  print_spacer ();
> > +  handle_aa64mmfr2_el1 (aa64mmfr2_el1);
> > +
> > +  print_spacer ();
> > +  handle_aa64pfr0_el1 (aa64pfr0_el1, aa64pfr1_el1);
> > +  print_spacer ();
> > +  handle_aa64pfr1_el1 (aa64pfr1_el1);
> > +
> > +  print_spacer ();
> > +  handle_aa64isar0_el1 (aa64isar0_el1);
> > +  print_spacer ();
> > +  handle_aa64isar1_el1 (aa64isar1_el1);
> > +  print_spacer ();
> > +  handle_aa64isar2_el1 (aa64isar2_el1);
> > +
> > +  print_spacer ();
> > +  handle_aa64dfr0_el1 (aa64dfr0_el1);
> > +
> > +  return EFI_SUCCESS;
> > +}
> > diff --git a/ArmPkg/Application/ArmCpuInfo/readregs.s b/ArmPkg/Application/ArmCpuInfo/readregs.s
>
> ASM files that require preprocessing should have a capital S here (.S vs .s)
>
> > new file mode 100644
> > index 000000000000..052834b3c3f2
> > --- /dev/null
> > +++ b/ArmPkg/Application/ArmCpuInfo/readregs.s
> > @@ -0,0 +1,49 @@
> > +#include <AsmMacroIoLibV8.h>
> > +
> > +ASM_FUNC(read_aa64pfr0_el1)
> > +        mrs x0, ID_AA64PFR0_EL1;
> > +        ret;
>
> ASM lines (for GAS at least) don't usually end in semicolons. so
>    +ASM_FUNC(read_aa64pfr0_el1)
>    +        mrs x0, ID_AA64PFR0_EL1
>    +        ret
>
> You'd only need the semicolons if you had multiple instructions in one
> line (like mrs x0, ID_AA...; ret)
>
> > +
> > +ASM_FUNC(read_aa64pfr1_el1)
> > +        mrs x0, ID_AA64PFR1_EL1;
> > +        ret;
> > +
> > +ASM_FUNC(read_aa64dfr0_el1)
> > +        mrs x0, ID_AA64DFR0_EL1;
> > +        ret;
> > +
> > +ASM_FUNC(read_aa64dfr1_el1)
> > +        mrs x0, ID_AA64DFR1_EL1;
> > +        ret;
> > +
> > +ASM_FUNC(read_aa64isar0_el1)
> > +        mrs x0, ID_AA64ISAR0_EL1;
> > +        ret;
> > +
> > +ASM_FUNC(read_aa64isar1_el1)
> > +        mrs x0, ID_AA64ISAR1_EL1;
> > +        ret;
> > +
> > +ASM_FUNC(read_aa64isar2_el1)
> > +        mrs x0, ID_AA64ISAR2_EL1;
> > +        ret;
> > +
> > +ASM_FUNC(read_aa64mmfr0_el1)
> > +        mrs x0, ID_AA64MMFR0_EL1;
> > +        ret;
> > +
> > +ASM_FUNC(read_aa64mmfr1_el1)
> > +        mrs x0, ID_AA64MMFR1_EL1;
> > +        ret;
> > +
> > +ASM_FUNC(read_aa64mmfr2_el1)
> > +        mrs x0, ID_AA64MMFR2_EL1;
> > +        ret;
> > +
> > +# ASM_FUNC(read_aa64zfr0_el1)
> > +#     mrs x0, ID_AA64ZFR0_EL1;
> > +#     ret;
> > +
> > +# ASM_FUNC(read_aa64smfr0_el1)
> > +#     mrs x0, ID_AA64SMFR0_EL1;
> > +#     ret;
>
> Dead code?
>
> > --
> > 2.40.0
>
> Marcin,
>
> Brief comments in general:
> 1) You use binary literals extensively, which are not portable (GNU C
> extension, AFAIK not in MSVC)
>
> 2) Naming of identifiers (vars, functions, etc) needs to follow the
> EDK2 style. eg:
>     description vs Description
>     read_aa64mmfr1_el1 vs ReadAa64MmfrEl1
>     etc...
>
> --
> Pedro



-- 
Pedro


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#102696): https://edk2.groups.io/g/devel/message/102696
Mute This Topic: https://groups.io/mt/98123579/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
[edk2-devel] [PATCH v4] add ArmCpuInfo EFI application
Posted by Marcin Juszkiewicz 1 year ago
App goes through ID_AA64*_EL1 system registers and decode their values.

Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
---
 ArmPkg/ArmPkg.dsc                            |    1 +
 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf |   38 +
 ArmPkg/Application/ArmCpuInfo/readargs.h     |   10 +
 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c   | 2319 ++++++++++++++++++++
 ArmPkg/Application/ArmCpuInfo/readregs.S     |   41 +
 5 files changed, 2409 insertions(+)

diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
index 3fb95d1951a9..6b938ce8b671 100644
--- a/ArmPkg/ArmPkg.dsc
+++ b/ArmPkg/ArmPkg.dsc
@@ -166,6 +166,7 @@ [Components.AARCH64]
   ArmPkg/Drivers/ArmPsciMpServicesDxe/ArmPsciMpServicesDxe.inf
   ArmPkg/Drivers/MmCommunicationDxe/MmCommunication.inf
   ArmPkg/Library/ArmMmuLib/ArmMmuPeiLib.inf
+  ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
 
 [Components.AARCH64, Components.ARM]
   ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStandaloneMmLib.inf
diff --git a/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
new file mode 100644
index 000000000000..d80a19660a55
--- /dev/null
+++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
@@ -0,0 +1,38 @@
+## @file
+#
+#  Attempt to have AArch64 cpu information.
+#
+#  Based on HelloWorld:
+#  Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.
+#  Copyright (c) 2023 Marcin Juszkiewicz
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010019
+  BASE_NAME                      = ArmCpuInfo
+  FILE_GUID                      = b3134491-6502-4faf-a9da-007184e32163
+  MODULE_TYPE                    = UEFI_APPLICATION
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = UefiMain
+
+#
+#  This flag specifies whether HII resource section is generated into PE image.
+#
+  UEFI_HII_RESOURCE_SECTION      = TRUE
+
+[Sources]
+  ArmCpuInfo.c
+  readregs.S
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  UefiApplicationEntryPoint
+  UefiLib
diff --git a/ArmPkg/Application/ArmCpuInfo/readargs.h b/ArmPkg/Application/ArmCpuInfo/readargs.h
new file mode 100644
index 000000000000..b154945c6562
--- /dev/null
+++ b/ArmPkg/Application/ArmCpuInfo/readargs.h
@@ -0,0 +1,10 @@
+UINT64 ReadAa64Pfr0El1(void);
+UINT64 ReadAa64Pfr1El1(void);
+UINT64 ReadAa64Dfr0El1(void);
+UINT64 ReadAa64Dfr1El1(void);
+UINT64 ReadAa64Isar0El1(void);
+UINT64 ReadAa64Isar1El1(void);
+UINT64 ReadAa64Isar2El1(void);
+UINT64 ReadAa64Mmfr0El1(void);
+UINT64 ReadAa64Mmfr1El1(void);
+UINT64 ReadAa64Mmfr2El1(void);
diff --git a/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
new file mode 100644
index 000000000000..13f77717215d
--- /dev/null
+++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
@@ -0,0 +1,2319 @@
+/** @file
+
+  Copyright  (c) 2023 Marcin Juszkiewicz
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ **/
+
+#include <Library/UefiLib.h>
+#include "readargs.h"
+
+VOID
+PrintText (
+  CONST CHAR8  *field,
+  CONST CHAR8  *Bits,
+  CONST CHAR8  *Value,
+  CONST CHAR8  *Description
+  )
+{
+  AsciiPrint (" %-16a | %5a | %5a | %a\n", field, Bits, Value, Description);
+}
+
+VOID
+PrintValues (
+  CONST CHAR8  *field,
+  CONST CHAR8  *Bits,
+  CONST UINT8  Value,
+  CONST CHAR8  *Description
+  )
+{
+  STATIC CONST CHAR8  binaries[][5] = {
+    "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
+    "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"
+  };
+
+  AsciiPrint (" %-16a | %5a | %5a | %a\n", field, Bits, binaries[Value & 0xf], Description);
+}
+
+VOID
+PrintSpacer (
+  VOID
+  )
+{
+  AsciiPrint ("------------------|-------|-------|----------------------------------------------\n");
+}
+
+VOID
+HandleAa64Mmfr0El1 (
+  CONST UINT64  Aa64Mmfr0El1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR0El1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = Aa64Mmfr0El1 & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "32 Bits  (4GB) of physical address range supported.";
+      break;
+    case 0b0001:
+      Description = "36 Bits  (64GB) of physical address range supported.";
+      break;
+    case 0b0010:
+      Description = "40 Bits  (1TB) of physical address range supported.";
+      break;
+    case 0b0011:
+      Description = "42 Bits  (4TB) of physical address range supported.";
+      break;
+    case 0b0100:
+      Description = "44 Bits  (16TB) of physical address range supported.";
+      break;
+    case 0b0101:
+      Description = "48 Bits  (256TB) of physical address range supported.";
+      break;
+    case 0b0110:
+      Description = "52 Bits  (4PB) of physical address range supported.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+  if (Value == 0b0110) {
+    PrintText ("", "", "", "FEAT_LPA implemented.");
+  }
+
+  Bits  = "7:4 ";
+  Value = (Aa64Mmfr0El1 >>  4) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "ASID: 8 Bits";
+      break;
+    case 0b0010:
+      Description = "ASID: 16 Bits";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Mmfr0El1 >>  8) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "No mixed-endian support.";
+      break;
+    case 0b0001:
+      Description = "Mixed-endian support.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // only valid for BigEnd != 0b0000
+  if (((Aa64Mmfr0El1 >>  8) & 0xf) != 0b0000 ) {
+    if (((Aa64Mmfr0El1 >> 16) & 0xf) == 0b0000 ) {
+      PrintValues ("ID_AA64MMFR0El1", "19:16", 0b0000, "No mixed-endian support at EL0.");
+    }
+
+    if (((Aa64Mmfr0El1 >> 16) & 0xf) == 0b0001 ) {
+      PrintValues ("ID_AA64MMFR0El1", "19:16", 0b0001, "Mixed-endian support at EL0.");
+    }
+  }
+
+  Bits  = "15:12";
+  Value = (Aa64Mmfr0El1 >> 12) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "No support for a distinction between Secure and Non-Secure Memory.";
+      break;
+    case 0b0001:
+      Description = "Supports a distinction between Secure and Non-Secure Memory.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "31:28";
+  Value = (Aa64Mmfr0El1 >> 28) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = " 4KB granule supported.";
+      break;
+    case 0b1111:
+      Description = " 4KB granule not supported.";
+      break;
+    case 0b0001:             // add FEAT_LPA2 check
+      Description = " 4KB granule supported for 52-bit address.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Mmfr0El1 >> 40) & 0xf;
+  switch (Value) {
+    case 0b0001:
+      Description = " 4KB granule not supported at stage 2.";
+      break;
+    case 0b0010:
+      Description = " 4KB granule supported at stage 2.";
+      break;
+    case 0b0011:
+      Description = " 4KB granule supported at stage 2 for 52-bit address.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Mmfr0El1 >> 20) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "16KB granule not supported.";
+      break;
+    case 0b0001:
+      Description = "16KB granule supported.";
+      break;
+    case 0b0010:             // add FEAT_LPA2 check
+      Description = "16KB granule supported for 52-bit address.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Mmfr0El1 >> 32) & 0xf;
+  switch (Value) {
+    case 0b0001:
+      Description = "16KB granule not supported at stage 2.";
+      break;
+    case 0b0010:
+      Description = "16KB granule supported at stage 2.";
+      break;
+    case 0b0011:
+      Description = "16KB granule supported at stage 2 for 52-bit address.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "27:24";
+  Value = (Aa64Mmfr0El1 >> 24) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "64KB granule supported.";
+      break;
+    case 0b1111:
+      Description = "64KB granule not supported.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Mmfr0El1 >> 36) & 0xf;
+  switch (Value) {
+    case 0b0001:
+      Description = "64KB granule not supported at stage 2.";
+      break;
+    case 0b0010:
+      Description = "64KB granule supported at stage 2.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Mmfr0El1 >> 44) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_ExS not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_ExS implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 55:48 reserved
+
+  Bits  = "59:56";
+  Value = (Aa64Mmfr0El1 >> 56) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_FGT not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_FGT implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "63:60";
+  Value = (Aa64Mmfr0El1 >> 60) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_ECV not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_ECV implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_ECV implemented with extras.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+VOID
+HandleAa64Mmfr1El1 (
+  CONST UINT64  Aa64Mmfr1El1,
+  CONST UINT64  Aa64Pfr0El1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR1El1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = Aa64Mmfr1El1 & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_HAFDBS not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_HAFDBS implemented without dirty status support.";
+      break;
+    case 0b0010:
+      Description = "FEAT_HAFDBS implemented with dirty status support.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Mmfr1El1 >>  4) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_VMID16 not implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_VMID16 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Mmfr1El1 >>  8) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_VHE not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_VHE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Mmfr1El1 >> 12) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_HPDS not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_HPDS implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_HPDS2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Mmfr1El1 >> 16) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_LOR not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_LOR implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Mmfr1El1 >> 20) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_PAN not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_PAN implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_PAN2 implemented.";
+      break;
+    case 0b0011:
+      Description = "FEAT_PAN3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // when FEAT_RAS implemented
+  if ((((Aa64Pfr0El1 >> 28) & 0xf) == 0b0001) ||
+      (((Aa64Pfr0El1 >> 28) & 0xf) == 0b0010))
+  {
+    if (((Aa64Mmfr1El1 >> 24) & 0xf) == 0b0000 ) {
+      PrintValues ("ID_AA64MMFR1El1", "27:24", 0b0000, "The PE never generates an SError interrupt due to");
+      PrintText ("", "", "", "an External abort on a speculative read.");
+    }
+
+    if (((Aa64Mmfr1El1 >> 24) & 0xf) == 0b0001 ) {
+      PrintValues ("ID_AA64MMFR1El1", "27:24", 0b0001, "The PE might generate an SError interrupt due to");
+      PrintText ("", "", "", "an External abort on a speculative read.");
+    }
+  }
+
+  Bits  = "31:28";
+  Value = (Aa64Mmfr1El1 >> 28) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_XNX not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_XNX implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Mmfr1El1 >> 32) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_TWED not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_TWED implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Mmfr1El1 >> 36) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_ETS not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_ETS implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Mmfr1El1 >> 40) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_HCX not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_HCX implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Mmfr1El1 >> 44) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_AFP not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_AFP implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "51:48";
+  Value = (Aa64Mmfr1El1 >> 48) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_nTLBPA not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_nTLBPA implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Mmfr1El1 >> 52) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_TIDCP1 not implemented";
+      break;
+    case 0b0001:
+      Description = "FEAT_TIDCP1 implemented";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "59:56";
+  Value = (Aa64Mmfr1El1 >> 56) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_CMOW not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_CMOW implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 63:60 reserved
+}
+
+VOID
+HandleAa64Mmfr2El1 (
+  CONST UINT64  Aa64Mmfr2El1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR2El1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Mmfr2El1)       & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_TTCNP not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_TTCNP implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Mmfr2El1 >>  4) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_UAO not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_UAO implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Mmfr2El1 >>  8) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_LSMAOC not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_LSMAOC implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Mmfr2El1 >> 12) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_IESB not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_IESB implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Mmfr2El1 >> 16) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_LVA not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_LVA implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Mmfr2El1 >> 20) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_CCIDX not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_CCIDX implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "27:24";
+  Value = (Aa64Mmfr2El1 >> 24) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_NV not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_NV implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_NV2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "31:28";
+  Value = (Aa64Mmfr2El1 >> 28) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_TTST not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_TTST implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Mmfr2El1 >> 32) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_LSE2 not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_LSE2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Mmfr2El1 >> 36) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_IDST not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_IDST implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Mmfr2El1 >> 40) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_S2FWB not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_S2FWB implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 47:44 reserved
+
+  Bits  = "51:48";
+  Value = (Aa64Mmfr2El1 >> 48) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_TTL not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_TTL implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Mmfr2El1 >> 52) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_BBM: Level 0 support for changing block size is supported.";
+      break;
+    case 0b0001:
+      Description = "FEAT_BBM: Level 1 support for changing block size is supported.";
+      break;
+    case 0b0010:
+      Description = "FEAT_BBM: Level 2 support for changing block size is supported.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "59:56";
+  Value = (Aa64Mmfr2El1 >> 56) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_EVT not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_EVT: HCR_EL2.{TOCU, TICAB, TID4} traps are supported.";
+      break;
+    case 0b0010:
+      Description = "FEAT_EVT: HCR_EL2.{TTLBOS, TTLSBIS, TOCU, TICAB, TID4} traps are supported.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "63:60";
+  Value = (Aa64Mmfr2El1 >> 60) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_E0PD not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_E0PD implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+VOID
+HandleAa64Pfr0El1 (
+  CONST UINT64  Aa64Pfr0El1,
+  CONST UINT64  Aa64Pfr1El1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR0El1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Pfr0El1)       & 0xf;
+  switch (Value) {
+    case 0b0001:
+      Description = "EL0 in AArch64 only";
+      break;
+    case 0b0010:
+      Description = "EL0 in AArch64 and AArch32";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Pfr0El1 >>  4) & 0xf;
+  switch (Value) {
+    case 0b0001:
+      Description = "EL1 in AArch64 only";
+      break;
+    case 0b0010:
+      Description = "EL1 in AArch64 and AArch32";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Pfr0El1 >>  8) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "EL2 not implemented.";
+      break;
+    case 0b0001:
+      Description = "EL2 in AArch64 only";
+      break;
+    case 0b0010:
+      Description = "EL2 in AArch64 and AArch32";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Pfr0El1 >> 12) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "EL3 not implemented.";
+      break;
+    case 0b0001:
+      Description = "EL3 in AArch64 only";
+      break;
+    case 0b0010:
+      Description = "EL3 in AArch64 and AArch32";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Pfr0El1 >> 16) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "Floating-point implemented.";
+      break;
+    case 0b0001:
+      Description = "Floating-point with half-precision support  (FEAT_FP16).";
+      break;
+    case 0b1111:
+      Description = "Floating-point not implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Pfr0El1 >> 20) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "Advanced SIMD implemented.";
+      break;
+    case 0b0001:
+      Description = "Advanced SIMD with half precision support  (FEAT_FP16).";
+      break;
+    case 0b1111:
+      Description = "Advanced SIMD not implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "27:24";
+  Value = (Aa64Pfr0El1 >> 24) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "System registers of GIC CPU not implemented.";
+      break;
+    case 0b0001:
+      Description = "System registers to versions 3.0/4.0 of GIC CPU implemented.";
+      break;
+    case 0b0011:
+      Description = "System registers to versions 4.1 of GIC CPU implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "31:28";
+  Value = (Aa64Pfr0El1 >> 28) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_RAS not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_RAS implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_RASv1p1 implemented.";
+      // 0b0010 FEAT_RASv1p1 implemented and, if EL3 is implemented, FEAT_DoubleFault implemented.
+      if ((((Aa64Pfr0El1 >> 12) & 0xf) == 0b0001) ||
+          (((Aa64Pfr0El1 >> 12) & 0xf) == 0b0010))
+      {
+        Description = "FEAT_RASv1p1 implemented. FEAT_DoubleFault implemented.";
+      }
+
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Pfr0El1 >> 32) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_SVE not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_SVE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Pfr0El1 >> 36) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "Secure EL2 not implemented.";
+      break;
+    case 0b0001:
+      Description = "Secure EL2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Pfr0El1 >> 40) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      if (((Aa64Pfr1El1 >> 16) & 0xf) == 0b0000 ) {
+        Description = "FEAT_MPAM not implemented.";
+      }
+
+      if (((Aa64Pfr1El1 >> 16) & 0xf) == 0b0001 ) {
+        Description = "FEAT_MPAM v0.1 implemented.";
+      }
+
+      break;
+    case 0b0001:
+      if (((Aa64Pfr1El1 >> 16) & 0xf) == 0b0000 ) {
+        Description = "FEAT_MPAM v1.0 implemented.";
+      }
+
+      if (((Aa64Pfr1El1 >> 16) & 0xf) == 0b0001 ) {
+        Description = "FEAT_MPAM v1.1 implemented.";
+      }
+
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Pfr0El1 >> 44) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_AMU not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_AMUv1 implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_AMUv1p1 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "51:48";
+  Value = (Aa64Pfr0El1 >> 48) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_DIT not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_DIT implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Pfr0El1 >> 52) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_RME not implemented";
+      break;
+    case 0b0001:
+      Description = "FEAT_RME implemented";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "59:56";
+  Value = (Aa64Pfr0El1 >> 56) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "no info is FEAT_CSV2 implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_CSV2 implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_CSV2_2 implemented.";
+      break;
+    case 0b0011:
+      Description = "FEAT_CSV2_3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+  if (Value == 0b0001) {
+    if (((Aa64Pfr1El1 >> 32) & 0xf) == 0b0001 ) {
+      PrintValues ("ID_AA64PRF1El1", "35:32", 0b0001, "FEAT_CSV2_1p1 implemented.");
+    }
+
+    if (((Aa64Pfr1El1 >> 32) & 0xf) == 0b0010 ) {
+      PrintValues ("ID_AA64PRF1El1", "35:32", 0b0010, "FEAT_CSV2_1p2 implemented.");
+    }
+  }
+
+  Bits  = "63:60";
+  Value = (Aa64Pfr0El1 >> 60) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_CSV3 not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_CSV3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+VOID
+HandleAa64Pfr1El1 (
+  CONST UINT64  Aa64Pfr1El1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR1El1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = Aa64Pfr1El1 & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_BTI not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_BTI implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Pfr1El1 >>  4) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_SSBS not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_SSBS implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_SSBS2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Pfr1El1 >>  8) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_MTE not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_MTE implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_MTE2 implemented.";
+      break;
+    case 0b0011:
+      Description = "FEAT_MTE3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 15:12 is RAS_frac
+  // 19:16 is MPAM_frac
+  // 23:20 is reserved
+
+  Bits  = "27:24";
+  Value = (Aa64Pfr1El1 >> 24) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_SME not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_SME implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "31:28";
+  Value = (Aa64Pfr1El1 >> 28) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_RNG_TRAP not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_RNG_TRAP implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 35:32 is CSV2_frac
+
+  Bits  = "39:36";
+  Value = (Aa64Pfr1El1 >> 36) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_NMI not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_NMI implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 63:40 are reserved
+}
+
+VOID
+HandleAa64Isar0El1 (
+  CONST UINT64  Aa64Isar0El1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR0El1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  // 3:0 reserved
+
+  Bits  = "7:4 ";
+  Value = (Aa64Isar0El1 >>  4) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_AES, FEAT_PMULL not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_AES implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_AES and FEAT_PMULL implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Isar0El1 >>  8) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_SHA1 not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_SHA1 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Isar0El1 >> 12) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_SHA256, FEAT_SHA512 not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_SHA256 implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_SHA512 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Isar0El1 >> 16) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "CRC32 not implemented.";
+      break;
+    case 0b0001:
+      Description = "CRC32 instructions implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Isar0El1 >> 20) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_LSE not implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_LSE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "27:24";
+  Value = (Aa64Isar0El1 >> 24) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "TME instructions not implemented.";
+      break;
+    case 0b0001:
+      Description = "TME instructions implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "31:28";
+  Value = (Aa64Isar0El1 >> 28) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_RDM not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_RDM implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Isar0El1 >> 32) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_SHA3 not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_SHA3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Isar0El1 >> 36) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_SM3 not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_SM3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Isar0El1 >> 40) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_SM4 not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_SM4 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Isar0El1 >> 44) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_DotProd not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_DotProd implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "51:48";
+  Value = (Aa64Isar0El1 >> 48) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_FHM not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_FHM implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Isar0El1 >> 52) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_FlagM/FEAT_FlagM2 not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_FlagM implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_FlagM2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "59:56";
+  Value = (Aa64Isar0El1 >> 56) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_TLBIOS/FEAT_TLBIRANGE not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_TLBIOS implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_TLBIRANGE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "63:60";
+  Value = (Aa64Isar0El1 >> 60) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_RNG not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_RNG implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+VOID
+HandleAa64Isar1El1 (
+  CONST UINT64  Aa64Isar1El1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR1El1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Isar1El1 >>  4) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "DC CVAP not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_DPB implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_DPB2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Isar1El1 >>  4) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "Address Authentication  (APA) not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_PAuth implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_EPAC implemented.";
+      break;
+    case 0b0011:
+      Description = "FEAT_PAuth2 implemented.";
+      break;
+    case 0b0100:
+      Description = "FEAT_FPAC implemented.";
+      break;
+    case 0b0101:
+      Description = "FEAT_FPACCOMBINE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+  if (Value > 0) {
+    PrintText ("", "", "", "FEAT_PACQARMA5 implemented.");
+  }
+
+  Bits  = "11:8 ";
+  Value = (Aa64Isar1El1 >>  8) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "Address Authentication  (API) not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_PAuth implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_EPAC implemented.";
+      break;
+    case 0b0011:
+      Description = "FEAT_PAuth2 implemented.";
+      break;
+    case 0b0100:
+      Description = "FEAT_FPAC implemented.";
+      break;
+    case 0b0101:
+      Description = "FEAT_FPACCOMBINE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+  if (Value > 0) {
+    PrintText ("", "", "", "FEAT_PACIMP implemented.");
+  }
+
+  Bits  = "15:12";
+  Value = (Aa64Isar1El1 >> 12) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_JSCVT not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_JSCVT implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Isar1El1 >> 16) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_FCMA not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_FCMA implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Isar1El1 >> 20) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_LRCPC (2) not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_LRCPC implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_LRCPC2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "27:24";
+  Value = (Aa64Isar1El1 >> 24) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_PACQARMA5 not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_PACQARMA5 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "31:28";
+  Value = (Aa64Isar1El1 >> 28) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_PACIMP not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_PACIMP implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Isar1El1 >> 32) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_FRINTTS not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_FRINTTS implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Isar1El1 >> 36) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_SB not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_SB implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Isar1El1 >> 40) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_SPECRES not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_SPECRES implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Isar1El1 >> 44) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_BF16 not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_BF16 implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_EBF16 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "51:48";
+  Value = (Aa64Isar1El1 >> 48) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_DGH not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_DGH implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Isar1El1 >> 52) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_I8MM not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_I8MM implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "59:56";
+  Value = (Aa64Isar1El1 >> 56) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_XS not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_XS implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "63:60";
+  Value = (Aa64Isar1El1 >> 60) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_LS64 not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_LS64 implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_LS64_V implemented.";
+      break;
+    case 0b0011:
+      Description = "FEAT_LS64_ACCDATA implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+VOID
+HandleAa64Isar2El1 (
+  CONST UINT64  Aa64Isar2El1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR2El1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Isar2El1 >>  4) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_WFxT not implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_WFxT implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Isar2El1 >>  4) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_RPRES not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_RPRES implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Isar2El1 >>  8) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_PACQARMA3 not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_PACQARMA3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Isar2El1 >> 12) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "Address Authentication  (APA3) not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_PAuth implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_EPAC implemented.";
+      break;
+    case 0b0011:
+      Description = "FEAT_PAuth2 implemented.";
+      break;
+    case 0b0100:
+      Description = "FEAT_FPAC implemented.";
+      break;
+    case 0b0101:
+      Description = "FEAT_FPACCOMBINE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Isar2El1 >> 16) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_MOPS not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_MOPS implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Isar2El1 >> 20) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_HBC not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_HBC implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "27:24";
+  Value = (Aa64Isar2El1 >> 24) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_CONSTPACFIELD not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_CONSTPACFIELD implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 63:28 reserved
+}
+
+VOID
+HandleAa64Dfr0El1 (
+  CONST UINT64  Aa64Dfr0El1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64DFR0El1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Dfr0El1 >>  4) & 0xf;
+  switch (Value) {
+    case 0b0110:
+      Description = "Armv8 debug architecture";
+      break;
+    case 0b0111:
+      Description = "Armv8 debug architecture with VHE";
+      break;
+    case 0b1000:
+      Description = "FEAT_Debugv8p2 implemented.";
+      break;
+    case 0b1001:
+      Description = "FEAT_Debugv8p4 implemented.";
+      break;
+    case 0b1010:
+      Description = "FEAT_Debugv8p8 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Dfr0El1 >>  4) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "Trace unit System registers not implemented.";
+      break;
+    case 0b0001:
+      Description = "Trace unit System registers implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Dfr0El1 >>  8) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "Performance Monitors Extension not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_PMUv3 implemented.";
+      break;
+    case 0b0100:
+      Description = "FEAT_PMUv3p1 implemented.";
+      break;
+    case 0b0101:
+      Description = "FEAT_PMUv3p4 implemented.";
+      break;
+    case 0b0110:
+      Description = "FEAT_PMUv3p5 implemented.";
+      break;
+    case 0b0111:
+      Description = "FEAT_PMUv3p7 implemented.";
+      break;
+    case 0b1000:
+      Description = "FEAT_PMUv3p8 implemented.";
+      break;
+    case 0b1111:
+      Description = "IMPLEMENTATION DEFINED form of performance monitors supported.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Dfr0El1 >> 12) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "reserved";
+      break;
+    default:
+      Description = "Number of breakpoints, minus 1.";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 19:16 reserved
+
+  Bits  = "23:20";
+  Value = (Aa64Dfr0El1 >> 20) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "reserved";
+      break;
+    default:
+      Description = "Number of watchpoints, minus 1.";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 27:24 reserved
+
+  Bits  = "31:28";
+  Value = (Aa64Dfr0El1 >> 28) & 0xf;
+  switch (Value) {
+    default:
+      Description = "Number of breakpoints that are context-aware, minus 1.";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Dfr0El1 >> 32) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_SPE not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_SPE implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_SPEv1p1 implemented.";
+      break;
+    case 0b0011:
+      Description = "FEAT_SPEv1p2 implemented.";
+      break;
+    case 0b0100:
+      Description = "FEAT_SPEv1p3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Dfr0El1 >> 36) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_DoubleLock implemented.";
+      break;
+    case 0b1111:
+      Description = "FEAT_DoubleLock not implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Dfr0El1 >> 40) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_TRF not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_TRF implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Dfr0El1 >> 44) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_TRBE not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_TRBE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "51:48";
+  Value = (Aa64Dfr0El1 >> 48) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_MTPMU not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_MTPMU and FEAT_PMUv3 implemented.";
+      break;
+    case 0b1111:
+      Description = "FEAT_MTPMU not implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Dfr0El1 >> 52) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "FEAT_BRBE not implemented.";
+      break;
+    case 0b0001:
+      Description = "FEAT_BRBE implemented.";
+      break;
+    case 0b0010:
+      Description = "FEAT_BRBEv1p1 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 59:56 reserved
+
+  Bits  = "63:60";
+  Value = (Aa64Dfr0El1 >> 60) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      Description = "Setting MDCR_EL2.HPMN to zero has CONSTRAINED UNPREDICTABLE behavior.";
+      break;
+    case 0b0001:
+      Description = "FEAT_HPMN0 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+EFI_STATUS
+EFIAPI
+UefiMain  (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  UINT64  Aa64Dfr0El1;
+  UINT64  Aa64Isar0El1;
+  UINT64  Aa64Isar1El1;
+  UINT64  Aa64Isar2El1;
+  UINT64  Aa64Mmfr0El1;
+  UINT64  Aa64Mmfr1El1;
+  UINT64  Aa64Mmfr2El1;
+  UINT64  Aa64Pfr0El1;
+  UINT64  Aa64Pfr1El1;
+
+  Aa64Dfr0El1  = ReadAa64Dfr0El1 ();
+  Aa64Isar0El1 = ReadAa64Isar0El1 ();
+  Aa64Isar1El1 = ReadAa64Isar1El1 ();
+  Aa64Isar2El1 = ReadAa64Isar2El1 ();
+  Aa64Mmfr0El1 = ReadAa64Mmfr0El1 ();
+  Aa64Mmfr1El1 = ReadAa64Mmfr1El1 ();
+  Aa64Mmfr2El1 = ReadAa64Mmfr2El1 ();
+  Aa64Pfr0El1  = ReadAa64Pfr0El1 ();
+  Aa64Pfr1El1  = ReadAa64Pfr1El1 ();
+
+  AsciiPrint ("ID_AA64MMFR0El1 = 0x%016lx\n", Aa64Mmfr0El1);
+  AsciiPrint ("ID_AA64MMFR1El1 = 0x%016lx\n", Aa64Mmfr1El1);
+  AsciiPrint ("ID_AA64MMFR2El1 = 0x%016lx\n", Aa64Mmfr2El1);
+  AsciiPrint ("ID_AA64PFR0El1  = 0x%016lx\n", Aa64Pfr0El1);
+  AsciiPrint ("ID_AA64PFR1El1  = 0x%016lx\n", Aa64Pfr1El1);
+  AsciiPrint ("ID_AA64ISAR0El1 = 0x%016lx\n", Aa64Isar0El1);
+  AsciiPrint ("ID_AA64ISAR1El1 = 0x%016lx\n", Aa64Isar1El1);
+  AsciiPrint ("ID_AA64ISAR2El1 = 0x%016lx\n", Aa64Isar2El1);
+  AsciiPrint ("ID_AA64DFR0El1  = 0x%016lx\n", Aa64Dfr0El1);
+
+  AsciiPrint ("\n");
+  PrintText ("Register", "Bits", "Value", "Feature");
+  PrintSpacer ();
+
+  HandleAa64Mmfr0El1 (Aa64Mmfr0El1);
+  PrintSpacer ();
+  HandleAa64Mmfr1El1 (Aa64Mmfr1El1, Aa64Pfr0El1);
+  PrintSpacer ();
+  HandleAa64Mmfr2El1 (Aa64Mmfr2El1);
+
+  PrintSpacer ();
+  HandleAa64Pfr0El1 (Aa64Pfr0El1, Aa64Pfr1El1);
+  PrintSpacer ();
+  HandleAa64Pfr1El1 (Aa64Pfr1El1);
+
+  PrintSpacer ();
+  HandleAa64Isar0El1 (Aa64Isar0El1);
+  PrintSpacer ();
+  HandleAa64Isar1El1 (Aa64Isar1El1);
+  PrintSpacer ();
+  HandleAa64Isar2El1 (Aa64Isar2El1);
+
+  PrintSpacer ();
+  HandleAa64Dfr0El1 (Aa64Dfr0El1);
+
+  return EFI_SUCCESS;
+}
diff --git a/ArmPkg/Application/ArmCpuInfo/readregs.S b/ArmPkg/Application/ArmCpuInfo/readregs.S
new file mode 100644
index 000000000000..21ba0a912823
--- /dev/null
+++ b/ArmPkg/Application/ArmCpuInfo/readregs.S
@@ -0,0 +1,41 @@
+#include <AsmMacroIoLibV8.h>
+
+ASM_FUNC(ReadAa64Pfr0El1)
+        mrs x0, ID_AA64PFR0_EL1
+        ret
+
+ASM_FUNC(ReadAa64Pfr1El1)
+        mrs x0, ID_AA64PFR1_EL1
+        ret
+
+ASM_FUNC(ReadAa64Dfr0El1)
+        mrs x0, ID_AA64DFR0_EL1
+        ret
+
+ASM_FUNC(ReadAa64Dfr1El1)
+        mrs x0, ID_AA64DFR1_EL1
+        ret
+
+ASM_FUNC(ReadAa64Isar0El1)
+        mrs x0, ID_AA64ISAR0_EL1
+        ret
+
+ASM_FUNC(ReadAa64Isar1El1)
+        mrs x0, ID_AA64ISAR1_EL1
+        ret
+
+ASM_FUNC(ReadAa64Isar2El1)
+        mrs x0, ID_AA64ISAR2_EL1
+        ret
+
+ASM_FUNC(ReadAa64Mmfr0El1)
+        mrs x0, ID_AA64MMFR0_EL1
+        ret
+
+ASM_FUNC(ReadAa64Mmfr1El1)
+        mrs x0, ID_AA64MMFR1_EL1
+        ret
+
+ASM_FUNC(ReadAa64Mmfr2El1)
+        mrs x0, ID_AA64MMFR2_EL1
+        ret
-- 
2.40.0



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#102703): https://edk2.groups.io/g/devel/message/102703
Mute This Topic: https://groups.io/mt/98124918/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-