@@ -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