blob: 7588929180ab8f020665150c86b4928eac101dc1 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <sys/prctl.h>
#include "dexcr.h"
#include "utils.h"
static unsigned int dexcr;
static unsigned int hdexcr;
static unsigned int effective;
static void print_list(const char *list[], size_t len)
{
for (size_t i = 0; i < len; i++) {
printf("%s", list[i]);
if (i + 1 < len)
printf(", ");
}
}
static void print_dexcr(char *name, unsigned int bits)
{
const char *enabled_aspects[ARRAY_SIZE(aspects) + 1] = {NULL};
size_t j = 0;
printf("%s: 0x%08x", name, bits);
if (bits == 0) {
printf("\n");
return;
}
for (size_t i = 0; i < ARRAY_SIZE(aspects); i++) {
unsigned int mask = DEXCR_PR_BIT(aspects[i].index);
if (bits & mask) {
enabled_aspects[j++] = aspects[i].name;
bits &= ~mask;
}
}
if (bits)
enabled_aspects[j++] = "unknown";
printf(" (");
print_list(enabled_aspects, j);
printf(")\n");
}
static void print_aspect(const struct dexcr_aspect *aspect)
{
const char *attributes[8] = {NULL};
size_t j = 0;
unsigned long mask;
mask = DEXCR_PR_BIT(aspect->index);
if (dexcr & mask)
attributes[j++] = "set";
if (hdexcr & mask)
attributes[j++] = "set (hypervisor)";
if (!(effective & mask))
attributes[j++] = "clear";
printf("%12s %c (%d): ", aspect->name, effective & mask ? '*' : ' ', aspect->index);
print_list(attributes, j);
printf(" \t(%s)\n", aspect->desc);
}
static void print_aspect_config(const struct dexcr_aspect *aspect)
{
const char *reason = NULL;
const char *reason_hyp = NULL;
const char *reason_prctl = "no prctl";
bool actual = effective & DEXCR_PR_BIT(aspect->index);
bool expected = actual; /* Assume it's fine if we don't expect a specific set/clear value */
if (actual)
reason = "set by unknown";
else
reason = "cleared by unknown";
if (aspect->prctl != -1) {
int ctrl = pr_get_dexcr(aspect->prctl);
if (ctrl < 0) {
reason_prctl = "failed to read prctl";
} else {
if (ctrl & PR_PPC_DEXCR_CTRL_SET) {
reason_prctl = "set by prctl";
expected = true;
} else if (ctrl & PR_PPC_DEXCR_CTRL_CLEAR) {
reason_prctl = "cleared by prctl";
expected = false;
} else {
reason_prctl = "unknown prctl";
}
reason = reason_prctl;
}
}
if (hdexcr & DEXCR_PR_BIT(aspect->index)) {
reason_hyp = "set by hypervisor";
reason = reason_hyp;
expected = true;
} else {
reason_hyp = "not modified by hypervisor";
}
printf("%12s (%d): %-28s (%s, %s)\n",
aspect->name,
aspect->index,
reason,
reason_hyp,
reason_prctl);
/*
* The checks are not atomic, so this can technically trigger if the
* hypervisor makes a change while we are checking each source. It's
* far more likely to be a bug if we see this though.
*/
if (actual != expected)
printf(" : ! actual %s does not match config\n", aspect->name);
}
int main(int argc, char *argv[])
{
if (!dexcr_exists()) {
printf("DEXCR not detected on this hardware\n");
return 1;
}
dexcr = get_dexcr(DEXCR);
hdexcr = get_dexcr(HDEXCR);
effective = dexcr | hdexcr;
printf("current status:\n");
print_dexcr(" DEXCR", dexcr);
print_dexcr(" HDEXCR", hdexcr);
print_dexcr("Effective", effective);
printf("\n");
for (size_t i = 0; i < ARRAY_SIZE(aspects); i++)
print_aspect(&aspects[i]);
printf("\n");
if (effective & DEXCR_PR_NPHIE) {
printf("DEXCR[NPHIE] enabled: hashst/hashchk ");
if (hashchk_triggers())
printf("working\n");
else
printf("failed to trigger\n");
} else {
printf("DEXCR[NPHIE] disabled: hashst/hashchk ");
if (hashchk_triggers())
printf("unexpectedly triggered\n");
else
printf("ignored\n");
}
printf("\n");
printf("configuration:\n");
for (size_t i = 0; i < ARRAY_SIZE(aspects); i++)
print_aspect_config(&aspects[i]);
printf("\n");
return 0;
}