@@ -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
14991501struct 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 */
15781713static 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