2525 */
2626
2727#include "qemu/osdep.h"
28+ #include <string.h>
2829#include "qemu/error-report.h"
2930#include "qemu/typedefs.h"
3031#include "qapi/error.h"
@@ -197,7 +198,7 @@ enum OtEGBoardDevice {
197198
198199#define OT_EG_IBEX_WRAPPER_NUM_REGIONS 2u
199200
200- static const uint8_t ot_eg_pmp_cfgs [] = {
201+ static uint8_t ot_eg_pmp_cfgs [] = {
201202 /* clang-format off */
202203 IBEX_PMP_CFG (0 , IBEX_PMP_MODE_OFF , 0 , 0 , 0 ),
203204 IBEX_PMP_CFG (0 , IBEX_PMP_MODE_OFF , 0 , 0 , 0 ),
@@ -218,7 +219,7 @@ static const uint8_t ot_eg_pmp_cfgs[] = {
218219 /* clang-format on */
219220};
220221
221- static const uint32_t ot_eg_pmp_addrs [] = {
222+ static uint32_t ot_eg_pmp_addrs [] = {
222223 /* clang-format off */
223224 IBEX_PMP_ADDR (0x00000000 ),
224225 IBEX_PMP_ADDR (0x00000000 ),
@@ -1492,6 +1493,8 @@ struct OtEGMachineState {
14921493 bool no_epmp_cfg ;
14931494 bool ignore_elf_entry ;
14941495 bool verilator ;
1496+ /* ePMP region specification string */
1497+ char * epmp_regions ;
14951498};
14961499
14971500struct OtEGMachineClass {
@@ -1553,6 +1556,126 @@ static void ot_eg_soc_flash_ctrl_configure(
15531556 }
15541557}
15551558
1559+ /*
1560+ * Parse and apply the PMP configuration specification provided as a property.
1561+ *
1562+ * The specification string contains one or more region configurations separated
1563+ * by `#` characters. Each configuration has the following syntax:
1564+ *
1565+ * <region index>:<address>:<mode>:<flags>`
1566+ *
1567+ * - `<region index>` is the zero-based index of the region to configure.
1568+ * - `<address>` is the hexadecimal address field for the region.
1569+ * - `<mode>` is an ePMP region mode: `OFF`, `TOR`, `NA4`, or `NAPOT`.
1570+ * - `<flags>` is a set of uppercase characters denoting thee region's flags.
1571+ *
1572+ * The supported flags are:
1573+ *
1574+ * - `L`: locked
1575+ * - `R`: readable
1576+ * - `W`: writable
1577+ * - `X`: executable
1578+ */
1579+ static void ot_eg_soc_configure_pmp (OtEGMachineState * ms , Error * * errp )
1580+ {
1581+ const char * config = ms -> epmp_regions ;
1582+
1583+ /* escape early if config is empty */
1584+ if (config == NULL || * config == '\0' ) {
1585+ return ;
1586+ }
1587+
1588+ while (true) {
1589+ char idx_str [3 ] = { 0 };
1590+ char addr_str [9 ] = { 0 };
1591+ char mode_str [6 ] = { 0 };
1592+ char flags [5 ] = { 0 };
1593+ unsigned len ;
1594+
1595+ /* extract one region configuration from the string */
1596+ int parsed = sscanf (config , "%2[0-9]:%8[0-9a-f]:%5[^:]:%4[LRWX]%n" ,
1597+ idx_str , addr_str , mode_str , flags , & len );
1598+
1599+ /* only accept when all parts of the configuration were present */
1600+ if (parsed != 4 ) {
1601+ error_setg (errp , "bad epmp format: expected 4 parts, got %d" ,
1602+ parsed );
1603+ return ;
1604+ }
1605+
1606+ /* parse the index */
1607+ unsigned pmp_idx = strtol (idx_str , NULL , 10 );
1608+
1609+ /* parse the address as hex */
1610+ target_ulong addr = strtol (addr_str , NULL , 16 );
1611+
1612+ /* parse the mode */
1613+ unsigned mode ;
1614+ if (strncmp (mode_str , "OFF" , 3 ) == 0 ) {
1615+ mode = IBEX_PMP_MODE_OFF ;
1616+ } else if (strncmp (mode_str , "TOR" , 3 ) == 0 ) {
1617+ mode = IBEX_PMP_MODE_TOR ;
1618+ } else if (strncmp (mode_str , "NA4" , 3 ) == 0 ) {
1619+ mode = IBEX_PMP_MODE_NA4 ;
1620+ } else if (strncmp (mode_str , "NAPOT" , 5 ) == 0 ) {
1621+ mode = IBEX_PMP_MODE_NAPOT ;
1622+ } else {
1623+ error_setg (errp ,
1624+ "bad mode %s, expected `OFF`, `TOR`, `NA4`, or `NAPOT`" ,
1625+ mode_str );
1626+ return ;
1627+ }
1628+
1629+ /* parse the flags */
1630+ bool l = false, r = false, w = false, x = false;
1631+ for (unsigned i = 0 ; flags [i ]; i ++ ) {
1632+ switch (flags [i ]) {
1633+ case 'L' :
1634+ l = true;
1635+ break ;
1636+ case 'R' :
1637+ r = true;
1638+ break ;
1639+ case 'W' :
1640+ w = true;
1641+ break ;
1642+ case 'X' :
1643+ x = true;
1644+ break ;
1645+ default :
1646+ error_setg (errp , "bad flag %c, expected `L`, `R`, `W`, or `X`" ,
1647+ flags [i ]);
1648+ return ;
1649+ }
1650+ }
1651+
1652+ /* prepare the `PMPCFG` and `PMPADDR` codes */
1653+ uint8_t pmpcfg = IBEX_PMP_CFG (l , mode , x , w , r );
1654+ target_ulong pmpaddr = IBEX_PMP_ADDR (addr );
1655+
1656+ (void )pmp_idx ;
1657+ (void )pmpcfg ;
1658+ (void )pmpaddr ;
1659+ ot_eg_pmp_cfgs [pmp_idx ] = pmpcfg ;
1660+ ot_eg_pmp_addrs [pmp_idx ] = pmpaddr ;
1661+
1662+ /* determine whether there are more configurations to parse */
1663+ if (config [len ] == '#' ) {
1664+ config = config + len + 1 ;
1665+ continue ;
1666+ }
1667+
1668+ if (config [len ] == '\0' ) {
1669+ break ;
1670+ }
1671+
1672+ error_setg (errp ,
1673+ "bad region format, expected `,` or end of string, got %c" ,
1674+ config [len ]);
1675+ return ;
1676+ }
1677+ }
1678+
15561679static void ot_eg_soc_hart_configure (DeviceState * dev , const IbexDeviceDef * def ,
15571680 DeviceState * parent )
15581681{
@@ -1566,6 +1689,8 @@ static void ot_eg_soc_hart_configure(DeviceState *dev, const IbexDeviceDef *def,
15661689 return ;
15671690 }
15681691
1692+ ot_eg_soc_configure_pmp (ms , & error_fatal );
1693+
15691694 pmp_cfg = qlist_new ();
15701695 for (unsigned ix = 0 ; ix < ARRAY_SIZE (ot_eg_pmp_cfgs ); ix ++ ) {
15711696 qlist_append_int (pmp_cfg , ot_eg_pmp_cfgs [ix ]);
@@ -2006,6 +2131,29 @@ static void ot_eg_machine_set_verilator(Object *obj, bool value, Error **errp)
20062131 s -> verilator = value ;
20072132}
20082133
2134+ static char * ot_eg_machine_get_epmp_regions (Object * obj , Error * * errp )
2135+ {
2136+ OtEGMachineState * s = RISCV_OT_EG_MACHINE (obj );
2137+ (void )errp ;
2138+
2139+ return s -> epmp_regions ;
2140+ }
2141+
2142+ static void
2143+ ot_eg_machine_set_epmp_regions (Object * obj , const char * value , Error * * errp )
2144+ {
2145+ OtEGMachineState * s = RISCV_OT_EG_MACHINE (obj );
2146+ (void )errp ;
2147+
2148+ if (s -> epmp_regions ) {
2149+ free (s -> epmp_regions );
2150+ }
2151+
2152+ size_t len = strlen (value ) + 1 ;
2153+ s -> epmp_regions = g_malloc (len );
2154+ strlcpy (s -> epmp_regions , value , len );
2155+ }
2156+
20092157static ResettableState * ot_eg_machine_get_reset_state (Object * obj )
20102158{
20112159 OtEGMachineState * s = RISCV_OT_EG_MACHINE (obj );
@@ -2047,6 +2195,11 @@ static void ot_eg_machine_instance_init(Object *obj)
20472195 object_property_add_bool (obj , "verilator" , & ot_eg_machine_get_verilator ,
20482196 & ot_eg_machine_set_verilator );
20492197 object_property_set_description (obj , "verilator" , "Use Verilator clocks" );
2198+ object_property_add_str (obj , "epmp-regions" ,
2199+ & ot_eg_machine_get_epmp_regions ,
2200+ & ot_eg_machine_set_epmp_regions );
2201+ object_property_set_description (
2202+ obj , "epmp-regions" , "Set default ePMP memory region configuration" );
20502203}
20512204
20522205static void ot_eg_machine_init (MachineState * state )
0 commit comments