@@ -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
15001502struct 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 */
15791713static 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