Skip to content

Commit 09c061f

Browse files
committed
[ot] hw/riscv: ot_earlgrey: allow regions to be configured
Signed-off-by: James Wainwright <[email protected]>
1 parent 39ae5e4 commit 09c061f

File tree

2 files changed

+160
-2
lines changed

2 files changed

+160
-2
lines changed

docs/opentitan/earlgrey.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,22 @@ See [`tools.md`](tools.md)
146146
`-M ot-earlgrey,no_epmp_cfg=true` to disable the initial ePMP configuration, which can be very
147147
useful to execute arbitrary code on the Ibex core without requiring an OT ROM image to boot up.
148148

149+
* `epmp_regions=<specification>` can be appended to the machine switch, _i.e._
150+
`-M ot-earlgrey,epmp_regions=1:00000000:OFF:FL#2:0000bffc:NAPOT:FLRX` to configure the default
151+
ePMP regions at startup. The specification string describes one or more regions separated with
152+
a '#' character. Each region specification has the following syntax:
153+
`<region index>:<address>:<mode>:<flags>` where:
154+
155+
- `<region index>` is the zero-based index of the region to configure.
156+
- `<address>` is the hexadecimal address field for the region.
157+
- `<mode>` is one of the following ePMP region modes: `OFF`, `TOR`, `NA4`, or `NAPOT`.
158+
- `<flags>` is a set of the following uppercase characters denoting region flags:
159+
160+
- `L`: locked
161+
- `R`: readable
162+
- `W`: writable
163+
- `X`: executable
164+
149165
* `ignore_elf_entry=true` can be appended to the machine option switch, _i.e._
150166
`-M ot-earlgrey,ignore_elf_entry=true` to prevent the ELF entry point of a loaded application to
151167
update the vCPU reset vector at startup. When this option is used, with `-kernel` option for

hw/riscv/ot_earlgrey.c

Lines changed: 144 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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

14971499
struct 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+
15561670
static 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+
20092147
static 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

20522194
static void ot_eg_machine_init(MachineState *state)

0 commit comments

Comments
 (0)