Skip to content

Commit 9d26137

Browse files
committed
[ot] target/riscv: ibex_csr: add PMP facade
Signed-off-by: James Wainwright <[email protected]>
1 parent bb869e5 commit 9d26137

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
@@ -1494,6 +1494,8 @@ struct OtEGMachineState {
14941494
bool verilator;
14951495
/* ePMP region specification string */
14961496
char *epmp_regions;
1497+
/* Whether to redirect each PMP region's CSR reads and writes to the facade */
1498+
bool pmp_region_masked[MAX_RISCV_PMPS];
14971499
};
14981500

14991501
struct OtEGMachineClass {
@@ -1555,6 +1557,135 @@ static void ot_eg_soc_flash_ctrl_configure(
15551557
}
15561558
}
15571559

1560+
/* whether to apply a PMP CSR read/write hook */
1561+
static RISCVException pmp_predicate(CPURISCVState *env, int csrno)
1562+
{
1563+
if (riscv_cpu_cfg(env)->pmp) {
1564+
if (csrno <= CSR_PMPCFG3) {
1565+
uint32_t reg_index = csrno - CSR_PMPCFG0;
1566+
1567+
/* TODO: RV128 restriction check */
1568+
if ((reg_index & 1) && (riscv_cpu_mxl(env) == MXL_RV64)) {
1569+
return RISCV_EXCP_ILLEGAL_INST;
1570+
}
1571+
}
1572+
1573+
return RISCV_EXCP_NONE;
1574+
}
1575+
1576+
return RISCV_EXCP_ILLEGAL_INST;
1577+
}
1578+
1579+
/*
1580+
* Facades for PMP CSRs - reads and writes to masked regions end up here instead
1581+
* of the effective PMP configuration.
1582+
*/
1583+
static target_ulong reg_pmpcfg_facade[MAX_RISCV_PMPS / 4] = { 0 };
1584+
static target_ulong reg_pmpaddr_facade[MAX_RISCV_PMPS] = { 0 };
1585+
1586+
static RISCVException read_pmpcfg_masked(CPURISCVState *env, int csrno,
1587+
target_ulong *val)
1588+
{
1589+
OtEGMachineState *ms = RISCV_OT_EG_MACHINE(qdev_get_machine());
1590+
1591+
uint32_t reg_index = csrno - CSR_PMPCFG0;
1592+
1593+
/* each PMPCFG CSR covers four PMP regions, determine which parts are masked */
1594+
target_ulong mask = 0;
1595+
for (unsigned i = 0; i < 4; i++) {
1596+
if (ms->pmp_region_masked[reg_index * 4 + i]) {
1597+
mask |= (0xff << (8 * i));
1598+
}
1599+
}
1600+
1601+
/* only read from the PMP config if there are unmasked regions in this CSR */
1602+
if (mask != -1) {
1603+
*val = pmpcfg_csr_read(env, reg_index) & ~mask;
1604+
}
1605+
1606+
/* overlay the facade for masked regions */
1607+
*val |= (reg_pmpcfg_facade[reg_index] & mask);
1608+
1609+
return RISCV_EXCP_NONE;
1610+
}
1611+
1612+
static RISCVException write_pmpcfg_masked(CPURISCVState *env, int csrno,
1613+
target_ulong val)
1614+
{
1615+
OtEGMachineState *ms = RISCV_OT_EG_MACHINE(qdev_get_machine());
1616+
1617+
uint32_t reg_index = csrno - CSR_PMPCFG0;
1618+
1619+
/* each PMPCFG CSR covers four PMP regions, determine which parts are masked */
1620+
target_ulong mask = 0;
1621+
for (unsigned i = 0; i < 4; i++) {
1622+
if (ms->pmp_region_masked[reg_index * 4 + i]) {
1623+
mask |= (0xff << (8 * i));
1624+
}
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 read_pmpaddr_masked(CPURISCVState *env, int csrno,
1642+
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 config */
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 write_pmpaddr_masked(CPURISCVState *env, int csrno,
1659+
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 config */
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+
15581689
/*
15591690
* Parse and apply the PMP configuration specification provided as a property.
15601691
*
@@ -1574,10 +1705,22 @@ static void ot_eg_soc_flash_ctrl_configure(
15741705
* - `R`: readable
15751706
* - `W`: writable
15761707
* - `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.
15771712
*/
15781713
static void ot_eg_soc_configure_pmp(OtEGMachineState *ms, Error **errp) {
15791714
const char *config = ms->epmp_regions;
15801715

1716+
/* configure the CSR hooks for all `PMPCFG` and `PMPADDR` CSRs */
1717+
for (unsigned csr = CSR_PMPCFG0; csr <= CSR_PMPCFG3; csr++) {
1718+
riscv_set_csr_ops(csr, &pmpcfg_masked);
1719+
}
1720+
for (unsigned csr = CSR_PMPADDR0; csr <= CSR_PMPADDR15; csr++) {
1721+
riscv_set_csr_ops(csr, &pmpaddr_masked);
1722+
}
1723+
15811724
/* escape early if config is empty */
15821725
if (config == NULL || *config == '\0') {
15831726
return;
@@ -1587,11 +1730,11 @@ static void ot_eg_soc_configure_pmp(OtEGMachineState *ms, Error **errp) {
15871730
unsigned pmp_idx;
15881731
target_ulong addr;
15891732
char mode_str[6] = {0};
1590-
char flags[5] = {0};
1733+
char flags[6] = {0};
15911734
unsigned len;
15921735

15931736
/* extract one region configuration from the string */
1594-
int parsed = sscanf(config, "%d:%8x:%5[^:]:%4[LRWX]%n", &pmp_idx, &addr, mode_str, flags, &len);
1737+
int parsed = sscanf(config, "%d:%8x:%5[^:]:%5[LRWXF]%n", &pmp_idx, &addr, mode_str, flags, &len);
15951738

15961739
/* only accept when all parts of the configuration were present */
15971740
if (parsed != 4) {
@@ -1615,7 +1758,7 @@ static void ot_eg_soc_configure_pmp(OtEGMachineState *ms, Error **errp) {
16151758
}
16161759

16171760
/* parse the flags */
1618-
bool l = false, r = false, w = false, x = false;
1761+
bool l = false, r = false, w = false, x = false, f = false;
16191762
for (unsigned i = 0; flags[i]; i++) {
16201763
switch (flags[i]) {
16211764
case 'L':
@@ -1630,8 +1773,11 @@ static void ot_eg_soc_configure_pmp(OtEGMachineState *ms, Error **errp) {
16301773
case 'X':
16311774
x = true;
16321775
break;
1776+
case 'F':
1777+
f = true;
1778+
break;
16331779
default:
1634-
error_setg(errp, "bad flag %c, expected `L`, `R`, `W`, or `X`", flags[i]);
1780+
error_setg(errp, "bad flag %c, expected `L`, `R`, `W`, `X`, or `F`", flags[i]);
16351781
abort();
16361782
}
16371783
}
@@ -1646,6 +1792,11 @@ static void ot_eg_soc_configure_pmp(OtEGMachineState *ms, Error **errp) {
16461792
ot_eg_pmp_cfgs[pmp_idx] = pmpcfg;
16471793
ot_eg_pmp_addrs[pmp_idx] = pmpaddr;
16481794

1795+
/* remember if region is masked against the facade */
1796+
if (f) {
1797+
ms->pmp_region_masked[pmp_idx] = true;
1798+
}
1799+
16491800
/* determine whether there are more configurations to parse */
16501801
if (config[len] == '#') {
16511802
config = config + len + 1;

0 commit comments

Comments
 (0)