173 lines
3.8 KiB
C
173 lines
3.8 KiB
C
// 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;
|
|
}
|