Skip to content

Commit 4a5c450

Browse files
committed
Configure individual PMP regions in TOR mode
Implements region configuration that validates addresses, constructs configuration bytes with proper addressing mode and permission bits, and synchronizes both hardware CSRs and shadow state. Supports optional region locking to prevent further modification.
1 parent 9e814c0 commit 4a5c450

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

arch/riscv/pmp.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,3 +186,60 @@ int32_t pmp_init_kernel(pmp_config_t *config)
186186
{
187187
return pmp_init_pools(config, kernel_mempools, KERNEL_MEMPOOL_COUNT);
188188
}
189+
190+
int32_t pmp_set_region(pmp_config_t *config, const pmp_region_t *region)
191+
{
192+
if (!config || !region)
193+
return ERR_PMP_INVALID_REGION;
194+
195+
/* Validate region index is within bounds */
196+
if (region->region_id >= PMP_MAX_REGIONS)
197+
return ERR_PMP_INVALID_REGION;
198+
199+
/* Validate address range */
200+
if (region->addr_start >= region->addr_end)
201+
return ERR_PMP_ADDR_RANGE;
202+
203+
/* Check if region is already locked */
204+
if (config->regions[region->region_id].locked)
205+
return ERR_PMP_LOCKED;
206+
207+
uint8_t region_idx = region->region_id;
208+
uint8_t pmpcfg_idx = region_idx / 4;
209+
uint8_t pmpcfg_offset = (region_idx % 4) * 8;
210+
211+
/* Build configuration byte with TOR mode and permissions */
212+
uint8_t pmpcfg_perm = region->permissions & (PMPCFG_R | PMPCFG_W | PMPCFG_X);
213+
uint8_t pmpcfg_byte = PMPCFG_A_TOR | pmpcfg_perm;
214+
if (region->locked)
215+
pmpcfg_byte |= PMPCFG_L;
216+
217+
/* Read current pmpcfg register to preserve other regions */
218+
uint32_t pmpcfg_val = read_pmpcfg(pmpcfg_idx);
219+
220+
/* Clear the configuration byte for this region */
221+
pmpcfg_val &= ~(0xFFU << pmpcfg_offset);
222+
223+
/* Write new configuration byte */
224+
pmpcfg_val |= (pmpcfg_byte << pmpcfg_offset);
225+
226+
/* Write pmpaddr register with the upper boundary */
227+
write_pmpaddr(region_idx, region->addr_end);
228+
229+
/* Write pmpcfg register with updated configuration */
230+
write_pmpcfg(pmpcfg_idx, pmpcfg_val);
231+
232+
/* Update shadow configuration */
233+
config->regions[region_idx].addr_start = region->addr_start;
234+
config->regions[region_idx].addr_end = region->addr_end;
235+
config->regions[region_idx].permissions = region->permissions;
236+
config->regions[region_idx].priority = region->priority;
237+
config->regions[region_idx].region_id = region_idx;
238+
config->regions[region_idx].locked = region->locked;
239+
240+
/* Update region count if this is a newly used region */
241+
if (region_idx >= config->region_count)
242+
config->region_count = region_idx + 1;
243+
244+
return ERR_OK;
245+
}

0 commit comments

Comments
 (0)