@@ -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 (int csr = CSR_PMPCFG0 ; csr <= CSR_PMPCFG3 ; csr ++ ) {
1718+ riscv_set_csr_ops (csr , & pmpcfg_masked );
1719+ }
1720+ for (int 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 char idx_str [3 ] = {0 };
15881731 char addr_str [9 ] = {0 };
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 , "%2[0-9]:%8[0-9a-f]:%5[^:]:%4[LRWX ]%n" , idx_str , addr_str , mode_str , flags , & len );
1737+ int parsed = sscanf (config , "%2[0-9]:%8[0-9a-f]:%5[^:]:%5[LRWXF ]%n" , idx_str , addr_str , mode_str , flags , & len );
15951738
15961739 /* only accept when all parts of the configuration were present */
15971740 if (parsed != 4 ) {
@@ -1621,7 +1764,7 @@ static void ot_eg_soc_configure_pmp(OtEGMachineState *ms, Error **errp) {
16211764 }
16221765
16231766 /* parse the flags */
1624- bool l = false, r = false, w = false, x = false;
1767+ bool l = false, r = false, w = false, x = false, f = false ;
16251768 for (unsigned i = 0 ; flags [i ]; i ++ ) {
16261769 switch (flags [i ]) {
16271770 case 'L' :
@@ -1636,8 +1779,11 @@ static void ot_eg_soc_configure_pmp(OtEGMachineState *ms, Error **errp) {
16361779 case 'X' :
16371780 x = true;
16381781 break ;
1782+ case 'F' :
1783+ f = true;
1784+ break ;
16391785 default :
1640- error_setg (errp , "bad flag %c, expected `L`, `R`, `W`, or `X `" , flags [i ]);
1786+ error_setg (errp , "bad flag %c, expected `L`, `R`, `W`, `X`, or `F `" , flags [i ]);
16411787 return ;
16421788 }
16431789 }
@@ -1652,6 +1798,11 @@ static void ot_eg_soc_configure_pmp(OtEGMachineState *ms, Error **errp) {
16521798 ot_eg_pmp_cfgs [pmp_idx ] = pmpcfg ;
16531799 ot_eg_pmp_addrs [pmp_idx ] = pmpaddr ;
16541800
1801+ /* remember if region is masked against the facade */
1802+ if (f ) {
1803+ ms -> pmp_region_masked [pmp_idx ] = true;
1804+ }
1805+
16551806 /* determine whether there are more configurations to parse */
16561807 if (config [len ] == '#' ) {
16571808 config = config + len + 1 ;
0 commit comments