@@ -197,7 +197,7 @@ enum OtEGBoardDevice {
197197
198198#define OT_EG_IBEX_WRAPPER_NUM_REGIONS 2u
199199
200- static const uint8_t ot_eg_pmp_cfgs [] = {
200+ static uint8_t ot_eg_pmp_cfgs [] = {
201201 /* clang-format off */
202202 IBEX_PMP_CFG (0 , IBEX_PMP_MODE_OFF , 0 , 0 , 0 ),
203203 IBEX_PMP_CFG (0 , IBEX_PMP_MODE_OFF , 0 , 0 , 0 ),
@@ -218,7 +218,7 @@ static const uint8_t ot_eg_pmp_cfgs[] = {
218218 /* clang-format on */
219219};
220220
221- static const uint32_t ot_eg_pmp_addrs [] = {
221+ static uint32_t ot_eg_pmp_addrs [] = {
222222 /* clang-format off */
223223 IBEX_PMP_ADDR (0x00000000 ),
224224 IBEX_PMP_ADDR (0x00000000 ),
@@ -1492,6 +1492,8 @@ struct OtEGMachineState {
14921492 bool no_epmp_cfg ;
14931493 bool ignore_elf_entry ;
14941494 bool verilator ;
1495+ /* ePMP region specification string */
1496+ char * epmp_regions ;
14951497};
14961498
14971499struct OtEGMachineClass {
@@ -1553,6 +1555,118 @@ static void ot_eg_soc_flash_ctrl_configure(
15531555 }
15541556}
15551557
1558+ /*
1559+ * Parse and apply the PMP configuration specification provided as a property.
1560+ *
1561+ * The specification string contains one or more region configurations separated
1562+ * by `#` characters. Each configuration has the following syntax:
1563+ *
1564+ * <region index>:<address>:<mode>:<flags>`
1565+ *
1566+ * - `<region index>` is the zero-based index of the region to configure.
1567+ * - `<address>` is the hexadecimal address field for the region.
1568+ * - `<mode>` is one of the following ePMP region modes: `OFF`, `TOR`, `NA4`, or `NAPOT`.
1569+ * - `<flags>` is a set of the following uppercase characters denoting region flags.
1570+ *
1571+ * The supported flags are:
1572+ *
1573+ * - `L`: locked
1574+ * - `R`: readable
1575+ * - `W`: writable
1576+ * - `X`: executable
1577+ */
1578+ static void ot_eg_soc_configure_pmp (OtEGMachineState * ms , Error * * errp ) {
1579+ const char * config = ms -> epmp_regions ;
1580+
1581+ /* escape early if config is empty */
1582+ if (config == NULL || * config == '\0' ) {
1583+ return ;
1584+ }
1585+
1586+ while (true) {
1587+ char idx_str [3 ] = {0 };
1588+ char addr_str [9 ] = {0 };
1589+ char mode_str [6 ] = {0 };
1590+ char flags [5 ] = {0 };
1591+ unsigned len ;
1592+
1593+ /* 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 );
1595+
1596+ /* only accept when all parts of the configuration were present */
1597+ if (parsed != 4 ) {
1598+ error_setg (errp , "bad epmp format: expected 4 parts, got %d" , parsed );
1599+ return ;
1600+ }
1601+
1602+ /* parse the index */
1603+ unsigned pmp_idx = strtol (idx_str , NULL , 10 );
1604+
1605+ /* parse the address as hex */
1606+ target_ulong addr = strtol (addr_str , NULL , 16 );
1607+
1608+ /* parse the mode */
1609+ unsigned mode ;
1610+ if (strncmp (mode_str , "OFF" , 3 ) == 0 ) {
1611+ mode = IBEX_PMP_MODE_OFF ;
1612+ } else if (strncmp (mode_str , "TOR" , 3 ) == 0 ) {
1613+ mode = IBEX_PMP_MODE_TOR ;
1614+ } else if (strncmp (mode_str , "NA4" , 3 ) == 0 ) {
1615+ mode = IBEX_PMP_MODE_NA4 ;
1616+ } else if (strncmp (mode_str , "NAPOT" , 5 ) == 0 ) {
1617+ mode = IBEX_PMP_MODE_NAPOT ;
1618+ } else {
1619+ error_setg (errp , "bad mode %s, expected `OFF`, `TOR`, `NA4`, or `NAPOT`" , mode_str );
1620+ return ;
1621+ }
1622+
1623+ /* parse the flags */
1624+ bool l = false, r = false, w = false, x = false;
1625+ for (unsigned i = 0 ; flags [i ]; i ++ ) {
1626+ switch (flags [i ]) {
1627+ case 'L' :
1628+ l = true;
1629+ break ;
1630+ case 'R' :
1631+ r = true;
1632+ break ;
1633+ case 'W' :
1634+ w = true;
1635+ break ;
1636+ case 'X' :
1637+ x = true;
1638+ break ;
1639+ default :
1640+ error_setg (errp , "bad flag %c, expected `L`, `R`, `W`, or `X`" , flags [i ]);
1641+ return ;
1642+ }
1643+ }
1644+
1645+ /* prepare the `PMPCFG` and `PMPADDR` codes */
1646+ uint8_t pmpcfg = IBEX_PMP_CFG (l , mode , x , w , r );
1647+ target_ulong pmpaddr = IBEX_PMP_ADDR (addr );
1648+
1649+ (void )pmp_idx ;
1650+ (void )pmpcfg ;
1651+ (void )pmpaddr ;
1652+ ot_eg_pmp_cfgs [pmp_idx ] = pmpcfg ;
1653+ ot_eg_pmp_addrs [pmp_idx ] = pmpaddr ;
1654+
1655+ /* determine whether there are more configurations to parse */
1656+ if (config [len ] == '#' ) {
1657+ config = config + len + 1 ;
1658+ continue ;
1659+ }
1660+
1661+ if (config [len ] == '\0' ) {
1662+ break ;
1663+ }
1664+
1665+ error_setg (errp , "bad region format, expected `,` or end of string, got %c" , config [len ]);
1666+ return ;
1667+ }
1668+ }
1669+
15561670static void ot_eg_soc_hart_configure (DeviceState * dev , const IbexDeviceDef * def ,
15571671 DeviceState * parent )
15581672{
@@ -1566,6 +1680,8 @@ static void ot_eg_soc_hart_configure(DeviceState *dev, const IbexDeviceDef *def,
15661680 return ;
15671681 }
15681682
1683+ ot_eg_soc_configure_pmp (ms , & error_fatal );
1684+
15691685 pmp_cfg = qlist_new ();
15701686 for (unsigned ix = 0 ; ix < ARRAY_SIZE (ot_eg_pmp_cfgs ); ix ++ ) {
15711687 qlist_append_int (pmp_cfg , ot_eg_pmp_cfgs [ix ]);
@@ -2006,6 +2122,28 @@ static void ot_eg_machine_set_verilator(Object *obj, bool value, Error **errp)
20062122 s -> verilator = value ;
20072123}
20082124
2125+ static char * ot_eg_machine_get_epmp_regions (Object * obj , Error * * errp )
2126+ {
2127+ OtEGMachineState * s = RISCV_OT_EG_MACHINE (obj );
2128+ (void )errp ;
2129+
2130+ return s -> epmp_regions ;
2131+ }
2132+
2133+ static void ot_eg_machine_set_epmp_regions (Object * obj , const char * value , Error * * errp )
2134+ {
2135+ OtEGMachineState * s = RISCV_OT_EG_MACHINE (obj );
2136+ (void )errp ;
2137+
2138+ if (s -> epmp_regions ) {
2139+ free (s -> epmp_regions );
2140+ }
2141+
2142+ size_t len = strlen (value ) + 1 ;
2143+ s -> epmp_regions = g_malloc (len );
2144+ strlcpy (s -> epmp_regions , value , len );
2145+ }
2146+
20092147static ResettableState * ot_eg_machine_get_reset_state (Object * obj )
20102148{
20112149 OtEGMachineState * s = RISCV_OT_EG_MACHINE (obj );
@@ -2047,6 +2185,10 @@ static void ot_eg_machine_instance_init(Object *obj)
20472185 object_property_add_bool (obj , "verilator" , & ot_eg_machine_get_verilator ,
20482186 & ot_eg_machine_set_verilator );
20492187 object_property_set_description (obj , "verilator" , "Use Verilator clocks" );
2188+ object_property_add_str (obj , "epmp-regions" , & ot_eg_machine_get_epmp_regions ,
2189+ & ot_eg_machine_set_epmp_regions );
2190+ object_property_set_description (obj , "epmp-regions" ,
2191+ "Set default ePMP memory region configuration" );
20502192}
20512193
20522194static void ot_eg_machine_init (MachineState * state )
0 commit comments