Skip to content

Commit f484ff0

Browse files
committed
Handle PMP access faults with dynamic region loading
When a task accesses memory that is not currently loaded in a PMP region, the hardware raises an access fault. Rather than immediately panicking, we now attempt to recover by dynamically loading the required region. This enables a task to access more memory than can fit simultaneously in the 16 available hardware regions. If all regions are in use, we select a victim region and evict it to make space. This requires exposing internal region management functions in the public header so the handler can invoke them. Simplify function documentation at implementation sites since detailed documentation now resides in headers. Address register read helpers are marked unused as the current implementation maintains shadow state in memory rather than reading hardware registers. They remain available for potential future use cases requiring hardware state verification.
1 parent ce1a02d commit f484ff0

File tree

5 files changed

+92
-28
lines changed

5 files changed

+92
-28
lines changed

arch/riscv/hal.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <sys/task.h>
44

55
#include "csr.h"
6+
#include "pmp.h"
67
#include "private/stdio.h"
78
#include "private/utils.h"
89

@@ -294,6 +295,12 @@ void do_trap(uint32_t cause, uint32_t epc)
294295
const char *reason = "Unknown exception";
295296
if (code < ARRAY_SIZE(exc_msg) && exc_msg[code])
296297
reason = exc_msg[code];
298+
299+
/* Attempt to recover PMP access faults */
300+
if ((code == 5 || code == 7) && pmp_handle_access_fault(epc, code == 7) == 0)
301+
return;
302+
303+
/* All other exceptions are fatal */
297304
printf("[EXCEPTION] code=%u (%s), epc=%08x, cause=%08x\n", code, reason,
298305
epc, cause);
299306
hal_panic();

arch/riscv/pmp.c

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <hal.h>
77
#include <sys/memprot.h>
8+
#include <sys/task.h>
89
#include "csr.h"
910
#include "pmp.h"
1011
#include "private/error.h"
@@ -42,8 +43,13 @@ static void write_pmpcfg(uint8_t idx, uint32_t val)
4243
}
4344
}
4445

45-
/* Read PMP address register by index (0-15) */
46-
static uint32_t read_pmpaddr(uint8_t idx)
46+
/* Read PMP address register by index (0-15)
47+
*
48+
* Currently unused as the implementation maintains shadow state in memory
49+
* rather than reading hardware registers. Provided for API completeness
50+
* and potential future use cases requiring hardware state verification.
51+
*/
52+
static uint32_t __attribute__((unused)) read_pmpaddr(uint8_t idx)
4753
{
4854
switch (idx) {
4955
case 0: return read_csr_num(CSR_PMPADDR0);
@@ -382,3 +388,40 @@ int32_t pmp_check_access(const pmp_config_t *config, uint32_t addr,
382388
/* Access not covered by any region */
383389
return 0;
384390
}
391+
392+
int32_t pmp_handle_access_fault(uint32_t epc, uint8_t is_write)
393+
{
394+
if (!kcb || !kcb->task_current || !kcb->task_current->data)
395+
return -1;
396+
397+
memspace_t *mspace = ((tcb_t *)kcb->task_current->data)->mspace;
398+
if (!mspace)
399+
return -1;
400+
401+
/* Find flexpage containing faulting address */
402+
fpage_t *target_fpage = NULL;
403+
for (fpage_t *fp = mspace->first; fp; fp = fp->as_next) {
404+
if (epc >= fp->base && epc < (fp->base + fp->size)) {
405+
target_fpage = fp;
406+
break;
407+
}
408+
}
409+
410+
if (!target_fpage || target_fpage->pmp_id != 0)
411+
return -1;
412+
413+
pmp_config_t *config = pmp_get_config();
414+
if (!config)
415+
return -1;
416+
417+
/* Load into available region or evict victim */
418+
if (config->next_region_idx < PMP_MAX_REGIONS)
419+
return pmp_load_fpage(target_fpage, config->next_region_idx);
420+
421+
fpage_t *victim = select_victim_fpage(mspace);
422+
if (!victim)
423+
return -1;
424+
425+
int32_t ret = pmp_evict_fpage(victim);
426+
return (ret == 0) ? pmp_load_fpage(target_fpage, victim->pmp_id) : ret;
427+
}

arch/riscv/pmp.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,15 @@ int32_t pmp_init_pools(pmp_config_t *config, const mempool_t *pools,
107107
* Returns 0 on success, or negative error code on failure.
108108
*/
109109
int32_t pmp_init_kernel(pmp_config_t *config);
110+
111+
/* Handles PMP access violations (exception codes 5 and 7).
112+
*
113+
* Attempts to recover from PMP access faults by loading the required memory
114+
* region into a hardware PMP region. If all 16 regions are in use, selects a
115+
* victim for eviction and reuses its region.
116+
*
117+
* @epc : Program counter where violation occurred
118+
* @is_write : 1 for store/AMO access (exception code 7), 0 for load (code 5)
119+
* Returns 0 on successful recovery, negative error code on failure.
120+
*/
121+
int32_t pmp_handle_access_fault(uint32_t epc, uint8_t is_write);

include/sys/memprot.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,26 @@ memspace_t *mo_memspace_create(uint32_t as_id, uint32_t shared);
105105
* @mspace : Pointer to memory space to destroy
106106
*/
107107
void mo_memspace_destroy(memspace_t *mspace);
108+
109+
/* PMP Hardware Loading Functions */
110+
111+
/* Loads a flexpage into a PMP hardware region.
112+
* @fpage : Pointer to flexpage to load
113+
* @region_idx : Hardware PMP region index (0-15)
114+
* Returns 0 on success, or negative error code on failure.
115+
*/
116+
int32_t pmp_load_fpage(fpage_t *fpage, uint8_t region_idx);
117+
118+
/* Evicts a flexpage from its PMP hardware region.
119+
* @fpage : Pointer to flexpage to evict
120+
* Returns 0 on success, or negative error code on failure.
121+
*/
122+
int32_t pmp_evict_fpage(fpage_t *fpage);
123+
124+
/* Victim Selection for PMP Region Eviction
125+
*
126+
* Selects a flexpage for eviction using priority-based algorithm.
127+
* @mspace : Pointer to memory space
128+
* Returns pointer to victim flexpage, or NULL if no evictable page found.
129+
*/
130+
fpage_t *select_victim_fpage(memspace_t *mspace);

kernel/memprot.c

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,7 @@ void mo_fpage_destroy(fpage_t *fpage)
4242
free(fpage);
4343
}
4444

45-
/* Selects victim flexpage for eviction using priority-based algorithm.
46-
*
47-
* @mspace : Pointer to memory space
48-
* Returns pointer to victim flexpage, or NULL if no evictable page found.
49-
*/
45+
/* Selects victim flexpage for eviction using priority-based algorithm */
5046
fpage_t *select_victim_fpage(memspace_t *mspace)
5147
{
5248
if (!mspace)
@@ -67,12 +63,7 @@ fpage_t *select_victim_fpage(memspace_t *mspace)
6763
return victim;
6864
}
6965

70-
/* Loads a flexpage into a PMP hardware region.
71-
*
72-
* @fpage : Pointer to flexpage to load
73-
* @region_idx : Hardware PMP region index (0-15)
74-
* Returns 0 on success, or negative error code on failure.
75-
*/
66+
/* Loads a flexpage into a PMP hardware region */
7667
int32_t pmp_load_fpage(fpage_t *fpage, uint8_t region_idx)
7768
{
7869
if (!fpage)
@@ -100,11 +91,7 @@ int32_t pmp_load_fpage(fpage_t *fpage, uint8_t region_idx)
10091
return ret;
10192
}
10293

103-
/* Evicts a flexpage from its PMP hardware region.
104-
*
105-
* @fpage : Pointer to flexpage to evict
106-
* Returns 0 on success, or negative error code on failure.
107-
*/
94+
/* Evicts a flexpage from its PMP hardware region */
10895
int32_t pmp_evict_fpage(fpage_t *fpage)
10996
{
11097
if (!fpage)
@@ -126,12 +113,7 @@ int32_t pmp_evict_fpage(fpage_t *fpage)
126113
return ret;
127114
}
128115

129-
/* Creates and initializes a memory space.
130-
*
131-
* @as_id : Memory space identifier
132-
* @shared : Whether this space can be shared across tasks
133-
* Returns pointer to created memory space, or NULL on failure.
134-
*/
116+
/* Creates and initializes a memory space */
135117
memspace_t *mo_memspace_create(uint32_t as_id, uint32_t shared)
136118
{
137119
memspace_t *mspace = malloc(sizeof(memspace_t));
@@ -147,10 +129,7 @@ memspace_t *mo_memspace_create(uint32_t as_id, uint32_t shared)
147129
return mspace;
148130
}
149131

150-
/* Destroys a memory space and all its flexpages.
151-
*
152-
* @mspace : Pointer to memory space to destroy
153-
*/
132+
/* Destroys a memory space and all its flexpages */
154133
void mo_memspace_destroy(memspace_t *mspace)
155134
{
156135
if (!mspace)

0 commit comments

Comments
 (0)