Skip to content

Commit 5d0bb34

Browse files
committed
[ot] target/riscv: ibex_csr: add PMP facade
Signed-off-by: James Wainwright <[email protected]>
1 parent 47c3795 commit 5d0bb34

File tree

2 files changed

+160
-4
lines changed

2 files changed

+160
-4
lines changed

docs/opentitan/earlgrey.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,11 @@ See [`tools.md`](tools.md)
161161
- `R`: readable
162162
- `W`: writable
163163
- `X`: executable
164+
- `F`: facade
165+
166+
The "facade" is a special flag which causes CSR reads and writes for this region not to have any
167+
effect on PMP logic, but still appear to have been successfully written to the CSRs. This can be
168+
used to change the ePMP regions for debugging or performance regions without Ibex knowing.
164169

165170
* `ignore_elf_entry=true` can be appended to the machine option switch, _i.e._
166171
`-M ot-earlgrey,ignore_elf_entry=true` to prevent the ELF entry point of a loaded application to

hw/riscv/ot_earlgrey.c

Lines changed: 155 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,6 +1495,8 @@ struct OtEGMachineState {
14951495
bool verilator;
14961496
/* ePMP region specification string */
14971497
char *epmp_regions;
1498+
/* Whether to redirect an PMP region's CSR reads and writes to the facade */
1499+
bool pmp_region_masked[MAX_RISCV_PMPS];
14981500
};
14991501

15001502
struct OtEGMachineClass {
@@ -1556,6 +1558,134 @@ static void ot_eg_soc_flash_ctrl_configure(
15561558
}
15571559
}
15581560

1561+
/* whether to apply a PMP CSR read/write hook */
1562+
static RISCVException pmp_predicate(CPURISCVState *env, int csrno)
1563+
{
1564+
if (riscv_cpu_cfg(env)->pmp) {
1565+
if (csrno <= CSR_PMPCFG3) {
1566+
uint32_t reg_index = csrno - CSR_PMPCFG0;
1567+
1568+
/* TODO: RV128 restriction check */
1569+
if ((reg_index & 1) && (riscv_cpu_mxl(env) == MXL_RV64)) {
1570+
return RISCV_EXCP_ILLEGAL_INST;
1571+
}
1572+
}
1573+
1574+
return RISCV_EXCP_NONE;
1575+
}
1576+
1577+
return RISCV_EXCP_ILLEGAL_INST;
1578+
}
1579+
1580+
/*
1581+
* Facades for PMP CSRs - reads and writes to masked regions end up here instead
1582+
* of the effective PMP configuration.
1583+
*/
1584+
static target_ulong reg_pmpcfg_facade[MAX_RISCV_PMPS / 4] = { 0 };
1585+
static target_ulong reg_pmpaddr_facade[MAX_RISCV_PMPS] = { 0 };
1586+
1587+
static RISCVException
1588+
read_pmpcfg_masked(CPURISCVState *env, int csrno, target_ulong *val)
1589+
{
1590+
OtEGMachineState *ms = RISCV_OT_EG_MACHINE(qdev_get_machine());
1591+
1592+
uint32_t reg_index = csrno - CSR_PMPCFG0;
1593+
1594+
/* each PMPCFG CSR covers four PMP regions; mask the affected parts */
1595+
target_ulong mask = 0;
1596+
for (unsigned i = 0; i < 4; i++) {
1597+
if (ms->pmp_region_masked[reg_index * 4 + i]) {
1598+
mask |= (0xff << (8 * i));
1599+
}
1600+
}
1601+
1602+
/* only read from the PMP if there are unmasked regions in this CSR */
1603+
if (mask != -1) {
1604+
*val = pmpcfg_csr_read(env, reg_index) & ~mask;
1605+
}
1606+
1607+
/* overlay the facade for masked regions */
1608+
*val |= (reg_pmpcfg_facade[reg_index] & mask);
1609+
1610+
return RISCV_EXCP_NONE;
1611+
}
1612+
1613+
static RISCVException
1614+
write_pmpcfg_masked(CPURISCVState *env, int csrno, target_ulong val)
1615+
{
1616+
OtEGMachineState *ms = RISCV_OT_EG_MACHINE(qdev_get_machine());
1617+
1618+
uint32_t reg_index = csrno - CSR_PMPCFG0;
1619+
1620+
/* each PMPCFG CSR covers four PMP regions; mask the affected parts */
1621+
target_ulong mask = 0;
1622+
for (unsigned i = 0; i < 4; i++) {
1623+
if (ms->pmp_region_masked[reg_index * 4 + i]) {
1624+
mask |= (0xff << (8 * i));
1625+
}
1626+
}
1627+
1628+
/* only write to the PMP config if there are unmasked regions in this CSR */
1629+
if (mask != -1) {
1630+
/* combine the current CSR value from the PMP with the facade */
1631+
target_ulong csr_val = pmpcfg_csr_read(env, reg_index) & mask;
1632+
csr_val |= val & ~mask;
1633+
pmpcfg_csr_write(env, reg_index, csr_val);
1634+
}
1635+
1636+
reg_pmpcfg_facade[reg_index] = val;
1637+
1638+
return RISCV_EXCP_NONE;
1639+
}
1640+
1641+
static RISCVException
1642+
read_pmpaddr_masked(CPURISCVState *env, int csrno, target_ulong *val)
1643+
{
1644+
OtEGMachineState *ms = RISCV_OT_EG_MACHINE(qdev_get_machine());
1645+
1646+
uint32_t reg_index = csrno - CSR_PMPADDR0;
1647+
1648+
/* if this region is masked, read from the facade instead of the PMP */
1649+
if (ms->pmp_region_masked[reg_index]) {
1650+
*val = reg_pmpaddr_facade[reg_index];
1651+
} else {
1652+
*val = pmpaddr_csr_read(env, reg_index);
1653+
}
1654+
1655+
return RISCV_EXCP_NONE;
1656+
}
1657+
1658+
static RISCVException
1659+
write_pmpaddr_masked(CPURISCVState *env, int csrno, target_ulong val)
1660+
{
1661+
OtEGMachineState *ms = RISCV_OT_EG_MACHINE(qdev_get_machine());
1662+
1663+
uint32_t reg_index = csrno - CSR_PMPADDR0;
1664+
1665+
/* if this region is masked, write to the facade instead of the PMP */
1666+
if (ms->pmp_region_masked[reg_index]) {
1667+
reg_pmpaddr_facade[reg_index] = val;
1668+
} else {
1669+
pmpaddr_csr_write(env, reg_index, val);
1670+
}
1671+
1672+
return RISCV_EXCP_NONE;
1673+
}
1674+
1675+
static riscv_csr_operations pmpcfg_masked = {
1676+
.name = "pmpcfg",
1677+
.predicate = pmp_predicate,
1678+
.read = read_pmpcfg_masked,
1679+
.write = write_pmpcfg_masked,
1680+
};
1681+
1682+
static riscv_csr_operations pmpaddr_masked = {
1683+
.name = "pmpaddr",
1684+
.predicate = pmp_predicate,
1685+
.read = read_pmpaddr_masked,
1686+
.write = write_pmpaddr_masked,
1687+
};
1688+
15591689
/*
15601690
* Parse and apply the PMP configuration specification provided as a property.
15611691
*
@@ -1575,11 +1705,23 @@ static void ot_eg_soc_flash_ctrl_configure(
15751705
* - `R`: readable
15761706
* - `W`: writable
15771707
* - `X`: executable
1708+
* - `F`: facade
1709+
*
1710+
* The "facade" flag causes writes to a region's CSRs to have no effect on PMP
1711+
* logic, but can still be read back as if they were successfully set.
15781712
*/
15791713
static void ot_eg_soc_configure_pmp(OtEGMachineState *ms, Error **errp)
15801714
{
15811715
const char *config = ms->epmp_regions;
15821716

1717+
/* configure the CSR hooks for all `PMPCFG` and `PMPADDR` CSRs */
1718+
for (int csr = CSR_PMPCFG0; csr <= CSR_PMPCFG3; csr++) {
1719+
riscv_set_csr_ops(csr, &pmpcfg_masked);
1720+
}
1721+
for (int csr = CSR_PMPADDR0; csr <= CSR_PMPADDR15; csr++) {
1722+
riscv_set_csr_ops(csr, &pmpaddr_masked);
1723+
}
1724+
15831725
/* escape early if config is empty */
15841726
if (config == NULL || *config == '\0') {
15851727
return;
@@ -1589,11 +1731,11 @@ static void ot_eg_soc_configure_pmp(OtEGMachineState *ms, Error **errp)
15891731
char idx_str[3] = { 0 };
15901732
char addr_str[9] = { 0 };
15911733
char mode_str[6] = { 0 };
1592-
char flags[5] = { 0 };
1734+
char flags[6] = { 0 };
15931735
unsigned len;
15941736

15951737
/* extract one region configuration from the string */
1596-
int parsed = sscanf(config, "%2[0-9]:%8[0-9a-f]:%5[^:]:%4[LRWX]%n",
1738+
int parsed = sscanf(config, "%2[0-9]:%8[0-9a-f]:%5[^:]:%5[LRWXF]%n",
15971739
idx_str, addr_str, mode_str, flags, &len);
15981740

15991741
/* only accept when all parts of the configuration were present */
@@ -1627,7 +1769,7 @@ static void ot_eg_soc_configure_pmp(OtEGMachineState *ms, Error **errp)
16271769
}
16281770

16291771
/* parse the flags */
1630-
bool l = false, r = false, w = false, x = false;
1772+
bool l = false, r = false, w = false, x = false, f = false;
16311773
for (unsigned i = 0; flags[i]; i++) {
16321774
switch (flags[i]) {
16331775
case 'L':
@@ -1642,8 +1784,12 @@ static void ot_eg_soc_configure_pmp(OtEGMachineState *ms, Error **errp)
16421784
case 'X':
16431785
x = true;
16441786
break;
1787+
case 'F':
1788+
f = true;
1789+
break;
16451790
default:
1646-
error_setg(errp, "bad flag %c, expected `L`, `R`, `W`, or `X`",
1791+
error_setg(errp,
1792+
"bad flag %c, expected `L`, `R`, `W`, `X`, or `F`",
16471793
flags[i]);
16481794
return;
16491795
}
@@ -1659,6 +1805,11 @@ static void ot_eg_soc_configure_pmp(OtEGMachineState *ms, Error **errp)
16591805
ot_eg_pmp_cfgs[pmp_idx] = pmpcfg;
16601806
ot_eg_pmp_addrs[pmp_idx] = pmpaddr;
16611807

1808+
/* remember if region is masked against the facade */
1809+
if (f) {
1810+
ms->pmp_region_masked[pmp_idx] = true;
1811+
}
1812+
16621813
/* determine whether there are more configurations to parse */
16631814
if (config[len] == '#') {
16641815
config = config + len + 1;

0 commit comments

Comments
 (0)