[Skiboot] [RFC PATCH] hw/phb4: Add fake scom to allow reading PHB registers / IODA tables
Oliver O'Halloran
oohall at gmail.com
Thu Apr 2 22:26:45 AEDT 2020
The motivation for this is largely so that I can have some way to
extracting PHB state in a post-secureboot world. Currently the way
this is done is by wacking the PHB registers directly using /dev/mem,
but that's pretty jank to begin with and with lockdown we can't do
that anyway.
What I figured we need is an architected way to access a register
space so this patch abuses to XSCOM API to do that. Each of the IODA
tables (and the PHB's HV regs) has a dedicated XSCOM "part id" which
can be used to access those registers from the host. Having a seperate
address space for the IODA tables is necessary since access them needs
to be done indirectly via the IODA_ADDR and IODA_DATA registers.
This setup works well enough for the non-config PHB registers and the
IODA tables since (like SCOMs) each register is 8 bytes. The cracks
start showing when you consider the root port config registers (part
of the HV register set) which only support four byte accesses. Moving
the config regs to a sepeate part ID would fix that, but eh.
The alternative would be something like adding a more generic set of
READ_REG / WRITE_REG OPAL calls which could handle things like varying
register access sizes, etc.
Comments welcome.
Not-Signed-off-by: Oliver O'Halloran <oohall at gmail.com>
---
hw/phb4.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 102 insertions(+)
diff --git a/hw/phb4.c b/hw/phb4.c
index 60e797cf6e61..733593d40632 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -1999,6 +1999,105 @@ static void __unused phb4_dump_peltv(struct phb4 *p)
}
}
+static struct ioda_table {
+ int index;
+ const char *name;
+} ioda_table_list[] = {
+ { IODA3_TBL_LIST, "list", },
+ { IODA3_TBL_MIST, "mist", },
+ { IODA3_TBL_RCAM, "rcam", },
+ { IODA3_TBL_MRT, "mrt", },
+ { IODA3_TBL_PESTA, "pesta", },
+ { IODA3_TBL_PESTB, "pestb", },
+ { IODA3_TBL_TVT, "tvt", },
+ { IODA3_TBL_TCAM, "tcam", },
+ { IODA3_TBL_TDR, "tdr", },
+ { IODA3_TBL_MBT, "mbt", },
+ { IODA3_TBL_MDT, "mdt", },
+ { IODA3_TBL_PEEV, "peev", },
+};
+
+static int64_t phb4_fake_scom_write(struct scom_controller *scom,
+ uint32_t chipid, uint64_t pcbaddr,
+ uint64_t val)
+{
+ (void) val;
+ (void) chipid;
+ (void) pcbaddr;
+ (void) scom;
+
+ return 0;
+}
+
+static int64_t phb4_fake_scom_read(struct scom_controller *scom,
+ uint32_t chipid, uint64_t pcbaddr,
+ uint64_t *val)
+{
+ struct phb4 *p = scom->private;
+
+ phb_lock(&p->phb);
+
+ if (chipid == p->chip_id) {
+ // FIXME: broken for the RC config space regs
+ *val = phb4_read_reg(p, pcbaddr);
+ } else {
+ /* otherwise it's an IODA reg, so go read that */
+ phb4_ioda_sel(p, chipid & 0x1f, pcbaddr, false);
+ *val = phb4_read_reg(p, PHB_IODA_DATA0);
+ }
+
+ phb_unlock(&p->phb);
+ return OPAL_SUCCESS;
+}
+
+static void phb4_register_fake_scom(struct phb4 *p)
+{
+ struct scom_controller *scom = zalloc(sizeof(*scom));
+ struct dt_node *regs, *n;
+ uint32_t chip_id;
+ int i;
+
+ if (!scom)
+ return;
+
+ chip_id = (0x2 << 28) | (p->phb.opal_id << 8);
+
+ /*
+ * FIXME: We probably want to have seperate "chip ids" for each
+ * ioda table so we can give each register range a sensible
+ * name.
+ */
+
+ regs = dt_new(p->phb.dt_node, "regs");
+ dt_add_property(regs, "scom-controller", NULL, 0);
+ dt_add_property_cells(regs, "ibm,chip-id", chip_id);
+
+ for (i = 0; i < ARRAY_SIZE(ioda_table_list); i++) {
+ int index = ioda_table_list[i].index;
+ struct scom_controller *scom;
+
+ scom = zalloc(sizeof(*scom));
+ if (!scom)
+ continue;
+
+ scom->private = p;
+ scom->part_id = chip_id | index;
+ scom->read = phb4_fake_scom_read;
+ scom->write = phb4_fake_scom_write;
+
+ if (scom_register(scom)) {
+ PHBERR(p, "Unable to add SCOM for IODA table %s\n",
+ ioda_table_list[i].name);
+ free(scom);
+ continue;
+ }
+
+ n = dt_new_addr(regs, ioda_table_list[i].name, index);
+ dt_add_property_cells(n, "ibm,chip-id", chip_id | index);
+ dt_add_property(n, "scom-controller", NULL, 0);
+ }
+}
+
static void __unused phb4_dump_ioda_table(struct phb4 *p, int table)
{
const char *name;
@@ -5814,6 +5913,9 @@ static void phb4_create(struct dt_node *np)
dt_add_property_string(np, "status", "okay");
+ if (nvram_query_eq_dangerous("ioda-scoms", "yes"))
+ phb4_register_fake_scom(p);
+
return;
failed:
--
2.21.1
More information about the Skiboot
mailing list