162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci
362306a36Sopenharmony_ci#include <errno.h>
462306a36Sopenharmony_ci#include <stddef.h>
562306a36Sopenharmony_ci#include <stdio.h>
662306a36Sopenharmony_ci#include <string.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "dexcr.h"
962306a36Sopenharmony_ci#include "utils.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_cistatic unsigned int dexcr;
1262306a36Sopenharmony_cistatic unsigned int hdexcr;
1362306a36Sopenharmony_cistatic unsigned int effective;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistruct dexcr_aspect {
1662306a36Sopenharmony_ci	const char *name;
1762306a36Sopenharmony_ci	const char *desc;
1862306a36Sopenharmony_ci	unsigned int index;
1962306a36Sopenharmony_ci};
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic const struct dexcr_aspect aspects[] = {
2262306a36Sopenharmony_ci	{
2362306a36Sopenharmony_ci		.name = "SBHE",
2462306a36Sopenharmony_ci		.desc = "Speculative branch hint enable",
2562306a36Sopenharmony_ci		.index = 0,
2662306a36Sopenharmony_ci	},
2762306a36Sopenharmony_ci	{
2862306a36Sopenharmony_ci		.name = "IBRTPD",
2962306a36Sopenharmony_ci		.desc = "Indirect branch recurrent target prediction disable",
3062306a36Sopenharmony_ci		.index = 3,
3162306a36Sopenharmony_ci	},
3262306a36Sopenharmony_ci	{
3362306a36Sopenharmony_ci		.name = "SRAPD",
3462306a36Sopenharmony_ci		.desc = "Subroutine return address prediction disable",
3562306a36Sopenharmony_ci		.index = 4,
3662306a36Sopenharmony_ci	},
3762306a36Sopenharmony_ci	{
3862306a36Sopenharmony_ci		.name = "NPHIE",
3962306a36Sopenharmony_ci		.desc = "Non-privileged hash instruction enable",
4062306a36Sopenharmony_ci		.index = 5,
4162306a36Sopenharmony_ci	},
4262306a36Sopenharmony_ci	{
4362306a36Sopenharmony_ci		.name = "PHIE",
4462306a36Sopenharmony_ci		.desc = "Privileged hash instruction enable",
4562306a36Sopenharmony_ci		.index = 6,
4662306a36Sopenharmony_ci	},
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic void print_list(const char *list[], size_t len)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	for (size_t i = 0; i < len; i++) {
5262306a36Sopenharmony_ci		printf("%s", list[i]);
5362306a36Sopenharmony_ci		if (i + 1 < len)
5462306a36Sopenharmony_ci			printf(", ");
5562306a36Sopenharmony_ci	}
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic void print_dexcr(char *name, unsigned int bits)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	const char *enabled_aspects[ARRAY_SIZE(aspects) + 1] = {NULL};
6162306a36Sopenharmony_ci	size_t j = 0;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	printf("%s: %08x", name, bits);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (bits == 0) {
6662306a36Sopenharmony_ci		printf("\n");
6762306a36Sopenharmony_ci		return;
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	for (size_t i = 0; i < ARRAY_SIZE(aspects); i++) {
7162306a36Sopenharmony_ci		unsigned int mask = DEXCR_PR_BIT(aspects[i].index);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci		if (bits & mask) {
7462306a36Sopenharmony_ci			enabled_aspects[j++] = aspects[i].name;
7562306a36Sopenharmony_ci			bits &= ~mask;
7662306a36Sopenharmony_ci		}
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (bits)
8062306a36Sopenharmony_ci		enabled_aspects[j++] = "unknown";
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	printf(" (");
8362306a36Sopenharmony_ci	print_list(enabled_aspects, j);
8462306a36Sopenharmony_ci	printf(")\n");
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic void print_aspect(const struct dexcr_aspect *aspect)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	const char *attributes[8] = {NULL};
9062306a36Sopenharmony_ci	size_t j = 0;
9162306a36Sopenharmony_ci	unsigned long mask;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	mask = DEXCR_PR_BIT(aspect->index);
9462306a36Sopenharmony_ci	if (dexcr & mask)
9562306a36Sopenharmony_ci		attributes[j++] = "set";
9662306a36Sopenharmony_ci	if (hdexcr & mask)
9762306a36Sopenharmony_ci		attributes[j++] = "set (hypervisor)";
9862306a36Sopenharmony_ci	if (!(effective & mask))
9962306a36Sopenharmony_ci		attributes[j++] = "clear";
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	printf("%12s %c (%d): ", aspect->name, effective & mask ? '*' : ' ', aspect->index);
10262306a36Sopenharmony_ci	print_list(attributes, j);
10362306a36Sopenharmony_ci	printf("  \t(%s)\n", aspect->desc);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ciint main(int argc, char *argv[])
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	if (!dexcr_exists()) {
10962306a36Sopenharmony_ci		printf("DEXCR not detected on this hardware\n");
11062306a36Sopenharmony_ci		return 1;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	dexcr = get_dexcr(DEXCR);
11462306a36Sopenharmony_ci	hdexcr = get_dexcr(HDEXCR);
11562306a36Sopenharmony_ci	effective = dexcr | hdexcr;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	print_dexcr("    DEXCR", dexcr);
11862306a36Sopenharmony_ci	print_dexcr("   HDEXCR", hdexcr);
11962306a36Sopenharmony_ci	print_dexcr("Effective", effective);
12062306a36Sopenharmony_ci	printf("\n");
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	for (size_t i = 0; i < ARRAY_SIZE(aspects); i++)
12362306a36Sopenharmony_ci		print_aspect(&aspects[i]);
12462306a36Sopenharmony_ci	printf("\n");
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	if (effective & DEXCR_PR_NPHIE) {
12762306a36Sopenharmony_ci		printf("DEXCR[NPHIE] enabled: hashst/hashchk ");
12862306a36Sopenharmony_ci		if (hashchk_triggers())
12962306a36Sopenharmony_ci			printf("working\n");
13062306a36Sopenharmony_ci		else
13162306a36Sopenharmony_ci			printf("failed to trigger\n");
13262306a36Sopenharmony_ci	} else {
13362306a36Sopenharmony_ci		printf("DEXCR[NPHIE] disabled: hashst/hashchk ");
13462306a36Sopenharmony_ci		if (hashchk_triggers())
13562306a36Sopenharmony_ci			printf("unexpectedly triggered\n");
13662306a36Sopenharmony_ci		else
13762306a36Sopenharmony_ci			printf("ignored\n");
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	return 0;
14162306a36Sopenharmony_ci}
142