@@ -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,110 @@ 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+ unsigned pmp_idx ;
1588+ target_ulong addr ;
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 , "%d:%8x:%5[^:]:%4[LRWX]%n" , & pmp_idx , & addr , 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+ abort ();
1600+ }
1601+
1602+ /* parse the mode */
1603+ unsigned mode ;
1604+ if (strncmp (mode_str , "OFF" , 3 ) == 0 ) {
1605+ mode = IBEX_PMP_MODE_OFF ;
1606+ } else if (strncmp (mode_str , "TOR" , 3 ) == 0 ) {
1607+ mode = IBEX_PMP_MODE_TOR ;
1608+ } else if (strncmp (mode_str , "NA4" , 3 ) == 0 ) {
1609+ mode = IBEX_PMP_MODE_NA4 ;
1610+ } else if (strncmp (mode_str , "NAPOT" , 5 ) == 0 ) {
1611+ mode = IBEX_PMP_MODE_NAPOT ;
1612+ } else {
1613+ error_setg (errp , "bad mode %s, expected `OFF`, `TOR`, `NA4`, or `NAPOT`" , mode_str );
1614+ abort ();
1615+ }
1616+
1617+ /* parse the flags */
1618+ bool l = false, r = false, w = false, x = false;
1619+ for (unsigned i = 0 ; flags [i ]; i ++ ) {
1620+ switch (flags [i ]) {
1621+ case 'L' :
1622+ l = true;
1623+ break ;
1624+ case 'R' :
1625+ r = true;
1626+ break ;
1627+ case 'W' :
1628+ w = true;
1629+ break ;
1630+ case 'X' :
1631+ x = true;
1632+ break ;
1633+ default :
1634+ error_setg (errp , "bad flag %c, expected `L`, `R`, `W`, or `X`" , flags [i ]);
1635+ abort ();
1636+ }
1637+ }
1638+
1639+ /* prepare the `PMPCFG` and `PMPADDR` codes */
1640+ uint8_t pmpcfg = IBEX_PMP_CFG (l , mode , x , w , r );
1641+ target_ulong pmpaddr = IBEX_PMP_ADDR (addr );
1642+
1643+ (void )pmp_idx ;
1644+ (void )pmpcfg ;
1645+ (void )pmpaddr ;
1646+ ot_eg_pmp_cfgs [pmp_idx ] = pmpcfg ;
1647+ ot_eg_pmp_addrs [pmp_idx ] = pmpaddr ;
1648+
1649+ /* determine whether there are more configurations to parse */
1650+ if (config [len ] == '#' ) {
1651+ config = config + len + 1 ;
1652+ continue ;
1653+ } else if (config [len ] == '\0' ) {
1654+ break ;
1655+ } else {
1656+ error_setg (errp , "bad region format, expected `,` or end of string, got %c" , config [len ]);
1657+ abort ();
1658+ }
1659+ }
1660+ }
1661+
15561662static void ot_eg_soc_hart_configure (DeviceState * dev , const IbexDeviceDef * def ,
15571663 DeviceState * parent )
15581664{
@@ -1566,6 +1672,8 @@ static void ot_eg_soc_hart_configure(DeviceState *dev, const IbexDeviceDef *def,
15661672 return ;
15671673 }
15681674
1675+ ot_eg_soc_configure_pmp (ms , & error_fatal );
1676+
15691677 pmp_cfg = qlist_new ();
15701678 for (unsigned ix = 0 ; ix < ARRAY_SIZE (ot_eg_pmp_cfgs ); ix ++ ) {
15711679 qlist_append_int (pmp_cfg , ot_eg_pmp_cfgs [ix ]);
@@ -2006,6 +2114,28 @@ static void ot_eg_machine_set_verilator(Object *obj, bool value, Error **errp)
20062114 s -> verilator = value ;
20072115}
20082116
2117+ static char * ot_eg_machine_get_epmp_regions (Object * obj , Error * * errp )
2118+ {
2119+ OtEGMachineState * s = RISCV_OT_EG_MACHINE (obj );
2120+ (void )errp ;
2121+
2122+ return s -> epmp_regions ;
2123+ }
2124+
2125+ static void ot_eg_machine_set_epmp_regions (Object * obj , const char * value , Error * * errp )
2126+ {
2127+ OtEGMachineState * s = RISCV_OT_EG_MACHINE (obj );
2128+ (void )errp ;
2129+
2130+ if (s -> epmp_regions ) {
2131+ free (s -> epmp_regions );
2132+ }
2133+
2134+ size_t len = strlen (value ) + 1 ;
2135+ s -> epmp_regions = g_malloc (len );
2136+ strcpy (s -> epmp_regions , value );
2137+ }
2138+
20092139static ResettableState * ot_eg_machine_get_reset_state (Object * obj )
20102140{
20112141 OtEGMachineState * s = RISCV_OT_EG_MACHINE (obj );
@@ -2047,6 +2177,10 @@ static void ot_eg_machine_instance_init(Object *obj)
20472177 object_property_add_bool (obj , "verilator" , & ot_eg_machine_get_verilator ,
20482178 & ot_eg_machine_set_verilator );
20492179 object_property_set_description (obj , "verilator" , "Use Verilator clocks" );
2180+ object_property_add_str (obj , "epmp-regions" , & ot_eg_machine_get_epmp_regions ,
2181+ & ot_eg_machine_set_epmp_regions );
2182+ object_property_set_description (obj , "epmp-regions" ,
2183+ "Set default ePMP memory region configuration" );
20502184}
20512185
20522186static void ot_eg_machine_init (MachineState * state )
0 commit comments