NMSIS-Core  Version 1.5.0
NMSIS-Core support for Nuclei processor-based devices
PMP Functions

Functions that related to the RISCV Phyiscal Memory Protection. More...

Data Structures

struct  pmp_config
 

Macros

#define PMPCFG_LIST_RV32_0_7    X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7)
 PMPCFG list for RV32 (indices 0-7) More...
 
#define PMPCFG_LIST_RV32_8_15    X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15)
 PMPCFG list for RV32 (indices 8-15) More...
 
#define PMPCFG_LIST_RV64_0_6    X(0) X(2) X(4) X(6)
 PMPCFG list for RV64 (even indices 0-6) More...
 
#define PMPCFG_LIST_RV64_8_14    X(8) X(10) X(12) X(14)
 PMPCFG list for RV64 (even indices 8-14) More...
 
#define PMPCFG_LIST   PMPCFG_LIST_RV32_0_7
 Select appropriate PMPCFG list based on architecture and PMP entry count. More...
 
#define PMPADDR_LIST_BASE    X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7)
 Base PMPADDR list (indices 0-7) More...
 
#define PMPADDR_LIST_8_15    X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15)
 Extended PMPADDR list (indices 8-15) More...
 
#define PMPADDR_LIST_16_31
 Extended PMPADDR list (indices 16-31) More...
 
#define PMPADDR_LIST_32_63
 Extended PMPADDR list (indices 32-63) More...
 
#define PMPADDR_LIST   PMPADDR_LIST_BASE PMPADDR_LIST_8_15
 Select appropriate PMPADDR list based on PMP_ENTRY_NUM. More...
 

Functions

__STATIC_INLINE rv_csr_t __get_PMPCFGx (uint32_t csr_idx)
 Get PMPCFGx Register by CSR index. More...
 
__STATIC_INLINE void __set_PMPCFGx (uint32_t csr_idx, rv_csr_t pmpcfg)
 Set PMPCFGx by CSR index. More...
 
__STATIC_INLINE uint8_t __get_PMPxCFG (uint32_t entry_idx)
 Get 8bit PMPxCFG Register by PMP entry index. More...
 
__STATIC_INLINE void __set_PMPxCFG (uint32_t entry_idx, uint8_t pmpxcfg)
 Set 8bit PMPxCFG by pmp entry index. More...
 
__STATIC_INLINE rv_csr_t __get_PMPADDRx (uint32_t csr_idx)
 Get PMPADDRx Register by CSR index. More...
 
__STATIC_INLINE void __set_PMPADDRx (uint32_t csr_idx, rv_csr_t pmpaddr)
 Set PMPADDRx by CSR index. More...
 
__STATIC_INLINE void __set_PMPENTRYx (uint32_t entry_idx, const pmp_config *pmp_cfg)
 Set PMP entry by entry idx. More...
 
__STATIC_INLINE int __get_PMPENTRYx (unsigned int entry_idx, pmp_config *pmp_cfg)
 Get PMP entry by entry idx. More...
 

Detailed Description

Functions that related to the RISCV Phyiscal Memory Protection.

Optional physical memory protection (PMP) unit provides per-hart machine-mode control registers to allow physical memory access privileges (read, write, execute) to be specified for each physical memory region.

The PMP can supports region access control settings as small as four bytes.

Macro Definition Documentation

◆ PMPADDR_LIST

#define PMPADDR_LIST   PMPADDR_LIST_BASE PMPADDR_LIST_8_15

Select appropriate PMPADDR list based on PMP_ENTRY_NUM.

This macro defines the complete PMPADDR list by combining base and extended lists according to the configured number of PMP entries.

Note
The actual list is determined by the __PMP_ENTRY_NUM configuration:
  • <=8: Only base list (0-7)
  • <=16: Base + 8-15
  • <=32: Base + 8-15 + 16-31
  • <=64: Base + 8-15 + 16-31 + 32-63

Definition at line 325 of file core_feature_pmp.h.

◆ PMPADDR_LIST_16_31

#define PMPADDR_LIST_16_31

Extended PMPADDR list (indices 16-31)

Definition at line 297 of file core_feature_pmp.h.

◆ PMPADDR_LIST_32_63

#define PMPADDR_LIST_32_63

Extended PMPADDR list (indices 32-63)

Definition at line 304 of file core_feature_pmp.h.

◆ PMPADDR_LIST_8_15

#define PMPADDR_LIST_8_15    X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15)

Extended PMPADDR list (indices 8-15)

Definition at line 291 of file core_feature_pmp.h.

◆ PMPADDR_LIST_BASE

#define PMPADDR_LIST_BASE    X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7)

Base PMPADDR list (indices 0-7)

Definition at line 285 of file core_feature_pmp.h.

◆ PMPCFG_LIST

#define PMPCFG_LIST   PMPCFG_LIST_RV32_0_7

Select appropriate PMPCFG list based on architecture and PMP entry count.

This macro defines the complete PMPCFG list according to:

  • RISC-V architecture (RV32/RV64)
  • Number of PMP entries (__PMP_ENTRY_NUM)
Note
Valid indices depend on configuration:
  • RV32:
    • <=32 entries: indices 0-7
    • <=64 entries: indices 0-15
  • RV64:
    • <=32 entries: indices 0,2,4,6
    • <=64 entries: indices 0,2,4,6,8,10,12,14

Definition at line 130 of file core_feature_pmp.h.

◆ PMPCFG_LIST_RV32_0_7

#define PMPCFG_LIST_RV32_0_7    X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7)

PMPCFG list for RV32 (indices 0-7)

For RV32, each PMPCFG register holds 4 PMP entries. This list covers the first 32 entries (registers 0-7).

Definition at line 83 of file core_feature_pmp.h.

◆ PMPCFG_LIST_RV32_8_15

#define PMPCFG_LIST_RV32_8_15    X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15)

PMPCFG list for RV32 (indices 8-15)

For RV32, each PMPCFG register holds 4 PMP entries. This list covers entries 33-64 (registers 8-15).

Definition at line 92 of file core_feature_pmp.h.

◆ PMPCFG_LIST_RV64_0_6

#define PMPCFG_LIST_RV64_0_6    X(0) X(2) X(4) X(6)

PMPCFG list for RV64 (even indices 0-6)

For RV64, each PMPCFG register holds 8 PMP entries. This list covers the first 32 entries (registers 0,2,4,6).

Definition at line 101 of file core_feature_pmp.h.

◆ PMPCFG_LIST_RV64_8_14

#define PMPCFG_LIST_RV64_8_14    X(8) X(10) X(12) X(14)

PMPCFG list for RV64 (even indices 8-14)

For RV64, each PMPCFG register holds 8 PMP entries. This list covers entries 33-64 (registers 8,10,12,14).

Definition at line 110 of file core_feature_pmp.h.

Function Documentation

◆ __get_PMPADDRx()

__STATIC_INLINE rv_csr_t __get_PMPADDRx ( uint32_t  csr_idx)

Get PMPADDRx Register by CSR index.

Return the content of the PMPADDRx Register.

Parameters
[in]csr_idxPMP region CSR index(0-63)
Returns
PMPADDRx Register value

Definition at line 340 of file core_feature_pmp.h.

341 {
342  switch (csr_idx) {
343  #define X(n) case n: return __RV_CSR_READ(CSR_PMPADDR##n);
345  #undef X
346  default: return 0;
347  }
348 }
#define PMPADDR_LIST
Select appropriate PMPADDR list based on PMP_ENTRY_NUM.

References PMPADDR_LIST.

Referenced by __get_PMPENTRYx().

◆ __get_PMPCFGx()

__STATIC_INLINE rv_csr_t __get_PMPCFGx ( uint32_t  csr_idx)

Get PMPCFGx Register by CSR index.

Return the content of the PMPCFGx Register.

Parameters
[in]csr_idxPMPCFG CSR index (0-15 for RV32, 0,2,4,6,8,10,12,14 for RV64)
Returns
PMPCFGx Register value
Note
Architecture-specific behavior:
  • RV32:
    • Each register holds 4 PMP entries
    • Valid indices: 0 to ceil(__PMP_ENTRY_NUM/4)-1
    • 64 entries require indices 0-15
  • RV64:
    • Each register holds 8 PMP entries
    • Only even indices are valid
    • 64 entries require indices 0,2,4,6,8,10,12,14
Remarks
The function returns 0 for invalid indices to prevent illegal accesses.

Definition at line 166 of file core_feature_pmp.h.

167 {
168  switch (csr_idx) {
169  #define X(n) case n: return __RV_CSR_READ(CSR_PMPCFG##n);
171  #undef X
172  default: return 0;
173  }
174 }
#define PMPCFG_LIST
Select appropriate PMPCFG list based on architecture and PMP entry count.

References PMPCFG_LIST.

Referenced by __get_PMPENTRYx(), __get_PMPxCFG(), __set_PMPENTRYx(), and __set_PMPxCFG().

◆ __get_PMPENTRYx()

__STATIC_INLINE int __get_PMPENTRYx ( unsigned int  entry_idx,
pmp_config pmp_cfg 
)

Get PMP entry by entry idx.

Write the given value to the PMPxCFG Register and PMPADDRx.

Parameters
[in]entry_idxPMP entry index(0-63)
[out]pmp_cfgstructure of L, X, W, R, A field of PMP configuration register, memory region base address and size of memory region as power of 2
Returns
-1 failure, else 0 success
Remarks
  • If the size of memory region is 2^12(4KB) range, pmp_cfg->order makes 12, and the like.
  • TOR of A field in PMP configuration register is not considered here.

Definition at line 438 of file core_feature_pmp.h.

439 {
440  unsigned int cfg_shift, cfg_csr_idx, addr_csr_idx = 0;
441  unsigned long cfgmask, pmpcfg, prot = 0;
442  unsigned long t1, addr, pmpaddr, len = 0;
443  uint8_t csr_cfg_num = 0;
444  /* check parameters */
445  if (entry_idx >= __PMP_ENTRY_NUM || !pmp_cfg) return -1;
446 
447  /* calculate PMP register and offset */
448 #if __RISCV_XLEN == 32
449  csr_cfg_num = 4;
450  cfg_csr_idx = entry_idx >> 2;
451 #elif __RISCV_XLEN == 64
452  csr_cfg_num = 8;
453  cfg_csr_idx = (entry_idx>> 2) & ~1;
454 #else
455  // TODO Add RV128 Handling
456  return -1;
457 #endif
458 
459  cfg_shift = (entry_idx & (csr_cfg_num - 1)) << 3;
460  addr_csr_idx = entry_idx;
461 
462  /* decode PMP config */
463  cfgmask = (0xFFUL << cfg_shift);
464  pmpcfg = (__get_PMPCFGx(cfg_csr_idx) & cfgmask);
465  prot = pmpcfg >> cfg_shift;
466 
467  /* decode PMP address */
468  pmpaddr = __get_PMPADDRx(addr_csr_idx);
469  if (PMP_A_NAPOT == (prot & PMP_A)) {
470  t1 = __CTZ(~pmpaddr);
471  addr = (pmpaddr & ~((1UL << t1) - 1)) << PMP_SHIFT;
472  len = (t1 + PMP_SHIFT + 1);
473  } else {
474  addr = pmpaddr << PMP_SHIFT;
475  len = PMP_SHIFT;
476  }
477 
478  /* return details */
479  pmp_cfg->protection = prot;
480  pmp_cfg->base_addr = addr;
481  pmp_cfg->order = len;
482 
483  return 0;
484 }
__STATIC_INLINE unsigned long __CTZ(unsigned long data)
Count tailing zero.
#define PMP_A
#define PMP_A_NAPOT
#define PMP_SHIFT
__STATIC_INLINE rv_csr_t __get_PMPCFGx(uint32_t csr_idx)
Get PMPCFGx Register by CSR index.
__STATIC_INLINE rv_csr_t __get_PMPADDRx(uint32_t csr_idx)
Get PMPADDRx Register by CSR index.
unsigned long order
Size of memory region as power of 2, it has to be minimum 2 and maxium __RISCV_XLEN according to the ...
unsigned long base_addr
Base address of memory region It must be 2^order aligned address.
unsigned int protection
set locking bit, addressing mode, read, write, and instruction execution permissions,...

References __CTZ(), __get_PMPADDRx(), __get_PMPCFGx(), pmp_config::base_addr, pmp_config::order, PMP_A, PMP_A_NAPOT, PMP_SHIFT, and pmp_config::protection.

◆ __get_PMPxCFG()

__STATIC_INLINE uint8_t __get_PMPxCFG ( uint32_t  entry_idx)

Get 8bit PMPxCFG Register by PMP entry index.

Return the content of the PMPxCFG Register.

Parameters
[in]entry_idxPMP region index(0-63)
Returns
PMPxCFG Register value

Definition at line 210 of file core_feature_pmp.h.

211 {
212  rv_csr_t pmpcfgx = 0;
213  uint8_t csr_cfg_num = 0;
214  uint16_t csr_idx = 0;
215  uint16_t cfg_shift = 0;
216 
217  if (entry_idx >= __PMP_ENTRY_NUM) return 0;
218 
219 #if __RISCV_XLEN == 32
220  csr_cfg_num = 4;
221  csr_idx = entry_idx >> 2;
222 #elif __RISCV_XLEN == 64
223  csr_cfg_num = 8;
224  /* For RV64, each PMPCFG register (pmpcfg0, pmpcfg2, etc.) holds 8 PMP entries */
225  /* Only even-numbered CSRs are used, so we align the index by clearing the LSB */
226  csr_idx = (entry_idx >> 2) & ~1;
227 #else
228  // TODO Add RV128 Handling
229  return 0;
230 #endif
231  pmpcfgx = __get_PMPCFGx(csr_idx);
232  /*
233  * first get specific pmpxcfg's order in one CSR composed of csr_cfg_num pmpxcfgs,
234  * then get pmpxcfg's bit position in one CSR by left shift 3(each pmpxcfg size is one byte)
235  */
236  cfg_shift = (entry_idx & (csr_cfg_num - 1)) << 3;
237 
238  /* read specific pmpxcfg register value */
239  return (uint8_t)(__RV_EXTRACT_FIELD(pmpcfgx, 0xFF << cfg_shift));
240 }
unsigned long rv_csr_t
Type of Control and Status Register(CSR), depends on the XLEN defined in RISC-V.

References __get_PMPCFGx().

◆ __set_PMPADDRx()

__STATIC_INLINE void __set_PMPADDRx ( uint32_t  csr_idx,
rv_csr_t  pmpaddr 
)

Set PMPADDRx by CSR index.

Write the given value to the PMPADDRx Register.

Parameters
[in]csr_idxPMP region CSR index(0-63)
[in]pmpaddrPMPADDRx Register value to set

Definition at line 356 of file core_feature_pmp.h.

357 {
358  switch (csr_idx) {
359  #define X(n) case n: __RV_CSR_WRITE(CSR_PMPADDR##n, pmpaddr); break;
361  #undef X
362  default: return;
363  }
364 }

References PMPADDR_LIST.

Referenced by __set_PMPENTRYx().

◆ __set_PMPCFGx()

__STATIC_INLINE void __set_PMPCFGx ( uint32_t  csr_idx,
rv_csr_t  pmpcfg 
)

Set PMPCFGx by CSR index.

Write the given value to the PMPCFGx Register.

Parameters
[in]csr_idxPMPCFG CSR index (0-15 for RV32, 0,2,4,6,8,10,12,14 for RV64)
[in]pmpcfgPMPCFGx Register value to set
Note
Architecture-specific behavior:
  • RV32:
    • Each register holds 4 PMP entries
    • Valid indices: 0 to ceil(__PMP_ENTRY_NUM/4)-1
    • 64 entries require indices 0-15
  • RV64:
    • Each register holds 8 PMP entries
    • Only even indices are valid
    • 64 entries require indices 0,2,4,6,8,10,12,14
Remarks
The function does nothing for invalid indices to prevent illegal accesses.

Definition at line 194 of file core_feature_pmp.h.

195 {
196  switch (csr_idx) {
197  #define X(n) case n: __RV_CSR_WRITE(CSR_PMPCFG##n, pmpcfg); break;
199  #undef X
200  default: return;
201  }
202 }

References PMPCFG_LIST.

Referenced by __set_PMPENTRYx(), and __set_PMPxCFG().

◆ __set_PMPENTRYx()

__STATIC_INLINE void __set_PMPENTRYx ( uint32_t  entry_idx,
const pmp_config pmp_cfg 
)

Set PMP entry by entry idx.

Write the given value to the PMPxCFG Register and PMPADDRx.

Parameters
[in]entry_idxPMP entry index(0-63)
[in]pmp_cfgstructure of L, X, W, R field of PMP configuration register, memory region base address and size of memory region as power of 2
Remarks
  • If the size of memory region is 2^12(4KB) range, pmp_cfg->order makes 12, and the like.
  • Suppose the size of memory region is 2^X bytes range, if X >=3, the NA4 mode is not selectable, NAPOT is selected.
  • TOR of A field in PMP configuration register is not considered here.

Definition at line 377 of file core_feature_pmp.h.

378 {
379  unsigned int cfg_shift, cfg_csr_idx, addr_csr_idx = 0;
380  unsigned long cfgmask, addrmask = 0;
381  unsigned long pmpcfg, pmpaddr = 0;
382  unsigned long protection, csr_cfg_num = 0;
383  /* check parameters */
384  if (entry_idx >= __PMP_ENTRY_NUM || pmp_cfg->order > __RISCV_XLEN || pmp_cfg->order < PMP_SHIFT) return;
385 
386  /* calculate PMP register and offset */
387 #if __RISCV_XLEN == 32
388  csr_cfg_num = 4;
389  cfg_csr_idx = (entry_idx >> 2);
390 #elif __RISCV_XLEN == 64
391  csr_cfg_num = 8;
392  cfg_csr_idx = ((entry_idx >> 2)) & ~1;
393 #else
394  // TODO Add RV128 Handling
395  return;
396 #endif
397  /*
398  * first get specific pmpxcfg's order in one CSR composed of csr_cfg_num pmpxcfgs,
399  * then get pmpxcfg's bit position in one CSR by left shift 3, each pmpxcfg size is one byte
400  */
401  cfg_shift = (entry_idx & (csr_cfg_num - 1)) << 3;
402  addr_csr_idx = entry_idx;
403 
404  /* encode PMP config */
405  protection = (unsigned long)pmp_cfg->protection;
406  protection |= (PMP_SHIFT == pmp_cfg->order) ? PMP_A_NA4 : PMP_A_NAPOT;
407  cfgmask = ~(0xFFUL << cfg_shift);
408  pmpcfg = (__get_PMPCFGx(cfg_csr_idx) & cfgmask);
409  pmpcfg |= ((protection << cfg_shift) & ~cfgmask);
410 
411  /* encode PMP address */
412  if (PMP_SHIFT == pmp_cfg->order) { /* NA4 */
413  pmpaddr = (pmp_cfg->base_addr >> PMP_SHIFT);
414  } else { /* NAPOT */
415  addrmask = (1UL << (pmp_cfg->order - PMP_SHIFT)) - 1;
416  pmpaddr = ((pmp_cfg->base_addr >> PMP_SHIFT) & ~addrmask);
417  pmpaddr |= (addrmask >> 1);
418  }
419  /*
420  * write csrs, update the address first, in case the entry is locked that
421  * we won't be able to modify it after we set the config csr.
422  */
423  __set_PMPADDRx(addr_csr_idx, pmpaddr);
424  __set_PMPCFGx(cfg_csr_idx, pmpcfg);
425 }
#define PMP_A_NA4
__STATIC_INLINE void __set_PMPCFGx(uint32_t csr_idx, rv_csr_t pmpcfg)
Set PMPCFGx by CSR index.
__STATIC_INLINE void __set_PMPADDRx(uint32_t csr_idx, rv_csr_t pmpaddr)
Set PMPADDRx by CSR index.
#define __RISCV_XLEN
Refer to the width of an integer register in bits(either 32 or 64)

References __get_PMPCFGx(), __RISCV_XLEN, __set_PMPADDRx(), __set_PMPCFGx(), pmp_config::base_addr, pmp_config::order, PMP_A_NA4, PMP_A_NAPOT, PMP_SHIFT, and pmp_config::protection.

◆ __set_PMPxCFG()

__STATIC_INLINE void __set_PMPxCFG ( uint32_t  entry_idx,
uint8_t  pmpxcfg 
)

Set 8bit PMPxCFG by pmp entry index.

Set the given pmpxcfg value to the PMPxCFG Register.

Parameters
[in]entry_idxPMPx region index(0-63)
[in]pmpxcfgPMPxCFG register value to set
Remarks
  • For RV32, 4 pmpxcfgs are densely packed into one CSR in order For RV64, 8 pmpxcfgs are densely packed into one CSR in order

Definition at line 251 of file core_feature_pmp.h.

252 {
253  rv_csr_t pmpcfgx = 0;
254  uint8_t csr_cfg_num = 0;
255  uint16_t csr_idx = 0;
256  uint16_t cfg_shift = 0;
257  if (entry_idx >= __PMP_ENTRY_NUM) return;
258 
259 #if __RISCV_XLEN == 32
260  csr_cfg_num = 4;
261  csr_idx = entry_idx >> 2;
262 #elif __RISCV_XLEN == 64
263  csr_cfg_num = 8;
264  /* For RV64, pmpcfg0 and pmpcfg2 each hold 8 PMP entries, align by 2 */
265  csr_idx = (entry_idx >> 2) & ~1;
266 #else
267  // TODO Add RV128 Handling
268  return;
269 #endif
270  /* read specific pmpcfgx register value */
271  pmpcfgx = __get_PMPCFGx(csr_idx);
272  /*
273  * first get specific pmpxcfg's order in one CSR composed of csr_cfg_num pmpxcfgs,
274  * then get pmpxcfg's bit position in one CSR by left shift 3(each pmpxcfg size is one byte)
275  */
276  cfg_shift = (entry_idx & (csr_cfg_num - 1)) << 3;
277 
278  pmpcfgx = __RV_INSERT_FIELD(pmpcfgx, 0xFFUL << cfg_shift, pmpxcfg);
279  __set_PMPCFGx(csr_idx, pmpcfgx);
280 }

References __get_PMPCFGx(), and __set_PMPCFGx().