public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH] add ArmCpuInfo EFI application
@ 2023-03-31 18:02 Marcin Juszkiewicz
  2023-04-06 21:05 ` [edk2-devel] " Rebecca Cran
  0 siblings, 1 reply; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-03-31 18:02 UTC (permalink / raw)
  To: devel; +Cc: Marcin Juszkiewicz

App goes through ID_AA64*_EL1 system registers and decode their values.

First version which does not use much of current AArch64 support code
present in EDK2. Written to check what data is there and what can be
done with it.
---
 .../Application/ArmCpuInfo/ArmCpuInfo.c       | 2277 +++++++++++++++++
 .../Application/ArmCpuInfo/ArmCpuInfo.inf     |   38 +
 .../Application/ArmCpuInfo/readargs.h         |   12 +
 .../Application/ArmCpuInfo/readregs.s         |   49 +
 MdeModulePkg/MdeModulePkg.dsc                 |    3 +-
 5 files changed, 2378 insertions(+), 1 deletion(-)
 create mode 100644 MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c
 create mode 100644 MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf
 create mode 100644 MdeModulePkg/Application/ArmCpuInfo/readargs.h
 create mode 100644 MdeModulePkg/Application/ArmCpuInfo/readregs.s

diff --git a/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c b/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c
new file mode 100644
index 0000000000..79a02ae430
--- /dev/null
+++ b/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c
@@ -0,0 +1,2277 @@
+/** @file
+
+  Copyright (c) 2023 Marcin Juszkiewicz
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ **/
+
+#include <stdbool.h>
+#include <Library/UefiLib.h>
+#include "readargs.h"
+
+bool sve_present = false;
+bool sme_present = false;
+
+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)
+{
+	char binaries[17][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], description);
+}
+
+void print_spacer(void)
+{
+	AsciiPrint("------------------|-------|-------|----------------------------------------------\n");
+}
+
+void handle_aa64mmfr0_el1(const UINT64 aa64mmfr0_el1)
+{
+	UINT64 value;
+	char* 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;
+	char* 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;
+	char* 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;
+	char* 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;
+	char* 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;
+	char* 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;
+	char* 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;
+	char* 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;
+	char* 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/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf b/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf
new file mode 100644
index 0000000000..aa4a1ea148
--- /dev/null
+++ b/MdeModulePkg/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/MdeModulePkg/Application/ArmCpuInfo/readargs.h b/MdeModulePkg/Application/ArmCpuInfo/readargs.h
new file mode 100644
index 0000000000..eaa52cf161
--- /dev/null
+++ b/MdeModulePkg/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/MdeModulePkg/Application/ArmCpuInfo/readregs.s b/MdeModulePkg/Application/ArmCpuInfo/readregs.s
new file mode 100644
index 0000000000..19312f1e27
--- /dev/null
+++ b/MdeModulePkg/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;
diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index 1014598f31..1ecfb34515 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -216,6 +216,7 @@
   gEfiMdeModulePkgTokenSpaceGuid.PcdRecoveryFileName|L"FVMAIN.FV"
 
 [Components]
+  MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf
   MdeModulePkg/Application/HelloWorld/HelloWorld.inf
   MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf
   MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf
@@ -520,4 +521,4 @@
   MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf
 
 [BuildOptions]
-
+GCC:*_*_AARCH64_CC_FLAGS = -march=armv9-a
-- 
2.40.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [PATCH] add ArmCpuInfo EFI application
  2023-03-31 18:02 [PATCH] add ArmCpuInfo EFI application Marcin Juszkiewicz
@ 2023-04-06 21:05 ` Rebecca Cran
  2023-04-07 10:39   ` [PATCH v2] " Marcin Juszkiewicz
  0 siblings, 1 reply; 32+ messages in thread
From: Rebecca Cran @ 2023-04-06 21:05 UTC (permalink / raw)
  To: devel, marcin.juszkiewicz; +Cc: Ard Biesheuvel, Leif Lindholm

Looks good - thanks.

There are a few style issues:


First, this patch came through as quoted-printable, with some lines 
wrapped. I'd be interested to learn how other people are dealing with 
this, since I've not seen complaints since Lazslo left the project.

Are people saving the _formatted_ output to apply with git? Or is there 
a script which can demangle the saved emails?


diff --git a/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c b/MdeModulePk=
g/Application/ArmCpuInfo/ArmCpuInfo.c
new file mode 100644
index 0000000000..79a02ae430
--- /dev/null
+++ b/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c
@@ -0,0 +1,2277 @@
+/** @file
+
+  Copyright (c) 2023 Marcin Juszkiewicz
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ **/
+
+#include <stdbool.h>
+#include <Library/UefiLib.h>
+#include "readargs.h"
+
+bool sve_present =3D false;
+bool sme_present =3D false;


There are also some style issues: the ones I've noticed are using tabs 
(edk2 uses spaces) and not having a space before the opening parenthesis 
in function calls - e.g.:


AsciiPrint("ID_AA64MMFR0_EL1 = 0x%016lx\n", aa64mmfr0_el1);


If you push your changes to a fork on GitHub you can submit a private PR 
and have CI run against it to tell you any further issues, or I can 
fixup the formatting and send you a copy if you'd like.


-- 

Rebecca Cran


On 3/31/23 12:02 PM, Marcin Juszkiewicz wrote:
> App goes through ID_AA64*_EL1 system registers and decode their values.
>
> First version which does not use much of current AArch64 support code
> present in EDK2. Written to check what data is there and what can be
> done with it.
> ---
>   .../Application/ArmCpuInfo/ArmCpuInfo.c       | 2277 +++++++++++++++++
>   .../Application/ArmCpuInfo/ArmCpuInfo.inf     |   38 +
>   .../Application/ArmCpuInfo/readargs.h         |   12 +
>   .../Application/ArmCpuInfo/readregs.s         |   49 +
>   MdeModulePkg/MdeModulePkg.dsc                 |    3 +-
>   5 files changed, 2378 insertions(+), 1 deletion(-)
>   create mode 100644 MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c
>   create mode 100644 MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf
>   create mode 100644 MdeModulePkg/Application/ArmCpuInfo/readargs.h
>   create mode 100644 MdeModulePkg/Application/ArmCpuInfo/readregs.s
>
> diff --git a/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c b/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c
> new file mode 100644
> index 0000000000..79a02ae430
> --- /dev/null
> +++ b/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c
> @@ -0,0 +1,2277 @@
> +/** @file
> +
> +  Copyright (c) 2023 Marcin Juszkiewicz
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + **/
> +
> +#include <stdbool.h>
> +#include <Library/UefiLib.h>
> +#include "readargs.h"
> +
> +bool sve_present = false;
> +bool sme_present = false;
> +
> +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)
> +{
> +	char binaries[17][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], description);
> +}
> +
> +void print_spacer(void)
> +{
> +	AsciiPrint("------------------|-------|-------|----------------------------------------------\n");
> +}
> +
> +void handle_aa64mmfr0_el1(const UINT64 aa64mmfr0_el1)
> +{
> +	UINT64 value;
> +	char* 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;
> +	char* 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;
> +	char* 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;
> +	char* 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;
> +	char* 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;
> +	char* 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;
> +	char* 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;
> +	char* 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;
> +	char* 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/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf b/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf
> new file mode 100644
> index 0000000000..aa4a1ea148
> --- /dev/null
> +++ b/MdeModulePkg/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/MdeModulePkg/Application/ArmCpuInfo/readargs.h b/MdeModulePkg/Application/ArmCpuInfo/readargs.h
> new file mode 100644
> index 0000000000..eaa52cf161
> --- /dev/null
> +++ b/MdeModulePkg/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/MdeModulePkg/Application/ArmCpuInfo/readregs.s b/MdeModulePkg/Application/ArmCpuInfo/readregs.s
> new file mode 100644
> index 0000000000..19312f1e27
> --- /dev/null
> +++ b/MdeModulePkg/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;
> diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
> index 1014598f31..1ecfb34515 100644
> --- a/MdeModulePkg/MdeModulePkg.dsc
> +++ b/MdeModulePkg/MdeModulePkg.dsc
> @@ -216,6 +216,7 @@
>     gEfiMdeModulePkgTokenSpaceGuid.PcdRecoveryFileName|L"FVMAIN.FV"
>   
>   [Components]
> +  MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf
>     MdeModulePkg/Application/HelloWorld/HelloWorld.inf
>     MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf
>     MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf
> @@ -520,4 +521,4 @@
>     MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf
>   
>   [BuildOptions]
> -
> +GCC:*_*_AARCH64_CC_FLAGS = -march=armv9-a

^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v2] add ArmCpuInfo EFI application
  2023-04-06 21:05 ` [edk2-devel] " Rebecca Cran
@ 2023-04-07 10:39   ` Marcin Juszkiewicz
  2023-04-07 10:55     ` [edk2-devel] " Ard Biesheuvel
  0 siblings, 1 reply; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-07 10:39 UTC (permalink / raw)
  To: devel; +Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran, Marcin Juszkiewicz

App goes through ID_AA64*_EL1 system registers and decode their values.

First version which does not use much of current AArch64 support code
present in EDK2. Written to check what data is there and what can be
done with it.

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

diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
index 1014598f31c3..1ecfb345159f 100644
--- a/MdeModulePkg/MdeModulePkg.dsc
+++ b/MdeModulePkg/MdeModulePkg.dsc
@@ -216,6 +216,7 @@ [PcdsDynamicExDefault]
   gEfiMdeModulePkgTokenSpaceGuid.PcdRecoveryFileName|L"FVMAIN.FV"
 
 [Components]
+  MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf
   MdeModulePkg/Application/HelloWorld/HelloWorld.inf
   MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf
   MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf
@@ -520,4 +521,4 @@ [Components.X64]
   MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf
 
 [BuildOptions]
-
+GCC:*_*_AARCH64_CC_FLAGS = -march=armv9-a
diff --git a/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf b/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf
new file mode 100644
index 000000000000..158f86a4740c
--- /dev/null
+++ b/MdeModulePkg/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/MdeModulePkg/Application/ArmCpuInfo/readargs.h b/MdeModulePkg/Application/ArmCpuInfo/readargs.h
new file mode 100644
index 000000000000..eaa52cf16145
--- /dev/null
+++ b/MdeModulePkg/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/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c b/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c
new file mode 100644
index 000000000000..ac27902e3533
--- /dev/null
+++ b/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c
@@ -0,0 +1,2274 @@
+/** @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)
+{
+        char binaries[17][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], description);
+}
+
+void print_spacer(void)
+{
+        AsciiPrint("------------------|-------|-------|----------------------------------------------\n");
+}
+
+void handle_aa64mmfr0_el1(const UINT64 aa64mmfr0_el1)
+{
+        UINT64 value;
+        char* 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;
+        char* 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;
+        char* 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;
+        char* 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;
+        char* 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;
+        char* 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;
+        char* 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;
+        char* 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;
+        char* 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/MdeModulePkg/Application/ArmCpuInfo/readregs.s b/MdeModulePkg/Application/ArmCpuInfo/readregs.s
new file mode 100644
index 000000000000..052834b3c3f2
--- /dev/null
+++ b/MdeModulePkg/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


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [PATCH v2] add ArmCpuInfo EFI application
  2023-04-07 10:39   ` [PATCH v2] " Marcin Juszkiewicz
@ 2023-04-07 10:55     ` Ard Biesheuvel
  2023-04-07 12:46       ` Marcin Juszkiewicz
  2023-04-07 12:47       ` [PATCH v3] " Marcin Juszkiewicz
  0 siblings, 2 replies; 32+ messages in thread
From: Ard Biesheuvel @ 2023-04-07 10:55 UTC (permalink / raw)
  To: devel, marcin.juszkiewicz; +Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran

Hello Marcin,

Thanks for this - it looks useful.

Some comments below.

On Fri, 7 Apr 2023 at 12:40, Marcin Juszkiewicz
<marcin.juszkiewicz@linaro.org> wrote:
>
> App goes through ID_AA64*_EL1 system registers and decode their values.
>
> First version which does not use much of current AArch64 support code
> present in EDK2. Written to check what data is there and what can be
> done with it.
>
> Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
> ---
>  MdeModulePkg/MdeModulePkg.dsc                      |    3 +-
>  MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf |   38 +
>  MdeModulePkg/Application/ArmCpuInfo/readargs.h     |   12 +
>  MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c   | 2274 ++++++++++++++++++++
>  MdeModulePkg/Application/ArmCpuInfo/readregs.s     |   49 +
>  5 files changed, 2375 insertions(+), 1 deletion(-)
>

Why are you adding this to MdeModulePkg rather than ArmPkg?


> diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
> index 1014598f31c3..1ecfb345159f 100644
> --- a/MdeModulePkg/MdeModulePkg.dsc
> +++ b/MdeModulePkg/MdeModulePkg.dsc
> @@ -216,6 +216,7 @@ [PcdsDynamicExDefault]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdRecoveryFileName|L"FVMAIN.FV"
>
>  [Components]
> +  MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf
>    MdeModulePkg/Application/HelloWorld/HelloWorld.inf
>    MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf
>    MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf
> @@ -520,4 +521,4 @@ [Components.X64]
>    MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf
>
>  [BuildOptions]
> -
> +GCC:*_*_AARCH64_CC_FLAGS = -march=armv9-a

This belongs in the app's INF, not in the package DSC where it affects
code generation for all components, which may need to run on much
older CPUs

> diff --git a/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf b/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf
> new file mode 100644
> index 000000000000..158f86a4740c
> --- /dev/null
> +++ b/MdeModulePkg/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/MdeModulePkg/Application/ArmCpuInfo/readargs.h b/MdeModulePkg/Application/ArmCpuInfo/readargs.h
> new file mode 100644
> index 000000000000..eaa52cf16145
> --- /dev/null
> +++ b/MdeModulePkg/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/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c b/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c
> new file mode 100644
> index 000000000000..ac27902e3533
> --- /dev/null
> +++ b/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c
> @@ -0,0 +1,2274 @@
> +/** @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)
> +{
> +        char binaries[17][5] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
> +                                "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
> +

STATIC CONST CHAR8[] please, and you can use [] for the first
dimension (and drop the final element)

> +        AsciiPrint(" %-16a | %5a | %5a | %a\n", field, bits, binaries[value], description);

This should be value & 0xf so you never access outside of the array.


> +}
> +
> +void print_spacer(void)
> +{
> +        AsciiPrint("------------------|-------|-------|----------------------------------------------\n");
> +}
> +
> +void handle_aa64mmfr0_el1(const UINT64 aa64mmfr0_el1)
> +{
> +        UINT64 value;
> +        char* regname = "ID_AA64MMFR0_EL1";

STATIC CONST CHAR8 RegName[] = ...

> +        char* description;
> +        char* bits;

CONST

> +
> +
> +        bits = "3:0 ";
> +        value = aa64mmfr0_el1 & 0xf;
> +        switch(value)

Space after switch

> +        {
> +                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)

Space after if

etc etc

There are some other style issues here, which I am sure the CI will
whine about, so you might want to run uncrustify on it.

Thanks,

> +                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;
> +        char* 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;
> +        char* 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;
> +        char* 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;
> +        char* 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;
> +        char* 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;
> +        char* 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;
> +        char* 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;
> +        char* 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/MdeModulePkg/Application/ArmCpuInfo/readregs.s b/MdeModulePkg/Application/ArmCpuInfo/readregs.s
> new file mode 100644
> index 000000000000..052834b3c3f2
> --- /dev/null
> +++ b/MdeModulePkg/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 (#102680): https://edk2.groups.io/g/devel/message/102680
> Mute This Topic: https://groups.io/mt/98122223/5717338
> Group Owner: devel+owner@edk2.groups.io
> Unsubscribe: https://edk2.groups.io/g/devel/unsub [ardb+tianocore@kernel.org]
> ------------
>
>

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [PATCH v2] add ArmCpuInfo EFI application
  2023-04-07 10:55     ` [edk2-devel] " Ard Biesheuvel
@ 2023-04-07 12:46       ` Marcin Juszkiewicz
  2023-04-07 13:07         ` Ard Biesheuvel
  2023-04-07 12:47       ` [PATCH v3] " Marcin Juszkiewicz
  1 sibling, 1 reply; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-07 12:46 UTC (permalink / raw)
  To: Ard Biesheuvel, devel; +Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran

W dniu 7.04.2023 o 12:55, Ard Biesheuvel pisze:
> Hello Marcin,
> 
> Thanks for this - it looks useful.
 > Some comments below.

Thanks.
> On Fri, 7 Apr 2023 at 12:40, Marcin Juszkiewicz
> <marcin.juszkiewicz@linaro.org> wrote:
>>
>> App goes through ID_AA64*_EL1 system registers and decode their values.
>>
>> First version which does not use much of current AArch64 support code
>> present in EDK2. Written to check what data is there and what can be
>> done with it.
>>
>> Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
>> ---
>>   MdeModulePkg/MdeModulePkg.dsc                      |    3 +-
>>   MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf |   38 +
>>   MdeModulePkg/Application/ArmCpuInfo/readargs.h     |   12 +
>>   MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c   | 2274 ++++++++++++++++++++
>>   MdeModulePkg/Application/ArmCpuInfo/readregs.s     |   49 +
>>   5 files changed, 2375 insertions(+), 1 deletion(-)
>>
> 
> Why are you adding this to MdeModulePkg rather than ArmPkg?

This is the first time I wrote something for EDK2 so worked to get it 
built first rather than to get it right. Looked at HelloWorld example 
and followed.

Moved to ArmPkg/Application/ArmCpuInfo/ in current code.

>> diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc
>> index 1014598f31c3..1ecfb345159f 100644
>> --- a/MdeModulePkg/MdeModulePkg.dsc
>> +++ b/MdeModulePkg/MdeModulePkg.dsc
>> @@ -216,6 +216,7 @@ [PcdsDynamicExDefault]
>>     gEfiMdeModulePkgTokenSpaceGuid.PcdRecoveryFileName|L"FVMAIN.FV"
>>
>>   [Components]
>> +  MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.inf
>>     MdeModulePkg/Application/HelloWorld/HelloWorld.inf
>>     MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf
>>     MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf
>> @@ -520,4 +521,4 @@ [Components.X64]
>>     MdeModulePkg/Universal/CapsulePei/CapsuleX64.inf
>>
>>   [BuildOptions]
>> -
>> +GCC:*_*_AARCH64_CC_FLAGS = -march=armv9-a
> 
> This belongs in the app's INF, not in the package DSC where it affects
> code generation for all components, which may need to run on much
> older CPUs

Dropped that line as it was not needed in the end.

>> diff --git a/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c b/MdeModulePkg/Application/ArmCpuInfo/ArmCpuInfo.c
>> new file mode 100644
>> index 000000000000..ac27902e3533
>> +void print_values(const char* field, const char* bits, const int value, const char* description)
>> +{
>> +        char binaries[17][5] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
>> +                                "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
>> +
> 
> STATIC CONST CHAR8[] please, and you can use [] for the first
> dimension (and drop the final element)

done

>> +        AsciiPrint(" %-16a | %5a | %5a | %a\n", field, bits, binaries[value], description);
> 
> This should be value & 0xf so you never access outside of the array.

done

>> +void handle_aa64mmfr0_el1(const UINT64 aa64mmfr0_el1)
>> +{
>> +        UINT64 value;
>> +        char* regname = "ID_AA64MMFR0_EL1";
> 
> STATIC CONST CHAR8 RegName[] = ...

done

>> +        char* description;
>> +        char* bits;
> 
> CONST

It is not const.

>> +
>> +
>> +        bits = "3:0 ";
>> +        value = aa64mmfr0_el1 & 0xf;
>> +        switch(value)
> 
> Space after switch

done

>> +        if(value == 0b0110)
> 
> Space after if

done

> etc etc
> 
> There are some other style issues here, which I am sure the CI will
> whine about, so you might want to run uncrustify on it.

done


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH v3] add ArmCpuInfo EFI application
  2023-04-07 10:55     ` [edk2-devel] " Ard Biesheuvel
  2023-04-07 12:46       ` Marcin Juszkiewicz
@ 2023-04-07 12:47       ` Marcin Juszkiewicz
  2023-04-07 13:02         ` [edk2-devel] " Pedro Falcato
  1 sibling, 1 reply; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-07 12:47 UTC (permalink / raw)
  To: devel; +Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran, Marcin Juszkiewicz

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


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [PATCH v3] add ArmCpuInfo EFI application
  2023-04-07 12:47       ` [PATCH v3] " Marcin Juszkiewicz
@ 2023-04-07 13:02         ` Pedro Falcato
  2023-04-07 13:05           ` Pedro Falcato
                             ` (3 more replies)
  0 siblings, 4 replies; 32+ messages in thread
From: Pedro Falcato @ 2023-04-07 13:02 UTC (permalink / raw)
  To: devel, marcin.juszkiewicz; +Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran

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

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [PATCH v3] add ArmCpuInfo EFI application
  2023-04-07 13:02         ` [edk2-devel] " Pedro Falcato
@ 2023-04-07 13:05           ` Pedro Falcato
  2023-04-07 13:29           ` Marcin Juszkiewicz
                             ` (2 subsequent siblings)
  3 siblings, 0 replies; 32+ messages in thread
From: Pedro Falcato @ 2023-04-07 13:05 UTC (permalink / raw)
  To: devel, marcin.juszkiewicz; +Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran

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

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [PATCH v2] add ArmCpuInfo EFI application
  2023-04-07 12:46       ` Marcin Juszkiewicz
@ 2023-04-07 13:07         ` Ard Biesheuvel
  0 siblings, 0 replies; 32+ messages in thread
From: Ard Biesheuvel @ 2023-04-07 13:07 UTC (permalink / raw)
  To: Marcin Juszkiewicz; +Cc: devel, Ard Biesheuvel, Leif Lindholm, Rebecca Cran

On Fri, 7 Apr 2023 at 14:46, Marcin Juszkiewicz
<marcin.juszkiewicz@linaro.org> wrote:
>
> W dniu 7.04.2023 o 12:55, Ard Biesheuvel pisze:
> > Hello Marcin,
> >
> > Thanks for this - it looks useful.
>  > Some comments below.
>
> Thanks.
> > On Fri, 7 Apr 2023 at 12:40, Marcin Juszkiewicz
> > <marcin.juszkiewicz@linaro.org> wrote:
> >>
...
> >> +        char* description;
> >> +        char* bits;
> >
> > CONST
>
> It is not const.
>

The pointer is not const but the string is

const char *bits;

allows you to make 'bits' point to different constant string literals.


char *bits;

is only needed if you are pointing 'bits' at a string and subsequently
modify the /contents/ of the string, but i don't thank that is what
you are doing here.


> >> +
> >> +
> >> +        bits = "3:0 ";
> >> +        value = aa64mmfr0_el1 & 0xf;
> >> +        switch(value)
> >
> > Space after switch
>
> done
>
> >> +        if(value == 0b0110)
> >
> > Space after if
>
> done
>
> > etc etc
> >
> > There are some other style issues here, which I am sure the CI will
> > whine about, so you might want to run uncrustify on it.
>
> done
>

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [PATCH v3] add ArmCpuInfo EFI application
  2023-04-07 13:02         ` [edk2-devel] " Pedro Falcato
  2023-04-07 13:05           ` Pedro Falcato
@ 2023-04-07 13:29           ` Marcin Juszkiewicz
  2023-04-07 13:40             ` Pedro Falcato
  2023-04-07 14:02           ` [PATCH v4] " Marcin Juszkiewicz
       [not found]           ` <1753ABF1A296B040.11304@groups.io>
  3 siblings, 1 reply; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-07 13:29 UTC (permalink / raw)
  To: devel

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.


^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [PATCH v3] add ArmCpuInfo EFI application
  2023-04-07 13:29           ` Marcin Juszkiewicz
@ 2023-04-07 13:40             ` Pedro Falcato
  2023-04-07 13:41               ` Pedro Falcato
  2023-04-07 13:42               ` Marcin Juszkiewicz
  0 siblings, 2 replies; 32+ messages in thread
From: Pedro Falcato @ 2023-04-07 13:40 UTC (permalink / raw)
  To: devel, marcin.juszkiewicz, Ard Biesheuvel, Leif Lindholm,
	Rebecca Cran

(+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

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [PATCH v3] add ArmCpuInfo EFI application
  2023-04-07 13:40             ` Pedro Falcato
@ 2023-04-07 13:41               ` Pedro Falcato
  2023-04-07 13:42               ` Marcin Juszkiewicz
  1 sibling, 0 replies; 32+ messages in thread
From: Pedro Falcato @ 2023-04-07 13:41 UTC (permalink / raw)
  To: devel, marcin.juszkiewicz; +Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran

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

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [PATCH v3] add ArmCpuInfo EFI application
  2023-04-07 13:40             ` Pedro Falcato
  2023-04-07 13:41               ` Pedro Falcato
@ 2023-04-07 13:42               ` Marcin Juszkiewicz
  1 sibling, 0 replies; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-07 13:42 UTC (permalink / raw)
  To: Pedro Falcato, devel, Ard Biesheuvel, Leif Lindholm, Rebecca Cran

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.


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH v4] add ArmCpuInfo EFI application
  2023-04-07 13:02         ` [edk2-devel] " Pedro Falcato
  2023-04-07 13:05           ` Pedro Falcato
  2023-04-07 13:29           ` Marcin Juszkiewicz
@ 2023-04-07 14:02           ` Marcin Juszkiewicz
       [not found]           ` <1753ABF1A296B040.11304@groups.io>
  3 siblings, 0 replies; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-07 14:02 UTC (permalink / raw)
  To: devel
  Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran, Pedro Falcato,
	Marcin Juszkiewicz

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


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [PATCH v4] add ArmCpuInfo EFI application
       [not found]           ` <1753ABF1A296B040.11304@groups.io>
@ 2023-04-07 15:11             ` Marcin Juszkiewicz
  2023-04-07 15:29             ` [PATCH v5 0/2] add ArmCpuInfo application Marcin Juszkiewicz
  1 sibling, 0 replies; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-07 15:11 UTC (permalink / raw)
  To: devel; +Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran, Pedro Falcato

W dniu 7.04.2023 o 16:02, Marcin Juszkiewicz via groups.io pisze:
> +++ 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

Those functions probably should be moved to 
ArmPkg/Library/ArmLib/AArch64/ code. But I do not understand EDK2 
buildbuildsystem enough to sort that part out.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH v5 0/2] add ArmCpuInfo application
       [not found]           ` <1753ABF1A296B040.11304@groups.io>
  2023-04-07 15:11             ` [edk2-devel] " Marcin Juszkiewicz
@ 2023-04-07 15:29             ` Marcin Juszkiewicz
  2023-04-07 15:29               ` [PATCH v5 1/2] ArmLib: add functions to read system registers Marcin Juszkiewicz
                                 ` (2 more replies)
  1 sibling, 3 replies; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-07 15:29 UTC (permalink / raw)
  To: devel
  Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran, Pedro Falcato,
	Marcin Juszkiewicz

Changes since v4:
- functions to read system registers are renamed and moved to ArmLib

Marcin Juszkiewicz (2):
  ArmLib: add functions to read system registers
  add ArmCpuInfo EFI application

 ArmPkg/ArmPkg.dsc                             |    1 +
 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf  |   38 +
 ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h    |   48 +
 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c    | 2319 +++++++++++++++++
 .../Library/ArmLib/AArch64/AArch64Support.S   |   32 +
 5 files changed, 2438 insertions(+)
 create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
 create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c

-- 
2.40.0


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH v5 1/2] ArmLib: add functions to read system registers
  2023-04-07 15:29             ` [PATCH v5 0/2] add ArmCpuInfo application Marcin Juszkiewicz
@ 2023-04-07 15:29               ` Marcin Juszkiewicz
  2023-04-20 10:54                 ` Leif Lindholm
  2023-04-07 15:29               ` [PATCH v5 2/2] add ArmCpuInfo EFI application Marcin Juszkiewicz
  2023-04-13  9:31               ` [PATCH v5 0/2] add ArmCpuInfo application Marcin Juszkiewicz
  2 siblings, 1 reply; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-07 15:29 UTC (permalink / raw)
  To: devel
  Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran, Pedro Falcato,
	Marcin Juszkiewicz

ArmCpuInfo uses those to read system registers and other parts of EDK2
may find them useful.

Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
---
 ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h    | 48 +++++++++++++++++++
 .../Library/ArmLib/AArch64/AArch64Support.S   | 32 +++++++++++++
 2 files changed, 80 insertions(+)

diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h
index 330481fc50db..d9744a66cdcf 100644
--- a/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h
+++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h
@@ -44,6 +44,54 @@ ArmReadIdAA64Pfr0 (
   VOID
   );
 
+UINTN
+EFIAPI
+ArmReadIdAA64Pfr1 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Dfr0 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Dfr1 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Isar0 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Isar1 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Isar2 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Mmfr0 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Mmfr1 (
+  VOID
+  );
+
 /** Reads the ID_AA64MMFR2_EL1 register.
 
    @return The contents of the ID_AA64MMFR2_EL1 register.
diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S b/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S
index d3cc1e86716b..3e8d461bc819 100644
--- a/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S
+++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S
@@ -482,4 +482,36 @@ ASM_FUNC(ArmWriteCntHctl)
   msr   cnthctl_el2, x0
   ret
 
+ASM_FUNC(ArmReadIdAA64Pfr1)
+  mrs   x0, ID_AA64PFR1_EL1
+  ret
+
+ASM_FUNC(ArmReadIdAA64Dfr0)
+  mrs   x0, ID_AA64DFR0_EL1
+  ret
+
+ASM_FUNC(ArmReadIdAA64Dfr1)
+  mrs   x0, ID_AA64DFR1_EL1
+  ret
+
+ASM_FUNC(ArmReadIdAA64Isar0)
+  mrs   x0, ID_AA64ISAR0_EL1
+  ret
+
+ASM_FUNC(ArmReadIdAA64Isar1)
+  mrs   x0, ID_AA64ISAR1_EL1
+  ret
+
+ASM_FUNC(ArmReadIdAA64Isar2)
+  mrs   x0, ID_AA64ISAR2_EL1
+  ret
+
+ASM_FUNC(ArmReadIdAA64Mmfr0)
+  mrs   x0, ID_AA64MMFR0_EL1
+  ret
+
+ASM_FUNC(ArmReadIdAA64Mmfr1)
+  mrs   x0, ID_AA64MMFR1_EL1
+  ret
+
 ASM_FUNCTION_REMOVE_IF_UNREFERENCED
-- 
2.40.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v5 2/2] add ArmCpuInfo EFI application
  2023-04-07 15:29             ` [PATCH v5 0/2] add ArmCpuInfo application Marcin Juszkiewicz
  2023-04-07 15:29               ` [PATCH v5 1/2] ArmLib: add functions to read system registers Marcin Juszkiewicz
@ 2023-04-07 15:29               ` Marcin Juszkiewicz
  2023-04-20 12:43                 ` Leif Lindholm
  2023-04-13  9:31               ` [PATCH v5 0/2] add ArmCpuInfo application Marcin Juszkiewicz
  2 siblings, 1 reply; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-07 15:29 UTC (permalink / raw)
  To: devel
  Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran, Pedro Falcato,
	Marcin Juszkiewicz

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/ArmCpuInfo.c   | 2319 ++++++++++++++++++
 3 files changed, 2358 insertions(+)
 create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
 create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c

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..c6f634cd01b7
--- /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
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  ArmLib
+  UefiApplicationEntryPoint
+  UefiLib
diff --git a/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
new file mode 100644
index 000000000000..2fc12059f727
--- /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 <Library/ArmLib/AArch64/AArch64Lib.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
+HandleAa64Mmfr0 (
+  CONST UINT64  Aa64Mmfr0
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR0";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = Aa64Mmfr0 & 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 = (Aa64Mmfr0 >>  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 = (Aa64Mmfr0 >>  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 (((Aa64Mmfr0 >>  8) & 0xf) != 0b0000 ) {
+    if (((Aa64Mmfr0 >> 16) & 0xf) == 0b0000 ) {
+      PrintValues ("ID_AA64MMFR0", "19:16", 0b0000, "No mixed-endian support at EL0.");
+    }
+
+    if (((Aa64Mmfr0 >> 16) & 0xf) == 0b0001 ) {
+      PrintValues ("ID_AA64MMFR0", "19:16", 0b0001, "Mixed-endian support at EL0.");
+    }
+  }
+
+  Bits  = "15:12";
+  Value = (Aa64Mmfr0 >> 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 = (Aa64Mmfr0 >> 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 = (Aa64Mmfr0 >> 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 = (Aa64Mmfr0 >> 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 = (Aa64Mmfr0 >> 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 = (Aa64Mmfr0 >> 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 = (Aa64Mmfr0 >> 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 = (Aa64Mmfr0 >> 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 = (Aa64Mmfr0 >> 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 = (Aa64Mmfr0 >> 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
+HandleAa64Mmfr1 (
+  CONST UINT64  Aa64Mmfr1,
+  CONST UINT64  Aa64Pfr0
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = Aa64Mmfr1 & 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 = (Aa64Mmfr1 >>  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 = (Aa64Mmfr1 >>  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 = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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 ((((Aa64Pfr0 >> 28) & 0xf) == 0b0001) ||
+      (((Aa64Pfr0 >> 28) & 0xf) == 0b0010))
+  {
+    if (((Aa64Mmfr1 >> 24) & 0xf) == 0b0000 ) {
+      PrintValues ("ID_AA64MMFR1", "27:24", 0b0000, "The PE never generates an SError interrupt due to");
+      PrintText ("", "", "", "an External abort on a speculative read.");
+    }
+
+    if (((Aa64Mmfr1 >> 24) & 0xf) == 0b0001 ) {
+      PrintValues ("ID_AA64MMFR1", "27:24", 0b0001, "The PE might generate an SError interrupt due to");
+      PrintText ("", "", "", "an External abort on a speculative read.");
+    }
+  }
+
+  Bits  = "31:28";
+  Value = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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
+HandleAa64Mmfr2 (
+  CONST UINT64  Aa64Mmfr2
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR2";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Mmfr2)       & 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 = (Aa64Mmfr2 >>  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 = (Aa64Mmfr2 >>  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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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
+HandleAa64Pfr0 (
+  CONST UINT64  Aa64Pfr0,
+  CONST UINT64  Aa64Pfr1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR0";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Pfr0)       & 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 = (Aa64Pfr0 >>  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 = (Aa64Pfr0 >>  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 = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 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 >> 12) & 0xf) == 0b0001) ||
+          (((Aa64Pfr0 >> 12) & 0xf) == 0b0010))
+      {
+        Description = "FEAT_RASv1p1 implemented. FEAT_DoubleFault implemented.";
+      }
+
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 40) & 0xf;
+  switch (Value) {
+    case 0b0000:
+      if (((Aa64Pfr1 >> 16) & 0xf) == 0b0000 ) {
+        Description = "FEAT_MPAM not implemented.";
+      }
+
+      if (((Aa64Pfr1 >> 16) & 0xf) == 0b0001 ) {
+        Description = "FEAT_MPAM v0.1 implemented.";
+      }
+
+      break;
+    case 0b0001:
+      if (((Aa64Pfr1 >> 16) & 0xf) == 0b0000 ) {
+        Description = "FEAT_MPAM v1.0 implemented.";
+      }
+
+      if (((Aa64Pfr1 >> 16) & 0xf) == 0b0001 ) {
+        Description = "FEAT_MPAM v1.1 implemented.";
+      }
+
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 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 (((Aa64Pfr1 >> 32) & 0xf) == 0b0001 ) {
+      PrintValues ("ID_AA64PRF1", "35:32", 0b0001, "FEAT_CSV2_1p1 implemented.");
+    }
+
+    if (((Aa64Pfr1 >> 32) & 0xf) == 0b0010 ) {
+      PrintValues ("ID_AA64PRF1", "35:32", 0b0010, "FEAT_CSV2_1p2 implemented.");
+    }
+  }
+
+  Bits  = "63:60";
+  Value = (Aa64Pfr0 >> 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
+HandleAa64Pfr1 (
+  CONST UINT64  Aa64Pfr1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = Aa64Pfr1 & 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 = (Aa64Pfr1 >>  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 = (Aa64Pfr1 >>  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 = (Aa64Pfr1 >> 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 = (Aa64Pfr1 >> 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 = (Aa64Pfr1 >> 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
+HandleAa64Isar0 (
+  CONST UINT64  Aa64Isar0
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR0";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  // 3:0 reserved
+
+  Bits  = "7:4 ";
+  Value = (Aa64Isar0 >>  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 = (Aa64Isar0 >>  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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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
+HandleAa64Isar1 (
+  CONST UINT64  Aa64Isar1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Isar1 >>  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 = (Aa64Isar1 >>  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 = (Aa64Isar1 >>  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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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
+HandleAa64Isar2 (
+  CONST UINT64  Aa64Isar2
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR2";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Isar2 >>  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 = (Aa64Isar2 >>  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 = (Aa64Isar2 >>  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 = (Aa64Isar2 >> 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 = (Aa64Isar2 >> 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 = (Aa64Isar2 >> 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 = (Aa64Isar2 >> 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
+HandleAa64Dfr0 (
+  CONST UINT64  Aa64Dfr0
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64DFR0";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Dfr0 >>  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 = (Aa64Dfr0 >>  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 = (Aa64Dfr0 >>  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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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  Aa64Dfr0;
+  UINT64  Aa64Isar0;
+  UINT64  Aa64Isar1;
+  UINT64  Aa64Isar2;
+  UINT64  Aa64Mmfr0;
+  UINT64  Aa64Mmfr1;
+  UINT64  Aa64Mmfr2;
+  UINT64  Aa64Pfr0;
+  UINT64  Aa64Pfr1;
+
+  Aa64Dfr0  = ArmReadIdAA64Dfr0 ();
+  Aa64Isar0 = ArmReadIdAA64Isar0 ();
+  Aa64Isar1 = ArmReadIdAA64Isar1 ();
+  Aa64Isar2 = ArmReadIdAA64Isar2 ();
+  Aa64Mmfr0 = ArmReadIdAA64Mmfr0 ();
+  Aa64Mmfr1 = ArmReadIdAA64Mmfr1 ();
+  Aa64Mmfr2 = ArmReadIdAA64Mmfr2 ();
+  Aa64Pfr0  = ArmReadIdAA64Pfr0 ();
+  Aa64Pfr1  = ArmReadIdAA64Pfr1 ();
+
+  AsciiPrint ("ID_AA64MMFR0_EL1 = 0x%016lx\n", Aa64Mmfr0);
+  AsciiPrint ("ID_AA64MMFR1_EL1 = 0x%016lx\n", Aa64Mmfr1);
+  AsciiPrint ("ID_AA64MMFR2_EL1 = 0x%016lx\n", Aa64Mmfr2);
+  AsciiPrint ("ID_AA64PFR0_EL1  = 0x%016lx\n", Aa64Pfr0);
+  AsciiPrint ("ID_AA64PFR1_EL1  = 0x%016lx\n", Aa64Pfr1);
+  AsciiPrint ("ID_AA64ISAR0_EL1 = 0x%016lx\n", Aa64Isar0);
+  AsciiPrint ("ID_AA64ISAR1_EL1 = 0x%016lx\n", Aa64Isar1);
+  AsciiPrint ("ID_AA64ISAR2_EL1 = 0x%016lx\n", Aa64Isar2);
+  AsciiPrint ("ID_AA64DFR0_EL1  = 0x%016lx\n", Aa64Dfr0);
+
+  AsciiPrint ("\n");
+  PrintText ("Register", "Bits", "Value", "Feature");
+  PrintSpacer ();
+
+  HandleAa64Mmfr0 (Aa64Mmfr0);
+  PrintSpacer ();
+  HandleAa64Mmfr1 (Aa64Mmfr1, Aa64Pfr0);
+  PrintSpacer ();
+  HandleAa64Mmfr2 (Aa64Mmfr2);
+
+  PrintSpacer ();
+  HandleAa64Pfr0 (Aa64Pfr0, Aa64Pfr1);
+  PrintSpacer ();
+  HandleAa64Pfr1 (Aa64Pfr1);
+
+  PrintSpacer ();
+  HandleAa64Isar0 (Aa64Isar0);
+  PrintSpacer ();
+  HandleAa64Isar1 (Aa64Isar1);
+  PrintSpacer ();
+  HandleAa64Isar2 (Aa64Isar2);
+
+  PrintSpacer ();
+  HandleAa64Dfr0 (Aa64Dfr0);
+
+  return EFI_SUCCESS;
+}
-- 
2.40.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH v5 0/2] add ArmCpuInfo application
  2023-04-07 15:29             ` [PATCH v5 0/2] add ArmCpuInfo application Marcin Juszkiewicz
  2023-04-07 15:29               ` [PATCH v5 1/2] ArmLib: add functions to read system registers Marcin Juszkiewicz
  2023-04-07 15:29               ` [PATCH v5 2/2] add ArmCpuInfo EFI application Marcin Juszkiewicz
@ 2023-04-13  9:31               ` Marcin Juszkiewicz
  2 siblings, 0 replies; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-13  9:31 UTC (permalink / raw)
  To: devel; +Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran, Pedro Falcato

W dniu 7.04.2023 o 17:29, Marcin Juszkiewicz pisze:
> Changes since v4:
> - functions to read system registers are renamed and moved to ArmLib
> 
> Marcin Juszkiewicz (2):
>    ArmLib: add functions to read system registers
>    add ArmCpuInfo EFI application
> 
>   ArmPkg/ArmPkg.dsc                             |    1 +
>   ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf  |   38 +
>   ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h    |   48 +
>   ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c    | 2319 +++++++++++++++++
>   .../Library/ArmLib/AArch64/AArch64Support.S   |   32 +
>   5 files changed, 2438 insertions(+)
>   create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
>   create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c

There was a suggestion to make it not application but shell command. For 
me app was easier to test. Also presence of helloworld app was helpful - 
not checked is there easy to clone shell command yet.



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v5 1/2] ArmLib: add functions to read system registers
  2023-04-07 15:29               ` [PATCH v5 1/2] ArmLib: add functions to read system registers Marcin Juszkiewicz
@ 2023-04-20 10:54                 ` Leif Lindholm
  0 siblings, 0 replies; 32+ messages in thread
From: Leif Lindholm @ 2023-04-20 10:54 UTC (permalink / raw)
  To: Marcin Juszkiewicz; +Cc: devel, Ard Biesheuvel, Rebecca Cran, Pedro Falcato

On Fri, Apr 07, 2023 at 17:29:56 +0200, Marcin Juszkiewicz wrote:
> ArmCpuInfo uses those to read system registers and other parts of EDK2
> may find them useful.

This is excellent, thanks!
Sorry for nitpicking, but could you please sort the function
declarations and definitions alphabetically?

/
    Leif

> Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
> ---
>  ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h    | 48 +++++++++++++++++++
>  .../Library/ArmLib/AArch64/AArch64Support.S   | 32 +++++++++++++
>  2 files changed, 80 insertions(+)
> 
> diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h
> index 330481fc50db..d9744a66cdcf 100644
> --- a/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h
> +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h
> @@ -44,6 +44,54 @@ ArmReadIdAA64Pfr0 (
>    VOID
>    );
>  
> +UINTN
> +EFIAPI
> +ArmReadIdAA64Pfr1 (
> +  VOID
> +  );
> +
> +UINTN
> +EFIAPI
> +ArmReadIdAA64Dfr0 (
> +  VOID
> +  );
> +
> +UINTN
> +EFIAPI
> +ArmReadIdAA64Dfr1 (
> +  VOID
> +  );
> +
> +UINTN
> +EFIAPI
> +ArmReadIdAA64Isar0 (
> +  VOID
> +  );
> +
> +UINTN
> +EFIAPI
> +ArmReadIdAA64Isar1 (
> +  VOID
> +  );
> +
> +UINTN
> +EFIAPI
> +ArmReadIdAA64Isar2 (
> +  VOID
> +  );
> +
> +UINTN
> +EFIAPI
> +ArmReadIdAA64Mmfr0 (
> +  VOID
> +  );
> +
> +UINTN
> +EFIAPI
> +ArmReadIdAA64Mmfr1 (
> +  VOID
> +  );
> +
>  /** Reads the ID_AA64MMFR2_EL1 register.
>  
>     @return The contents of the ID_AA64MMFR2_EL1 register.
> diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S b/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S
> index d3cc1e86716b..3e8d461bc819 100644
> --- a/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S
> +++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S
> @@ -482,4 +482,36 @@ ASM_FUNC(ArmWriteCntHctl)
>    msr   cnthctl_el2, x0
>    ret
>  
> +ASM_FUNC(ArmReadIdAA64Pfr1)
> +  mrs   x0, ID_AA64PFR1_EL1
> +  ret
> +
> +ASM_FUNC(ArmReadIdAA64Dfr0)
> +  mrs   x0, ID_AA64DFR0_EL1
> +  ret
> +
> +ASM_FUNC(ArmReadIdAA64Dfr1)
> +  mrs   x0, ID_AA64DFR1_EL1
> +  ret
> +
> +ASM_FUNC(ArmReadIdAA64Isar0)
> +  mrs   x0, ID_AA64ISAR0_EL1
> +  ret
> +
> +ASM_FUNC(ArmReadIdAA64Isar1)
> +  mrs   x0, ID_AA64ISAR1_EL1
> +  ret
> +
> +ASM_FUNC(ArmReadIdAA64Isar2)
> +  mrs   x0, ID_AA64ISAR2_EL1
> +  ret
> +
> +ASM_FUNC(ArmReadIdAA64Mmfr0)
> +  mrs   x0, ID_AA64MMFR0_EL1
> +  ret
> +
> +ASM_FUNC(ArmReadIdAA64Mmfr1)
> +  mrs   x0, ID_AA64MMFR1_EL1
> +  ret
> +
>  ASM_FUNCTION_REMOVE_IF_UNREFERENCED
> -- 
> 2.40.0
> 

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v5 2/2] add ArmCpuInfo EFI application
  2023-04-07 15:29               ` [PATCH v5 2/2] add ArmCpuInfo EFI application Marcin Juszkiewicz
@ 2023-04-20 12:43                 ` Leif Lindholm
  2023-04-20 14:42                   ` [edk2-devel] " Marcin Juszkiewicz
  2023-04-20 14:44                   ` [PATCH v6 1/2] ArmLib: add functions to read system registers Marcin Juszkiewicz
  0 siblings, 2 replies; 32+ messages in thread
From: Leif Lindholm @ 2023-04-20 12:43 UTC (permalink / raw)
  To: Marcin Juszkiewicz; +Cc: devel, Ard Biesheuvel, Rebecca Cran, Pedro Falcato

On Fri, Apr 07, 2023 at 17:29:57 +0200, Marcin Juszkiewicz 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/ArmCpuInfo.c   | 2319 ++++++++++++++++++
>  3 files changed, 2358 insertions(+)
>  create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
>  create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
> 
> 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..c6f634cd01b7
> --- /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

The above stanza, and its comment, can be dropped.
This relates to native language support, which there isn't any in this app.

> +
> +[Sources]
> +  ArmCpuInfo.c
> +
> +[Packages]
> +  ArmPkg/ArmPkg.dec
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +
> +[LibraryClasses]
> +  ArmLib
> +  UefiApplicationEntryPoint
> +  UefiLib
> diff --git a/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
> new file mode 100644
> index 000000000000..2fc12059f727
> --- /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 <Library/ArmLib/AArch64/AArch64Lib.h>
> +
> +VOID
> +PrintText (
> +  CONST CHAR8  *field,

For coding style, name should be "*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,

"*Field"

> +  CONST CHAR8  *Bits,
> +  CONST UINT8  Value,
> +  CONST CHAR8  *Description
> +  )
> +{
> +  STATIC CONST CHAR8  binaries[][5] = {

Could I propose renaming "binaries" to "Nibbles", since this is an
array holding string values for all possible nibbles?

> +    "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
> +HandleAa64Mmfr0 (
> +  CONST UINT64  Aa64Mmfr0
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR0";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = Aa64Mmfr0 & 0xf;
> +  switch (Value) {
> +    case 0b0000:

I agree with Pedro's concern w.r.t. binary literals being a GCC
extension. But I also think this is the most appropriate
representation since this is how it's documented in the ARM ARM.

A bit hacky, but could we do

enum {
  b0000,
  b0001,
  ...
  b1111
};

and then use those instead?

(you can build with -pedantic to verify you catch them all)

> +      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 = (Aa64Mmfr0 >>  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 = (Aa64Mmfr0 >>  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

Could we possibly reword as
  // If mixed-endian support is present, check whether supported at EL0
?

> +  if (((Aa64Mmfr0 >>  8) & 0xf) != 0b0000 ) {
> +    if (((Aa64Mmfr0 >> 16) & 0xf) == 0b0000 ) {
> +      PrintValues ("ID_AA64MMFR0", "19:16", 0b0000, "No mixed-endian support at EL0.");
> +    }
> +
> +    if (((Aa64Mmfr0 >> 16) & 0xf) == 0b0001 ) {
> +      PrintValues ("ID_AA64MMFR0", "19:16", 0b0001, "Mixed-endian support at EL0.");
> +    }
> +  }
> +
> +  Bits  = "15:12";
> +  Value = (Aa64Mmfr0 >> 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 = (Aa64Mmfr0 >> 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

That's sounds like a TODO. And we don't want TODOs in code.
Can we either drop the comment, add the check, or skip the test?
(That is my order of preference - we shouldn't need to be verifying
architectural compliance.)

> +      Description = " 4KB granule supported for 52-bit address.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "43:40";
> +  Value = (Aa64Mmfr0 >> 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 = (Aa64Mmfr0 >> 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

Same comment as for 4k.

> +      Description = "16KB granule supported for 52-bit address.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "35:32";
> +  Value = (Aa64Mmfr0 >> 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 = (Aa64Mmfr0 >> 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 = (Aa64Mmfr0 >> 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 = (Aa64Mmfr0 >> 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 = (Aa64Mmfr0 >> 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 = (Aa64Mmfr0 >> 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
> +HandleAa64Mmfr1 (
> +  CONST UINT64  Aa64Mmfr1,
> +  CONST UINT64  Aa64Pfr0
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR1";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = Aa64Mmfr1 & 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 = (Aa64Mmfr1 >>  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 = (Aa64Mmfr1 >>  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 = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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 ((((Aa64Pfr0 >> 28) & 0xf) == 0b0001) ||
> +      (((Aa64Pfr0 >> 28) & 0xf) == 0b0010))
> +  {
> +    if (((Aa64Mmfr1 >> 24) & 0xf) == 0b0000 ) {
> +      PrintValues ("ID_AA64MMFR1", "27:24", 0b0000, "The PE never generates an SError interrupt due to");
> +      PrintText ("", "", "", "an External abort on a speculative read.");
> +    }
> +
> +    if (((Aa64Mmfr1 >> 24) & 0xf) == 0b0001 ) {
> +      PrintValues ("ID_AA64MMFR1", "27:24", 0b0001, "The PE might generate an SError interrupt due to");
> +      PrintText ("", "", "", "an External abort on a speculative read.");
> +    }
> +  }
> +
> +  Bits  = "31:28";
> +  Value = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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 = (Aa64Mmfr1 >> 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
> +HandleAa64Mmfr2 (
> +  CONST UINT64  Aa64Mmfr2
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR2";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = (Aa64Mmfr2)       & 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 = (Aa64Mmfr2 >>  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 = (Aa64Mmfr2 >>  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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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 = (Aa64Mmfr2 >> 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
> +HandleAa64Pfr0 (
> +  CONST UINT64  Aa64Pfr0,
> +  CONST UINT64  Aa64Pfr1
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR0";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = (Aa64Pfr0)       & 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 = (Aa64Pfr0 >>  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 = (Aa64Pfr0 >>  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 = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 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 >> 12) & 0xf) == 0b0001) ||
> +          (((Aa64Pfr0 >> 12) & 0xf) == 0b0010))
> +      {
> +        Description = "FEAT_RASv1p1 implemented. FEAT_DoubleFault implemented.";
> +      }
> +
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "35:32";
> +  Value = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 40) & 0xf;
> +  switch (Value) {
> +    case 0b0000:
> +      if (((Aa64Pfr1 >> 16) & 0xf) == 0b0000 ) {
> +        Description = "FEAT_MPAM not implemented.";
> +      }
> +
> +      if (((Aa64Pfr1 >> 16) & 0xf) == 0b0001 ) {
> +        Description = "FEAT_MPAM v0.1 implemented.";
> +      }
> +
> +      break;
> +    case 0b0001:
> +      if (((Aa64Pfr1 >> 16) & 0xf) == 0b0000 ) {
> +        Description = "FEAT_MPAM v1.0 implemented.";
> +      }
> +
> +      if (((Aa64Pfr1 >> 16) & 0xf) == 0b0001 ) {
> +        Description = "FEAT_MPAM v1.1 implemented.";
> +      }
> +
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "47:44";
> +  Value = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 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 = (Aa64Pfr0 >> 56) & 0xf;
> +  switch (Value) {
> +    case 0b0000:
> +      Description = "no info is FEAT_CSV2 implemented.";

Consider rewording.
Is the text from the ARM ARM too long?
"The implementation does not disclose whether FEAT_CSV2 is
implemented."
if so, maybe
"Not disclosed whether FEAT_CSV2 is 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 (((Aa64Pfr1 >> 32) & 0xf) == 0b0001 ) {
> +      PrintValues ("ID_AA64PRF1", "35:32", 0b0001, "FEAT_CSV2_1p1 implemented.");
> +    }
> +
> +    if (((Aa64Pfr1 >> 32) & 0xf) == 0b0010 ) {
> +      PrintValues ("ID_AA64PRF1", "35:32", 0b0010, "FEAT_CSV2_1p2 implemented.");
> +    }
> +  }
> +
> +  Bits  = "63:60";
> +  Value = (Aa64Pfr0 >> 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
> +HandleAa64Pfr1 (
> +  CONST UINT64  Aa64Pfr1
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR1";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = Aa64Pfr1 & 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 = (Aa64Pfr1 >>  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 = (Aa64Pfr1 >>  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 = (Aa64Pfr1 >> 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 = (Aa64Pfr1 >> 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

That's a TODO.

> +
> +  Bits  = "39:36";
> +  Value = (Aa64Pfr1 >> 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
> +HandleAa64Isar0 (
> +  CONST UINT64  Aa64Isar0
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR0";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  // 3:0 reserved
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Isar0 >>  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 = (Aa64Isar0 >>  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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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 = (Aa64Isar0 >> 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
> +HandleAa64Isar1 (
> +  CONST UINT64  Aa64Isar1
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR1";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = (Aa64Isar1 >>  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 = (Aa64Isar1 >>  4) & 0xf;
> +  switch (Value) {
> +    case 0b0000:
> +      Description = "Address Authentication  (APA) not implemented.";

Double space before '('. (drop one?)
Hmm, I see this pattern repeated - is it intentional?

> +      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 = (Aa64Isar1 >>  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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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 = (Aa64Isar1 >> 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
> +HandleAa64Isar2 (
> +  CONST UINT64  Aa64Isar2
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR2";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = (Aa64Isar2 >>  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 = (Aa64Isar2 >>  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 = (Aa64Isar2 >>  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 = (Aa64Isar2 >> 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 = (Aa64Isar2 >> 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 = (Aa64Isar2 >> 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 = (Aa64Isar2 >> 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
> +HandleAa64Dfr0 (
> +  CONST UINT64  Aa64Dfr0
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64DFR0";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = (Aa64Dfr0 >>  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 = (Aa64Dfr0 >>  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 = (Aa64Dfr0 >>  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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 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  (

Stray space before '(' here too. Is it an editor setting?

/
    Leif

> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +  UINT64  Aa64Dfr0;
> +  UINT64  Aa64Isar0;
> +  UINT64  Aa64Isar1;
> +  UINT64  Aa64Isar2;
> +  UINT64  Aa64Mmfr0;
> +  UINT64  Aa64Mmfr1;
> +  UINT64  Aa64Mmfr2;
> +  UINT64  Aa64Pfr0;
> +  UINT64  Aa64Pfr1;
> +
> +  Aa64Dfr0  = ArmReadIdAA64Dfr0 ();
> +  Aa64Isar0 = ArmReadIdAA64Isar0 ();
> +  Aa64Isar1 = ArmReadIdAA64Isar1 ();
> +  Aa64Isar2 = ArmReadIdAA64Isar2 ();
> +  Aa64Mmfr0 = ArmReadIdAA64Mmfr0 ();
> +  Aa64Mmfr1 = ArmReadIdAA64Mmfr1 ();
> +  Aa64Mmfr2 = ArmReadIdAA64Mmfr2 ();
> +  Aa64Pfr0  = ArmReadIdAA64Pfr0 ();
> +  Aa64Pfr1  = ArmReadIdAA64Pfr1 ();
> +
> +  AsciiPrint ("ID_AA64MMFR0_EL1 = 0x%016lx\n", Aa64Mmfr0);
> +  AsciiPrint ("ID_AA64MMFR1_EL1 = 0x%016lx\n", Aa64Mmfr1);
> +  AsciiPrint ("ID_AA64MMFR2_EL1 = 0x%016lx\n", Aa64Mmfr2);
> +  AsciiPrint ("ID_AA64PFR0_EL1  = 0x%016lx\n", Aa64Pfr0);
> +  AsciiPrint ("ID_AA64PFR1_EL1  = 0x%016lx\n", Aa64Pfr1);
> +  AsciiPrint ("ID_AA64ISAR0_EL1 = 0x%016lx\n", Aa64Isar0);
> +  AsciiPrint ("ID_AA64ISAR1_EL1 = 0x%016lx\n", Aa64Isar1);
> +  AsciiPrint ("ID_AA64ISAR2_EL1 = 0x%016lx\n", Aa64Isar2);
> +  AsciiPrint ("ID_AA64DFR0_EL1  = 0x%016lx\n", Aa64Dfr0);
> +
> +  AsciiPrint ("\n");
> +  PrintText ("Register", "Bits", "Value", "Feature");
> +  PrintSpacer ();
> +
> +  HandleAa64Mmfr0 (Aa64Mmfr0);
> +  PrintSpacer ();
> +  HandleAa64Mmfr1 (Aa64Mmfr1, Aa64Pfr0);
> +  PrintSpacer ();
> +  HandleAa64Mmfr2 (Aa64Mmfr2);
> +
> +  PrintSpacer ();
> +  HandleAa64Pfr0 (Aa64Pfr0, Aa64Pfr1);
> +  PrintSpacer ();
> +  HandleAa64Pfr1 (Aa64Pfr1);
> +
> +  PrintSpacer ();
> +  HandleAa64Isar0 (Aa64Isar0);
> +  PrintSpacer ();
> +  HandleAa64Isar1 (Aa64Isar1);
> +  PrintSpacer ();
> +  HandleAa64Isar2 (Aa64Isar2);
> +
> +  PrintSpacer ();
> +  HandleAa64Dfr0 (Aa64Dfr0);
> +
> +  return EFI_SUCCESS;
> +}
> -- 
> 2.40.0
> 

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [PATCH v5 2/2] add ArmCpuInfo EFI application
  2023-04-20 12:43                 ` Leif Lindholm
@ 2023-04-20 14:42                   ` Marcin Juszkiewicz
  2023-04-20 14:44                   ` [PATCH v6 1/2] ArmLib: add functions to read system registers Marcin Juszkiewicz
  1 sibling, 0 replies; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-20 14:42 UTC (permalink / raw)
  To: devel, quic_llindhol

W dniu 20.04.2023 o 14:43, Leif Lindholm pisze:
> On Fri, Apr 07, 2023 at 17:29:57 +0200, Marcin Juszkiewicz wrote:

>> +#
>> +#  This flag specifies whether HII resource section is generated into PE image.
>> +#
>> +  UEFI_HII_RESOURCE_SECTION      = TRUE
> 
> The above stanza, and its comment, can be dropped.
> This relates to native language support, which there isn't any in this app.

done


>> +VOID
>> +PrintText (
>> +  CONST CHAR8  *field,
> 
> For coding style, name should be "*Field".

done, in all places

>> +  CONST CHAR8  *Bits,
>> +  CONST UINT8  Value,
>> +  CONST CHAR8  *Description
>> +  )
>> +{
>> +  STATIC CONST CHAR8  binaries[][5] = {
> 
> Could I propose renaming "binaries" to "Nibbles", since this is an
> array holding string values for all possible nibbles?

done

>> +    "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
>> +    "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"
>> +  };

>> +  switch (Value) {
>> +    case 0b0000:
> 
> I agree with Pedro's concern w.r.t. binary literals being a GCC
> extension. But I also think this is the most appropriate
> representation since this is how it's documented in the ARM ARM.
> 
> A bit hacky, but could we do
> 
> enum {
>    b0000,
>    b0001,
>    ...
>    b1111
> };
> 
> and then use those instead?
> 
> (you can build with -pedantic to verify you catch them all)

done, passed with -pedantic

>> +  // only valid for BigEnd != 0b0000
> 
> Could we possibly reword as
>    // If mixed-endian support is present, check whether supported at EL0

done


>> +    case 0b0001:             // add FEAT_LPA2 check
> 
> That's sounds like a TODO. And we don't want TODOs in code.
> Can we either drop the comment, add the check, or skip the test?
> (That is my order of preference - we shouldn't need to be verifying
> architectural compliance.)

dropped

>> +    case 0b0010:             // add FEAT_LPA2 check
> 
> Same comment as for 4k.

dropped as well

>> +  Bits  = "59:56";
>> +  Value = (Aa64Pfr0 >> 56) & 0xf;
>> +  switch (Value) {
>> +    case 0b0000:
>> +      Description = "no info is FEAT_CSV2 implemented.";
> 
> Consider rewording.
> Is the text from the ARM ARM too long?
> "The implementation does not disclose whether FEAT_CSV2 is
> implemented."
> if so, maybe
> "Not disclosed whether FEAT_CSV2 is implemented."?

thx, done

>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  // 35:32 is CSV2_frac
> 
> That's a TODO.

Is it more info why those bits are not handled here. Same with 15:12 for 
RAS_frac and 19:16 for MPAM_frac. They are not reserved like 63:40 are.

And CSV2_frac bits are used earlier, in PRF0 handling. If we have CSV2 
implemented then CSV2_frac says do we have CSV2_1p1 or CSV2_1p2 implemented.

MPAM_frac and RAS_frac are used in PRF0 handling as well.

>> +EFI_STATUS
>> +EFIAPI
>> +UefiMain  (
> 
> Stray space before '(' here too. Is it an editor setting?

fixed

^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH v6 1/2] ArmLib: add functions to read system registers
  2023-04-20 12:43                 ` Leif Lindholm
  2023-04-20 14:42                   ` [edk2-devel] " Marcin Juszkiewicz
@ 2023-04-20 14:44                   ` Marcin Juszkiewicz
  2023-04-20 14:44                     ` [PATCH v6 2/2] add ArmCpuInfo EFI application Marcin Juszkiewicz
  1 sibling, 1 reply; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-20 14:44 UTC (permalink / raw)
  To: devel
  Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran, Pedro Falcato,
	Marcin Juszkiewicz

ArmCpuInfo uses those to read system registers and other parts of EDK2
may find them useful.

Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
---
 ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h    | 50 +++++++++++++++-
 .../Library/ArmLib/AArch64/AArch64Support.S   | 58 ++++++++++++++++---
 2 files changed, 99 insertions(+), 9 deletions(-)

diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h
index 330481fc50db..6380a019ddc5 100644
--- a/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h
+++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h
@@ -40,7 +40,43 @@ ArmCleanInvalidateDataCacheEntryBySetWay (
 
 UINTN
 EFIAPI
-ArmReadIdAA64Pfr0 (
+ArmReadIdAA64Dfr0 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Dfr1 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Isar0 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Isar1 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Isar2 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Mmfr0 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Mmfr1 (
   VOID
   );
 
@@ -54,4 +90,16 @@ ArmReadIdAA64Mmfr2 (
   VOID
   );
 
+UINTN
+EFIAPI
+ArmReadIdAA64Pfr0 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Pfr1 (
+  VOID
+  );
+
 #endif // AARCH64_LIB_H_
diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S b/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S
index d3cc1e86716b..a7111e51882c 100644
--- a/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S
+++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S
@@ -425,10 +425,6 @@ ASM_FUNC(ArmCallWFI)
   wfi
   ret
 
-ASM_FUNC(ArmReadIdAA64Mmfr2)
-  mrs   x0, ID_AA64MMFR2_EL1           // read EL1 MMFR2
-  ret
-
 ASM_FUNC(ArmReadMpidr)
   mrs   x0, mpidr_el1           // read EL1 MPIDR
   ret
@@ -452,10 +448,6 @@ ASM_FUNC(ArmIsArchTimerImplemented)
   ret
 
 
-ASM_FUNC(ArmReadIdAA64Pfr0)
-  mrs   x0, id_aa64pfr0_el1   // Read ID_AA64PFR0 Register
-  ret
-
 
 // VOID ArmWriteHcr(UINTN Hcr)
 ASM_FUNC(ArmWriteHcr)
@@ -482,4 +474,54 @@ ASM_FUNC(ArmWriteCntHctl)
   msr   cnthctl_el2, x0
   ret
 
+
+ASM_FUNC(ArmReadIdAA64Dfr0)
+  mrs   x0, ID_AA64DFR0_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Dfr1)
+  mrs   x0, ID_AA64DFR1_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Isar0)
+  mrs   x0, ID_AA64ISAR0_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Isar1)
+  mrs   x0, ID_AA64ISAR1_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Isar2)
+  mrs   x0, ID_AA64ISAR2_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Mmfr0)
+  mrs   x0, ID_AA64MMFR0_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Mmfr1)
+  mrs   x0, ID_AA64MMFR1_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Mmfr2)
+  mrs   x0, ID_AA64MMFR2_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Pfr0)
+  mrs   x0, ID_AA64PFR0_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Pfr1)
+  mrs   x0, ID_AA64PFR1_EL1
+  ret
+
 ASM_FUNCTION_REMOVE_IF_UNREFERENCED
-- 
2.40.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v6 2/2] add ArmCpuInfo EFI application
  2023-04-20 14:44                   ` [PATCH v6 1/2] ArmLib: add functions to read system registers Marcin Juszkiewicz
@ 2023-04-20 14:44                     ` Marcin Juszkiewicz
  2023-04-20 17:29                       ` Leif Lindholm
  0 siblings, 1 reply; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-20 14:44 UTC (permalink / raw)
  To: devel
  Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran, Pedro Falcato,
	Marcin Juszkiewicz

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 |   33 +
 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c   | 2346 ++++++++++++++++++
 3 files changed, 2380 insertions(+)
 create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
 create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c

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..d2235d3aa911
--- /dev/null
+++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
@@ -0,0 +1,33 @@
+## @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
+
+[Sources]
+  ArmCpuInfo.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  ArmLib
+  UefiApplicationEntryPoint
+  UefiLib
diff --git a/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
new file mode 100644
index 000000000000..63914d9815c6
--- /dev/null
+++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
@@ -0,0 +1,2346 @@
+/** @file
+
+  Copyright  (c) 2023 Marcin Juszkiewicz
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ **/
+
+#include <Library/UefiLib.h>
+#include <Library/ArmLib/AArch64/AArch64Lib.h>
+
+// We cannot assume GCC extensions to be present so let use
+// binary numbers via enum.
+// Arm ARM uses binary numbers so this way it is more readable.
+enum {
+   b0000,
+   b0001,
+   b0010,
+   b0011,
+   b0100,
+   b0101,
+   b0110,
+   b0111,
+   b1000,
+   b1001,
+   b1010,
+   b1011,
+   b1100,
+   b1101,
+   b1110,
+   b1111
+};
+
+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  Nibbles[][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, Nibbles[Value & 0xf], Description);
+}
+
+VOID
+PrintSpacer (
+  VOID
+  )
+{
+  AsciiPrint ("------------------|-------|-------|----------------------------------------------\n");
+}
+
+VOID
+HandleAa64Mmfr0 (
+  CONST UINT64  Aa64Mmfr0
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR0";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = Aa64Mmfr0 & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "32 Bits  (4GB) of physical address range supported.";
+      break;
+    case b0001:
+      Description = "36 Bits  (64GB) of physical address range supported.";
+      break;
+    case b0010:
+      Description = "40 Bits  (1TB) of physical address range supported.";
+      break;
+    case b0011:
+      Description = "42 Bits  (4TB) of physical address range supported.";
+      break;
+    case b0100:
+      Description = "44 Bits  (16TB) of physical address range supported.";
+      break;
+    case b0101:
+      Description = "48 Bits  (256TB) of physical address range supported.";
+      break;
+    case b0110:
+      Description = "52 Bits  (4PB) of physical address range supported.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+  if (Value == b0110) {
+    PrintText ("", "", "", "FEAT_LPA implemented.");
+  }
+
+  Bits  = "7:4 ";
+  Value = (Aa64Mmfr0 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "ASID: 8 Bits";
+      break;
+    case b0010:
+      Description = "ASID: 16 Bits";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Mmfr0 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "No mixed-endian support.";
+      break;
+    case b0001:
+      Description = "Mixed-endian support.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // If mixed-endian is present, check whether supported at EL0
+  if (((Aa64Mmfr0 >>  8) & 0xf) != b0000 ) {
+    if (((Aa64Mmfr0 >> 16) & 0xf) == b0000 ) {
+      PrintValues ("ID_AA64MMFR0", "19:16", b0000, "No mixed-endian support at EL0.");
+    }
+
+    if (((Aa64Mmfr0 >> 16) & 0xf) == b0001 ) {
+      PrintValues ("ID_AA64MMFR0", "19:16", b0001, "Mixed-endian support at EL0.");
+    }
+  }
+
+  Bits  = "15:12";
+  Value = (Aa64Mmfr0 >> 12) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "No support for a distinction between Secure and Non-Secure Memory.";
+      break;
+    case b0001:
+      Description = "Supports a distinction between Secure and Non-Secure Memory.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "31:28";
+  Value = (Aa64Mmfr0 >> 28) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = " 4KB granule supported.";
+      break;
+    case b1111:
+      Description = " 4KB granule not supported.";
+      break;
+    case b0001:
+      Description = " 4KB granule supported for 52-bit address.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Mmfr0 >> 40) & 0xf;
+  switch (Value) {
+    case b0001:
+      Description = " 4KB granule not supported at stage 2.";
+      break;
+    case b0010:
+      Description = " 4KB granule supported at stage 2.";
+      break;
+    case b0011:
+      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 = (Aa64Mmfr0 >> 20) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "16KB granule not supported.";
+      break;
+    case b0001:
+      Description = "16KB granule supported.";
+      break;
+    case b0010:
+      Description = "16KB granule supported for 52-bit address.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Mmfr0 >> 32) & 0xf;
+  switch (Value) {
+    case b0001:
+      Description = "16KB granule not supported at stage 2.";
+      break;
+    case b0010:
+      Description = "16KB granule supported at stage 2.";
+      break;
+    case b0011:
+      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 = (Aa64Mmfr0 >> 24) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "64KB granule supported.";
+      break;
+    case b1111:
+      Description = "64KB granule not supported.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Mmfr0 >> 36) & 0xf;
+  switch (Value) {
+    case b0001:
+      Description = "64KB granule not supported at stage 2.";
+      break;
+    case b0010:
+      Description = "64KB granule supported at stage 2.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Mmfr0 >> 44) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_ExS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_ExS implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 55:48 reserved
+
+  Bits  = "59:56";
+  Value = (Aa64Mmfr0 >> 56) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_FGT not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_FGT implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "63:60";
+  Value = (Aa64Mmfr0 >> 60) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_ECV not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_ECV implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_ECV implemented with extras.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+VOID
+HandleAa64Mmfr1 (
+  CONST UINT64  Aa64Mmfr1,
+  CONST UINT64  Aa64Pfr0
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = Aa64Mmfr1 & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_HAFDBS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_HAFDBS implemented without dirty status support.";
+      break;
+    case b0010:
+      Description = "FEAT_HAFDBS implemented with dirty status support.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Mmfr1 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_VMID16 not implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_VMID16 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Mmfr1 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_VHE not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_VHE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Mmfr1 >> 12) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_HPDS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_HPDS implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_HPDS2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Mmfr1 >> 16) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_LOR not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_LOR implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Mmfr1 >> 20) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_PAN not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_PAN implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_PAN2 implemented.";
+      break;
+    case b0011:
+      Description = "FEAT_PAN3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // when FEAT_RAS implemented
+  if ((((Aa64Pfr0 >> 28) & 0xf) == b0001) ||
+      (((Aa64Pfr0 >> 28) & 0xf) == b0010))
+  {
+    if (((Aa64Mmfr1 >> 24) & 0xf) == b0000 ) {
+      PrintValues ("ID_AA64MMFR1", "27:24", b0000, "The PE never generates an SError interrupt due to");
+      PrintText ("", "", "", "an External abort on a speculative read.");
+    }
+
+    if (((Aa64Mmfr1 >> 24) & 0xf) == b0001 ) {
+      PrintValues ("ID_AA64MMFR1", "27:24", b0001, "The PE might generate an SError interrupt due to");
+      PrintText ("", "", "", "an External abort on a speculative read.");
+    }
+  }
+
+  Bits  = "31:28";
+  Value = (Aa64Mmfr1 >> 28) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_XNX not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_XNX implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Mmfr1 >> 32) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_TWED not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_TWED implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Mmfr1 >> 36) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_ETS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_ETS implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Mmfr1 >> 40) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_HCX not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_HCX implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Mmfr1 >> 44) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_AFP not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_AFP implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "51:48";
+  Value = (Aa64Mmfr1 >> 48) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_nTLBPA not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_nTLBPA implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Mmfr1 >> 52) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_TIDCP1 not implemented";
+      break;
+    case b0001:
+      Description = "FEAT_TIDCP1 implemented";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "59:56";
+  Value = (Aa64Mmfr1 >> 56) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_CMOW not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_CMOW implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 63:60 reserved
+}
+
+VOID
+HandleAa64Mmfr2 (
+  CONST UINT64  Aa64Mmfr2
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR2";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Mmfr2)       & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_TTCNP not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_TTCNP implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Mmfr2 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_UAO not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_UAO implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Mmfr2 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_LSMAOC not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_LSMAOC implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Mmfr2 >> 12) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_IESB not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_IESB implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Mmfr2 >> 16) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_LVA not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_LVA implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Mmfr2 >> 20) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_CCIDX not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_CCIDX implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "27:24";
+  Value = (Aa64Mmfr2 >> 24) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_NV not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_NV implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_NV2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "31:28";
+  Value = (Aa64Mmfr2 >> 28) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_TTST not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_TTST implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Mmfr2 >> 32) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_LSE2 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_LSE2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Mmfr2 >> 36) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_IDST not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_IDST implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Mmfr2 >> 40) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_S2FWB not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_S2FWB implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 47:44 reserved
+
+  Bits  = "51:48";
+  Value = (Aa64Mmfr2 >> 48) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_TTL not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_TTL implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Mmfr2 >> 52) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_BBM: Level 0 support for changing block size is supported.";
+      break;
+    case b0001:
+      Description = "FEAT_BBM: Level 1 support for changing block size is supported.";
+      break;
+    case b0010:
+      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 = (Aa64Mmfr2 >> 56) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_EVT not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_EVT: HCR_EL2.{TOCU, TICAB, TID4} traps are supported.";
+      break;
+    case b0010:
+      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 = (Aa64Mmfr2 >> 60) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_E0PD not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_E0PD implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+VOID
+HandleAa64Pfr0 (
+  CONST UINT64  Aa64Pfr0,
+  CONST UINT64  Aa64Pfr1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR0";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Pfr0)       & 0xf;
+  switch (Value) {
+    case b0001:
+      Description = "EL0 in AArch64 only";
+      break;
+    case b0010:
+      Description = "EL0 in AArch64 and AArch32";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Pfr0 >>  4) & 0xf;
+  switch (Value) {
+    case b0001:
+      Description = "EL1 in AArch64 only";
+      break;
+    case b0010:
+      Description = "EL1 in AArch64 and AArch32";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Pfr0 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "EL2 not implemented.";
+      break;
+    case b0001:
+      Description = "EL2 in AArch64 only";
+      break;
+    case b0010:
+      Description = "EL2 in AArch64 and AArch32";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Pfr0 >> 12) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "EL3 not implemented.";
+      break;
+    case b0001:
+      Description = "EL3 in AArch64 only";
+      break;
+    case b0010:
+      Description = "EL3 in AArch64 and AArch32";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Pfr0 >> 16) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Floating-point implemented.";
+      break;
+    case b0001:
+      Description = "Floating-point with half-precision support  (FEAT_FP16).";
+      break;
+    case b1111:
+      Description = "Floating-point not implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Pfr0 >> 20) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Advanced SIMD implemented.";
+      break;
+    case b0001:
+      Description = "Advanced SIMD with half precision support  (FEAT_FP16).";
+      break;
+    case b1111:
+      Description = "Advanced SIMD not implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "27:24";
+  Value = (Aa64Pfr0 >> 24) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "System registers of GIC CPU not implemented.";
+      break;
+    case b0001:
+      Description = "System registers to versions 3.0/4.0 of GIC CPU implemented.";
+      break;
+    case b0011:
+      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 = (Aa64Pfr0 >> 28) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_RAS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_RAS implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_RASv1p1 implemented.";
+      // b0010 FEAT_RASv1p1 implemented and, if EL3 is implemented, FEAT_DoubleFault implemented.
+      if ((((Aa64Pfr0 >> 12) & 0xf) == b0001) ||
+          (((Aa64Pfr0 >> 12) & 0xf) == b0010))
+      {
+        Description = "FEAT_RASv1p1 implemented. FEAT_DoubleFault implemented.";
+      }
+
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+  if (Value == b0001) {
+    if (((Aa64Pfr1 >> 12) & 0xf) == b0001 ) {
+      PrintValues ("ID_AA64PRF1", "15:12", b0001, "FEAT_RASv1p1 implemented.");
+    }
+  }
+
+  Bits  = "35:32";
+  Value = (Aa64Pfr0 >> 32) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SVE not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SVE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Pfr0 >> 36) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Secure EL2 not implemented.";
+      break;
+    case b0001:
+      Description = "Secure EL2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Pfr0 >> 40) & 0xf;
+  switch (Value) {
+    case b0000:
+      if (((Aa64Pfr1 >> 16) & 0xf) == b0000 ) {
+        Description = "FEAT_MPAM not implemented.";
+      }
+
+      if (((Aa64Pfr1 >> 16) & 0xf) == b0001 ) {
+        Description = "FEAT_MPAM v0.1 implemented.";
+      }
+
+      break;
+    case b0001:
+      if (((Aa64Pfr1 >> 16) & 0xf) == b0000 ) {
+        Description = "FEAT_MPAM v1.0 implemented.";
+      }
+
+      if (((Aa64Pfr1 >> 16) & 0xf) == b0001 ) {
+        Description = "FEAT_MPAM v1.1 implemented.";
+      }
+
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Pfr0 >> 44) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_AMU not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_AMUv1 implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_AMUv1p1 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "51:48";
+  Value = (Aa64Pfr0 >> 48) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_DIT not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_DIT implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Pfr0 >> 52) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_RME not implemented";
+      break;
+    case b0001:
+      Description = "FEAT_RME implemented";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "59:56";
+  Value = (Aa64Pfr0 >> 56) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Not disclosed whether FEAT_CSV2 is implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_CSV2 implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_CSV2_2 implemented.";
+      break;
+    case b0011:
+      Description = "FEAT_CSV2_3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+  if (Value == b0001) {
+    if (((Aa64Pfr1 >> 32) & 0xf) == b0001 ) {
+      PrintValues ("ID_AA64PRF1", "35:32", b0001, "FEAT_CSV2_1p1 implemented.");
+    }
+
+    if (((Aa64Pfr1 >> 32) & 0xf) == b0010 ) {
+      PrintValues ("ID_AA64PRF1", "35:32", b0010, "FEAT_CSV2_1p2 implemented.");
+    }
+  }
+
+  Bits  = "63:60";
+  Value = (Aa64Pfr0 >> 60) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_CSV3 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_CSV3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+VOID
+HandleAa64Pfr1 (
+  CONST UINT64  Aa64Pfr1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = Aa64Pfr1 & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_BTI not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_BTI implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Pfr1 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SSBS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SSBS implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_SSBS2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Pfr1 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_MTE not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_MTE implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_MTE2 implemented.";
+      break;
+    case b0011:
+      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 = (Aa64Pfr1 >> 24) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SME not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SME implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "31:28";
+  Value = (Aa64Pfr1 >> 28) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_RNG_TRAP not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_RNG_TRAP implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 35:32 is CSV2_frac
+
+  Bits  = "39:36";
+  Value = (Aa64Pfr1 >> 36) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_NMI not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_NMI implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 63:40 are reserved
+}
+
+VOID
+HandleAa64Isar0 (
+  CONST UINT64  Aa64Isar0
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR0";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  // 3:0 reserved
+
+  Bits  = "7:4 ";
+  Value = (Aa64Isar0 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_AES, FEAT_PMULL not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_AES implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_AES and FEAT_PMULL implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Isar0 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SHA1 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SHA1 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Isar0 >> 12) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SHA256, FEAT_SHA512 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SHA256 implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_SHA512 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Isar0 >> 16) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "CRC32 not implemented.";
+      break;
+    case b0001:
+      Description = "CRC32 instructions implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Isar0 >> 20) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_LSE not implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_LSE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "27:24";
+  Value = (Aa64Isar0 >> 24) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "TME instructions not implemented.";
+      break;
+    case b0001:
+      Description = "TME instructions implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "31:28";
+  Value = (Aa64Isar0 >> 28) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_RDM not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_RDM implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Isar0 >> 32) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SHA3 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SHA3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Isar0 >> 36) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SM3 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SM3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Isar0 >> 40) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SM4 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SM4 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Isar0 >> 44) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_DotProd not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_DotProd implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "51:48";
+  Value = (Aa64Isar0 >> 48) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_FHM not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_FHM implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Isar0 >> 52) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_FlagM/FEAT_FlagM2 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_FlagM implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_FlagM2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "59:56";
+  Value = (Aa64Isar0 >> 56) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_TLBIOS/FEAT_TLBIRANGE not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_TLBIOS implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_TLBIRANGE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "63:60";
+  Value = (Aa64Isar0 >> 60) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_RNG not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_RNG implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+VOID
+HandleAa64Isar1 (
+  CONST UINT64  Aa64Isar1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Isar1 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "DC CVAP not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_DPB implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_DPB2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Isar1 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Address Authentication  (APA) not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_PAuth implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_EPAC implemented.";
+      break;
+    case b0011:
+      Description = "FEAT_PAuth2 implemented.";
+      break;
+    case b0100:
+      Description = "FEAT_FPAC implemented.";
+      break;
+    case b0101:
+      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 = (Aa64Isar1 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Address Authentication  (API) not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_PAuth implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_EPAC implemented.";
+      break;
+    case b0011:
+      Description = "FEAT_PAuth2 implemented.";
+      break;
+    case b0100:
+      Description = "FEAT_FPAC implemented.";
+      break;
+    case b0101:
+      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 = (Aa64Isar1 >> 12) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_JSCVT not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_JSCVT implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Isar1 >> 16) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_FCMA not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_FCMA implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Isar1 >> 20) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_LRCPC (2) not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_LRCPC implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_LRCPC2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "27:24";
+  Value = (Aa64Isar1 >> 24) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_PACQARMA5 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_PACQARMA5 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "31:28";
+  Value = (Aa64Isar1 >> 28) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_PACIMP not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_PACIMP implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Isar1 >> 32) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_FRINTTS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_FRINTTS implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Isar1 >> 36) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SB not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SB implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Isar1 >> 40) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SPECRES not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SPECRES implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Isar1 >> 44) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_BF16 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_BF16 implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_EBF16 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "51:48";
+  Value = (Aa64Isar1 >> 48) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_DGH not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_DGH implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Isar1 >> 52) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_I8MM not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_I8MM implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "59:56";
+  Value = (Aa64Isar1 >> 56) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_XS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_XS implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "63:60";
+  Value = (Aa64Isar1 >> 60) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_LS64 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_LS64 implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_LS64_V implemented.";
+      break;
+    case b0011:
+      Description = "FEAT_LS64_ACCDATA implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+VOID
+HandleAa64Isar2 (
+  CONST UINT64  Aa64Isar2
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR2";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Isar2 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_WFxT not implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_WFxT implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Isar2 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_RPRES not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_RPRES implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Isar2 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_PACQARMA3 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_PACQARMA3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Isar2 >> 12) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Address Authentication  (APA3) not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_PAuth implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_EPAC implemented.";
+      break;
+    case b0011:
+      Description = "FEAT_PAuth2 implemented.";
+      break;
+    case b0100:
+      Description = "FEAT_FPAC implemented.";
+      break;
+    case b0101:
+      Description = "FEAT_FPACCOMBINE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Isar2 >> 16) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_MOPS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_MOPS implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Isar2 >> 20) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_HBC not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_HBC implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "27:24";
+  Value = (Aa64Isar2 >> 24) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_CONSTPACFIELD not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_CONSTPACFIELD implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 63:28 reserved
+}
+
+VOID
+HandleAa64Dfr0 (
+  CONST UINT64  Aa64Dfr0
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64DFR0";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Dfr0 >>  4) & 0xf;
+  switch (Value) {
+    case b0110:
+      Description = "Armv8 debug architecture";
+      break;
+    case b0111:
+      Description = "Armv8 debug architecture with VHE";
+      break;
+    case b1000:
+      Description = "FEAT_Debugv8p2 implemented.";
+      break;
+    case b1001:
+      Description = "FEAT_Debugv8p4 implemented.";
+      break;
+    case b1010:
+      Description = "FEAT_Debugv8p8 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Dfr0 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Trace unit System registers not implemented.";
+      break;
+    case b0001:
+      Description = "Trace unit System registers implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Dfr0 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Performance Monitors Extension not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_PMUv3 implemented.";
+      break;
+    case b0100:
+      Description = "FEAT_PMUv3p1 implemented.";
+      break;
+    case b0101:
+      Description = "FEAT_PMUv3p4 implemented.";
+      break;
+    case b0110:
+      Description = "FEAT_PMUv3p5 implemented.";
+      break;
+    case b0111:
+      Description = "FEAT_PMUv3p7 implemented.";
+      break;
+    case b1000:
+      Description = "FEAT_PMUv3p8 implemented.";
+      break;
+    case b1111:
+      Description = "IMPLEMENTATION DEFINED form of performance monitors supported.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Dfr0 >> 12) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "reserved";
+      break;
+    default:
+      Description = "Number of breakpoints, minus 1.";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 19:16 reserved
+
+  Bits  = "23:20";
+  Value = (Aa64Dfr0 >> 20) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "reserved";
+      break;
+    default:
+      Description = "Number of watchpoints, minus 1.";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 27:24 reserved
+
+  Bits  = "31:28";
+  Value = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 32) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SPE not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SPE implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_SPEv1p1 implemented.";
+      break;
+    case b0011:
+      Description = "FEAT_SPEv1p2 implemented.";
+      break;
+    case b0100:
+      Description = "FEAT_SPEv1p3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Dfr0 >> 36) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_DoubleLock implemented.";
+      break;
+    case b1111:
+      Description = "FEAT_DoubleLock not implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Dfr0 >> 40) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_TRF not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_TRF implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Dfr0 >> 44) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_TRBE not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_TRBE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "51:48";
+  Value = (Aa64Dfr0 >> 48) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_MTPMU not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_MTPMU and FEAT_PMUv3 implemented.";
+      break;
+    case b1111:
+      Description = "FEAT_MTPMU not implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Dfr0 >> 52) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_BRBE not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_BRBE implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_BRBEv1p1 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 59:56 reserved
+
+  Bits  = "63:60";
+  Value = (Aa64Dfr0 >> 60) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Setting MDCR_EL2.HPMN to zero has CONSTRAINED UNPREDICTABLE behavior.";
+      break;
+    case b0001:
+      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  Aa64Dfr0;
+  UINT64  Aa64Isar0;
+  UINT64  Aa64Isar1;
+  UINT64  Aa64Isar2;
+  UINT64  Aa64Mmfr0;
+  UINT64  Aa64Mmfr1;
+  UINT64  Aa64Mmfr2;
+  UINT64  Aa64Pfr0;
+  UINT64  Aa64Pfr1;
+
+  Aa64Dfr0  = ArmReadIdAA64Dfr0 ();
+  Aa64Isar0 = ArmReadIdAA64Isar0 ();
+  Aa64Isar1 = ArmReadIdAA64Isar1 ();
+  Aa64Isar2 = ArmReadIdAA64Isar2 ();
+  Aa64Mmfr0 = ArmReadIdAA64Mmfr0 ();
+  Aa64Mmfr1 = ArmReadIdAA64Mmfr1 ();
+  Aa64Mmfr2 = ArmReadIdAA64Mmfr2 ();
+  Aa64Pfr0  = ArmReadIdAA64Pfr0 ();
+  Aa64Pfr1  = ArmReadIdAA64Pfr1 ();
+
+  AsciiPrint ("ID_AA64MMFR0_EL1 = 0x%016lx\n", Aa64Mmfr0);
+  AsciiPrint ("ID_AA64MMFR1_EL1 = 0x%016lx\n", Aa64Mmfr1);
+  AsciiPrint ("ID_AA64MMFR2_EL1 = 0x%016lx\n", Aa64Mmfr2);
+  AsciiPrint ("ID_AA64PFR0_EL1  = 0x%016lx\n", Aa64Pfr0);
+  AsciiPrint ("ID_AA64PFR1_EL1  = 0x%016lx\n", Aa64Pfr1);
+  AsciiPrint ("ID_AA64ISAR0_EL1 = 0x%016lx\n", Aa64Isar0);
+  AsciiPrint ("ID_AA64ISAR1_EL1 = 0x%016lx\n", Aa64Isar1);
+  AsciiPrint ("ID_AA64ISAR2_EL1 = 0x%016lx\n", Aa64Isar2);
+  AsciiPrint ("ID_AA64DFR0_EL1  = 0x%016lx\n", Aa64Dfr0);
+
+  AsciiPrint ("\n");
+  PrintText ("Register", "Bits", "Value", "Feature");
+  PrintSpacer ();
+
+  HandleAa64Mmfr0 (Aa64Mmfr0);
+  PrintSpacer ();
+  HandleAa64Mmfr1 (Aa64Mmfr1, Aa64Pfr0);
+  PrintSpacer ();
+  HandleAa64Mmfr2 (Aa64Mmfr2);
+
+  PrintSpacer ();
+  HandleAa64Pfr0 (Aa64Pfr0, Aa64Pfr1);
+  PrintSpacer ();
+  HandleAa64Pfr1 (Aa64Pfr1);
+
+  PrintSpacer ();
+  HandleAa64Isar0 (Aa64Isar0);
+  PrintSpacer ();
+  HandleAa64Isar1 (Aa64Isar1);
+  PrintSpacer ();
+  HandleAa64Isar2 (Aa64Isar2);
+
+  PrintSpacer ();
+  HandleAa64Dfr0 (Aa64Dfr0);
+
+  return EFI_SUCCESS;
+}
-- 
2.40.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [PATCH v6 2/2] add ArmCpuInfo EFI application
  2023-04-20 14:44                     ` [PATCH v6 2/2] add ArmCpuInfo EFI application Marcin Juszkiewicz
@ 2023-04-20 17:29                       ` Leif Lindholm
  2023-04-21 14:37                         ` [edk2-devel] " Rebecca Cran
  0 siblings, 1 reply; 32+ messages in thread
From: Leif Lindholm @ 2023-04-20 17:29 UTC (permalink / raw)
  To: Marcin Juszkiewicz; +Cc: devel, Ard Biesheuvel, Rebecca Cran, Pedro Falcato

On Thu, Apr 20, 2023 at 16:44:23 +0200, Marcin Juszkiewicz wrote:
> App goes through ID_AA64*_EL1 system registers and decode their values.
> 
> Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>

For the series:
Reviewed-by: Leif Lindholm <quic_llindhol@quicinc.com>

After discussing with Marcin on side channel, I folded in a statement
at the head of ArmCpuInfo.c that the app was written against ARM DDI
0487I.a version (current) of the ARM Architecture Reference Manual (A
profile), and that this information should be updated when features
are added from a subsequent version of the document.

Submitted as github merge request #4292, currently going through CI.

Thanks!

/
    Leif

> ---
>  ArmPkg/ArmPkg.dsc                            |    1 +
>  ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf |   33 +
>  ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c   | 2346 ++++++++++++++++++
>  3 files changed, 2380 insertions(+)
>  create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
>  create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
> 
> 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..d2235d3aa911
> --- /dev/null
> +++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
> @@ -0,0 +1,33 @@
> +## @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
> +
> +[Sources]
> +  ArmCpuInfo.c
> +
> +[Packages]
> +  ArmPkg/ArmPkg.dec
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +
> +[LibraryClasses]
> +  ArmLib
> +  UefiApplicationEntryPoint
> +  UefiLib
> diff --git a/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
> new file mode 100644
> index 000000000000..63914d9815c6
> --- /dev/null
> +++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
> @@ -0,0 +1,2346 @@
> +/** @file
> +
> +  Copyright  (c) 2023 Marcin Juszkiewicz
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> + **/
> +
> +#include <Library/UefiLib.h>
> +#include <Library/ArmLib/AArch64/AArch64Lib.h>
> +
> +// We cannot assume GCC extensions to be present so let use
> +// binary numbers via enum.
> +// Arm ARM uses binary numbers so this way it is more readable.
> +enum {
> +   b0000,
> +   b0001,
> +   b0010,
> +   b0011,
> +   b0100,
> +   b0101,
> +   b0110,
> +   b0111,
> +   b1000,
> +   b1001,
> +   b1010,
> +   b1011,
> +   b1100,
> +   b1101,
> +   b1110,
> +   b1111
> +};
> +
> +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  Nibbles[][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, Nibbles[Value & 0xf], Description);
> +}
> +
> +VOID
> +PrintSpacer (
> +  VOID
> +  )
> +{
> +  AsciiPrint ("------------------|-------|-------|----------------------------------------------\n");
> +}
> +
> +VOID
> +HandleAa64Mmfr0 (
> +  CONST UINT64  Aa64Mmfr0
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR0";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = Aa64Mmfr0 & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "32 Bits  (4GB) of physical address range supported.";
> +      break;
> +    case b0001:
> +      Description = "36 Bits  (64GB) of physical address range supported.";
> +      break;
> +    case b0010:
> +      Description = "40 Bits  (1TB) of physical address range supported.";
> +      break;
> +    case b0011:
> +      Description = "42 Bits  (4TB) of physical address range supported.";
> +      break;
> +    case b0100:
> +      Description = "44 Bits  (16TB) of physical address range supported.";
> +      break;
> +    case b0101:
> +      Description = "48 Bits  (256TB) of physical address range supported.";
> +      break;
> +    case b0110:
> +      Description = "52 Bits  (4PB) of physical address range supported.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +  if (Value == b0110) {
> +    PrintText ("", "", "", "FEAT_LPA implemented.");
> +  }
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Mmfr0 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "ASID: 8 Bits";
> +      break;
> +    case b0010:
> +      Description = "ASID: 16 Bits";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "11:8 ";
> +  Value = (Aa64Mmfr0 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "No mixed-endian support.";
> +      break;
> +    case b0001:
> +      Description = "Mixed-endian support.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // If mixed-endian is present, check whether supported at EL0
> +  if (((Aa64Mmfr0 >>  8) & 0xf) != b0000 ) {
> +    if (((Aa64Mmfr0 >> 16) & 0xf) == b0000 ) {
> +      PrintValues ("ID_AA64MMFR0", "19:16", b0000, "No mixed-endian support at EL0.");
> +    }
> +
> +    if (((Aa64Mmfr0 >> 16) & 0xf) == b0001 ) {
> +      PrintValues ("ID_AA64MMFR0", "19:16", b0001, "Mixed-endian support at EL0.");
> +    }
> +  }
> +
> +  Bits  = "15:12";
> +  Value = (Aa64Mmfr0 >> 12) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "No support for a distinction between Secure and Non-Secure Memory.";
> +      break;
> +    case b0001:
> +      Description = "Supports a distinction between Secure and Non-Secure Memory.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "31:28";
> +  Value = (Aa64Mmfr0 >> 28) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = " 4KB granule supported.";
> +      break;
> +    case b1111:
> +      Description = " 4KB granule not supported.";
> +      break;
> +    case b0001:
> +      Description = " 4KB granule supported for 52-bit address.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "43:40";
> +  Value = (Aa64Mmfr0 >> 40) & 0xf;
> +  switch (Value) {
> +    case b0001:
> +      Description = " 4KB granule not supported at stage 2.";
> +      break;
> +    case b0010:
> +      Description = " 4KB granule supported at stage 2.";
> +      break;
> +    case b0011:
> +      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 = (Aa64Mmfr0 >> 20) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "16KB granule not supported.";
> +      break;
> +    case b0001:
> +      Description = "16KB granule supported.";
> +      break;
> +    case b0010:
> +      Description = "16KB granule supported for 52-bit address.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "35:32";
> +  Value = (Aa64Mmfr0 >> 32) & 0xf;
> +  switch (Value) {
> +    case b0001:
> +      Description = "16KB granule not supported at stage 2.";
> +      break;
> +    case b0010:
> +      Description = "16KB granule supported at stage 2.";
> +      break;
> +    case b0011:
> +      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 = (Aa64Mmfr0 >> 24) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "64KB granule supported.";
> +      break;
> +    case b1111:
> +      Description = "64KB granule not supported.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "39:36";
> +  Value = (Aa64Mmfr0 >> 36) & 0xf;
> +  switch (Value) {
> +    case b0001:
> +      Description = "64KB granule not supported at stage 2.";
> +      break;
> +    case b0010:
> +      Description = "64KB granule supported at stage 2.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "47:44";
> +  Value = (Aa64Mmfr0 >> 44) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_ExS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_ExS implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 55:48 reserved
> +
> +  Bits  = "59:56";
> +  Value = (Aa64Mmfr0 >> 56) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_FGT not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_FGT implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "63:60";
> +  Value = (Aa64Mmfr0 >> 60) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_ECV not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_ECV implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_ECV implemented with extras.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +}
> +
> +VOID
> +HandleAa64Mmfr1 (
> +  CONST UINT64  Aa64Mmfr1,
> +  CONST UINT64  Aa64Pfr0
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR1";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = Aa64Mmfr1 & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_HAFDBS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_HAFDBS implemented without dirty status support.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_HAFDBS implemented with dirty status support.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Mmfr1 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_VMID16 not implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_VMID16 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "11:8 ";
> +  Value = (Aa64Mmfr1 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_VHE not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_VHE implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "15:12";
> +  Value = (Aa64Mmfr1 >> 12) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_HPDS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_HPDS implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_HPDS2 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "19:16";
> +  Value = (Aa64Mmfr1 >> 16) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_LOR not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_LOR implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "23:20";
> +  Value = (Aa64Mmfr1 >> 20) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_PAN not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_PAN implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_PAN2 implemented.";
> +      break;
> +    case b0011:
> +      Description = "FEAT_PAN3 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // when FEAT_RAS implemented
> +  if ((((Aa64Pfr0 >> 28) & 0xf) == b0001) ||
> +      (((Aa64Pfr0 >> 28) & 0xf) == b0010))
> +  {
> +    if (((Aa64Mmfr1 >> 24) & 0xf) == b0000 ) {
> +      PrintValues ("ID_AA64MMFR1", "27:24", b0000, "The PE never generates an SError interrupt due to");
> +      PrintText ("", "", "", "an External abort on a speculative read.");
> +    }
> +
> +    if (((Aa64Mmfr1 >> 24) & 0xf) == b0001 ) {
> +      PrintValues ("ID_AA64MMFR1", "27:24", b0001, "The PE might generate an SError interrupt due to");
> +      PrintText ("", "", "", "an External abort on a speculative read.");
> +    }
> +  }
> +
> +  Bits  = "31:28";
> +  Value = (Aa64Mmfr1 >> 28) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_XNX not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_XNX implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "35:32";
> +  Value = (Aa64Mmfr1 >> 32) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_TWED not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_TWED implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "39:36";
> +  Value = (Aa64Mmfr1 >> 36) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_ETS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_ETS implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "43:40";
> +  Value = (Aa64Mmfr1 >> 40) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_HCX not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_HCX implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "47:44";
> +  Value = (Aa64Mmfr1 >> 44) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_AFP not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_AFP implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "51:48";
> +  Value = (Aa64Mmfr1 >> 48) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_nTLBPA not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_nTLBPA implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "55:52";
> +  Value = (Aa64Mmfr1 >> 52) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_TIDCP1 not implemented";
> +      break;
> +    case b0001:
> +      Description = "FEAT_TIDCP1 implemented";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "59:56";
> +  Value = (Aa64Mmfr1 >> 56) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_CMOW not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_CMOW implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 63:60 reserved
> +}
> +
> +VOID
> +HandleAa64Mmfr2 (
> +  CONST UINT64  Aa64Mmfr2
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR2";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = (Aa64Mmfr2)       & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_TTCNP not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_TTCNP implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Mmfr2 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_UAO not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_UAO implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "11:8 ";
> +  Value = (Aa64Mmfr2 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_LSMAOC not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_LSMAOC implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "15:12";
> +  Value = (Aa64Mmfr2 >> 12) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_IESB not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_IESB implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "19:16";
> +  Value = (Aa64Mmfr2 >> 16) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_LVA not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_LVA implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "23:20";
> +  Value = (Aa64Mmfr2 >> 20) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_CCIDX not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_CCIDX implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "27:24";
> +  Value = (Aa64Mmfr2 >> 24) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_NV not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_NV implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_NV2 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "31:28";
> +  Value = (Aa64Mmfr2 >> 28) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_TTST not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_TTST implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "35:32";
> +  Value = (Aa64Mmfr2 >> 32) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_LSE2 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_LSE2 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "39:36";
> +  Value = (Aa64Mmfr2 >> 36) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_IDST not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_IDST implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "43:40";
> +  Value = (Aa64Mmfr2 >> 40) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_S2FWB not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_S2FWB implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 47:44 reserved
> +
> +  Bits  = "51:48";
> +  Value = (Aa64Mmfr2 >> 48) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_TTL not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_TTL implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "55:52";
> +  Value = (Aa64Mmfr2 >> 52) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_BBM: Level 0 support for changing block size is supported.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_BBM: Level 1 support for changing block size is supported.";
> +      break;
> +    case b0010:
> +      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 = (Aa64Mmfr2 >> 56) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_EVT not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_EVT: HCR_EL2.{TOCU, TICAB, TID4} traps are supported.";
> +      break;
> +    case b0010:
> +      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 = (Aa64Mmfr2 >> 60) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_E0PD not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_E0PD implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +}
> +
> +VOID
> +HandleAa64Pfr0 (
> +  CONST UINT64  Aa64Pfr0,
> +  CONST UINT64  Aa64Pfr1
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR0";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = (Aa64Pfr0)       & 0xf;
> +  switch (Value) {
> +    case b0001:
> +      Description = "EL0 in AArch64 only";
> +      break;
> +    case b0010:
> +      Description = "EL0 in AArch64 and AArch32";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Pfr0 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0001:
> +      Description = "EL1 in AArch64 only";
> +      break;
> +    case b0010:
> +      Description = "EL1 in AArch64 and AArch32";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "11:8 ";
> +  Value = (Aa64Pfr0 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "EL2 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "EL2 in AArch64 only";
> +      break;
> +    case b0010:
> +      Description = "EL2 in AArch64 and AArch32";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "15:12";
> +  Value = (Aa64Pfr0 >> 12) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "EL3 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "EL3 in AArch64 only";
> +      break;
> +    case b0010:
> +      Description = "EL3 in AArch64 and AArch32";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "19:16";
> +  Value = (Aa64Pfr0 >> 16) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Floating-point implemented.";
> +      break;
> +    case b0001:
> +      Description = "Floating-point with half-precision support  (FEAT_FP16).";
> +      break;
> +    case b1111:
> +      Description = "Floating-point not implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "23:20";
> +  Value = (Aa64Pfr0 >> 20) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Advanced SIMD implemented.";
> +      break;
> +    case b0001:
> +      Description = "Advanced SIMD with half precision support  (FEAT_FP16).";
> +      break;
> +    case b1111:
> +      Description = "Advanced SIMD not implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "27:24";
> +  Value = (Aa64Pfr0 >> 24) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "System registers of GIC CPU not implemented.";
> +      break;
> +    case b0001:
> +      Description = "System registers to versions 3.0/4.0 of GIC CPU implemented.";
> +      break;
> +    case b0011:
> +      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 = (Aa64Pfr0 >> 28) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_RAS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_RAS implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_RASv1p1 implemented.";
> +      // b0010 FEAT_RASv1p1 implemented and, if EL3 is implemented, FEAT_DoubleFault implemented.
> +      if ((((Aa64Pfr0 >> 12) & 0xf) == b0001) ||
> +          (((Aa64Pfr0 >> 12) & 0xf) == b0010))
> +      {
> +        Description = "FEAT_RASv1p1 implemented. FEAT_DoubleFault implemented.";
> +      }
> +
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +  if (Value == b0001) {
> +    if (((Aa64Pfr1 >> 12) & 0xf) == b0001 ) {
> +      PrintValues ("ID_AA64PRF1", "15:12", b0001, "FEAT_RASv1p1 implemented.");
> +    }
> +  }
> +
> +  Bits  = "35:32";
> +  Value = (Aa64Pfr0 >> 32) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SVE not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SVE implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "39:36";
> +  Value = (Aa64Pfr0 >> 36) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Secure EL2 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "Secure EL2 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "43:40";
> +  Value = (Aa64Pfr0 >> 40) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      if (((Aa64Pfr1 >> 16) & 0xf) == b0000 ) {
> +        Description = "FEAT_MPAM not implemented.";
> +      }
> +
> +      if (((Aa64Pfr1 >> 16) & 0xf) == b0001 ) {
> +        Description = "FEAT_MPAM v0.1 implemented.";
> +      }
> +
> +      break;
> +    case b0001:
> +      if (((Aa64Pfr1 >> 16) & 0xf) == b0000 ) {
> +        Description = "FEAT_MPAM v1.0 implemented.";
> +      }
> +
> +      if (((Aa64Pfr1 >> 16) & 0xf) == b0001 ) {
> +        Description = "FEAT_MPAM v1.1 implemented.";
> +      }
> +
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "47:44";
> +  Value = (Aa64Pfr0 >> 44) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_AMU not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_AMUv1 implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_AMUv1p1 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "51:48";
> +  Value = (Aa64Pfr0 >> 48) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_DIT not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_DIT implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "55:52";
> +  Value = (Aa64Pfr0 >> 52) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_RME not implemented";
> +      break;
> +    case b0001:
> +      Description = "FEAT_RME implemented";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "59:56";
> +  Value = (Aa64Pfr0 >> 56) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Not disclosed whether FEAT_CSV2 is implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_CSV2 implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_CSV2_2 implemented.";
> +      break;
> +    case b0011:
> +      Description = "FEAT_CSV2_3 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +  if (Value == b0001) {
> +    if (((Aa64Pfr1 >> 32) & 0xf) == b0001 ) {
> +      PrintValues ("ID_AA64PRF1", "35:32", b0001, "FEAT_CSV2_1p1 implemented.");
> +    }
> +
> +    if (((Aa64Pfr1 >> 32) & 0xf) == b0010 ) {
> +      PrintValues ("ID_AA64PRF1", "35:32", b0010, "FEAT_CSV2_1p2 implemented.");
> +    }
> +  }
> +
> +  Bits  = "63:60";
> +  Value = (Aa64Pfr0 >> 60) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_CSV3 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_CSV3 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +}
> +
> +VOID
> +HandleAa64Pfr1 (
> +  CONST UINT64  Aa64Pfr1
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR1";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = Aa64Pfr1 & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_BTI not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_BTI implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Pfr1 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SSBS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SSBS implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_SSBS2 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "11:8 ";
> +  Value = (Aa64Pfr1 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_MTE not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_MTE implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_MTE2 implemented.";
> +      break;
> +    case b0011:
> +      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 = (Aa64Pfr1 >> 24) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SME not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SME implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "31:28";
> +  Value = (Aa64Pfr1 >> 28) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_RNG_TRAP not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_RNG_TRAP implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 35:32 is CSV2_frac
> +
> +  Bits  = "39:36";
> +  Value = (Aa64Pfr1 >> 36) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_NMI not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_NMI implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 63:40 are reserved
> +}
> +
> +VOID
> +HandleAa64Isar0 (
> +  CONST UINT64  Aa64Isar0
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR0";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  // 3:0 reserved
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Isar0 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_AES, FEAT_PMULL not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_AES implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_AES and FEAT_PMULL implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "11:8 ";
> +  Value = (Aa64Isar0 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SHA1 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SHA1 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "15:12";
> +  Value = (Aa64Isar0 >> 12) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SHA256, FEAT_SHA512 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SHA256 implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_SHA512 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "19:16";
> +  Value = (Aa64Isar0 >> 16) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "CRC32 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "CRC32 instructions implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "23:20";
> +  Value = (Aa64Isar0 >> 20) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_LSE not implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_LSE implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "27:24";
> +  Value = (Aa64Isar0 >> 24) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "TME instructions not implemented.";
> +      break;
> +    case b0001:
> +      Description = "TME instructions implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "31:28";
> +  Value = (Aa64Isar0 >> 28) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_RDM not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_RDM implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "35:32";
> +  Value = (Aa64Isar0 >> 32) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SHA3 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SHA3 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "39:36";
> +  Value = (Aa64Isar0 >> 36) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SM3 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SM3 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "43:40";
> +  Value = (Aa64Isar0 >> 40) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SM4 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SM4 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "47:44";
> +  Value = (Aa64Isar0 >> 44) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_DotProd not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_DotProd implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "51:48";
> +  Value = (Aa64Isar0 >> 48) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_FHM not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_FHM implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "55:52";
> +  Value = (Aa64Isar0 >> 52) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_FlagM/FEAT_FlagM2 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_FlagM implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_FlagM2 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "59:56";
> +  Value = (Aa64Isar0 >> 56) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_TLBIOS/FEAT_TLBIRANGE not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_TLBIOS implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_TLBIRANGE implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "63:60";
> +  Value = (Aa64Isar0 >> 60) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_RNG not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_RNG implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +}
> +
> +VOID
> +HandleAa64Isar1 (
> +  CONST UINT64  Aa64Isar1
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR1";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = (Aa64Isar1 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "DC CVAP not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_DPB implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_DPB2 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Isar1 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Address Authentication  (APA) not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_PAuth implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_EPAC implemented.";
> +      break;
> +    case b0011:
> +      Description = "FEAT_PAuth2 implemented.";
> +      break;
> +    case b0100:
> +      Description = "FEAT_FPAC implemented.";
> +      break;
> +    case b0101:
> +      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 = (Aa64Isar1 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Address Authentication  (API) not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_PAuth implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_EPAC implemented.";
> +      break;
> +    case b0011:
> +      Description = "FEAT_PAuth2 implemented.";
> +      break;
> +    case b0100:
> +      Description = "FEAT_FPAC implemented.";
> +      break;
> +    case b0101:
> +      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 = (Aa64Isar1 >> 12) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_JSCVT not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_JSCVT implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "19:16";
> +  Value = (Aa64Isar1 >> 16) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_FCMA not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_FCMA implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "23:20";
> +  Value = (Aa64Isar1 >> 20) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_LRCPC (2) not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_LRCPC implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_LRCPC2 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "27:24";
> +  Value = (Aa64Isar1 >> 24) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_PACQARMA5 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_PACQARMA5 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "31:28";
> +  Value = (Aa64Isar1 >> 28) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_PACIMP not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_PACIMP implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "35:32";
> +  Value = (Aa64Isar1 >> 32) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_FRINTTS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_FRINTTS implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "39:36";
> +  Value = (Aa64Isar1 >> 36) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SB not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SB implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "43:40";
> +  Value = (Aa64Isar1 >> 40) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SPECRES not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SPECRES implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "47:44";
> +  Value = (Aa64Isar1 >> 44) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_BF16 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_BF16 implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_EBF16 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "51:48";
> +  Value = (Aa64Isar1 >> 48) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_DGH not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_DGH implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "55:52";
> +  Value = (Aa64Isar1 >> 52) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_I8MM not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_I8MM implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "59:56";
> +  Value = (Aa64Isar1 >> 56) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_XS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_XS implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "63:60";
> +  Value = (Aa64Isar1 >> 60) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_LS64 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_LS64 implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_LS64_V implemented.";
> +      break;
> +    case b0011:
> +      Description = "FEAT_LS64_ACCDATA implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +}
> +
> +VOID
> +HandleAa64Isar2 (
> +  CONST UINT64  Aa64Isar2
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR2";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = (Aa64Isar2 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_WFxT not implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_WFxT implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Isar2 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_RPRES not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_RPRES implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "11:8 ";
> +  Value = (Aa64Isar2 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_PACQARMA3 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_PACQARMA3 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "15:12";
> +  Value = (Aa64Isar2 >> 12) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Address Authentication  (APA3) not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_PAuth implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_EPAC implemented.";
> +      break;
> +    case b0011:
> +      Description = "FEAT_PAuth2 implemented.";
> +      break;
> +    case b0100:
> +      Description = "FEAT_FPAC implemented.";
> +      break;
> +    case b0101:
> +      Description = "FEAT_FPACCOMBINE implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "19:16";
> +  Value = (Aa64Isar2 >> 16) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_MOPS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_MOPS implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "23:20";
> +  Value = (Aa64Isar2 >> 20) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_HBC not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_HBC implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "27:24";
> +  Value = (Aa64Isar2 >> 24) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_CONSTPACFIELD not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_CONSTPACFIELD implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 63:28 reserved
> +}
> +
> +VOID
> +HandleAa64Dfr0 (
> +  CONST UINT64  Aa64Dfr0
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64DFR0";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = (Aa64Dfr0 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0110:
> +      Description = "Armv8 debug architecture";
> +      break;
> +    case b0111:
> +      Description = "Armv8 debug architecture with VHE";
> +      break;
> +    case b1000:
> +      Description = "FEAT_Debugv8p2 implemented.";
> +      break;
> +    case b1001:
> +      Description = "FEAT_Debugv8p4 implemented.";
> +      break;
> +    case b1010:
> +      Description = "FEAT_Debugv8p8 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Dfr0 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Trace unit System registers not implemented.";
> +      break;
> +    case b0001:
> +      Description = "Trace unit System registers implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "11:8 ";
> +  Value = (Aa64Dfr0 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Performance Monitors Extension not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_PMUv3 implemented.";
> +      break;
> +    case b0100:
> +      Description = "FEAT_PMUv3p1 implemented.";
> +      break;
> +    case b0101:
> +      Description = "FEAT_PMUv3p4 implemented.";
> +      break;
> +    case b0110:
> +      Description = "FEAT_PMUv3p5 implemented.";
> +      break;
> +    case b0111:
> +      Description = "FEAT_PMUv3p7 implemented.";
> +      break;
> +    case b1000:
> +      Description = "FEAT_PMUv3p8 implemented.";
> +      break;
> +    case b1111:
> +      Description = "IMPLEMENTATION DEFINED form of performance monitors supported.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "15:12";
> +  Value = (Aa64Dfr0 >> 12) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "reserved";
> +      break;
> +    default:
> +      Description = "Number of breakpoints, minus 1.";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 19:16 reserved
> +
> +  Bits  = "23:20";
> +  Value = (Aa64Dfr0 >> 20) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "reserved";
> +      break;
> +    default:
> +      Description = "Number of watchpoints, minus 1.";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 27:24 reserved
> +
> +  Bits  = "31:28";
> +  Value = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 32) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SPE not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SPE implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_SPEv1p1 implemented.";
> +      break;
> +    case b0011:
> +      Description = "FEAT_SPEv1p2 implemented.";
> +      break;
> +    case b0100:
> +      Description = "FEAT_SPEv1p3 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "39:36";
> +  Value = (Aa64Dfr0 >> 36) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_DoubleLock implemented.";
> +      break;
> +    case b1111:
> +      Description = "FEAT_DoubleLock not implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "43:40";
> +  Value = (Aa64Dfr0 >> 40) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_TRF not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_TRF implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "47:44";
> +  Value = (Aa64Dfr0 >> 44) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_TRBE not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_TRBE implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "51:48";
> +  Value = (Aa64Dfr0 >> 48) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_MTPMU not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_MTPMU and FEAT_PMUv3 implemented.";
> +      break;
> +    case b1111:
> +      Description = "FEAT_MTPMU not implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "55:52";
> +  Value = (Aa64Dfr0 >> 52) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_BRBE not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_BRBE implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_BRBEv1p1 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 59:56 reserved
> +
> +  Bits  = "63:60";
> +  Value = (Aa64Dfr0 >> 60) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Setting MDCR_EL2.HPMN to zero has CONSTRAINED UNPREDICTABLE behavior.";
> +      break;
> +    case b0001:
> +      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  Aa64Dfr0;
> +  UINT64  Aa64Isar0;
> +  UINT64  Aa64Isar1;
> +  UINT64  Aa64Isar2;
> +  UINT64  Aa64Mmfr0;
> +  UINT64  Aa64Mmfr1;
> +  UINT64  Aa64Mmfr2;
> +  UINT64  Aa64Pfr0;
> +  UINT64  Aa64Pfr1;
> +
> +  Aa64Dfr0  = ArmReadIdAA64Dfr0 ();
> +  Aa64Isar0 = ArmReadIdAA64Isar0 ();
> +  Aa64Isar1 = ArmReadIdAA64Isar1 ();
> +  Aa64Isar2 = ArmReadIdAA64Isar2 ();
> +  Aa64Mmfr0 = ArmReadIdAA64Mmfr0 ();
> +  Aa64Mmfr1 = ArmReadIdAA64Mmfr1 ();
> +  Aa64Mmfr2 = ArmReadIdAA64Mmfr2 ();
> +  Aa64Pfr0  = ArmReadIdAA64Pfr0 ();
> +  Aa64Pfr1  = ArmReadIdAA64Pfr1 ();
> +
> +  AsciiPrint ("ID_AA64MMFR0_EL1 = 0x%016lx\n", Aa64Mmfr0);
> +  AsciiPrint ("ID_AA64MMFR1_EL1 = 0x%016lx\n", Aa64Mmfr1);
> +  AsciiPrint ("ID_AA64MMFR2_EL1 = 0x%016lx\n", Aa64Mmfr2);
> +  AsciiPrint ("ID_AA64PFR0_EL1  = 0x%016lx\n", Aa64Pfr0);
> +  AsciiPrint ("ID_AA64PFR1_EL1  = 0x%016lx\n", Aa64Pfr1);
> +  AsciiPrint ("ID_AA64ISAR0_EL1 = 0x%016lx\n", Aa64Isar0);
> +  AsciiPrint ("ID_AA64ISAR1_EL1 = 0x%016lx\n", Aa64Isar1);
> +  AsciiPrint ("ID_AA64ISAR2_EL1 = 0x%016lx\n", Aa64Isar2);
> +  AsciiPrint ("ID_AA64DFR0_EL1  = 0x%016lx\n", Aa64Dfr0);
> +
> +  AsciiPrint ("\n");
> +  PrintText ("Register", "Bits", "Value", "Feature");
> +  PrintSpacer ();
> +
> +  HandleAa64Mmfr0 (Aa64Mmfr0);
> +  PrintSpacer ();
> +  HandleAa64Mmfr1 (Aa64Mmfr1, Aa64Pfr0);
> +  PrintSpacer ();
> +  HandleAa64Mmfr2 (Aa64Mmfr2);
> +
> +  PrintSpacer ();
> +  HandleAa64Pfr0 (Aa64Pfr0, Aa64Pfr1);
> +  PrintSpacer ();
> +  HandleAa64Pfr1 (Aa64Pfr1);
> +
> +  PrintSpacer ();
> +  HandleAa64Isar0 (Aa64Isar0);
> +  PrintSpacer ();
> +  HandleAa64Isar1 (Aa64Isar1);
> +  PrintSpacer ();
> +  HandleAa64Isar2 (Aa64Isar2);
> +
> +  PrintSpacer ();
> +  HandleAa64Dfr0 (Aa64Dfr0);
> +
> +  return EFI_SUCCESS;
> +}
> -- 
> 2.40.0
> 

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [PATCH v6 2/2] add ArmCpuInfo EFI application
  2023-04-20 17:29                       ` Leif Lindholm
@ 2023-04-21 14:37                         ` Rebecca Cran
  2023-04-21 14:59                           ` Marcin Juszkiewicz
  2023-04-21 16:33                           ` [edk2-devel] [PATCH v6 " Leif Lindholm
  0 siblings, 2 replies; 32+ messages in thread
From: Rebecca Cran @ 2023-04-21 14:37 UTC (permalink / raw)
  To: devel, quic_llindhol, Marcin Juszkiewicz; +Cc: Ard Biesheuvel, Pedro Falcato

I noticed CI failed for the push PR 
(https://github.com/tianocore/edk2/pull/4292).


Ecc is complaining about missing Doxygen info for the functions:

https://dev.azure.com/tianocore/edk2-ci/_build/results?buildId=88023&view=logs&j=d36e2059-ab45-57a4-e2a1-e73032481054&t=463dc808-035c-5fe4-17fd-50a99c74a4aa


It looks like there's a stray commit merging out from master, that 
doesn't have a Signed-off-by line?


And it looks like there might be Uncrustify problems too: 
https://dev.azure.com/tianocore/edk2-ci/_build/results?buildId=88024&view=logs&jobId=2640d2b2-7c53-5a2b-80c7-040377c664fd&j=2640d2b2-7c53-5a2b-80c7-040377c664fd&t=a7f329c1-489d-56ab-b670-1c248e984338


-- 

Rebecca Cran



On 4/20/23 11:29, Leif Lindholm wrote:
> On Thu, Apr 20, 2023 at 16:44:23 +0200, Marcin Juszkiewicz wrote:
>> App goes through ID_AA64*_EL1 system registers and decode their values.
>>
>> Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
> For the series:
> Reviewed-by: Leif Lindholm <quic_llindhol@quicinc.com>
>
> After discussing with Marcin on side channel, I folded in a statement
> at the head of ArmCpuInfo.c that the app was written against ARM DDI
> 0487I.a version (current) of the ARM Architecture Reference Manual (A
> profile), and that this information should be updated when features
> are added from a subsequent version of the document.
>
> Submitted as github merge request #4292, currently going through CI.
>
> Thanks!
>
> /
>      Leif
>
>> ---
>>   ArmPkg/ArmPkg.dsc                            |    1 +
>>   ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf |   33 +
>>   ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c   | 2346 ++++++++++++++++++
>>   3 files changed, 2380 insertions(+)
>>   create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
>>   create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
>>
>> 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..d2235d3aa911
>> --- /dev/null
>> +++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
>> @@ -0,0 +1,33 @@
>> +## @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
>> +
>> +[Sources]
>> +  ArmCpuInfo.c
>> +
>> +[Packages]
>> +  ArmPkg/ArmPkg.dec
>> +  MdePkg/MdePkg.dec
>> +  MdeModulePkg/MdeModulePkg.dec
>> +
>> +[LibraryClasses]
>> +  ArmLib
>> +  UefiApplicationEntryPoint
>> +  UefiLib
>> diff --git a/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
>> new file mode 100644
>> index 000000000000..63914d9815c6
>> --- /dev/null
>> +++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
>> @@ -0,0 +1,2346 @@
>> +/** @file
>> +
>> +  Copyright  (c) 2023 Marcin Juszkiewicz
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> + **/
>> +
>> +#include <Library/UefiLib.h>
>> +#include <Library/ArmLib/AArch64/AArch64Lib.h>
>> +
>> +// We cannot assume GCC extensions to be present so let use
>> +// binary numbers via enum.
>> +// Arm ARM uses binary numbers so this way it is more readable.
>> +enum {
>> +   b0000,
>> +   b0001,
>> +   b0010,
>> +   b0011,
>> +   b0100,
>> +   b0101,
>> +   b0110,
>> +   b0111,
>> +   b1000,
>> +   b1001,
>> +   b1010,
>> +   b1011,
>> +   b1100,
>> +   b1101,
>> +   b1110,
>> +   b1111
>> +};
>> +
>> +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  Nibbles[][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, Nibbles[Value & 0xf], Description);
>> +}
>> +
>> +VOID
>> +PrintSpacer (
>> +  VOID
>> +  )
>> +{
>> +  AsciiPrint ("------------------|-------|-------|----------------------------------------------\n");
>> +}
>> +
>> +VOID
>> +HandleAa64Mmfr0 (
>> +  CONST UINT64  Aa64Mmfr0
>> +  )
>> +{
>> +  UINT64              Value;
>> +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR0";
>> +  CONST CHAR8         *Description;
>> +  CONST CHAR8         *Bits;
>> +
>> +  Bits  = "3:0 ";
>> +  Value = Aa64Mmfr0 & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "32 Bits  (4GB) of physical address range supported.";
>> +      break;
>> +    case b0001:
>> +      Description = "36 Bits  (64GB) of physical address range supported.";
>> +      break;
>> +    case b0010:
>> +      Description = "40 Bits  (1TB) of physical address range supported.";
>> +      break;
>> +    case b0011:
>> +      Description = "42 Bits  (4TB) of physical address range supported.";
>> +      break;
>> +    case b0100:
>> +      Description = "44 Bits  (16TB) of physical address range supported.";
>> +      break;
>> +    case b0101:
>> +      Description = "48 Bits  (256TB) of physical address range supported.";
>> +      break;
>> +    case b0110:
>> +      Description = "52 Bits  (4PB) of physical address range supported.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +  if (Value == b0110) {
>> +    PrintText ("", "", "", "FEAT_LPA implemented.");
>> +  }
>> +
>> +  Bits  = "7:4 ";
>> +  Value = (Aa64Mmfr0 >>  4) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "ASID: 8 Bits";
>> +      break;
>> +    case b0010:
>> +      Description = "ASID: 16 Bits";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "11:8 ";
>> +  Value = (Aa64Mmfr0 >>  8) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "No mixed-endian support.";
>> +      break;
>> +    case b0001:
>> +      Description = "Mixed-endian support.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  // If mixed-endian is present, check whether supported at EL0
>> +  if (((Aa64Mmfr0 >>  8) & 0xf) != b0000 ) {
>> +    if (((Aa64Mmfr0 >> 16) & 0xf) == b0000 ) {
>> +      PrintValues ("ID_AA64MMFR0", "19:16", b0000, "No mixed-endian support at EL0.");
>> +    }
>> +
>> +    if (((Aa64Mmfr0 >> 16) & 0xf) == b0001 ) {
>> +      PrintValues ("ID_AA64MMFR0", "19:16", b0001, "Mixed-endian support at EL0.");
>> +    }
>> +  }
>> +
>> +  Bits  = "15:12";
>> +  Value = (Aa64Mmfr0 >> 12) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "No support for a distinction between Secure and Non-Secure Memory.";
>> +      break;
>> +    case b0001:
>> +      Description = "Supports a distinction between Secure and Non-Secure Memory.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "31:28";
>> +  Value = (Aa64Mmfr0 >> 28) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = " 4KB granule supported.";
>> +      break;
>> +    case b1111:
>> +      Description = " 4KB granule not supported.";
>> +      break;
>> +    case b0001:
>> +      Description = " 4KB granule supported for 52-bit address.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "43:40";
>> +  Value = (Aa64Mmfr0 >> 40) & 0xf;
>> +  switch (Value) {
>> +    case b0001:
>> +      Description = " 4KB granule not supported at stage 2.";
>> +      break;
>> +    case b0010:
>> +      Description = " 4KB granule supported at stage 2.";
>> +      break;
>> +    case b0011:
>> +      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 = (Aa64Mmfr0 >> 20) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "16KB granule not supported.";
>> +      break;
>> +    case b0001:
>> +      Description = "16KB granule supported.";
>> +      break;
>> +    case b0010:
>> +      Description = "16KB granule supported for 52-bit address.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "35:32";
>> +  Value = (Aa64Mmfr0 >> 32) & 0xf;
>> +  switch (Value) {
>> +    case b0001:
>> +      Description = "16KB granule not supported at stage 2.";
>> +      break;
>> +    case b0010:
>> +      Description = "16KB granule supported at stage 2.";
>> +      break;
>> +    case b0011:
>> +      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 = (Aa64Mmfr0 >> 24) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "64KB granule supported.";
>> +      break;
>> +    case b1111:
>> +      Description = "64KB granule not supported.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "39:36";
>> +  Value = (Aa64Mmfr0 >> 36) & 0xf;
>> +  switch (Value) {
>> +    case b0001:
>> +      Description = "64KB granule not supported at stage 2.";
>> +      break;
>> +    case b0010:
>> +      Description = "64KB granule supported at stage 2.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "47:44";
>> +  Value = (Aa64Mmfr0 >> 44) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_ExS not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_ExS implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  // 55:48 reserved
>> +
>> +  Bits  = "59:56";
>> +  Value = (Aa64Mmfr0 >> 56) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_FGT not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_FGT implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "63:60";
>> +  Value = (Aa64Mmfr0 >> 60) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_ECV not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_ECV implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_ECV implemented with extras.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +}
>> +
>> +VOID
>> +HandleAa64Mmfr1 (
>> +  CONST UINT64  Aa64Mmfr1,
>> +  CONST UINT64  Aa64Pfr0
>> +  )
>> +{
>> +  UINT64              Value;
>> +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR1";
>> +  CONST CHAR8         *Description;
>> +  CONST CHAR8         *Bits;
>> +
>> +  Bits  = "3:0 ";
>> +  Value = Aa64Mmfr1 & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_HAFDBS not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_HAFDBS implemented without dirty status support.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_HAFDBS implemented with dirty status support.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "7:4 ";
>> +  Value = (Aa64Mmfr1 >>  4) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_VMID16 not implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_VMID16 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "11:8 ";
>> +  Value = (Aa64Mmfr1 >>  8) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_VHE not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_VHE implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "15:12";
>> +  Value = (Aa64Mmfr1 >> 12) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_HPDS not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_HPDS implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_HPDS2 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "19:16";
>> +  Value = (Aa64Mmfr1 >> 16) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_LOR not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_LOR implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "23:20";
>> +  Value = (Aa64Mmfr1 >> 20) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_PAN not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_PAN implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_PAN2 implemented.";
>> +      break;
>> +    case b0011:
>> +      Description = "FEAT_PAN3 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  // when FEAT_RAS implemented
>> +  if ((((Aa64Pfr0 >> 28) & 0xf) == b0001) ||
>> +      (((Aa64Pfr0 >> 28) & 0xf) == b0010))
>> +  {
>> +    if (((Aa64Mmfr1 >> 24) & 0xf) == b0000 ) {
>> +      PrintValues ("ID_AA64MMFR1", "27:24", b0000, "The PE never generates an SError interrupt due to");
>> +      PrintText ("", "", "", "an External abort on a speculative read.");
>> +    }
>> +
>> +    if (((Aa64Mmfr1 >> 24) & 0xf) == b0001 ) {
>> +      PrintValues ("ID_AA64MMFR1", "27:24", b0001, "The PE might generate an SError interrupt due to");
>> +      PrintText ("", "", "", "an External abort on a speculative read.");
>> +    }
>> +  }
>> +
>> +  Bits  = "31:28";
>> +  Value = (Aa64Mmfr1 >> 28) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_XNX not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_XNX implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "35:32";
>> +  Value = (Aa64Mmfr1 >> 32) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_TWED not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_TWED implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "39:36";
>> +  Value = (Aa64Mmfr1 >> 36) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_ETS not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_ETS implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "43:40";
>> +  Value = (Aa64Mmfr1 >> 40) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_HCX not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_HCX implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "47:44";
>> +  Value = (Aa64Mmfr1 >> 44) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_AFP not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_AFP implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "51:48";
>> +  Value = (Aa64Mmfr1 >> 48) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_nTLBPA not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_nTLBPA implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "55:52";
>> +  Value = (Aa64Mmfr1 >> 52) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_TIDCP1 not implemented";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_TIDCP1 implemented";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "59:56";
>> +  Value = (Aa64Mmfr1 >> 56) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_CMOW not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_CMOW implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  // 63:60 reserved
>> +}
>> +
>> +VOID
>> +HandleAa64Mmfr2 (
>> +  CONST UINT64  Aa64Mmfr2
>> +  )
>> +{
>> +  UINT64              Value;
>> +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR2";
>> +  CONST CHAR8         *Description;
>> +  CONST CHAR8         *Bits;
>> +
>> +  Bits  = "3:0 ";
>> +  Value = (Aa64Mmfr2)       & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_TTCNP not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_TTCNP implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "7:4 ";
>> +  Value = (Aa64Mmfr2 >>  4) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_UAO not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_UAO implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "11:8 ";
>> +  Value = (Aa64Mmfr2 >>  8) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_LSMAOC not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_LSMAOC implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "15:12";
>> +  Value = (Aa64Mmfr2 >> 12) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_IESB not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_IESB implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "19:16";
>> +  Value = (Aa64Mmfr2 >> 16) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_LVA not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_LVA implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "23:20";
>> +  Value = (Aa64Mmfr2 >> 20) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_CCIDX not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_CCIDX implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "27:24";
>> +  Value = (Aa64Mmfr2 >> 24) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_NV not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_NV implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_NV2 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "31:28";
>> +  Value = (Aa64Mmfr2 >> 28) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_TTST not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_TTST implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "35:32";
>> +  Value = (Aa64Mmfr2 >> 32) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_LSE2 not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_LSE2 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "39:36";
>> +  Value = (Aa64Mmfr2 >> 36) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_IDST not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_IDST implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "43:40";
>> +  Value = (Aa64Mmfr2 >> 40) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_S2FWB not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_S2FWB implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  // 47:44 reserved
>> +
>> +  Bits  = "51:48";
>> +  Value = (Aa64Mmfr2 >> 48) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_TTL not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_TTL implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "55:52";
>> +  Value = (Aa64Mmfr2 >> 52) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_BBM: Level 0 support for changing block size is supported.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_BBM: Level 1 support for changing block size is supported.";
>> +      break;
>> +    case b0010:
>> +      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 = (Aa64Mmfr2 >> 56) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_EVT not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_EVT: HCR_EL2.{TOCU, TICAB, TID4} traps are supported.";
>> +      break;
>> +    case b0010:
>> +      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 = (Aa64Mmfr2 >> 60) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_E0PD not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_E0PD implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +}
>> +
>> +VOID
>> +HandleAa64Pfr0 (
>> +  CONST UINT64  Aa64Pfr0,
>> +  CONST UINT64  Aa64Pfr1
>> +  )
>> +{
>> +  UINT64              Value;
>> +  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR0";
>> +  CONST CHAR8         *Description;
>> +  CONST CHAR8         *Bits;
>> +
>> +  Bits  = "3:0 ";
>> +  Value = (Aa64Pfr0)       & 0xf;
>> +  switch (Value) {
>> +    case b0001:
>> +      Description = "EL0 in AArch64 only";
>> +      break;
>> +    case b0010:
>> +      Description = "EL0 in AArch64 and AArch32";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "7:4 ";
>> +  Value = (Aa64Pfr0 >>  4) & 0xf;
>> +  switch (Value) {
>> +    case b0001:
>> +      Description = "EL1 in AArch64 only";
>> +      break;
>> +    case b0010:
>> +      Description = "EL1 in AArch64 and AArch32";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "11:8 ";
>> +  Value = (Aa64Pfr0 >>  8) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "EL2 not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "EL2 in AArch64 only";
>> +      break;
>> +    case b0010:
>> +      Description = "EL2 in AArch64 and AArch32";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "15:12";
>> +  Value = (Aa64Pfr0 >> 12) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "EL3 not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "EL3 in AArch64 only";
>> +      break;
>> +    case b0010:
>> +      Description = "EL3 in AArch64 and AArch32";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "19:16";
>> +  Value = (Aa64Pfr0 >> 16) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "Floating-point implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "Floating-point with half-precision support  (FEAT_FP16).";
>> +      break;
>> +    case b1111:
>> +      Description = "Floating-point not implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "23:20";
>> +  Value = (Aa64Pfr0 >> 20) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "Advanced SIMD implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "Advanced SIMD with half precision support  (FEAT_FP16).";
>> +      break;
>> +    case b1111:
>> +      Description = "Advanced SIMD not implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "27:24";
>> +  Value = (Aa64Pfr0 >> 24) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "System registers of GIC CPU not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "System registers to versions 3.0/4.0 of GIC CPU implemented.";
>> +      break;
>> +    case b0011:
>> +      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 = (Aa64Pfr0 >> 28) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_RAS not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_RAS implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_RASv1p1 implemented.";
>> +      // b0010 FEAT_RASv1p1 implemented and, if EL3 is implemented, FEAT_DoubleFault implemented.
>> +      if ((((Aa64Pfr0 >> 12) & 0xf) == b0001) ||
>> +          (((Aa64Pfr0 >> 12) & 0xf) == b0010))
>> +      {
>> +        Description = "FEAT_RASv1p1 implemented. FEAT_DoubleFault implemented.";
>> +      }
>> +
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +  if (Value == b0001) {
>> +    if (((Aa64Pfr1 >> 12) & 0xf) == b0001 ) {
>> +      PrintValues ("ID_AA64PRF1", "15:12", b0001, "FEAT_RASv1p1 implemented.");
>> +    }
>> +  }
>> +
>> +  Bits  = "35:32";
>> +  Value = (Aa64Pfr0 >> 32) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_SVE not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_SVE implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "39:36";
>> +  Value = (Aa64Pfr0 >> 36) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "Secure EL2 not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "Secure EL2 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "43:40";
>> +  Value = (Aa64Pfr0 >> 40) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      if (((Aa64Pfr1 >> 16) & 0xf) == b0000 ) {
>> +        Description = "FEAT_MPAM not implemented.";
>> +      }
>> +
>> +      if (((Aa64Pfr1 >> 16) & 0xf) == b0001 ) {
>> +        Description = "FEAT_MPAM v0.1 implemented.";
>> +      }
>> +
>> +      break;
>> +    case b0001:
>> +      if (((Aa64Pfr1 >> 16) & 0xf) == b0000 ) {
>> +        Description = "FEAT_MPAM v1.0 implemented.";
>> +      }
>> +
>> +      if (((Aa64Pfr1 >> 16) & 0xf) == b0001 ) {
>> +        Description = "FEAT_MPAM v1.1 implemented.";
>> +      }
>> +
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "47:44";
>> +  Value = (Aa64Pfr0 >> 44) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_AMU not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_AMUv1 implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_AMUv1p1 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "51:48";
>> +  Value = (Aa64Pfr0 >> 48) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_DIT not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_DIT implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "55:52";
>> +  Value = (Aa64Pfr0 >> 52) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_RME not implemented";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_RME implemented";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "59:56";
>> +  Value = (Aa64Pfr0 >> 56) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "Not disclosed whether FEAT_CSV2 is implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_CSV2 implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_CSV2_2 implemented.";
>> +      break;
>> +    case b0011:
>> +      Description = "FEAT_CSV2_3 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +  if (Value == b0001) {
>> +    if (((Aa64Pfr1 >> 32) & 0xf) == b0001 ) {
>> +      PrintValues ("ID_AA64PRF1", "35:32", b0001, "FEAT_CSV2_1p1 implemented.");
>> +    }
>> +
>> +    if (((Aa64Pfr1 >> 32) & 0xf) == b0010 ) {
>> +      PrintValues ("ID_AA64PRF1", "35:32", b0010, "FEAT_CSV2_1p2 implemented.");
>> +    }
>> +  }
>> +
>> +  Bits  = "63:60";
>> +  Value = (Aa64Pfr0 >> 60) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_CSV3 not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_CSV3 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +}
>> +
>> +VOID
>> +HandleAa64Pfr1 (
>> +  CONST UINT64  Aa64Pfr1
>> +  )
>> +{
>> +  UINT64              Value;
>> +  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR1";
>> +  CONST CHAR8         *Description;
>> +  CONST CHAR8         *Bits;
>> +
>> +  Bits  = "3:0 ";
>> +  Value = Aa64Pfr1 & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_BTI not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_BTI implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "7:4 ";
>> +  Value = (Aa64Pfr1 >>  4) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_SSBS not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_SSBS implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_SSBS2 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "11:8 ";
>> +  Value = (Aa64Pfr1 >>  8) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_MTE not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_MTE implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_MTE2 implemented.";
>> +      break;
>> +    case b0011:
>> +      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 = (Aa64Pfr1 >> 24) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_SME not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_SME implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "31:28";
>> +  Value = (Aa64Pfr1 >> 28) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_RNG_TRAP not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_RNG_TRAP implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  // 35:32 is CSV2_frac
>> +
>> +  Bits  = "39:36";
>> +  Value = (Aa64Pfr1 >> 36) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_NMI not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_NMI implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  // 63:40 are reserved
>> +}
>> +
>> +VOID
>> +HandleAa64Isar0 (
>> +  CONST UINT64  Aa64Isar0
>> +  )
>> +{
>> +  UINT64              Value;
>> +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR0";
>> +  CONST CHAR8         *Description;
>> +  CONST CHAR8         *Bits;
>> +
>> +  // 3:0 reserved
>> +
>> +  Bits  = "7:4 ";
>> +  Value = (Aa64Isar0 >>  4) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_AES, FEAT_PMULL not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_AES implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_AES and FEAT_PMULL implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "11:8 ";
>> +  Value = (Aa64Isar0 >>  8) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_SHA1 not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_SHA1 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "15:12";
>> +  Value = (Aa64Isar0 >> 12) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_SHA256, FEAT_SHA512 not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_SHA256 implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_SHA512 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "19:16";
>> +  Value = (Aa64Isar0 >> 16) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "CRC32 not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "CRC32 instructions implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "23:20";
>> +  Value = (Aa64Isar0 >> 20) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_LSE not implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_LSE implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "27:24";
>> +  Value = (Aa64Isar0 >> 24) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "TME instructions not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "TME instructions implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "31:28";
>> +  Value = (Aa64Isar0 >> 28) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_RDM not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_RDM implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "35:32";
>> +  Value = (Aa64Isar0 >> 32) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_SHA3 not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_SHA3 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "39:36";
>> +  Value = (Aa64Isar0 >> 36) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_SM3 not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_SM3 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "43:40";
>> +  Value = (Aa64Isar0 >> 40) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_SM4 not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_SM4 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "47:44";
>> +  Value = (Aa64Isar0 >> 44) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_DotProd not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_DotProd implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "51:48";
>> +  Value = (Aa64Isar0 >> 48) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_FHM not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_FHM implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "55:52";
>> +  Value = (Aa64Isar0 >> 52) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_FlagM/FEAT_FlagM2 not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_FlagM implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_FlagM2 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "59:56";
>> +  Value = (Aa64Isar0 >> 56) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_TLBIOS/FEAT_TLBIRANGE not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_TLBIOS implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_TLBIRANGE implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "63:60";
>> +  Value = (Aa64Isar0 >> 60) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_RNG not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_RNG implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +}
>> +
>> +VOID
>> +HandleAa64Isar1 (
>> +  CONST UINT64  Aa64Isar1
>> +  )
>> +{
>> +  UINT64              Value;
>> +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR1";
>> +  CONST CHAR8         *Description;
>> +  CONST CHAR8         *Bits;
>> +
>> +  Bits  = "3:0 ";
>> +  Value = (Aa64Isar1 >>  4) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "DC CVAP not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_DPB implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_DPB2 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "7:4 ";
>> +  Value = (Aa64Isar1 >>  4) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "Address Authentication  (APA) not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_PAuth implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_EPAC implemented.";
>> +      break;
>> +    case b0011:
>> +      Description = "FEAT_PAuth2 implemented.";
>> +      break;
>> +    case b0100:
>> +      Description = "FEAT_FPAC implemented.";
>> +      break;
>> +    case b0101:
>> +      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 = (Aa64Isar1 >>  8) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "Address Authentication  (API) not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_PAuth implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_EPAC implemented.";
>> +      break;
>> +    case b0011:
>> +      Description = "FEAT_PAuth2 implemented.";
>> +      break;
>> +    case b0100:
>> +      Description = "FEAT_FPAC implemented.";
>> +      break;
>> +    case b0101:
>> +      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 = (Aa64Isar1 >> 12) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_JSCVT not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_JSCVT implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "19:16";
>> +  Value = (Aa64Isar1 >> 16) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_FCMA not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_FCMA implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "23:20";
>> +  Value = (Aa64Isar1 >> 20) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_LRCPC (2) not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_LRCPC implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_LRCPC2 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "27:24";
>> +  Value = (Aa64Isar1 >> 24) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_PACQARMA5 not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_PACQARMA5 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "31:28";
>> +  Value = (Aa64Isar1 >> 28) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_PACIMP not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_PACIMP implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "35:32";
>> +  Value = (Aa64Isar1 >> 32) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_FRINTTS not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_FRINTTS implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "39:36";
>> +  Value = (Aa64Isar1 >> 36) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_SB not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_SB implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "43:40";
>> +  Value = (Aa64Isar1 >> 40) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_SPECRES not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_SPECRES implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "47:44";
>> +  Value = (Aa64Isar1 >> 44) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_BF16 not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_BF16 implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_EBF16 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "51:48";
>> +  Value = (Aa64Isar1 >> 48) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_DGH not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_DGH implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "55:52";
>> +  Value = (Aa64Isar1 >> 52) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_I8MM not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_I8MM implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "59:56";
>> +  Value = (Aa64Isar1 >> 56) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_XS not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_XS implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "63:60";
>> +  Value = (Aa64Isar1 >> 60) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_LS64 not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_LS64 implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_LS64_V implemented.";
>> +      break;
>> +    case b0011:
>> +      Description = "FEAT_LS64_ACCDATA implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +}
>> +
>> +VOID
>> +HandleAa64Isar2 (
>> +  CONST UINT64  Aa64Isar2
>> +  )
>> +{
>> +  UINT64              Value;
>> +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR2";
>> +  CONST CHAR8         *Description;
>> +  CONST CHAR8         *Bits;
>> +
>> +  Bits  = "3:0 ";
>> +  Value = (Aa64Isar2 >>  4) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_WFxT not implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_WFxT implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "7:4 ";
>> +  Value = (Aa64Isar2 >>  4) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_RPRES not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_RPRES implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "11:8 ";
>> +  Value = (Aa64Isar2 >>  8) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_PACQARMA3 not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_PACQARMA3 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "15:12";
>> +  Value = (Aa64Isar2 >> 12) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "Address Authentication  (APA3) not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_PAuth implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_EPAC implemented.";
>> +      break;
>> +    case b0011:
>> +      Description = "FEAT_PAuth2 implemented.";
>> +      break;
>> +    case b0100:
>> +      Description = "FEAT_FPAC implemented.";
>> +      break;
>> +    case b0101:
>> +      Description = "FEAT_FPACCOMBINE implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "19:16";
>> +  Value = (Aa64Isar2 >> 16) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_MOPS not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_MOPS implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "23:20";
>> +  Value = (Aa64Isar2 >> 20) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_HBC not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_HBC implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "27:24";
>> +  Value = (Aa64Isar2 >> 24) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_CONSTPACFIELD not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_CONSTPACFIELD implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  // 63:28 reserved
>> +}
>> +
>> +VOID
>> +HandleAa64Dfr0 (
>> +  CONST UINT64  Aa64Dfr0
>> +  )
>> +{
>> +  UINT64              Value;
>> +  STATIC CONST CHAR8  RegName[] = "ID_AA64DFR0";
>> +  CONST CHAR8         *Description;
>> +  CONST CHAR8         *Bits;
>> +
>> +  Bits  = "3:0 ";
>> +  Value = (Aa64Dfr0 >>  4) & 0xf;
>> +  switch (Value) {
>> +    case b0110:
>> +      Description = "Armv8 debug architecture";
>> +      break;
>> +    case b0111:
>> +      Description = "Armv8 debug architecture with VHE";
>> +      break;
>> +    case b1000:
>> +      Description = "FEAT_Debugv8p2 implemented.";
>> +      break;
>> +    case b1001:
>> +      Description = "FEAT_Debugv8p4 implemented.";
>> +      break;
>> +    case b1010:
>> +      Description = "FEAT_Debugv8p8 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "7:4 ";
>> +  Value = (Aa64Dfr0 >>  4) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "Trace unit System registers not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "Trace unit System registers implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "11:8 ";
>> +  Value = (Aa64Dfr0 >>  8) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "Performance Monitors Extension not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_PMUv3 implemented.";
>> +      break;
>> +    case b0100:
>> +      Description = "FEAT_PMUv3p1 implemented.";
>> +      break;
>> +    case b0101:
>> +      Description = "FEAT_PMUv3p4 implemented.";
>> +      break;
>> +    case b0110:
>> +      Description = "FEAT_PMUv3p5 implemented.";
>> +      break;
>> +    case b0111:
>> +      Description = "FEAT_PMUv3p7 implemented.";
>> +      break;
>> +    case b1000:
>> +      Description = "FEAT_PMUv3p8 implemented.";
>> +      break;
>> +    case b1111:
>> +      Description = "IMPLEMENTATION DEFINED form of performance monitors supported.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "15:12";
>> +  Value = (Aa64Dfr0 >> 12) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "reserved";
>> +      break;
>> +    default:
>> +      Description = "Number of breakpoints, minus 1.";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  // 19:16 reserved
>> +
>> +  Bits  = "23:20";
>> +  Value = (Aa64Dfr0 >> 20) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "reserved";
>> +      break;
>> +    default:
>> +      Description = "Number of watchpoints, minus 1.";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  // 27:24 reserved
>> +
>> +  Bits  = "31:28";
>> +  Value = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 32) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_SPE not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_SPE implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_SPEv1p1 implemented.";
>> +      break;
>> +    case b0011:
>> +      Description = "FEAT_SPEv1p2 implemented.";
>> +      break;
>> +    case b0100:
>> +      Description = "FEAT_SPEv1p3 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "39:36";
>> +  Value = (Aa64Dfr0 >> 36) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_DoubleLock implemented.";
>> +      break;
>> +    case b1111:
>> +      Description = "FEAT_DoubleLock not implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "43:40";
>> +  Value = (Aa64Dfr0 >> 40) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_TRF not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_TRF implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "47:44";
>> +  Value = (Aa64Dfr0 >> 44) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_TRBE not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_TRBE implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "51:48";
>> +  Value = (Aa64Dfr0 >> 48) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_MTPMU not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_MTPMU and FEAT_PMUv3 implemented.";
>> +      break;
>> +    case b1111:
>> +      Description = "FEAT_MTPMU not implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  Bits  = "55:52";
>> +  Value = (Aa64Dfr0 >> 52) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "FEAT_BRBE not implemented.";
>> +      break;
>> +    case b0001:
>> +      Description = "FEAT_BRBE implemented.";
>> +      break;
>> +    case b0010:
>> +      Description = "FEAT_BRBEv1p1 implemented.";
>> +      break;
>> +    default:
>> +      Description = "unknown";
>> +      break;
>> +  }
>> +
>> +  PrintValues (RegName, Bits, Value, Description);
>> +
>> +  // 59:56 reserved
>> +
>> +  Bits  = "63:60";
>> +  Value = (Aa64Dfr0 >> 60) & 0xf;
>> +  switch (Value) {
>> +    case b0000:
>> +      Description = "Setting MDCR_EL2.HPMN to zero has CONSTRAINED UNPREDICTABLE behavior.";
>> +      break;
>> +    case b0001:
>> +      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  Aa64Dfr0;
>> +  UINT64  Aa64Isar0;
>> +  UINT64  Aa64Isar1;
>> +  UINT64  Aa64Isar2;
>> +  UINT64  Aa64Mmfr0;
>> +  UINT64  Aa64Mmfr1;
>> +  UINT64  Aa64Mmfr2;
>> +  UINT64  Aa64Pfr0;
>> +  UINT64  Aa64Pfr1;
>> +
>> +  Aa64Dfr0  = ArmReadIdAA64Dfr0 ();
>> +  Aa64Isar0 = ArmReadIdAA64Isar0 ();
>> +  Aa64Isar1 = ArmReadIdAA64Isar1 ();
>> +  Aa64Isar2 = ArmReadIdAA64Isar2 ();
>> +  Aa64Mmfr0 = ArmReadIdAA64Mmfr0 ();
>> +  Aa64Mmfr1 = ArmReadIdAA64Mmfr1 ();
>> +  Aa64Mmfr2 = ArmReadIdAA64Mmfr2 ();
>> +  Aa64Pfr0  = ArmReadIdAA64Pfr0 ();
>> +  Aa64Pfr1  = ArmReadIdAA64Pfr1 ();
>> +
>> +  AsciiPrint ("ID_AA64MMFR0_EL1 = 0x%016lx\n", Aa64Mmfr0);
>> +  AsciiPrint ("ID_AA64MMFR1_EL1 = 0x%016lx\n", Aa64Mmfr1);
>> +  AsciiPrint ("ID_AA64MMFR2_EL1 = 0x%016lx\n", Aa64Mmfr2);
>> +  AsciiPrint ("ID_AA64PFR0_EL1  = 0x%016lx\n", Aa64Pfr0);
>> +  AsciiPrint ("ID_AA64PFR1_EL1  = 0x%016lx\n", Aa64Pfr1);
>> +  AsciiPrint ("ID_AA64ISAR0_EL1 = 0x%016lx\n", Aa64Isar0);
>> +  AsciiPrint ("ID_AA64ISAR1_EL1 = 0x%016lx\n", Aa64Isar1);
>> +  AsciiPrint ("ID_AA64ISAR2_EL1 = 0x%016lx\n", Aa64Isar2);
>> +  AsciiPrint ("ID_AA64DFR0_EL1  = 0x%016lx\n", Aa64Dfr0);
>> +
>> +  AsciiPrint ("\n");
>> +  PrintText ("Register", "Bits", "Value", "Feature");
>> +  PrintSpacer ();
>> +
>> +  HandleAa64Mmfr0 (Aa64Mmfr0);
>> +  PrintSpacer ();
>> +  HandleAa64Mmfr1 (Aa64Mmfr1, Aa64Pfr0);
>> +  PrintSpacer ();
>> +  HandleAa64Mmfr2 (Aa64Mmfr2);
>> +
>> +  PrintSpacer ();
>> +  HandleAa64Pfr0 (Aa64Pfr0, Aa64Pfr1);
>> +  PrintSpacer ();
>> +  HandleAa64Pfr1 (Aa64Pfr1);
>> +
>> +  PrintSpacer ();
>> +  HandleAa64Isar0 (Aa64Isar0);
>> +  PrintSpacer ();
>> +  HandleAa64Isar1 (Aa64Isar1);
>> +  PrintSpacer ();
>> +  HandleAa64Isar2 (Aa64Isar2);
>> +
>> +  PrintSpacer ();
>> +  HandleAa64Dfr0 (Aa64Dfr0);
>> +
>> +  return EFI_SUCCESS;
>> +}
>> -- 
>> 2.40.0
>>
>
> 
>
>

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [PATCH v6 2/2] add ArmCpuInfo EFI application
  2023-04-21 14:37                         ` [edk2-devel] " Rebecca Cran
@ 2023-04-21 14:59                           ` Marcin Juszkiewicz
  2023-04-21 15:15                             ` Rebecca Cran
  2023-04-21 16:33                           ` [edk2-devel] [PATCH v6 " Leif Lindholm
  1 sibling, 1 reply; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-21 14:59 UTC (permalink / raw)
  To: Rebecca Cran, devel, quic_llindhol; +Cc: Ard Biesheuvel, Pedro Falcato

W dniu 21.04.2023 o 16:37, Rebecca Cran pisze:
> I noticed CI failed for the push PR 
> (https://github.com/tianocore/edk2/pull/4292).
> 
> 
> Ecc is complaining about missing Doxygen info for the functions:
> 
> https://dev.azure.com/tianocore/edk2-ci/_build/results?buildId=88023&view=logs&j=d36e2059-ab45-57a4-e2a1-e73032481054&t=463dc808-035c-5fe4-17fd-50a99c74a4aa

 > And it looks like there might be Uncrustify problems too:
 > 
https://dev.azure.com/tianocore/edk2-ci/_build/results?buildId=88024&view=logs&jobId=2640d2b2-7c53-5a2b-80c7-040377c664fd&j=2640d2b2-7c53-5a2b-80c7-040377c664fd&t=a7f329c1-489d-56ab-b670-1c248e984338


Thanks for links. Interface for EDK2 CI is not easy for beginners.

Uncrustify dislikes enum. Easy to fix as those are only spaces.

Doxygen info is something I probably never wrote so would need to look 
at rest of EDK2 code to find out what it is and how to use it.

There is also this:

 > ERROR - EFI coding style error
 > ERROR - *Error code: 9001
 > ERROR - *The file headers should follow Doxygen special
 > documentation blocks in section 2.3.5
 > ERROR - *file: D:\a\1\s\Build\.pytool\Plugin\EccCheck\ArmPkg
 > \Application\ArmCpuInfo\ArmCpuInfo.inf
 > ERROR - *Line number: 1
 > ERROR - *Header comment section must have Abstract information.

Same situation as with Doxygen above.

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [PATCH v6 2/2] add ArmCpuInfo EFI application
  2023-04-21 14:59                           ` Marcin Juszkiewicz
@ 2023-04-21 15:15                             ` Rebecca Cran
  2023-04-21 15:51                               ` [PATCH v7 1/2] ArmLib: add functions to read system registers Marcin Juszkiewicz
  0 siblings, 1 reply; 32+ messages in thread
From: Rebecca Cran @ 2023-04-21 15:15 UTC (permalink / raw)
  To: Marcin Juszkiewicz, devel, quic_llindhol; +Cc: Ard Biesheuvel, Pedro Falcato

On 4/21/23 08:59, Marcin Juszkiewicz wrote:
> Thanks for links. Interface for EDK2 CI is not easy for beginners.

It really isn't, unfortunately.

> Doxygen info is something I probably never wrote so would need to look 
> at rest of EDK2 code to find out what it is and how to use it.

It's pretty straightforward. The format EDK2 uses is:


/** Description of the function.


   @param FirstParam      Description of FirstParam:

                                       Can use multiple lines.

   @param SecondParam Description of SecondParam.


   @return Explanation of return values - or can use @retval instead.

   @retval FirstPossibleReturnValue Can use @retval instead of @return 
to describe individual values.

   @retval SecondPossibleReturnValue Description.


**/


>
> There is also this:
>
> > ERROR - EFI coding style error
> > ERROR - *Error code: 9001
> > ERROR - *The file headers should follow Doxygen special
> > documentation blocks in section 2.3.5
> > ERROR - *file: D:\a\1\s\Build\.pytool\Plugin\EccCheck\ArmPkg
> > \Application\ArmCpuInfo\ArmCpuInfo.inf
> > ERROR - *Line number: 1
> > ERROR - *Header comment section must have Abstract information.
>
> Same situation as with Doxygen above.

Oh, that's something I've had trouble with in the past. For your patch, 
it's probably due to the blank line between @file and the description:


## @file
#
#  Attempt to have AArch64 cpu information.


One more thing: copyright lines should ideally have "<BR>" at the end, 
to indicate to Doxygen to add a line break.


-- 

Rebecca Cran


^ permalink raw reply	[flat|nested] 32+ messages in thread

* [PATCH v7 1/2] ArmLib: add functions to read system registers
  2023-04-21 15:15                             ` Rebecca Cran
@ 2023-04-21 15:51                               ` Marcin Juszkiewicz
  2023-04-21 15:51                                 ` [PATCH v7 2/2] add ArmCpuInfo EFI application Marcin Juszkiewicz
  0 siblings, 1 reply; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-21 15:51 UTC (permalink / raw)
  To: devel
  Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran, Pedro Falcato,
	Marcin Juszkiewicz

ArmCpuInfo uses those to read system registers and other parts of EDK2
may find them useful.

Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
---
 ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h    | 50 +++++++++++++++-
 .../Library/ArmLib/AArch64/AArch64Support.S   | 58 ++++++++++++++++---
 2 files changed, 99 insertions(+), 9 deletions(-)

diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h
index 330481fc50db..6380a019ddc5 100644
--- a/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h
+++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Lib.h
@@ -40,7 +40,43 @@ ArmCleanInvalidateDataCacheEntryBySetWay (
 
 UINTN
 EFIAPI
-ArmReadIdAA64Pfr0 (
+ArmReadIdAA64Dfr0 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Dfr1 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Isar0 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Isar1 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Isar2 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Mmfr0 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Mmfr1 (
   VOID
   );
 
@@ -54,4 +90,16 @@ ArmReadIdAA64Mmfr2 (
   VOID
   );
 
+UINTN
+EFIAPI
+ArmReadIdAA64Pfr0 (
+  VOID
+  );
+
+UINTN
+EFIAPI
+ArmReadIdAA64Pfr1 (
+  VOID
+  );
+
 #endif // AARCH64_LIB_H_
diff --git a/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S b/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S
index d3cc1e86716b..a7111e51882c 100644
--- a/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S
+++ b/ArmPkg/Library/ArmLib/AArch64/AArch64Support.S
@@ -425,10 +425,6 @@ ASM_FUNC(ArmCallWFI)
   wfi
   ret
 
-ASM_FUNC(ArmReadIdAA64Mmfr2)
-  mrs   x0, ID_AA64MMFR2_EL1           // read EL1 MMFR2
-  ret
-
 ASM_FUNC(ArmReadMpidr)
   mrs   x0, mpidr_el1           // read EL1 MPIDR
   ret
@@ -452,10 +448,6 @@ ASM_FUNC(ArmIsArchTimerImplemented)
   ret
 
 
-ASM_FUNC(ArmReadIdAA64Pfr0)
-  mrs   x0, id_aa64pfr0_el1   // Read ID_AA64PFR0 Register
-  ret
-
 
 // VOID ArmWriteHcr(UINTN Hcr)
 ASM_FUNC(ArmWriteHcr)
@@ -482,4 +474,54 @@ ASM_FUNC(ArmWriteCntHctl)
   msr   cnthctl_el2, x0
   ret
 
+
+ASM_FUNC(ArmReadIdAA64Dfr0)
+  mrs   x0, ID_AA64DFR0_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Dfr1)
+  mrs   x0, ID_AA64DFR1_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Isar0)
+  mrs   x0, ID_AA64ISAR0_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Isar1)
+  mrs   x0, ID_AA64ISAR1_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Isar2)
+  mrs   x0, ID_AA64ISAR2_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Mmfr0)
+  mrs   x0, ID_AA64MMFR0_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Mmfr1)
+  mrs   x0, ID_AA64MMFR1_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Mmfr2)
+  mrs   x0, ID_AA64MMFR2_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Pfr0)
+  mrs   x0, ID_AA64PFR0_EL1
+  ret
+
+
+ASM_FUNC(ArmReadIdAA64Pfr1)
+  mrs   x0, ID_AA64PFR1_EL1
+  ret
+
 ASM_FUNCTION_REMOVE_IF_UNREFERENCED
-- 
2.40.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* [PATCH v7 2/2] add ArmCpuInfo EFI application
  2023-04-21 15:51                               ` [PATCH v7 1/2] ArmLib: add functions to read system registers Marcin Juszkiewicz
@ 2023-04-21 15:51                                 ` Marcin Juszkiewicz
  2023-04-21 20:18                                   ` Leif Lindholm
  0 siblings, 1 reply; 32+ messages in thread
From: Marcin Juszkiewicz @ 2023-04-21 15:51 UTC (permalink / raw)
  To: devel
  Cc: Ard Biesheuvel, Leif Lindholm, Rebecca Cran, Pedro Falcato,
	Marcin Juszkiewicz

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 |   31 +
 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c   | 2427 ++++++++++++++++++
 3 files changed, 2459 insertions(+)
 create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
 create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c

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..da29548a7f43
--- /dev/null
+++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
@@ -0,0 +1,31 @@
+## @file
+#  Application to present AArch64 cpu information.
+#
+#  Based on HelloWorld:
+#  Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2023, Linaro Ltd. All rights reserved.<BR>
+#
+#  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
+
+[Sources]
+  ArmCpuInfo.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  ArmLib
+  UefiApplicationEntryPoint
+  UefiLib
diff --git a/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
new file mode 100644
index 000000000000..70d628a69ae9
--- /dev/null
+++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
@@ -0,0 +1,2427 @@
+/** @file
+  Application to present AArch64 cpu information.
+
+Copyright (c) 2023, Linaro Ltd. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/UefiLib.h>
+#include <Library/ArmLib/AArch64/AArch64Lib.h>
+
+// We cannot assume GCC extensions to be present so let use
+// binary numbers via enum.
+// Arm ARM uses binary numbers so this way it is more readable.
+enum {
+  b0000,
+  b0001,
+  b0010,
+  b0011,
+  b0100,
+  b0101,
+  b0110,
+  b0111,
+  b1000,
+  b1001,
+  b1010,
+  b1011,
+  b1100,
+  b1101,
+  b1110,
+  b1111
+};
+
+/**
+  Print formatted table line.
+
+  Values can be empty if only new description line is needed.
+
+  @param[in] Field       name of system register
+  @param[in] Bits        bits of system register
+  @param[in] Value       value of those bits
+  @param[in] Description meaning of value
+**/
+VOID
+PrintText (
+  CONST CHAR8  *Field,
+  CONST CHAR8  *Bits,
+  CONST CHAR8  *Value,
+  CONST CHAR8  *Description
+  )
+{
+  AsciiPrint (" %-16a | %5a | %5a | %a\n", Field, Bits, Value, Description);
+}
+
+/**
+  Print formatted table line with value printed in binary.
+
+  @param[in] Field       name of system register
+  @param[in] Bits        bits of system register
+  @param[in] Value       value of those bits
+  @param[in] Description meaning of value
+**/
+VOID
+PrintValues (
+  CONST CHAR8  *Field,
+  CONST CHAR8  *Bits,
+  CONST UINT8  Value,
+  CONST CHAR8  *Description
+  )
+{
+  STATIC CONST CHAR8  Nibbles[][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, Nibbles[Value & 0xf], Description);
+}
+
+/**
+  Print spacer for results table.
+**/
+VOID
+PrintSpacer (
+  VOID
+  )
+{
+  AsciiPrint ("------------------|-------|-------|----------------------------------------------\n");
+}
+
+/**
+  Handle ID_AA64DFR0_EL1 system register
+
+  @param[in] Aa64Dfr0  value of ID_AA64DFR0_EL1 system register
+**/
+VOID
+HandleAa64Dfr0 (
+  CONST UINT64  Aa64Dfr0
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64DFR0";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Dfr0 >>  4) & 0xf;
+  switch (Value) {
+    case b0110:
+      Description = "Armv8 debug architecture";
+      break;
+    case b0111:
+      Description = "Armv8 debug architecture with VHE";
+      break;
+    case b1000:
+      Description = "FEAT_Debugv8p2 implemented.";
+      break;
+    case b1001:
+      Description = "FEAT_Debugv8p4 implemented.";
+      break;
+    case b1010:
+      Description = "FEAT_Debugv8p8 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Dfr0 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Trace unit System registers not implemented.";
+      break;
+    case b0001:
+      Description = "Trace unit System registers implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Dfr0 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Performance Monitors Extension not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_PMUv3 implemented.";
+      break;
+    case b0100:
+      Description = "FEAT_PMUv3p1 implemented.";
+      break;
+    case b0101:
+      Description = "FEAT_PMUv3p4 implemented.";
+      break;
+    case b0110:
+      Description = "FEAT_PMUv3p5 implemented.";
+      break;
+    case b0111:
+      Description = "FEAT_PMUv3p7 implemented.";
+      break;
+    case b1000:
+      Description = "FEAT_PMUv3p8 implemented.";
+      break;
+    case b1111:
+      Description = "IMPLEMENTATION DEFINED form of performance monitors supported.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Dfr0 >> 12) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "reserved";
+      break;
+    default:
+      Description = "Number of breakpoints, minus 1.";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 19:16 reserved
+
+  Bits  = "23:20";
+  Value = (Aa64Dfr0 >> 20) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "reserved";
+      break;
+    default:
+      Description = "Number of watchpoints, minus 1.";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 27:24 reserved
+
+  Bits  = "31:28";
+  Value = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 32) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SPE not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SPE implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_SPEv1p1 implemented.";
+      break;
+    case b0011:
+      Description = "FEAT_SPEv1p2 implemented.";
+      break;
+    case b0100:
+      Description = "FEAT_SPEv1p3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Dfr0 >> 36) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_DoubleLock implemented.";
+      break;
+    case b1111:
+      Description = "FEAT_DoubleLock not implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Dfr0 >> 40) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_TRF not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_TRF implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Dfr0 >> 44) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_TRBE not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_TRBE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "51:48";
+  Value = (Aa64Dfr0 >> 48) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_MTPMU not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_MTPMU and FEAT_PMUv3 implemented.";
+      break;
+    case b1111:
+      Description = "FEAT_MTPMU not implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Dfr0 >> 52) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_BRBE not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_BRBE implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_BRBEv1p1 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 59:56 reserved
+
+  Bits  = "63:60";
+  Value = (Aa64Dfr0 >> 60) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Setting MDCR_EL2.HPMN to zero has CONSTRAINED UNPREDICTABLE behavior.";
+      break;
+    case b0001:
+      Description = "FEAT_HPMN0 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+/**
+  Handle ID_AA64ISAR0_EL1 system register
+
+  @param[in] Aa64Isar0  value of ID_AA64ISAR0_EL1 system register
+**/
+VOID
+HandleAa64Isar0 (
+  CONST UINT64  Aa64Isar0
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR0";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  // 3:0 reserved
+
+  Bits  = "7:4 ";
+  Value = (Aa64Isar0 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_AES, FEAT_PMULL not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_AES implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_AES and FEAT_PMULL implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Isar0 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SHA1 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SHA1 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Isar0 >> 12) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SHA256, FEAT_SHA512 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SHA256 implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_SHA512 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Isar0 >> 16) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "CRC32 not implemented.";
+      break;
+    case b0001:
+      Description = "CRC32 instructions implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Isar0 >> 20) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_LSE not implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_LSE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "27:24";
+  Value = (Aa64Isar0 >> 24) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "TME instructions not implemented.";
+      break;
+    case b0001:
+      Description = "TME instructions implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "31:28";
+  Value = (Aa64Isar0 >> 28) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_RDM not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_RDM implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Isar0 >> 32) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SHA3 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SHA3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Isar0 >> 36) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SM3 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SM3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Isar0 >> 40) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SM4 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SM4 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Isar0 >> 44) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_DotProd not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_DotProd implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "51:48";
+  Value = (Aa64Isar0 >> 48) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_FHM not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_FHM implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Isar0 >> 52) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_FlagM/FEAT_FlagM2 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_FlagM implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_FlagM2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "59:56";
+  Value = (Aa64Isar0 >> 56) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_TLBIOS/FEAT_TLBIRANGE not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_TLBIOS implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_TLBIRANGE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "63:60";
+  Value = (Aa64Isar0 >> 60) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_RNG not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_RNG implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+/**
+  Handle ID_AA64ISAR1_EL1 system register
+
+  @param[in] Aa64Isar1  value of ID_AA64ISAR1_EL1 system register
+**/
+VOID
+HandleAa64Isar1 (
+  CONST UINT64  Aa64Isar1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Isar1 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "DC CVAP not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_DPB implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_DPB2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Isar1 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Address Authentication  (APA) not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_PAuth implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_EPAC implemented.";
+      break;
+    case b0011:
+      Description = "FEAT_PAuth2 implemented.";
+      break;
+    case b0100:
+      Description = "FEAT_FPAC implemented.";
+      break;
+    case b0101:
+      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 = (Aa64Isar1 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Address Authentication  (API) not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_PAuth implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_EPAC implemented.";
+      break;
+    case b0011:
+      Description = "FEAT_PAuth2 implemented.";
+      break;
+    case b0100:
+      Description = "FEAT_FPAC implemented.";
+      break;
+    case b0101:
+      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 = (Aa64Isar1 >> 12) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_JSCVT not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_JSCVT implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Isar1 >> 16) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_FCMA not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_FCMA implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Isar1 >> 20) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_LRCPC (2) not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_LRCPC implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_LRCPC2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "27:24";
+  Value = (Aa64Isar1 >> 24) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_PACQARMA5 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_PACQARMA5 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "31:28";
+  Value = (Aa64Isar1 >> 28) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_PACIMP not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_PACIMP implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Isar1 >> 32) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_FRINTTS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_FRINTTS implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Isar1 >> 36) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SB not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SB implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Isar1 >> 40) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SPECRES not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SPECRES implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Isar1 >> 44) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_BF16 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_BF16 implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_EBF16 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "51:48";
+  Value = (Aa64Isar1 >> 48) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_DGH not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_DGH implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Isar1 >> 52) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_I8MM not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_I8MM implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "59:56";
+  Value = (Aa64Isar1 >> 56) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_XS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_XS implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "63:60";
+  Value = (Aa64Isar1 >> 60) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_LS64 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_LS64 implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_LS64_V implemented.";
+      break;
+    case b0011:
+      Description = "FEAT_LS64_ACCDATA implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+/**
+  Handle ID_AA64ISAR2_EL1 system register
+
+  @param[in] Aa64Isar2  value of ID_AA64ISAR2_EL1 system register
+**/
+VOID
+HandleAa64Isar2 (
+  CONST UINT64  Aa64Isar2
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR2";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Isar2 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_WFxT not implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_WFxT implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Isar2 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_RPRES not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_RPRES implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Isar2 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_PACQARMA3 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_PACQARMA3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Isar2 >> 12) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Address Authentication  (APA3) not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_PAuth implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_EPAC implemented.";
+      break;
+    case b0011:
+      Description = "FEAT_PAuth2 implemented.";
+      break;
+    case b0100:
+      Description = "FEAT_FPAC implemented.";
+      break;
+    case b0101:
+      Description = "FEAT_FPACCOMBINE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Isar2 >> 16) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_MOPS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_MOPS implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Isar2 >> 20) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_HBC not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_HBC implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "27:24";
+  Value = (Aa64Isar2 >> 24) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_CONSTPACFIELD not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_CONSTPACFIELD implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 63:28 reserved
+}
+
+/**
+  Handle ID_AA64MMFR0_EL1 system register
+
+  @param[in] Aa64Mmfr0  value of ID_AA64MMFR0_EL1 system register
+**/
+VOID
+HandleAa64Mmfr0 (
+  CONST UINT64  Aa64Mmfr0
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR0";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = Aa64Mmfr0 & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "32 Bits  (4GB) of physical address range supported.";
+      break;
+    case b0001:
+      Description = "36 Bits  (64GB) of physical address range supported.";
+      break;
+    case b0010:
+      Description = "40 Bits  (1TB) of physical address range supported.";
+      break;
+    case b0011:
+      Description = "42 Bits  (4TB) of physical address range supported.";
+      break;
+    case b0100:
+      Description = "44 Bits  (16TB) of physical address range supported.";
+      break;
+    case b0101:
+      Description = "48 Bits  (256TB) of physical address range supported.";
+      break;
+    case b0110:
+      Description = "52 Bits  (4PB) of physical address range supported.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+  if (Value == b0110) {
+    PrintText ("", "", "", "FEAT_LPA implemented.");
+  }
+
+  Bits  = "7:4 ";
+  Value = (Aa64Mmfr0 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "ASID: 8 Bits";
+      break;
+    case b0010:
+      Description = "ASID: 16 Bits";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Mmfr0 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "No mixed-endian support.";
+      break;
+    case b0001:
+      Description = "Mixed-endian support.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // If mixed-endian is present, check whether supported at EL0
+  if (((Aa64Mmfr0 >>  8) & 0xf) != b0000 ) {
+    if (((Aa64Mmfr0 >> 16) & 0xf) == b0000 ) {
+      PrintValues ("ID_AA64MMFR0", "19:16", b0000, "No mixed-endian support at EL0.");
+    }
+
+    if (((Aa64Mmfr0 >> 16) & 0xf) == b0001 ) {
+      PrintValues ("ID_AA64MMFR0", "19:16", b0001, "Mixed-endian support at EL0.");
+    }
+  }
+
+  Bits  = "15:12";
+  Value = (Aa64Mmfr0 >> 12) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "No support for a distinction between Secure and Non-Secure Memory.";
+      break;
+    case b0001:
+      Description = "Supports a distinction between Secure and Non-Secure Memory.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "31:28";
+  Value = (Aa64Mmfr0 >> 28) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = " 4KB granule supported.";
+      break;
+    case b1111:
+      Description = " 4KB granule not supported.";
+      break;
+    case b0001:
+      Description = " 4KB granule supported for 52-bit address.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Mmfr0 >> 40) & 0xf;
+  switch (Value) {
+    case b0001:
+      Description = " 4KB granule not supported at stage 2.";
+      break;
+    case b0010:
+      Description = " 4KB granule supported at stage 2.";
+      break;
+    case b0011:
+      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 = (Aa64Mmfr0 >> 20) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "16KB granule not supported.";
+      break;
+    case b0001:
+      Description = "16KB granule supported.";
+      break;
+    case b0010:
+      Description = "16KB granule supported for 52-bit address.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Mmfr0 >> 32) & 0xf;
+  switch (Value) {
+    case b0001:
+      Description = "16KB granule not supported at stage 2.";
+      break;
+    case b0010:
+      Description = "16KB granule supported at stage 2.";
+      break;
+    case b0011:
+      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 = (Aa64Mmfr0 >> 24) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "64KB granule supported.";
+      break;
+    case b1111:
+      Description = "64KB granule not supported.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Mmfr0 >> 36) & 0xf;
+  switch (Value) {
+    case b0001:
+      Description = "64KB granule not supported at stage 2.";
+      break;
+    case b0010:
+      Description = "64KB granule supported at stage 2.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Mmfr0 >> 44) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_ExS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_ExS implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 55:48 reserved
+
+  Bits  = "59:56";
+  Value = (Aa64Mmfr0 >> 56) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_FGT not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_FGT implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "63:60";
+  Value = (Aa64Mmfr0 >> 60) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_ECV not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_ECV implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_ECV implemented with extras.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+/**
+  Handle ID_AA64MMFR1_EL1 system register
+
+  @param[in] Aa64Mmfr1  value of ID_AA64MMFR1_EL1 system register
+  @param[in] Aa64Pfr0,  value of ID_AA64PFR0_EL1 system register
+**/
+VOID
+HandleAa64Mmfr1 (
+  CONST UINT64  Aa64Mmfr1,
+  CONST UINT64  Aa64Pfr0
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = Aa64Mmfr1 & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_HAFDBS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_HAFDBS implemented without dirty status support.";
+      break;
+    case b0010:
+      Description = "FEAT_HAFDBS implemented with dirty status support.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Mmfr1 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_VMID16 not implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_VMID16 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Mmfr1 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_VHE not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_VHE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Mmfr1 >> 12) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_HPDS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_HPDS implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_HPDS2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Mmfr1 >> 16) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_LOR not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_LOR implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Mmfr1 >> 20) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_PAN not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_PAN implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_PAN2 implemented.";
+      break;
+    case b0011:
+      Description = "FEAT_PAN3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // when FEAT_RAS implemented
+  if ((((Aa64Pfr0 >> 28) & 0xf) == b0001) ||
+      (((Aa64Pfr0 >> 28) & 0xf) == b0010))
+  {
+    if (((Aa64Mmfr1 >> 24) & 0xf) == b0000 ) {
+      PrintValues ("ID_AA64MMFR1", "27:24", b0000, "The PE never generates an SError interrupt due to");
+      PrintText ("", "", "", "an External abort on a speculative read.");
+    }
+
+    if (((Aa64Mmfr1 >> 24) & 0xf) == b0001 ) {
+      PrintValues ("ID_AA64MMFR1", "27:24", b0001, "The PE might generate an SError interrupt due to");
+      PrintText ("", "", "", "an External abort on a speculative read.");
+    }
+  }
+
+  Bits  = "31:28";
+  Value = (Aa64Mmfr1 >> 28) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_XNX not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_XNX implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Mmfr1 >> 32) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_TWED not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_TWED implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Mmfr1 >> 36) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_ETS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_ETS implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Mmfr1 >> 40) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_HCX not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_HCX implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Mmfr1 >> 44) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_AFP not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_AFP implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "51:48";
+  Value = (Aa64Mmfr1 >> 48) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_nTLBPA not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_nTLBPA implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Mmfr1 >> 52) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_TIDCP1 not implemented";
+      break;
+    case b0001:
+      Description = "FEAT_TIDCP1 implemented";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "59:56";
+  Value = (Aa64Mmfr1 >> 56) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_CMOW not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_CMOW implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 63:60 reserved
+}
+
+/**
+  Handle ID_AA64MMFR2_EL1 system register
+
+  @param[in] Aa64Mmfr2  value of ID_AA64MMFR2_EL1 system register
+**/
+VOID
+HandleAa64Mmfr2 (
+  CONST UINT64  Aa64Mmfr2
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR2";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Mmfr2)       & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_TTCNP not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_TTCNP implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Mmfr2 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_UAO not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_UAO implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Mmfr2 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_LSMAOC not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_LSMAOC implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Mmfr2 >> 12) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_IESB not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_IESB implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Mmfr2 >> 16) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_LVA not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_LVA implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Mmfr2 >> 20) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_CCIDX not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_CCIDX implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "27:24";
+  Value = (Aa64Mmfr2 >> 24) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_NV not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_NV implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_NV2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "31:28";
+  Value = (Aa64Mmfr2 >> 28) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_TTST not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_TTST implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "35:32";
+  Value = (Aa64Mmfr2 >> 32) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_LSE2 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_LSE2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Mmfr2 >> 36) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_IDST not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_IDST implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Mmfr2 >> 40) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_S2FWB not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_S2FWB implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 47:44 reserved
+
+  Bits  = "51:48";
+  Value = (Aa64Mmfr2 >> 48) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_TTL not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_TTL implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Mmfr2 >> 52) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_BBM: Level 0 support for changing block size is supported.";
+      break;
+    case b0001:
+      Description = "FEAT_BBM: Level 1 support for changing block size is supported.";
+      break;
+    case b0010:
+      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 = (Aa64Mmfr2 >> 56) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_EVT not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_EVT: HCR_EL2.{TOCU, TICAB, TID4} traps are supported.";
+      break;
+    case b0010:
+      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 = (Aa64Mmfr2 >> 60) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_E0PD not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_E0PD implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+/**
+  Handle ID_AA64PFR0_EL1 system register
+
+  @param[in] Aa64Pfr0,  value of ID_AA64PFR0_EL1 system register
+  @param[in] Aa64Pfr1,  value of ID_AA64PFR1_EL1 system register
+**/
+VOID
+HandleAa64Pfr0 (
+  CONST UINT64  Aa64Pfr0,
+  CONST UINT64  Aa64Pfr1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR0";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = (Aa64Pfr0)       & 0xf;
+  switch (Value) {
+    case b0001:
+      Description = "EL0 in AArch64 only";
+      break;
+    case b0010:
+      Description = "EL0 in AArch64 and AArch32";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Pfr0 >>  4) & 0xf;
+  switch (Value) {
+    case b0001:
+      Description = "EL1 in AArch64 only";
+      break;
+    case b0010:
+      Description = "EL1 in AArch64 and AArch32";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Pfr0 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "EL2 not implemented.";
+      break;
+    case b0001:
+      Description = "EL2 in AArch64 only";
+      break;
+    case b0010:
+      Description = "EL2 in AArch64 and AArch32";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "15:12";
+  Value = (Aa64Pfr0 >> 12) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "EL3 not implemented.";
+      break;
+    case b0001:
+      Description = "EL3 in AArch64 only";
+      break;
+    case b0010:
+      Description = "EL3 in AArch64 and AArch32";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "19:16";
+  Value = (Aa64Pfr0 >> 16) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Floating-point implemented.";
+      break;
+    case b0001:
+      Description = "Floating-point with half-precision support  (FEAT_FP16).";
+      break;
+    case b1111:
+      Description = "Floating-point not implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "23:20";
+  Value = (Aa64Pfr0 >> 20) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Advanced SIMD implemented.";
+      break;
+    case b0001:
+      Description = "Advanced SIMD with half precision support  (FEAT_FP16).";
+      break;
+    case b1111:
+      Description = "Advanced SIMD not implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "27:24";
+  Value = (Aa64Pfr0 >> 24) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "System registers of GIC CPU not implemented.";
+      break;
+    case b0001:
+      Description = "System registers to versions 3.0/4.0 of GIC CPU implemented.";
+      break;
+    case b0011:
+      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 = (Aa64Pfr0 >> 28) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_RAS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_RAS implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_RASv1p1 implemented.";
+      // b0010 FEAT_RASv1p1 implemented and, if EL3 is implemented, FEAT_DoubleFault implemented.
+      if ((((Aa64Pfr0 >> 12) & 0xf) == b0001) ||
+          (((Aa64Pfr0 >> 12) & 0xf) == b0010))
+      {
+        Description = "FEAT_RASv1p1 implemented. FEAT_DoubleFault implemented.";
+      }
+
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+  if (Value == b0001) {
+    if (((Aa64Pfr1 >> 12) & 0xf) == b0001 ) {
+      PrintValues ("ID_AA64PRF1", "15:12", b0001, "FEAT_RASv1p1 implemented.");
+    }
+  }
+
+  Bits  = "35:32";
+  Value = (Aa64Pfr0 >> 32) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SVE not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SVE implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "39:36";
+  Value = (Aa64Pfr0 >> 36) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Secure EL2 not implemented.";
+      break;
+    case b0001:
+      Description = "Secure EL2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "43:40";
+  Value = (Aa64Pfr0 >> 40) & 0xf;
+  switch (Value) {
+    case b0000:
+      if (((Aa64Pfr1 >> 16) & 0xf) == b0000 ) {
+        Description = "FEAT_MPAM not implemented.";
+      }
+
+      if (((Aa64Pfr1 >> 16) & 0xf) == b0001 ) {
+        Description = "FEAT_MPAM v0.1 implemented.";
+      }
+
+      break;
+    case b0001:
+      if (((Aa64Pfr1 >> 16) & 0xf) == b0000 ) {
+        Description = "FEAT_MPAM v1.0 implemented.";
+      }
+
+      if (((Aa64Pfr1 >> 16) & 0xf) == b0001 ) {
+        Description = "FEAT_MPAM v1.1 implemented.";
+      }
+
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "47:44";
+  Value = (Aa64Pfr0 >> 44) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_AMU not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_AMUv1 implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_AMUv1p1 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "51:48";
+  Value = (Aa64Pfr0 >> 48) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_DIT not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_DIT implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "55:52";
+  Value = (Aa64Pfr0 >> 52) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_RME not implemented";
+      break;
+    case b0001:
+      Description = "FEAT_RME implemented";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "59:56";
+  Value = (Aa64Pfr0 >> 56) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "Not disclosed whether FEAT_CSV2 is implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_CSV2 implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_CSV2_2 implemented.";
+      break;
+    case b0011:
+      Description = "FEAT_CSV2_3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+  if (Value == b0001) {
+    if (((Aa64Pfr1 >> 32) & 0xf) == b0001 ) {
+      PrintValues ("ID_AA64PRF1", "35:32", b0001, "FEAT_CSV2_1p1 implemented.");
+    }
+
+    if (((Aa64Pfr1 >> 32) & 0xf) == b0010 ) {
+      PrintValues ("ID_AA64PRF1", "35:32", b0010, "FEAT_CSV2_1p2 implemented.");
+    }
+  }
+
+  Bits  = "63:60";
+  Value = (Aa64Pfr0 >> 60) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_CSV3 not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_CSV3 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+}
+
+/**
+  Handle ID_AA64PFR1_EL1 system register
+
+  @param[in] Aa64Pfr1  value of ID_AA64PFR1_EL1 system register
+**/
+VOID
+HandleAa64Pfr1 (
+  CONST UINT64  Aa64Pfr1
+  )
+{
+  UINT64              Value;
+  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR1";
+  CONST CHAR8         *Description;
+  CONST CHAR8         *Bits;
+
+  Bits  = "3:0 ";
+  Value = Aa64Pfr1 & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_BTI not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_BTI implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "7:4 ";
+  Value = (Aa64Pfr1 >>  4) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SSBS not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SSBS implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_SSBS2 implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "11:8 ";
+  Value = (Aa64Pfr1 >>  8) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_MTE not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_MTE implemented.";
+      break;
+    case b0010:
+      Description = "FEAT_MTE2 implemented.";
+      break;
+    case b0011:
+      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 = (Aa64Pfr1 >> 24) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_SME not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_SME implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  Bits  = "31:28";
+  Value = (Aa64Pfr1 >> 28) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_RNG_TRAP not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_RNG_TRAP implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 35:32 is CSV2_frac
+
+  Bits  = "39:36";
+  Value = (Aa64Pfr1 >> 36) & 0xf;
+  switch (Value) {
+    case b0000:
+      Description = "FEAT_NMI not implemented.";
+      break;
+    case b0001:
+      Description = "FEAT_NMI implemented.";
+      break;
+    default:
+      Description = "unknown";
+      break;
+  }
+
+  PrintValues (RegName, Bits, Value, Description);
+
+  // 63:40 are reserved
+}
+
+/**
+  The user Entry Point for Application. The user code starts with this function
+  as the real entry point for the application.
+
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
+  @param[in] SystemTable    A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS       The entry point is executed successfully.
+  @retval other             Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+UefiMain (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  UINT64  Aa64Dfr0;
+  UINT64  Aa64Isar0;
+  UINT64  Aa64Isar1;
+  UINT64  Aa64Isar2;
+  UINT64  Aa64Mmfr0;
+  UINT64  Aa64Mmfr1;
+  UINT64  Aa64Mmfr2;
+  UINT64  Aa64Pfr0;
+  UINT64  Aa64Pfr1;
+
+  Aa64Dfr0  = ArmReadIdAA64Dfr0 ();
+  Aa64Isar0 = ArmReadIdAA64Isar0 ();
+  Aa64Isar1 = ArmReadIdAA64Isar1 ();
+  Aa64Isar2 = ArmReadIdAA64Isar2 ();
+  Aa64Mmfr0 = ArmReadIdAA64Mmfr0 ();
+  Aa64Mmfr1 = ArmReadIdAA64Mmfr1 ();
+  Aa64Mmfr2 = ArmReadIdAA64Mmfr2 ();
+  Aa64Pfr0  = ArmReadIdAA64Pfr0 ();
+  Aa64Pfr1  = ArmReadIdAA64Pfr1 ();
+
+  AsciiPrint ("ID_AA64MMFR0_EL1 = 0x%016lx\n", Aa64Mmfr0);
+  AsciiPrint ("ID_AA64MMFR1_EL1 = 0x%016lx\n", Aa64Mmfr1);
+  AsciiPrint ("ID_AA64MMFR2_EL1 = 0x%016lx\n", Aa64Mmfr2);
+  AsciiPrint ("ID_AA64PFR0_EL1  = 0x%016lx\n", Aa64Pfr0);
+  AsciiPrint ("ID_AA64PFR1_EL1  = 0x%016lx\n", Aa64Pfr1);
+  AsciiPrint ("ID_AA64ISAR0_EL1 = 0x%016lx\n", Aa64Isar0);
+  AsciiPrint ("ID_AA64ISAR1_EL1 = 0x%016lx\n", Aa64Isar1);
+  AsciiPrint ("ID_AA64ISAR2_EL1 = 0x%016lx\n", Aa64Isar2);
+  AsciiPrint ("ID_AA64DFR0_EL1  = 0x%016lx\n", Aa64Dfr0);
+  AsciiPrint ("\n");
+
+  PrintText ("Register", "Bits", "Value", "Feature");
+  PrintSpacer ();
+
+  HandleAa64Mmfr0 (Aa64Mmfr0);
+  PrintSpacer ();
+  HandleAa64Mmfr1 (Aa64Mmfr1, Aa64Pfr0);
+  PrintSpacer ();
+  HandleAa64Mmfr2 (Aa64Mmfr2);
+
+  PrintSpacer ();
+  HandleAa64Pfr0 (Aa64Pfr0, Aa64Pfr1);
+  PrintSpacer ();
+  HandleAa64Pfr1 (Aa64Pfr1);
+
+  PrintSpacer ();
+  HandleAa64Isar0 (Aa64Isar0);
+  PrintSpacer ();
+  HandleAa64Isar1 (Aa64Isar1);
+  PrintSpacer ();
+  HandleAa64Isar2 (Aa64Isar2);
+
+  PrintSpacer ();
+  HandleAa64Dfr0 (Aa64Dfr0);
+
+  return EFI_SUCCESS;
+}
-- 
2.40.0


^ permalink raw reply related	[flat|nested] 32+ messages in thread

* Re: [edk2-devel] [PATCH v6 2/2] add ArmCpuInfo EFI application
  2023-04-21 14:37                         ` [edk2-devel] " Rebecca Cran
  2023-04-21 14:59                           ` Marcin Juszkiewicz
@ 2023-04-21 16:33                           ` Leif Lindholm
  1 sibling, 0 replies; 32+ messages in thread
From: Leif Lindholm @ 2023-04-21 16:33 UTC (permalink / raw)
  To: Rebecca Cran; +Cc: devel, Marcin Juszkiewicz, Ard Biesheuvel, Pedro Falcato

On Fri, Apr 21, 2023 at 08:37:42 -0600, Rebecca Cran wrote:
> I noticed CI failed for the push PR
> (https://github.com/tianocore/edk2/pull/4292).
> 
> 
> Ecc is complaining about missing Doxygen info for the functions:
> 
> https://dev.azure.com/tianocore/edk2-ci/_build/results?buildId=88023&view=logs&j=d36e2059-ab45-57a4-e2a1-e73032481054&t=463dc808-035c-5fe4-17fd-50a99c74a4aa
> 
> 
> It looks like there's a stray commit merging out from master, that doesn't
> have a Signed-off-by line?

Ah. My bad.
Didn't realise github generated those when it asked the seemingly
helpful question of whether it should update mr to latest master...

/
    Leif

> And it looks like there might be Uncrustify problems too: https://dev.azure.com/tianocore/edk2-ci/_build/results?buildId=88024&view=logs&jobId=2640d2b2-7c53-5a2b-80c7-040377c664fd&j=2640d2b2-7c53-5a2b-80c7-040377c664fd&t=a7f329c1-489d-56ab-b670-1c248e984338
> 
> 
> -- 
> 
> Rebecca Cran
> 
> 
> 
> On 4/20/23 11:29, Leif Lindholm wrote:
> > On Thu, Apr 20, 2023 at 16:44:23 +0200, Marcin Juszkiewicz wrote:
> > > App goes through ID_AA64*_EL1 system registers and decode their values.
> > > 
> > > Signed-off-by: Marcin Juszkiewicz <marcin.juszkiewicz@linaro.org>
> > For the series:
> > Reviewed-by: Leif Lindholm <quic_llindhol@quicinc.com>
> > 
> > After discussing with Marcin on side channel, I folded in a statement
> > at the head of ArmCpuInfo.c that the app was written against ARM DDI
> > 0487I.a version (current) of the ARM Architecture Reference Manual (A
> > profile), and that this information should be updated when features
> > are added from a subsequent version of the document.
> > 
> > Submitted as github merge request #4292, currently going through CI.
> > 
> > Thanks!
> > 
> > /
> >      Leif
> > 
> > > ---
> > >   ArmPkg/ArmPkg.dsc                            |    1 +
> > >   ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf |   33 +
> > >   ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c   | 2346 ++++++++++++++++++
> > >   3 files changed, 2380 insertions(+)
> > >   create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
> > >   create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
> > > 
> > > 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..d2235d3aa911
> > > --- /dev/null
> > > +++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
> > > @@ -0,0 +1,33 @@
> > > +## @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
> > > +
> > > +[Sources]
> > > +  ArmCpuInfo.c
> > > +
> > > +[Packages]
> > > +  ArmPkg/ArmPkg.dec
> > > +  MdePkg/MdePkg.dec
> > > +  MdeModulePkg/MdeModulePkg.dec
> > > +
> > > +[LibraryClasses]
> > > +  ArmLib
> > > +  UefiApplicationEntryPoint
> > > +  UefiLib
> > > diff --git a/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
> > > new file mode 100644
> > > index 000000000000..63914d9815c6
> > > --- /dev/null
> > > +++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
> > > @@ -0,0 +1,2346 @@
> > > +/** @file
> > > +
> > > +  Copyright  (c) 2023 Marcin Juszkiewicz
> > > +  SPDX-License-Identifier: BSD-2-Clause-Patent
> > > +
> > > + **/
> > > +
> > > +#include <Library/UefiLib.h>
> > > +#include <Library/ArmLib/AArch64/AArch64Lib.h>
> > > +
> > > +// We cannot assume GCC extensions to be present so let use
> > > +// binary numbers via enum.
> > > +// Arm ARM uses binary numbers so this way it is more readable.
> > > +enum {
> > > +   b0000,
> > > +   b0001,
> > > +   b0010,
> > > +   b0011,
> > > +   b0100,
> > > +   b0101,
> > > +   b0110,
> > > +   b0111,
> > > +   b1000,
> > > +   b1001,
> > > +   b1010,
> > > +   b1011,
> > > +   b1100,
> > > +   b1101,
> > > +   b1110,
> > > +   b1111
> > > +};
> > > +
> > > +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  Nibbles[][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, Nibbles[Value & 0xf], Description);
> > > +}
> > > +
> > > +VOID
> > > +PrintSpacer (
> > > +  VOID
> > > +  )
> > > +{
> > > +  AsciiPrint ("------------------|-------|-------|----------------------------------------------\n");
> > > +}
> > > +
> > > +VOID
> > > +HandleAa64Mmfr0 (
> > > +  CONST UINT64  Aa64Mmfr0
> > > +  )
> > > +{
> > > +  UINT64              Value;
> > > +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR0";
> > > +  CONST CHAR8         *Description;
> > > +  CONST CHAR8         *Bits;
> > > +
> > > +  Bits  = "3:0 ";
> > > +  Value = Aa64Mmfr0 & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "32 Bits  (4GB) of physical address range supported.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "36 Bits  (64GB) of physical address range supported.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "40 Bits  (1TB) of physical address range supported.";
> > > +      break;
> > > +    case b0011:
> > > +      Description = "42 Bits  (4TB) of physical address range supported.";
> > > +      break;
> > > +    case b0100:
> > > +      Description = "44 Bits  (16TB) of physical address range supported.";
> > > +      break;
> > > +    case b0101:
> > > +      Description = "48 Bits  (256TB) of physical address range supported.";
> > > +      break;
> > > +    case b0110:
> > > +      Description = "52 Bits  (4PB) of physical address range supported.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +  if (Value == b0110) {
> > > +    PrintText ("", "", "", "FEAT_LPA implemented.");
> > > +  }
> > > +
> > > +  Bits  = "7:4 ";
> > > +  Value = (Aa64Mmfr0 >>  4) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "ASID: 8 Bits";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "ASID: 16 Bits";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "11:8 ";
> > > +  Value = (Aa64Mmfr0 >>  8) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "No mixed-endian support.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "Mixed-endian support.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  // If mixed-endian is present, check whether supported at EL0
> > > +  if (((Aa64Mmfr0 >>  8) & 0xf) != b0000 ) {
> > > +    if (((Aa64Mmfr0 >> 16) & 0xf) == b0000 ) {
> > > +      PrintValues ("ID_AA64MMFR0", "19:16", b0000, "No mixed-endian support at EL0.");
> > > +    }
> > > +
> > > +    if (((Aa64Mmfr0 >> 16) & 0xf) == b0001 ) {
> > > +      PrintValues ("ID_AA64MMFR0", "19:16", b0001, "Mixed-endian support at EL0.");
> > > +    }
> > > +  }
> > > +
> > > +  Bits  = "15:12";
> > > +  Value = (Aa64Mmfr0 >> 12) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "No support for a distinction between Secure and Non-Secure Memory.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "Supports a distinction between Secure and Non-Secure Memory.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "31:28";
> > > +  Value = (Aa64Mmfr0 >> 28) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = " 4KB granule supported.";
> > > +      break;
> > > +    case b1111:
> > > +      Description = " 4KB granule not supported.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = " 4KB granule supported for 52-bit address.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "43:40";
> > > +  Value = (Aa64Mmfr0 >> 40) & 0xf;
> > > +  switch (Value) {
> > > +    case b0001:
> > > +      Description = " 4KB granule not supported at stage 2.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = " 4KB granule supported at stage 2.";
> > > +      break;
> > > +    case b0011:
> > > +      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 = (Aa64Mmfr0 >> 20) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "16KB granule not supported.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "16KB granule supported.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "16KB granule supported for 52-bit address.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "35:32";
> > > +  Value = (Aa64Mmfr0 >> 32) & 0xf;
> > > +  switch (Value) {
> > > +    case b0001:
> > > +      Description = "16KB granule not supported at stage 2.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "16KB granule supported at stage 2.";
> > > +      break;
> > > +    case b0011:
> > > +      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 = (Aa64Mmfr0 >> 24) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "64KB granule supported.";
> > > +      break;
> > > +    case b1111:
> > > +      Description = "64KB granule not supported.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "39:36";
> > > +  Value = (Aa64Mmfr0 >> 36) & 0xf;
> > > +  switch (Value) {
> > > +    case b0001:
> > > +      Description = "64KB granule not supported at stage 2.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "64KB granule supported at stage 2.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "47:44";
> > > +  Value = (Aa64Mmfr0 >> 44) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_ExS not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_ExS implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  // 55:48 reserved
> > > +
> > > +  Bits  = "59:56";
> > > +  Value = (Aa64Mmfr0 >> 56) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_FGT not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_FGT implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "63:60";
> > > +  Value = (Aa64Mmfr0 >> 60) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_ECV not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_ECV implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_ECV implemented with extras.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +}
> > > +
> > > +VOID
> > > +HandleAa64Mmfr1 (
> > > +  CONST UINT64  Aa64Mmfr1,
> > > +  CONST UINT64  Aa64Pfr0
> > > +  )
> > > +{
> > > +  UINT64              Value;
> > > +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR1";
> > > +  CONST CHAR8         *Description;
> > > +  CONST CHAR8         *Bits;
> > > +
> > > +  Bits  = "3:0 ";
> > > +  Value = Aa64Mmfr1 & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_HAFDBS not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_HAFDBS implemented without dirty status support.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_HAFDBS implemented with dirty status support.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "7:4 ";
> > > +  Value = (Aa64Mmfr1 >>  4) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_VMID16 not implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_VMID16 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "11:8 ";
> > > +  Value = (Aa64Mmfr1 >>  8) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_VHE not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_VHE implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "15:12";
> > > +  Value = (Aa64Mmfr1 >> 12) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_HPDS not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_HPDS implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_HPDS2 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "19:16";
> > > +  Value = (Aa64Mmfr1 >> 16) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_LOR not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_LOR implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "23:20";
> > > +  Value = (Aa64Mmfr1 >> 20) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_PAN not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_PAN implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_PAN2 implemented.";
> > > +      break;
> > > +    case b0011:
> > > +      Description = "FEAT_PAN3 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  // when FEAT_RAS implemented
> > > +  if ((((Aa64Pfr0 >> 28) & 0xf) == b0001) ||
> > > +      (((Aa64Pfr0 >> 28) & 0xf) == b0010))
> > > +  {
> > > +    if (((Aa64Mmfr1 >> 24) & 0xf) == b0000 ) {
> > > +      PrintValues ("ID_AA64MMFR1", "27:24", b0000, "The PE never generates an SError interrupt due to");
> > > +      PrintText ("", "", "", "an External abort on a speculative read.");
> > > +    }
> > > +
> > > +    if (((Aa64Mmfr1 >> 24) & 0xf) == b0001 ) {
> > > +      PrintValues ("ID_AA64MMFR1", "27:24", b0001, "The PE might generate an SError interrupt due to");
> > > +      PrintText ("", "", "", "an External abort on a speculative read.");
> > > +    }
> > > +  }
> > > +
> > > +  Bits  = "31:28";
> > > +  Value = (Aa64Mmfr1 >> 28) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_XNX not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_XNX implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "35:32";
> > > +  Value = (Aa64Mmfr1 >> 32) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_TWED not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_TWED implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "39:36";
> > > +  Value = (Aa64Mmfr1 >> 36) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_ETS not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_ETS implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "43:40";
> > > +  Value = (Aa64Mmfr1 >> 40) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_HCX not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_HCX implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "47:44";
> > > +  Value = (Aa64Mmfr1 >> 44) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_AFP not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_AFP implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "51:48";
> > > +  Value = (Aa64Mmfr1 >> 48) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_nTLBPA not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_nTLBPA implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "55:52";
> > > +  Value = (Aa64Mmfr1 >> 52) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_TIDCP1 not implemented";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_TIDCP1 implemented";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "59:56";
> > > +  Value = (Aa64Mmfr1 >> 56) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_CMOW not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_CMOW implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  // 63:60 reserved
> > > +}
> > > +
> > > +VOID
> > > +HandleAa64Mmfr2 (
> > > +  CONST UINT64  Aa64Mmfr2
> > > +  )
> > > +{
> > > +  UINT64              Value;
> > > +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR2";
> > > +  CONST CHAR8         *Description;
> > > +  CONST CHAR8         *Bits;
> > > +
> > > +  Bits  = "3:0 ";
> > > +  Value = (Aa64Mmfr2)       & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_TTCNP not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_TTCNP implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "7:4 ";
> > > +  Value = (Aa64Mmfr2 >>  4) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_UAO not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_UAO implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "11:8 ";
> > > +  Value = (Aa64Mmfr2 >>  8) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_LSMAOC not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_LSMAOC implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "15:12";
> > > +  Value = (Aa64Mmfr2 >> 12) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_IESB not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_IESB implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "19:16";
> > > +  Value = (Aa64Mmfr2 >> 16) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_LVA not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_LVA implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "23:20";
> > > +  Value = (Aa64Mmfr2 >> 20) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_CCIDX not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_CCIDX implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "27:24";
> > > +  Value = (Aa64Mmfr2 >> 24) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_NV not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_NV implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_NV2 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "31:28";
> > > +  Value = (Aa64Mmfr2 >> 28) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_TTST not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_TTST implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "35:32";
> > > +  Value = (Aa64Mmfr2 >> 32) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_LSE2 not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_LSE2 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "39:36";
> > > +  Value = (Aa64Mmfr2 >> 36) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_IDST not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_IDST implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "43:40";
> > > +  Value = (Aa64Mmfr2 >> 40) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_S2FWB not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_S2FWB implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  // 47:44 reserved
> > > +
> > > +  Bits  = "51:48";
> > > +  Value = (Aa64Mmfr2 >> 48) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_TTL not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_TTL implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "55:52";
> > > +  Value = (Aa64Mmfr2 >> 52) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_BBM: Level 0 support for changing block size is supported.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_BBM: Level 1 support for changing block size is supported.";
> > > +      break;
> > > +    case b0010:
> > > +      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 = (Aa64Mmfr2 >> 56) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_EVT not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_EVT: HCR_EL2.{TOCU, TICAB, TID4} traps are supported.";
> > > +      break;
> > > +    case b0010:
> > > +      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 = (Aa64Mmfr2 >> 60) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_E0PD not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_E0PD implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +}
> > > +
> > > +VOID
> > > +HandleAa64Pfr0 (
> > > +  CONST UINT64  Aa64Pfr0,
> > > +  CONST UINT64  Aa64Pfr1
> > > +  )
> > > +{
> > > +  UINT64              Value;
> > > +  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR0";
> > > +  CONST CHAR8         *Description;
> > > +  CONST CHAR8         *Bits;
> > > +
> > > +  Bits  = "3:0 ";
> > > +  Value = (Aa64Pfr0)       & 0xf;
> > > +  switch (Value) {
> > > +    case b0001:
> > > +      Description = "EL0 in AArch64 only";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "EL0 in AArch64 and AArch32";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "7:4 ";
> > > +  Value = (Aa64Pfr0 >>  4) & 0xf;
> > > +  switch (Value) {
> > > +    case b0001:
> > > +      Description = "EL1 in AArch64 only";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "EL1 in AArch64 and AArch32";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "11:8 ";
> > > +  Value = (Aa64Pfr0 >>  8) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "EL2 not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "EL2 in AArch64 only";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "EL2 in AArch64 and AArch32";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "15:12";
> > > +  Value = (Aa64Pfr0 >> 12) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "EL3 not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "EL3 in AArch64 only";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "EL3 in AArch64 and AArch32";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "19:16";
> > > +  Value = (Aa64Pfr0 >> 16) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "Floating-point implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "Floating-point with half-precision support  (FEAT_FP16).";
> > > +      break;
> > > +    case b1111:
> > > +      Description = "Floating-point not implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "23:20";
> > > +  Value = (Aa64Pfr0 >> 20) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "Advanced SIMD implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "Advanced SIMD with half precision support  (FEAT_FP16).";
> > > +      break;
> > > +    case b1111:
> > > +      Description = "Advanced SIMD not implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "27:24";
> > > +  Value = (Aa64Pfr0 >> 24) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "System registers of GIC CPU not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "System registers to versions 3.0/4.0 of GIC CPU implemented.";
> > > +      break;
> > > +    case b0011:
> > > +      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 = (Aa64Pfr0 >> 28) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_RAS not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_RAS implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_RASv1p1 implemented.";
> > > +      // b0010 FEAT_RASv1p1 implemented and, if EL3 is implemented, FEAT_DoubleFault implemented.
> > > +      if ((((Aa64Pfr0 >> 12) & 0xf) == b0001) ||
> > > +          (((Aa64Pfr0 >> 12) & 0xf) == b0010))
> > > +      {
> > > +        Description = "FEAT_RASv1p1 implemented. FEAT_DoubleFault implemented.";
> > > +      }
> > > +
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +  if (Value == b0001) {
> > > +    if (((Aa64Pfr1 >> 12) & 0xf) == b0001 ) {
> > > +      PrintValues ("ID_AA64PRF1", "15:12", b0001, "FEAT_RASv1p1 implemented.");
> > > +    }
> > > +  }
> > > +
> > > +  Bits  = "35:32";
> > > +  Value = (Aa64Pfr0 >> 32) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_SVE not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_SVE implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "39:36";
> > > +  Value = (Aa64Pfr0 >> 36) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "Secure EL2 not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "Secure EL2 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "43:40";
> > > +  Value = (Aa64Pfr0 >> 40) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      if (((Aa64Pfr1 >> 16) & 0xf) == b0000 ) {
> > > +        Description = "FEAT_MPAM not implemented.";
> > > +      }
> > > +
> > > +      if (((Aa64Pfr1 >> 16) & 0xf) == b0001 ) {
> > > +        Description = "FEAT_MPAM v0.1 implemented.";
> > > +      }
> > > +
> > > +      break;
> > > +    case b0001:
> > > +      if (((Aa64Pfr1 >> 16) & 0xf) == b0000 ) {
> > > +        Description = "FEAT_MPAM v1.0 implemented.";
> > > +      }
> > > +
> > > +      if (((Aa64Pfr1 >> 16) & 0xf) == b0001 ) {
> > > +        Description = "FEAT_MPAM v1.1 implemented.";
> > > +      }
> > > +
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "47:44";
> > > +  Value = (Aa64Pfr0 >> 44) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_AMU not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_AMUv1 implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_AMUv1p1 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "51:48";
> > > +  Value = (Aa64Pfr0 >> 48) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_DIT not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_DIT implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "55:52";
> > > +  Value = (Aa64Pfr0 >> 52) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_RME not implemented";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_RME implemented";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "59:56";
> > > +  Value = (Aa64Pfr0 >> 56) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "Not disclosed whether FEAT_CSV2 is implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_CSV2 implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_CSV2_2 implemented.";
> > > +      break;
> > > +    case b0011:
> > > +      Description = "FEAT_CSV2_3 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +  if (Value == b0001) {
> > > +    if (((Aa64Pfr1 >> 32) & 0xf) == b0001 ) {
> > > +      PrintValues ("ID_AA64PRF1", "35:32", b0001, "FEAT_CSV2_1p1 implemented.");
> > > +    }
> > > +
> > > +    if (((Aa64Pfr1 >> 32) & 0xf) == b0010 ) {
> > > +      PrintValues ("ID_AA64PRF1", "35:32", b0010, "FEAT_CSV2_1p2 implemented.");
> > > +    }
> > > +  }
> > > +
> > > +  Bits  = "63:60";
> > > +  Value = (Aa64Pfr0 >> 60) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_CSV3 not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_CSV3 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +}
> > > +
> > > +VOID
> > > +HandleAa64Pfr1 (
> > > +  CONST UINT64  Aa64Pfr1
> > > +  )
> > > +{
> > > +  UINT64              Value;
> > > +  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR1";
> > > +  CONST CHAR8         *Description;
> > > +  CONST CHAR8         *Bits;
> > > +
> > > +  Bits  = "3:0 ";
> > > +  Value = Aa64Pfr1 & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_BTI not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_BTI implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "7:4 ";
> > > +  Value = (Aa64Pfr1 >>  4) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_SSBS not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_SSBS implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_SSBS2 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "11:8 ";
> > > +  Value = (Aa64Pfr1 >>  8) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_MTE not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_MTE implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_MTE2 implemented.";
> > > +      break;
> > > +    case b0011:
> > > +      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 = (Aa64Pfr1 >> 24) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_SME not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_SME implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "31:28";
> > > +  Value = (Aa64Pfr1 >> 28) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_RNG_TRAP not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_RNG_TRAP implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  // 35:32 is CSV2_frac
> > > +
> > > +  Bits  = "39:36";
> > > +  Value = (Aa64Pfr1 >> 36) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_NMI not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_NMI implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  // 63:40 are reserved
> > > +}
> > > +
> > > +VOID
> > > +HandleAa64Isar0 (
> > > +  CONST UINT64  Aa64Isar0
> > > +  )
> > > +{
> > > +  UINT64              Value;
> > > +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR0";
> > > +  CONST CHAR8         *Description;
> > > +  CONST CHAR8         *Bits;
> > > +
> > > +  // 3:0 reserved
> > > +
> > > +  Bits  = "7:4 ";
> > > +  Value = (Aa64Isar0 >>  4) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_AES, FEAT_PMULL not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_AES implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_AES and FEAT_PMULL implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "11:8 ";
> > > +  Value = (Aa64Isar0 >>  8) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_SHA1 not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_SHA1 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "15:12";
> > > +  Value = (Aa64Isar0 >> 12) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_SHA256, FEAT_SHA512 not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_SHA256 implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_SHA512 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "19:16";
> > > +  Value = (Aa64Isar0 >> 16) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "CRC32 not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "CRC32 instructions implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "23:20";
> > > +  Value = (Aa64Isar0 >> 20) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_LSE not implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_LSE implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "27:24";
> > > +  Value = (Aa64Isar0 >> 24) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "TME instructions not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "TME instructions implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "31:28";
> > > +  Value = (Aa64Isar0 >> 28) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_RDM not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_RDM implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "35:32";
> > > +  Value = (Aa64Isar0 >> 32) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_SHA3 not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_SHA3 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "39:36";
> > > +  Value = (Aa64Isar0 >> 36) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_SM3 not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_SM3 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "43:40";
> > > +  Value = (Aa64Isar0 >> 40) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_SM4 not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_SM4 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "47:44";
> > > +  Value = (Aa64Isar0 >> 44) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_DotProd not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_DotProd implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "51:48";
> > > +  Value = (Aa64Isar0 >> 48) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_FHM not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_FHM implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "55:52";
> > > +  Value = (Aa64Isar0 >> 52) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_FlagM/FEAT_FlagM2 not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_FlagM implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_FlagM2 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "59:56";
> > > +  Value = (Aa64Isar0 >> 56) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_TLBIOS/FEAT_TLBIRANGE not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_TLBIOS implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_TLBIRANGE implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "63:60";
> > > +  Value = (Aa64Isar0 >> 60) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_RNG not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_RNG implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +}
> > > +
> > > +VOID
> > > +HandleAa64Isar1 (
> > > +  CONST UINT64  Aa64Isar1
> > > +  )
> > > +{
> > > +  UINT64              Value;
> > > +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR1";
> > > +  CONST CHAR8         *Description;
> > > +  CONST CHAR8         *Bits;
> > > +
> > > +  Bits  = "3:0 ";
> > > +  Value = (Aa64Isar1 >>  4) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "DC CVAP not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_DPB implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_DPB2 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "7:4 ";
> > > +  Value = (Aa64Isar1 >>  4) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "Address Authentication  (APA) not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_PAuth implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_EPAC implemented.";
> > > +      break;
> > > +    case b0011:
> > > +      Description = "FEAT_PAuth2 implemented.";
> > > +      break;
> > > +    case b0100:
> > > +      Description = "FEAT_FPAC implemented.";
> > > +      break;
> > > +    case b0101:
> > > +      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 = (Aa64Isar1 >>  8) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "Address Authentication  (API) not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_PAuth implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_EPAC implemented.";
> > > +      break;
> > > +    case b0011:
> > > +      Description = "FEAT_PAuth2 implemented.";
> > > +      break;
> > > +    case b0100:
> > > +      Description = "FEAT_FPAC implemented.";
> > > +      break;
> > > +    case b0101:
> > > +      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 = (Aa64Isar1 >> 12) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_JSCVT not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_JSCVT implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "19:16";
> > > +  Value = (Aa64Isar1 >> 16) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_FCMA not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_FCMA implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "23:20";
> > > +  Value = (Aa64Isar1 >> 20) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_LRCPC (2) not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_LRCPC implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_LRCPC2 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "27:24";
> > > +  Value = (Aa64Isar1 >> 24) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_PACQARMA5 not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_PACQARMA5 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "31:28";
> > > +  Value = (Aa64Isar1 >> 28) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_PACIMP not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_PACIMP implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "35:32";
> > > +  Value = (Aa64Isar1 >> 32) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_FRINTTS not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_FRINTTS implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "39:36";
> > > +  Value = (Aa64Isar1 >> 36) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_SB not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_SB implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "43:40";
> > > +  Value = (Aa64Isar1 >> 40) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_SPECRES not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_SPECRES implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "47:44";
> > > +  Value = (Aa64Isar1 >> 44) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_BF16 not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_BF16 implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_EBF16 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "51:48";
> > > +  Value = (Aa64Isar1 >> 48) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_DGH not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_DGH implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "55:52";
> > > +  Value = (Aa64Isar1 >> 52) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_I8MM not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_I8MM implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "59:56";
> > > +  Value = (Aa64Isar1 >> 56) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_XS not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_XS implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "63:60";
> > > +  Value = (Aa64Isar1 >> 60) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_LS64 not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_LS64 implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_LS64_V implemented.";
> > > +      break;
> > > +    case b0011:
> > > +      Description = "FEAT_LS64_ACCDATA implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +}
> > > +
> > > +VOID
> > > +HandleAa64Isar2 (
> > > +  CONST UINT64  Aa64Isar2
> > > +  )
> > > +{
> > > +  UINT64              Value;
> > > +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR2";
> > > +  CONST CHAR8         *Description;
> > > +  CONST CHAR8         *Bits;
> > > +
> > > +  Bits  = "3:0 ";
> > > +  Value = (Aa64Isar2 >>  4) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_WFxT not implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_WFxT implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "7:4 ";
> > > +  Value = (Aa64Isar2 >>  4) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_RPRES not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_RPRES implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "11:8 ";
> > > +  Value = (Aa64Isar2 >>  8) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_PACQARMA3 not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_PACQARMA3 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "15:12";
> > > +  Value = (Aa64Isar2 >> 12) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "Address Authentication  (APA3) not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_PAuth implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_EPAC implemented.";
> > > +      break;
> > > +    case b0011:
> > > +      Description = "FEAT_PAuth2 implemented.";
> > > +      break;
> > > +    case b0100:
> > > +      Description = "FEAT_FPAC implemented.";
> > > +      break;
> > > +    case b0101:
> > > +      Description = "FEAT_FPACCOMBINE implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "19:16";
> > > +  Value = (Aa64Isar2 >> 16) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_MOPS not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_MOPS implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "23:20";
> > > +  Value = (Aa64Isar2 >> 20) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_HBC not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_HBC implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "27:24";
> > > +  Value = (Aa64Isar2 >> 24) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_CONSTPACFIELD not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_CONSTPACFIELD implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  // 63:28 reserved
> > > +}
> > > +
> > > +VOID
> > > +HandleAa64Dfr0 (
> > > +  CONST UINT64  Aa64Dfr0
> > > +  )
> > > +{
> > > +  UINT64              Value;
> > > +  STATIC CONST CHAR8  RegName[] = "ID_AA64DFR0";
> > > +  CONST CHAR8         *Description;
> > > +  CONST CHAR8         *Bits;
> > > +
> > > +  Bits  = "3:0 ";
> > > +  Value = (Aa64Dfr0 >>  4) & 0xf;
> > > +  switch (Value) {
> > > +    case b0110:
> > > +      Description = "Armv8 debug architecture";
> > > +      break;
> > > +    case b0111:
> > > +      Description = "Armv8 debug architecture with VHE";
> > > +      break;
> > > +    case b1000:
> > > +      Description = "FEAT_Debugv8p2 implemented.";
> > > +      break;
> > > +    case b1001:
> > > +      Description = "FEAT_Debugv8p4 implemented.";
> > > +      break;
> > > +    case b1010:
> > > +      Description = "FEAT_Debugv8p8 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "7:4 ";
> > > +  Value = (Aa64Dfr0 >>  4) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "Trace unit System registers not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "Trace unit System registers implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "11:8 ";
> > > +  Value = (Aa64Dfr0 >>  8) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "Performance Monitors Extension not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_PMUv3 implemented.";
> > > +      break;
> > > +    case b0100:
> > > +      Description = "FEAT_PMUv3p1 implemented.";
> > > +      break;
> > > +    case b0101:
> > > +      Description = "FEAT_PMUv3p4 implemented.";
> > > +      break;
> > > +    case b0110:
> > > +      Description = "FEAT_PMUv3p5 implemented.";
> > > +      break;
> > > +    case b0111:
> > > +      Description = "FEAT_PMUv3p7 implemented.";
> > > +      break;
> > > +    case b1000:
> > > +      Description = "FEAT_PMUv3p8 implemented.";
> > > +      break;
> > > +    case b1111:
> > > +      Description = "IMPLEMENTATION DEFINED form of performance monitors supported.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "15:12";
> > > +  Value = (Aa64Dfr0 >> 12) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "reserved";
> > > +      break;
> > > +    default:
> > > +      Description = "Number of breakpoints, minus 1.";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  // 19:16 reserved
> > > +
> > > +  Bits  = "23:20";
> > > +  Value = (Aa64Dfr0 >> 20) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "reserved";
> > > +      break;
> > > +    default:
> > > +      Description = "Number of watchpoints, minus 1.";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  // 27:24 reserved
> > > +
> > > +  Bits  = "31:28";
> > > +  Value = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 32) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_SPE not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_SPE implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_SPEv1p1 implemented.";
> > > +      break;
> > > +    case b0011:
> > > +      Description = "FEAT_SPEv1p2 implemented.";
> > > +      break;
> > > +    case b0100:
> > > +      Description = "FEAT_SPEv1p3 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "39:36";
> > > +  Value = (Aa64Dfr0 >> 36) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_DoubleLock implemented.";
> > > +      break;
> > > +    case b1111:
> > > +      Description = "FEAT_DoubleLock not implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "43:40";
> > > +  Value = (Aa64Dfr0 >> 40) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_TRF not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_TRF implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "47:44";
> > > +  Value = (Aa64Dfr0 >> 44) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_TRBE not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_TRBE implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "51:48";
> > > +  Value = (Aa64Dfr0 >> 48) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_MTPMU not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_MTPMU and FEAT_PMUv3 implemented.";
> > > +      break;
> > > +    case b1111:
> > > +      Description = "FEAT_MTPMU not implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  Bits  = "55:52";
> > > +  Value = (Aa64Dfr0 >> 52) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "FEAT_BRBE not implemented.";
> > > +      break;
> > > +    case b0001:
> > > +      Description = "FEAT_BRBE implemented.";
> > > +      break;
> > > +    case b0010:
> > > +      Description = "FEAT_BRBEv1p1 implemented.";
> > > +      break;
> > > +    default:
> > > +      Description = "unknown";
> > > +      break;
> > > +  }
> > > +
> > > +  PrintValues (RegName, Bits, Value, Description);
> > > +
> > > +  // 59:56 reserved
> > > +
> > > +  Bits  = "63:60";
> > > +  Value = (Aa64Dfr0 >> 60) & 0xf;
> > > +  switch (Value) {
> > > +    case b0000:
> > > +      Description = "Setting MDCR_EL2.HPMN to zero has CONSTRAINED UNPREDICTABLE behavior.";
> > > +      break;
> > > +    case b0001:
> > > +      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  Aa64Dfr0;
> > > +  UINT64  Aa64Isar0;
> > > +  UINT64  Aa64Isar1;
> > > +  UINT64  Aa64Isar2;
> > > +  UINT64  Aa64Mmfr0;
> > > +  UINT64  Aa64Mmfr1;
> > > +  UINT64  Aa64Mmfr2;
> > > +  UINT64  Aa64Pfr0;
> > > +  UINT64  Aa64Pfr1;
> > > +
> > > +  Aa64Dfr0  = ArmReadIdAA64Dfr0 ();
> > > +  Aa64Isar0 = ArmReadIdAA64Isar0 ();
> > > +  Aa64Isar1 = ArmReadIdAA64Isar1 ();
> > > +  Aa64Isar2 = ArmReadIdAA64Isar2 ();
> > > +  Aa64Mmfr0 = ArmReadIdAA64Mmfr0 ();
> > > +  Aa64Mmfr1 = ArmReadIdAA64Mmfr1 ();
> > > +  Aa64Mmfr2 = ArmReadIdAA64Mmfr2 ();
> > > +  Aa64Pfr0  = ArmReadIdAA64Pfr0 ();
> > > +  Aa64Pfr1  = ArmReadIdAA64Pfr1 ();
> > > +
> > > +  AsciiPrint ("ID_AA64MMFR0_EL1 = 0x%016lx\n", Aa64Mmfr0);
> > > +  AsciiPrint ("ID_AA64MMFR1_EL1 = 0x%016lx\n", Aa64Mmfr1);
> > > +  AsciiPrint ("ID_AA64MMFR2_EL1 = 0x%016lx\n", Aa64Mmfr2);
> > > +  AsciiPrint ("ID_AA64PFR0_EL1  = 0x%016lx\n", Aa64Pfr0);
> > > +  AsciiPrint ("ID_AA64PFR1_EL1  = 0x%016lx\n", Aa64Pfr1);
> > > +  AsciiPrint ("ID_AA64ISAR0_EL1 = 0x%016lx\n", Aa64Isar0);
> > > +  AsciiPrint ("ID_AA64ISAR1_EL1 = 0x%016lx\n", Aa64Isar1);
> > > +  AsciiPrint ("ID_AA64ISAR2_EL1 = 0x%016lx\n", Aa64Isar2);
> > > +  AsciiPrint ("ID_AA64DFR0_EL1  = 0x%016lx\n", Aa64Dfr0);
> > > +
> > > +  AsciiPrint ("\n");
> > > +  PrintText ("Register", "Bits", "Value", "Feature");
> > > +  PrintSpacer ();
> > > +
> > > +  HandleAa64Mmfr0 (Aa64Mmfr0);
> > > +  PrintSpacer ();
> > > +  HandleAa64Mmfr1 (Aa64Mmfr1, Aa64Pfr0);
> > > +  PrintSpacer ();
> > > +  HandleAa64Mmfr2 (Aa64Mmfr2);
> > > +
> > > +  PrintSpacer ();
> > > +  HandleAa64Pfr0 (Aa64Pfr0, Aa64Pfr1);
> > > +  PrintSpacer ();
> > > +  HandleAa64Pfr1 (Aa64Pfr1);
> > > +
> > > +  PrintSpacer ();
> > > +  HandleAa64Isar0 (Aa64Isar0);
> > > +  PrintSpacer ();
> > > +  HandleAa64Isar1 (Aa64Isar1);
> > > +  PrintSpacer ();
> > > +  HandleAa64Isar2 (Aa64Isar2);
> > > +
> > > +  PrintSpacer ();
> > > +  HandleAa64Dfr0 (Aa64Dfr0);
> > > +
> > > +  return EFI_SUCCESS;
> > > +}
> > > -- 
> > > 2.40.0
> > > 
> > 
> > 
> > 
> > 

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: [PATCH v7 2/2] add ArmCpuInfo EFI application
  2023-04-21 15:51                                 ` [PATCH v7 2/2] add ArmCpuInfo EFI application Marcin Juszkiewicz
@ 2023-04-21 20:18                                   ` Leif Lindholm
  0 siblings, 0 replies; 32+ messages in thread
From: Leif Lindholm @ 2023-04-21 20:18 UTC (permalink / raw)
  To: Marcin Juszkiewicz; +Cc: devel, Ard Biesheuvel, Rebecca Cran, Pedro Falcato

I addressed some final few ECC complaints, and it finally went through
- now merged as ed2ff315db7e..2c2cb2352896.

Thanks!

On Fri, Apr 21, 2023 at 17:51:16 +0200, Marcin Juszkiewicz 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 |   31 +
>  ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c   | 2427 ++++++++++++++++++
>  3 files changed, 2459 insertions(+)
>  create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
>  create mode 100644 ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
> 
> 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..da29548a7f43
> --- /dev/null
> +++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.inf
> @@ -0,0 +1,31 @@
> +## @file
> +#  Application to present AArch64 cpu information.
> +#
> +#  Based on HelloWorld:
> +#  Copyright (c) 2008 - 2018, Intel Corporation. All rights reserved.<BR>
> +#  Copyright (c) 2023, Linaro Ltd. All rights reserved.<BR>
> +#
> +#  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
> +
> +[Sources]
> +  ArmCpuInfo.c
> +
> +[Packages]
> +  ArmPkg/ArmPkg.dec
> +  MdePkg/MdePkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +
> +[LibraryClasses]
> +  ArmLib
> +  UefiApplicationEntryPoint
> +  UefiLib
> diff --git a/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
> new file mode 100644
> index 000000000000..70d628a69ae9
> --- /dev/null
> +++ b/ArmPkg/Application/ArmCpuInfo/ArmCpuInfo.c
> @@ -0,0 +1,2427 @@
> +/** @file
> +  Application to present AArch64 cpu information.
> +
> +Copyright (c) 2023, Linaro Ltd. All rights reserved.<BR>
> +
> +SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Library/UefiLib.h>
> +#include <Library/ArmLib/AArch64/AArch64Lib.h>
> +
> +// We cannot assume GCC extensions to be present so let use
> +// binary numbers via enum.
> +// Arm ARM uses binary numbers so this way it is more readable.
> +enum {
> +  b0000,
> +  b0001,
> +  b0010,
> +  b0011,
> +  b0100,
> +  b0101,
> +  b0110,
> +  b0111,
> +  b1000,
> +  b1001,
> +  b1010,
> +  b1011,
> +  b1100,
> +  b1101,
> +  b1110,
> +  b1111
> +};
> +
> +/**
> +  Print formatted table line.
> +
> +  Values can be empty if only new description line is needed.
> +
> +  @param[in] Field       name of system register
> +  @param[in] Bits        bits of system register
> +  @param[in] Value       value of those bits
> +  @param[in] Description meaning of value
> +**/
> +VOID
> +PrintText (
> +  CONST CHAR8  *Field,
> +  CONST CHAR8  *Bits,
> +  CONST CHAR8  *Value,
> +  CONST CHAR8  *Description
> +  )
> +{
> +  AsciiPrint (" %-16a | %5a | %5a | %a\n", Field, Bits, Value, Description);
> +}
> +
> +/**
> +  Print formatted table line with value printed in binary.
> +
> +  @param[in] Field       name of system register
> +  @param[in] Bits        bits of system register
> +  @param[in] Value       value of those bits
> +  @param[in] Description meaning of value
> +**/
> +VOID
> +PrintValues (
> +  CONST CHAR8  *Field,
> +  CONST CHAR8  *Bits,
> +  CONST UINT8  Value,
> +  CONST CHAR8  *Description
> +  )
> +{
> +  STATIC CONST CHAR8  Nibbles[][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, Nibbles[Value & 0xf], Description);
> +}
> +
> +/**
> +  Print spacer for results table.
> +**/
> +VOID
> +PrintSpacer (
> +  VOID
> +  )
> +{
> +  AsciiPrint ("------------------|-------|-------|----------------------------------------------\n");
> +}
> +
> +/**
> +  Handle ID_AA64DFR0_EL1 system register
> +
> +  @param[in] Aa64Dfr0  value of ID_AA64DFR0_EL1 system register
> +**/
> +VOID
> +HandleAa64Dfr0 (
> +  CONST UINT64  Aa64Dfr0
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64DFR0";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = (Aa64Dfr0 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0110:
> +      Description = "Armv8 debug architecture";
> +      break;
> +    case b0111:
> +      Description = "Armv8 debug architecture with VHE";
> +      break;
> +    case b1000:
> +      Description = "FEAT_Debugv8p2 implemented.";
> +      break;
> +    case b1001:
> +      Description = "FEAT_Debugv8p4 implemented.";
> +      break;
> +    case b1010:
> +      Description = "FEAT_Debugv8p8 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Dfr0 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Trace unit System registers not implemented.";
> +      break;
> +    case b0001:
> +      Description = "Trace unit System registers implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "11:8 ";
> +  Value = (Aa64Dfr0 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Performance Monitors Extension not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_PMUv3 implemented.";
> +      break;
> +    case b0100:
> +      Description = "FEAT_PMUv3p1 implemented.";
> +      break;
> +    case b0101:
> +      Description = "FEAT_PMUv3p4 implemented.";
> +      break;
> +    case b0110:
> +      Description = "FEAT_PMUv3p5 implemented.";
> +      break;
> +    case b0111:
> +      Description = "FEAT_PMUv3p7 implemented.";
> +      break;
> +    case b1000:
> +      Description = "FEAT_PMUv3p8 implemented.";
> +      break;
> +    case b1111:
> +      Description = "IMPLEMENTATION DEFINED form of performance monitors supported.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "15:12";
> +  Value = (Aa64Dfr0 >> 12) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "reserved";
> +      break;
> +    default:
> +      Description = "Number of breakpoints, minus 1.";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 19:16 reserved
> +
> +  Bits  = "23:20";
> +  Value = (Aa64Dfr0 >> 20) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "reserved";
> +      break;
> +    default:
> +      Description = "Number of watchpoints, minus 1.";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 27:24 reserved
> +
> +  Bits  = "31:28";
> +  Value = (Aa64Dfr0 >> 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 = (Aa64Dfr0 >> 32) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SPE not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SPE implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_SPEv1p1 implemented.";
> +      break;
> +    case b0011:
> +      Description = "FEAT_SPEv1p2 implemented.";
> +      break;
> +    case b0100:
> +      Description = "FEAT_SPEv1p3 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "39:36";
> +  Value = (Aa64Dfr0 >> 36) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_DoubleLock implemented.";
> +      break;
> +    case b1111:
> +      Description = "FEAT_DoubleLock not implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "43:40";
> +  Value = (Aa64Dfr0 >> 40) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_TRF not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_TRF implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "47:44";
> +  Value = (Aa64Dfr0 >> 44) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_TRBE not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_TRBE implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "51:48";
> +  Value = (Aa64Dfr0 >> 48) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_MTPMU not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_MTPMU and FEAT_PMUv3 implemented.";
> +      break;
> +    case b1111:
> +      Description = "FEAT_MTPMU not implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "55:52";
> +  Value = (Aa64Dfr0 >> 52) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_BRBE not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_BRBE implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_BRBEv1p1 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 59:56 reserved
> +
> +  Bits  = "63:60";
> +  Value = (Aa64Dfr0 >> 60) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Setting MDCR_EL2.HPMN to zero has CONSTRAINED UNPREDICTABLE behavior.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_HPMN0 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +}
> +
> +/**
> +  Handle ID_AA64ISAR0_EL1 system register
> +
> +  @param[in] Aa64Isar0  value of ID_AA64ISAR0_EL1 system register
> +**/
> +VOID
> +HandleAa64Isar0 (
> +  CONST UINT64  Aa64Isar0
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR0";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  // 3:0 reserved
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Isar0 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_AES, FEAT_PMULL not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_AES implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_AES and FEAT_PMULL implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "11:8 ";
> +  Value = (Aa64Isar0 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SHA1 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SHA1 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "15:12";
> +  Value = (Aa64Isar0 >> 12) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SHA256, FEAT_SHA512 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SHA256 implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_SHA512 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "19:16";
> +  Value = (Aa64Isar0 >> 16) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "CRC32 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "CRC32 instructions implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "23:20";
> +  Value = (Aa64Isar0 >> 20) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_LSE not implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_LSE implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "27:24";
> +  Value = (Aa64Isar0 >> 24) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "TME instructions not implemented.";
> +      break;
> +    case b0001:
> +      Description = "TME instructions implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "31:28";
> +  Value = (Aa64Isar0 >> 28) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_RDM not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_RDM implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "35:32";
> +  Value = (Aa64Isar0 >> 32) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SHA3 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SHA3 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "39:36";
> +  Value = (Aa64Isar0 >> 36) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SM3 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SM3 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "43:40";
> +  Value = (Aa64Isar0 >> 40) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SM4 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SM4 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "47:44";
> +  Value = (Aa64Isar0 >> 44) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_DotProd not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_DotProd implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "51:48";
> +  Value = (Aa64Isar0 >> 48) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_FHM not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_FHM implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "55:52";
> +  Value = (Aa64Isar0 >> 52) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_FlagM/FEAT_FlagM2 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_FlagM implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_FlagM2 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "59:56";
> +  Value = (Aa64Isar0 >> 56) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_TLBIOS/FEAT_TLBIRANGE not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_TLBIOS implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_TLBIRANGE implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "63:60";
> +  Value = (Aa64Isar0 >> 60) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_RNG not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_RNG implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +}
> +
> +/**
> +  Handle ID_AA64ISAR1_EL1 system register
> +
> +  @param[in] Aa64Isar1  value of ID_AA64ISAR1_EL1 system register
> +**/
> +VOID
> +HandleAa64Isar1 (
> +  CONST UINT64  Aa64Isar1
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR1";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = (Aa64Isar1 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "DC CVAP not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_DPB implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_DPB2 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Isar1 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Address Authentication  (APA) not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_PAuth implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_EPAC implemented.";
> +      break;
> +    case b0011:
> +      Description = "FEAT_PAuth2 implemented.";
> +      break;
> +    case b0100:
> +      Description = "FEAT_FPAC implemented.";
> +      break;
> +    case b0101:
> +      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 = (Aa64Isar1 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Address Authentication  (API) not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_PAuth implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_EPAC implemented.";
> +      break;
> +    case b0011:
> +      Description = "FEAT_PAuth2 implemented.";
> +      break;
> +    case b0100:
> +      Description = "FEAT_FPAC implemented.";
> +      break;
> +    case b0101:
> +      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 = (Aa64Isar1 >> 12) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_JSCVT not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_JSCVT implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "19:16";
> +  Value = (Aa64Isar1 >> 16) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_FCMA not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_FCMA implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "23:20";
> +  Value = (Aa64Isar1 >> 20) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_LRCPC (2) not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_LRCPC implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_LRCPC2 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "27:24";
> +  Value = (Aa64Isar1 >> 24) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_PACQARMA5 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_PACQARMA5 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "31:28";
> +  Value = (Aa64Isar1 >> 28) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_PACIMP not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_PACIMP implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "35:32";
> +  Value = (Aa64Isar1 >> 32) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_FRINTTS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_FRINTTS implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "39:36";
> +  Value = (Aa64Isar1 >> 36) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SB not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SB implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "43:40";
> +  Value = (Aa64Isar1 >> 40) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SPECRES not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SPECRES implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "47:44";
> +  Value = (Aa64Isar1 >> 44) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_BF16 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_BF16 implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_EBF16 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "51:48";
> +  Value = (Aa64Isar1 >> 48) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_DGH not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_DGH implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "55:52";
> +  Value = (Aa64Isar1 >> 52) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_I8MM not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_I8MM implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "59:56";
> +  Value = (Aa64Isar1 >> 56) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_XS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_XS implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "63:60";
> +  Value = (Aa64Isar1 >> 60) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_LS64 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_LS64 implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_LS64_V implemented.";
> +      break;
> +    case b0011:
> +      Description = "FEAT_LS64_ACCDATA implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +}
> +
> +/**
> +  Handle ID_AA64ISAR2_EL1 system register
> +
> +  @param[in] Aa64Isar2  value of ID_AA64ISAR2_EL1 system register
> +**/
> +VOID
> +HandleAa64Isar2 (
> +  CONST UINT64  Aa64Isar2
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64ISAR2";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = (Aa64Isar2 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_WFxT not implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_WFxT implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Isar2 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_RPRES not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_RPRES implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "11:8 ";
> +  Value = (Aa64Isar2 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_PACQARMA3 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_PACQARMA3 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "15:12";
> +  Value = (Aa64Isar2 >> 12) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Address Authentication  (APA3) not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_PAuth implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_EPAC implemented.";
> +      break;
> +    case b0011:
> +      Description = "FEAT_PAuth2 implemented.";
> +      break;
> +    case b0100:
> +      Description = "FEAT_FPAC implemented.";
> +      break;
> +    case b0101:
> +      Description = "FEAT_FPACCOMBINE implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "19:16";
> +  Value = (Aa64Isar2 >> 16) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_MOPS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_MOPS implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "23:20";
> +  Value = (Aa64Isar2 >> 20) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_HBC not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_HBC implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "27:24";
> +  Value = (Aa64Isar2 >> 24) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_CONSTPACFIELD not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_CONSTPACFIELD implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 63:28 reserved
> +}
> +
> +/**
> +  Handle ID_AA64MMFR0_EL1 system register
> +
> +  @param[in] Aa64Mmfr0  value of ID_AA64MMFR0_EL1 system register
> +**/
> +VOID
> +HandleAa64Mmfr0 (
> +  CONST UINT64  Aa64Mmfr0
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR0";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = Aa64Mmfr0 & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "32 Bits  (4GB) of physical address range supported.";
> +      break;
> +    case b0001:
> +      Description = "36 Bits  (64GB) of physical address range supported.";
> +      break;
> +    case b0010:
> +      Description = "40 Bits  (1TB) of physical address range supported.";
> +      break;
> +    case b0011:
> +      Description = "42 Bits  (4TB) of physical address range supported.";
> +      break;
> +    case b0100:
> +      Description = "44 Bits  (16TB) of physical address range supported.";
> +      break;
> +    case b0101:
> +      Description = "48 Bits  (256TB) of physical address range supported.";
> +      break;
> +    case b0110:
> +      Description = "52 Bits  (4PB) of physical address range supported.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +  if (Value == b0110) {
> +    PrintText ("", "", "", "FEAT_LPA implemented.");
> +  }
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Mmfr0 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "ASID: 8 Bits";
> +      break;
> +    case b0010:
> +      Description = "ASID: 16 Bits";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "11:8 ";
> +  Value = (Aa64Mmfr0 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "No mixed-endian support.";
> +      break;
> +    case b0001:
> +      Description = "Mixed-endian support.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // If mixed-endian is present, check whether supported at EL0
> +  if (((Aa64Mmfr0 >>  8) & 0xf) != b0000 ) {
> +    if (((Aa64Mmfr0 >> 16) & 0xf) == b0000 ) {
> +      PrintValues ("ID_AA64MMFR0", "19:16", b0000, "No mixed-endian support at EL0.");
> +    }
> +
> +    if (((Aa64Mmfr0 >> 16) & 0xf) == b0001 ) {
> +      PrintValues ("ID_AA64MMFR0", "19:16", b0001, "Mixed-endian support at EL0.");
> +    }
> +  }
> +
> +  Bits  = "15:12";
> +  Value = (Aa64Mmfr0 >> 12) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "No support for a distinction between Secure and Non-Secure Memory.";
> +      break;
> +    case b0001:
> +      Description = "Supports a distinction between Secure and Non-Secure Memory.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "31:28";
> +  Value = (Aa64Mmfr0 >> 28) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = " 4KB granule supported.";
> +      break;
> +    case b1111:
> +      Description = " 4KB granule not supported.";
> +      break;
> +    case b0001:
> +      Description = " 4KB granule supported for 52-bit address.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "43:40";
> +  Value = (Aa64Mmfr0 >> 40) & 0xf;
> +  switch (Value) {
> +    case b0001:
> +      Description = " 4KB granule not supported at stage 2.";
> +      break;
> +    case b0010:
> +      Description = " 4KB granule supported at stage 2.";
> +      break;
> +    case b0011:
> +      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 = (Aa64Mmfr0 >> 20) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "16KB granule not supported.";
> +      break;
> +    case b0001:
> +      Description = "16KB granule supported.";
> +      break;
> +    case b0010:
> +      Description = "16KB granule supported for 52-bit address.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "35:32";
> +  Value = (Aa64Mmfr0 >> 32) & 0xf;
> +  switch (Value) {
> +    case b0001:
> +      Description = "16KB granule not supported at stage 2.";
> +      break;
> +    case b0010:
> +      Description = "16KB granule supported at stage 2.";
> +      break;
> +    case b0011:
> +      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 = (Aa64Mmfr0 >> 24) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "64KB granule supported.";
> +      break;
> +    case b1111:
> +      Description = "64KB granule not supported.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "39:36";
> +  Value = (Aa64Mmfr0 >> 36) & 0xf;
> +  switch (Value) {
> +    case b0001:
> +      Description = "64KB granule not supported at stage 2.";
> +      break;
> +    case b0010:
> +      Description = "64KB granule supported at stage 2.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "47:44";
> +  Value = (Aa64Mmfr0 >> 44) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_ExS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_ExS implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 55:48 reserved
> +
> +  Bits  = "59:56";
> +  Value = (Aa64Mmfr0 >> 56) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_FGT not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_FGT implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "63:60";
> +  Value = (Aa64Mmfr0 >> 60) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_ECV not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_ECV implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_ECV implemented with extras.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +}
> +
> +/**
> +  Handle ID_AA64MMFR1_EL1 system register
> +
> +  @param[in] Aa64Mmfr1  value of ID_AA64MMFR1_EL1 system register
> +  @param[in] Aa64Pfr0,  value of ID_AA64PFR0_EL1 system register
> +**/
> +VOID
> +HandleAa64Mmfr1 (
> +  CONST UINT64  Aa64Mmfr1,
> +  CONST UINT64  Aa64Pfr0
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR1";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = Aa64Mmfr1 & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_HAFDBS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_HAFDBS implemented without dirty status support.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_HAFDBS implemented with dirty status support.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Mmfr1 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_VMID16 not implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_VMID16 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "11:8 ";
> +  Value = (Aa64Mmfr1 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_VHE not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_VHE implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "15:12";
> +  Value = (Aa64Mmfr1 >> 12) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_HPDS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_HPDS implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_HPDS2 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "19:16";
> +  Value = (Aa64Mmfr1 >> 16) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_LOR not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_LOR implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "23:20";
> +  Value = (Aa64Mmfr1 >> 20) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_PAN not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_PAN implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_PAN2 implemented.";
> +      break;
> +    case b0011:
> +      Description = "FEAT_PAN3 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // when FEAT_RAS implemented
> +  if ((((Aa64Pfr0 >> 28) & 0xf) == b0001) ||
> +      (((Aa64Pfr0 >> 28) & 0xf) == b0010))
> +  {
> +    if (((Aa64Mmfr1 >> 24) & 0xf) == b0000 ) {
> +      PrintValues ("ID_AA64MMFR1", "27:24", b0000, "The PE never generates an SError interrupt due to");
> +      PrintText ("", "", "", "an External abort on a speculative read.");
> +    }
> +
> +    if (((Aa64Mmfr1 >> 24) & 0xf) == b0001 ) {
> +      PrintValues ("ID_AA64MMFR1", "27:24", b0001, "The PE might generate an SError interrupt due to");
> +      PrintText ("", "", "", "an External abort on a speculative read.");
> +    }
> +  }
> +
> +  Bits  = "31:28";
> +  Value = (Aa64Mmfr1 >> 28) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_XNX not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_XNX implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "35:32";
> +  Value = (Aa64Mmfr1 >> 32) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_TWED not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_TWED implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "39:36";
> +  Value = (Aa64Mmfr1 >> 36) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_ETS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_ETS implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "43:40";
> +  Value = (Aa64Mmfr1 >> 40) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_HCX not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_HCX implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "47:44";
> +  Value = (Aa64Mmfr1 >> 44) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_AFP not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_AFP implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "51:48";
> +  Value = (Aa64Mmfr1 >> 48) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_nTLBPA not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_nTLBPA implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "55:52";
> +  Value = (Aa64Mmfr1 >> 52) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_TIDCP1 not implemented";
> +      break;
> +    case b0001:
> +      Description = "FEAT_TIDCP1 implemented";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "59:56";
> +  Value = (Aa64Mmfr1 >> 56) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_CMOW not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_CMOW implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 63:60 reserved
> +}
> +
> +/**
> +  Handle ID_AA64MMFR2_EL1 system register
> +
> +  @param[in] Aa64Mmfr2  value of ID_AA64MMFR2_EL1 system register
> +**/
> +VOID
> +HandleAa64Mmfr2 (
> +  CONST UINT64  Aa64Mmfr2
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64MMFR2";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = (Aa64Mmfr2)       & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_TTCNP not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_TTCNP implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Mmfr2 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_UAO not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_UAO implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "11:8 ";
> +  Value = (Aa64Mmfr2 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_LSMAOC not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_LSMAOC implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "15:12";
> +  Value = (Aa64Mmfr2 >> 12) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_IESB not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_IESB implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "19:16";
> +  Value = (Aa64Mmfr2 >> 16) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_LVA not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_LVA implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "23:20";
> +  Value = (Aa64Mmfr2 >> 20) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_CCIDX not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_CCIDX implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "27:24";
> +  Value = (Aa64Mmfr2 >> 24) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_NV not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_NV implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_NV2 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "31:28";
> +  Value = (Aa64Mmfr2 >> 28) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_TTST not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_TTST implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "35:32";
> +  Value = (Aa64Mmfr2 >> 32) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_LSE2 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_LSE2 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "39:36";
> +  Value = (Aa64Mmfr2 >> 36) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_IDST not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_IDST implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "43:40";
> +  Value = (Aa64Mmfr2 >> 40) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_S2FWB not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_S2FWB implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 47:44 reserved
> +
> +  Bits  = "51:48";
> +  Value = (Aa64Mmfr2 >> 48) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_TTL not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_TTL implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "55:52";
> +  Value = (Aa64Mmfr2 >> 52) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_BBM: Level 0 support for changing block size is supported.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_BBM: Level 1 support for changing block size is supported.";
> +      break;
> +    case b0010:
> +      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 = (Aa64Mmfr2 >> 56) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_EVT not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_EVT: HCR_EL2.{TOCU, TICAB, TID4} traps are supported.";
> +      break;
> +    case b0010:
> +      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 = (Aa64Mmfr2 >> 60) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_E0PD not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_E0PD implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +}
> +
> +/**
> +  Handle ID_AA64PFR0_EL1 system register
> +
> +  @param[in] Aa64Pfr0,  value of ID_AA64PFR0_EL1 system register
> +  @param[in] Aa64Pfr1,  value of ID_AA64PFR1_EL1 system register
> +**/
> +VOID
> +HandleAa64Pfr0 (
> +  CONST UINT64  Aa64Pfr0,
> +  CONST UINT64  Aa64Pfr1
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR0";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = (Aa64Pfr0)       & 0xf;
> +  switch (Value) {
> +    case b0001:
> +      Description = "EL0 in AArch64 only";
> +      break;
> +    case b0010:
> +      Description = "EL0 in AArch64 and AArch32";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Pfr0 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0001:
> +      Description = "EL1 in AArch64 only";
> +      break;
> +    case b0010:
> +      Description = "EL1 in AArch64 and AArch32";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "11:8 ";
> +  Value = (Aa64Pfr0 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "EL2 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "EL2 in AArch64 only";
> +      break;
> +    case b0010:
> +      Description = "EL2 in AArch64 and AArch32";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "15:12";
> +  Value = (Aa64Pfr0 >> 12) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "EL3 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "EL3 in AArch64 only";
> +      break;
> +    case b0010:
> +      Description = "EL3 in AArch64 and AArch32";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "19:16";
> +  Value = (Aa64Pfr0 >> 16) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Floating-point implemented.";
> +      break;
> +    case b0001:
> +      Description = "Floating-point with half-precision support  (FEAT_FP16).";
> +      break;
> +    case b1111:
> +      Description = "Floating-point not implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "23:20";
> +  Value = (Aa64Pfr0 >> 20) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Advanced SIMD implemented.";
> +      break;
> +    case b0001:
> +      Description = "Advanced SIMD with half precision support  (FEAT_FP16).";
> +      break;
> +    case b1111:
> +      Description = "Advanced SIMD not implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "27:24";
> +  Value = (Aa64Pfr0 >> 24) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "System registers of GIC CPU not implemented.";
> +      break;
> +    case b0001:
> +      Description = "System registers to versions 3.0/4.0 of GIC CPU implemented.";
> +      break;
> +    case b0011:
> +      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 = (Aa64Pfr0 >> 28) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_RAS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_RAS implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_RASv1p1 implemented.";
> +      // b0010 FEAT_RASv1p1 implemented and, if EL3 is implemented, FEAT_DoubleFault implemented.
> +      if ((((Aa64Pfr0 >> 12) & 0xf) == b0001) ||
> +          (((Aa64Pfr0 >> 12) & 0xf) == b0010))
> +      {
> +        Description = "FEAT_RASv1p1 implemented. FEAT_DoubleFault implemented.";
> +      }
> +
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +  if (Value == b0001) {
> +    if (((Aa64Pfr1 >> 12) & 0xf) == b0001 ) {
> +      PrintValues ("ID_AA64PRF1", "15:12", b0001, "FEAT_RASv1p1 implemented.");
> +    }
> +  }
> +
> +  Bits  = "35:32";
> +  Value = (Aa64Pfr0 >> 32) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SVE not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SVE implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "39:36";
> +  Value = (Aa64Pfr0 >> 36) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Secure EL2 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "Secure EL2 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "43:40";
> +  Value = (Aa64Pfr0 >> 40) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      if (((Aa64Pfr1 >> 16) & 0xf) == b0000 ) {
> +        Description = "FEAT_MPAM not implemented.";
> +      }
> +
> +      if (((Aa64Pfr1 >> 16) & 0xf) == b0001 ) {
> +        Description = "FEAT_MPAM v0.1 implemented.";
> +      }
> +
> +      break;
> +    case b0001:
> +      if (((Aa64Pfr1 >> 16) & 0xf) == b0000 ) {
> +        Description = "FEAT_MPAM v1.0 implemented.";
> +      }
> +
> +      if (((Aa64Pfr1 >> 16) & 0xf) == b0001 ) {
> +        Description = "FEAT_MPAM v1.1 implemented.";
> +      }
> +
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "47:44";
> +  Value = (Aa64Pfr0 >> 44) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_AMU not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_AMUv1 implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_AMUv1p1 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "51:48";
> +  Value = (Aa64Pfr0 >> 48) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_DIT not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_DIT implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "55:52";
> +  Value = (Aa64Pfr0 >> 52) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_RME not implemented";
> +      break;
> +    case b0001:
> +      Description = "FEAT_RME implemented";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "59:56";
> +  Value = (Aa64Pfr0 >> 56) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "Not disclosed whether FEAT_CSV2 is implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_CSV2 implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_CSV2_2 implemented.";
> +      break;
> +    case b0011:
> +      Description = "FEAT_CSV2_3 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +  if (Value == b0001) {
> +    if (((Aa64Pfr1 >> 32) & 0xf) == b0001 ) {
> +      PrintValues ("ID_AA64PRF1", "35:32", b0001, "FEAT_CSV2_1p1 implemented.");
> +    }
> +
> +    if (((Aa64Pfr1 >> 32) & 0xf) == b0010 ) {
> +      PrintValues ("ID_AA64PRF1", "35:32", b0010, "FEAT_CSV2_1p2 implemented.");
> +    }
> +  }
> +
> +  Bits  = "63:60";
> +  Value = (Aa64Pfr0 >> 60) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_CSV3 not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_CSV3 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +}
> +
> +/**
> +  Handle ID_AA64PFR1_EL1 system register
> +
> +  @param[in] Aa64Pfr1  value of ID_AA64PFR1_EL1 system register
> +**/
> +VOID
> +HandleAa64Pfr1 (
> +  CONST UINT64  Aa64Pfr1
> +  )
> +{
> +  UINT64              Value;
> +  STATIC CONST CHAR8  RegName[] = "ID_AA64PFR1";
> +  CONST CHAR8         *Description;
> +  CONST CHAR8         *Bits;
> +
> +  Bits  = "3:0 ";
> +  Value = Aa64Pfr1 & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_BTI not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_BTI implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "7:4 ";
> +  Value = (Aa64Pfr1 >>  4) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SSBS not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SSBS implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_SSBS2 implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "11:8 ";
> +  Value = (Aa64Pfr1 >>  8) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_MTE not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_MTE implemented.";
> +      break;
> +    case b0010:
> +      Description = "FEAT_MTE2 implemented.";
> +      break;
> +    case b0011:
> +      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 = (Aa64Pfr1 >> 24) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_SME not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_SME implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  Bits  = "31:28";
> +  Value = (Aa64Pfr1 >> 28) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_RNG_TRAP not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_RNG_TRAP implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 35:32 is CSV2_frac
> +
> +  Bits  = "39:36";
> +  Value = (Aa64Pfr1 >> 36) & 0xf;
> +  switch (Value) {
> +    case b0000:
> +      Description = "FEAT_NMI not implemented.";
> +      break;
> +    case b0001:
> +      Description = "FEAT_NMI implemented.";
> +      break;
> +    default:
> +      Description = "unknown";
> +      break;
> +  }
> +
> +  PrintValues (RegName, Bits, Value, Description);
> +
> +  // 63:40 are reserved
> +}
> +
> +/**
> +  The user Entry Point for Application. The user code starts with this function
> +  as the real entry point for the application.
> +
> +  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
> +  @param[in] SystemTable    A pointer to the EFI System Table.
> +
> +  @retval EFI_SUCCESS       The entry point is executed successfully.
> +  @retval other             Some error occurs when executing this entry point.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +UefiMain (
> +  IN EFI_HANDLE        ImageHandle,
> +  IN EFI_SYSTEM_TABLE  *SystemTable
> +  )
> +{
> +  UINT64  Aa64Dfr0;
> +  UINT64  Aa64Isar0;
> +  UINT64  Aa64Isar1;
> +  UINT64  Aa64Isar2;
> +  UINT64  Aa64Mmfr0;
> +  UINT64  Aa64Mmfr1;
> +  UINT64  Aa64Mmfr2;
> +  UINT64  Aa64Pfr0;
> +  UINT64  Aa64Pfr1;
> +
> +  Aa64Dfr0  = ArmReadIdAA64Dfr0 ();
> +  Aa64Isar0 = ArmReadIdAA64Isar0 ();
> +  Aa64Isar1 = ArmReadIdAA64Isar1 ();
> +  Aa64Isar2 = ArmReadIdAA64Isar2 ();
> +  Aa64Mmfr0 = ArmReadIdAA64Mmfr0 ();
> +  Aa64Mmfr1 = ArmReadIdAA64Mmfr1 ();
> +  Aa64Mmfr2 = ArmReadIdAA64Mmfr2 ();
> +  Aa64Pfr0  = ArmReadIdAA64Pfr0 ();
> +  Aa64Pfr1  = ArmReadIdAA64Pfr1 ();
> +
> +  AsciiPrint ("ID_AA64MMFR0_EL1 = 0x%016lx\n", Aa64Mmfr0);
> +  AsciiPrint ("ID_AA64MMFR1_EL1 = 0x%016lx\n", Aa64Mmfr1);
> +  AsciiPrint ("ID_AA64MMFR2_EL1 = 0x%016lx\n", Aa64Mmfr2);
> +  AsciiPrint ("ID_AA64PFR0_EL1  = 0x%016lx\n", Aa64Pfr0);
> +  AsciiPrint ("ID_AA64PFR1_EL1  = 0x%016lx\n", Aa64Pfr1);
> +  AsciiPrint ("ID_AA64ISAR0_EL1 = 0x%016lx\n", Aa64Isar0);
> +  AsciiPrint ("ID_AA64ISAR1_EL1 = 0x%016lx\n", Aa64Isar1);
> +  AsciiPrint ("ID_AA64ISAR2_EL1 = 0x%016lx\n", Aa64Isar2);
> +  AsciiPrint ("ID_AA64DFR0_EL1  = 0x%016lx\n", Aa64Dfr0);
> +  AsciiPrint ("\n");
> +
> +  PrintText ("Register", "Bits", "Value", "Feature");
> +  PrintSpacer ();
> +
> +  HandleAa64Mmfr0 (Aa64Mmfr0);
> +  PrintSpacer ();
> +  HandleAa64Mmfr1 (Aa64Mmfr1, Aa64Pfr0);
> +  PrintSpacer ();
> +  HandleAa64Mmfr2 (Aa64Mmfr2);
> +
> +  PrintSpacer ();
> +  HandleAa64Pfr0 (Aa64Pfr0, Aa64Pfr1);
> +  PrintSpacer ();
> +  HandleAa64Pfr1 (Aa64Pfr1);
> +
> +  PrintSpacer ();
> +  HandleAa64Isar0 (Aa64Isar0);
> +  PrintSpacer ();
> +  HandleAa64Isar1 (Aa64Isar1);
> +  PrintSpacer ();
> +  HandleAa64Isar2 (Aa64Isar2);
> +
> +  PrintSpacer ();
> +  HandleAa64Dfr0 (Aa64Dfr0);
> +
> +  return EFI_SUCCESS;
> +}
> -- 
> 2.40.0
> 

^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2023-04-21 20:18 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-03-31 18:02 [PATCH] add ArmCpuInfo EFI application Marcin Juszkiewicz
2023-04-06 21:05 ` [edk2-devel] " Rebecca Cran
2023-04-07 10:39   ` [PATCH v2] " Marcin Juszkiewicz
2023-04-07 10:55     ` [edk2-devel] " Ard Biesheuvel
2023-04-07 12:46       ` Marcin Juszkiewicz
2023-04-07 13:07         ` Ard Biesheuvel
2023-04-07 12:47       ` [PATCH v3] " Marcin Juszkiewicz
2023-04-07 13:02         ` [edk2-devel] " Pedro Falcato
2023-04-07 13:05           ` Pedro Falcato
2023-04-07 13:29           ` Marcin Juszkiewicz
2023-04-07 13:40             ` Pedro Falcato
2023-04-07 13:41               ` Pedro Falcato
2023-04-07 13:42               ` Marcin Juszkiewicz
2023-04-07 14:02           ` [PATCH v4] " Marcin Juszkiewicz
     [not found]           ` <1753ABF1A296B040.11304@groups.io>
2023-04-07 15:11             ` [edk2-devel] " Marcin Juszkiewicz
2023-04-07 15:29             ` [PATCH v5 0/2] add ArmCpuInfo application Marcin Juszkiewicz
2023-04-07 15:29               ` [PATCH v5 1/2] ArmLib: add functions to read system registers Marcin Juszkiewicz
2023-04-20 10:54                 ` Leif Lindholm
2023-04-07 15:29               ` [PATCH v5 2/2] add ArmCpuInfo EFI application Marcin Juszkiewicz
2023-04-20 12:43                 ` Leif Lindholm
2023-04-20 14:42                   ` [edk2-devel] " Marcin Juszkiewicz
2023-04-20 14:44                   ` [PATCH v6 1/2] ArmLib: add functions to read system registers Marcin Juszkiewicz
2023-04-20 14:44                     ` [PATCH v6 2/2] add ArmCpuInfo EFI application Marcin Juszkiewicz
2023-04-20 17:29                       ` Leif Lindholm
2023-04-21 14:37                         ` [edk2-devel] " Rebecca Cran
2023-04-21 14:59                           ` Marcin Juszkiewicz
2023-04-21 15:15                             ` Rebecca Cran
2023-04-21 15:51                               ` [PATCH v7 1/2] ArmLib: add functions to read system registers Marcin Juszkiewicz
2023-04-21 15:51                                 ` [PATCH v7 2/2] add ArmCpuInfo EFI application Marcin Juszkiewicz
2023-04-21 20:18                                   ` Leif Lindholm
2023-04-21 16:33                           ` [edk2-devel] [PATCH v6 " Leif Lindholm
2023-04-13  9:31               ` [PATCH v5 0/2] add ArmCpuInfo application Marcin Juszkiewicz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox