arch: riscv: pmp: introduce riscv_pmp_region structure
Using struct riscv_pmp_region to modulize PMP CSR handling, including PMP NAPOT/TOR mode handling. This patch can make us more easily to add/remove RISC-V PMP regions without considering register handling. Signed-off-by: Jim Shu <cwshu@andestech.com>
This commit is contained in:
parent
e4c5d96a8b
commit
e3c8b4cae4
2 changed files with 309 additions and 140 deletions
|
@ -15,12 +15,54 @@
|
||||||
#include <logging/log.h>
|
#include <logging/log.h>
|
||||||
LOG_MODULE_REGISTER(mpu);
|
LOG_MODULE_REGISTER(mpu);
|
||||||
|
|
||||||
#define PMP_SLOT_NUMBER CONFIG_PMP_SLOT
|
#ifdef CONFIG_64BIT
|
||||||
|
# define PR_ADDR "0x%016lx"
|
||||||
|
#else
|
||||||
|
# define PR_ADDR "0x%08lx"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_64BIT
|
||||||
|
# define PMPCFG_NUM(index) (((index) / 8) * 2)
|
||||||
|
# define PMPCFG_SHIFT(index) (((index) % 8) * 8)
|
||||||
|
#else
|
||||||
|
# define PMPCFG_NUM(index) ((index) / 4)
|
||||||
|
# define PMPCFG_SHIFT(index) (((index) % 4) * 8)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_PMP_POWER_OF_TWO_ALIGNMENT)
|
||||||
|
# define PMP_MODE_DEFAULT PMP_MODE_NAPOT
|
||||||
|
#else
|
||||||
|
# define PMP_MODE_DEFAULT PMP_MODE_TOR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum pmp_region_mode {
|
||||||
|
PMP_MODE_NA4,
|
||||||
|
/* If NAPOT mode region size is 4, apply NA4 region to PMP CSR. */
|
||||||
|
PMP_MODE_NAPOT,
|
||||||
|
PMP_MODE_TOR,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Region definition data structure */
|
||||||
|
struct riscv_pmp_region {
|
||||||
|
ulong_t start;
|
||||||
|
ulong_t size;
|
||||||
|
uint8_t perm;
|
||||||
|
enum pmp_region_mode mode;
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_USERSPACE
|
#ifdef CONFIG_USERSPACE
|
||||||
extern ulong_t is_user_mode;
|
extern ulong_t is_user_mode;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_PMP_STACK_GUARD
|
||||||
|
static const struct riscv_pmp_region irq_stack_guard_region = {
|
||||||
|
.start = (ulong_t) z_interrupt_stacks[0],
|
||||||
|
.size = PMP_GUARD_ALIGN_AND_SIZE,
|
||||||
|
.perm = 0,
|
||||||
|
.mode = PMP_MODE_NAPOT,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
CSR_PMPCFG0,
|
CSR_PMPCFG0,
|
||||||
CSR_PMPCFG1,
|
CSR_PMPCFG1,
|
||||||
|
@ -44,7 +86,7 @@ enum {
|
||||||
CSR_PMPADDR15
|
CSR_PMPADDR15
|
||||||
};
|
};
|
||||||
|
|
||||||
static ulong_t csr_read_enum(int pmp_csr_enum)
|
static __unused ulong_t csr_read_enum(int pmp_csr_enum)
|
||||||
{
|
{
|
||||||
ulong_t res = -1;
|
ulong_t res = -1;
|
||||||
|
|
||||||
|
@ -143,44 +185,203 @@ static void csr_write_enum(int pmp_csr_enum, ulong_t value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int z_riscv_pmp_set(unsigned int index, ulong_t cfg_val, ulong_t addr_val)
|
/*
|
||||||
|
* @brief Set a Physical Memory Protection slot
|
||||||
|
*
|
||||||
|
* Configure a memory region to be secured by one of the 16 PMP entries.
|
||||||
|
*
|
||||||
|
* @param index Number of the targeted PMP entrie (0 to 15 only).
|
||||||
|
* @param cfg_val Configuration value (cf datasheet or defined flags)
|
||||||
|
* @param addr_val Address register value
|
||||||
|
*
|
||||||
|
* This function shall only be called from Secure state.
|
||||||
|
*
|
||||||
|
* @return -1 if bad argument, 0 otherwise.
|
||||||
|
*/
|
||||||
|
static __unused int riscv_pmp_set(unsigned int index, ulong_t cfg_val, ulong_t addr_val)
|
||||||
{
|
{
|
||||||
ulong_t reg_val;
|
ulong_t reg_val;
|
||||||
ulong_t shift, mask;
|
ulong_t shift, mask;
|
||||||
int pmpcfg_csr;
|
int pmpcfg_csr;
|
||||||
int pmpaddr_csr;
|
int pmpaddr_csr;
|
||||||
|
|
||||||
if (index >= PMP_SLOT_NUMBER) {
|
if (index >= CONFIG_PMP_SLOT) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate PMP config/addr register, shift and mask */
|
/* Calculate PMP config/addr register, shift and mask */
|
||||||
#ifdef CONFIG_64BIT
|
pmpcfg_csr = CSR_PMPCFG0 + PMPCFG_NUM(index);
|
||||||
pmpcfg_csr = CSR_PMPCFG0 + ((index >> 3) << 1);
|
|
||||||
shift = (index & 0x7) << 3;
|
|
||||||
#else
|
|
||||||
pmpcfg_csr = CSR_PMPCFG0 + (index >> 2);
|
|
||||||
shift = (index & 0x3) << 3;
|
|
||||||
#endif /* CONFIG_64BIT */
|
|
||||||
pmpaddr_csr = CSR_PMPADDR0 + index;
|
pmpaddr_csr = CSR_PMPADDR0 + index;
|
||||||
|
shift = PMPCFG_SHIFT(index);
|
||||||
/* Mask = 0x000000FF<<((index%4)*8) */
|
mask = 0xFF << shift;
|
||||||
mask = 0x000000FF << shift;
|
|
||||||
|
|
||||||
cfg_val = cfg_val << shift;
|
|
||||||
addr_val = TO_PMP_ADDR(addr_val);
|
|
||||||
|
|
||||||
reg_val = csr_read_enum(pmpcfg_csr);
|
reg_val = csr_read_enum(pmpcfg_csr);
|
||||||
reg_val = reg_val & ~mask;
|
reg_val = reg_val & ~mask;
|
||||||
reg_val = reg_val | cfg_val;
|
reg_val = reg_val | (cfg_val << shift);
|
||||||
|
|
||||||
csr_write_enum(pmpaddr_csr, addr_val);
|
csr_write_enum(pmpaddr_csr, addr_val);
|
||||||
csr_write_enum(pmpcfg_csr, reg_val);
|
csr_write_enum(pmpcfg_csr, reg_val);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int riscv_pmp_region_translate(int index,
|
||||||
|
const struct riscv_pmp_region *region, bool to_csr,
|
||||||
|
ulong_t pmpcfg[], ulong_t pmpaddr[])
|
||||||
|
{
|
||||||
|
int result, pmp_mode;
|
||||||
|
|
||||||
|
if ((region->start == 0) && (region->size == 0)) {
|
||||||
|
/* special case: set whole memory as single PMP region.
|
||||||
|
* RV32: 0 ~ (2**32 - 1)
|
||||||
|
* RV64: 0 ~ (2**64 - 1)
|
||||||
|
*/
|
||||||
|
if (index >= CONFIG_PMP_SLOT) {
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
pmp_mode = PMP_NAPOT;
|
||||||
|
|
||||||
|
uint8_t cfg_val = PMP_NAPOT | region->perm;
|
||||||
|
#ifdef CONFIG_64BIT
|
||||||
|
ulong_t addr_val = 0x1FFFFFFFFFFFFFFF;
|
||||||
|
#else
|
||||||
|
ulong_t addr_val = 0x1FFFFFFF;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (to_csr) {
|
||||||
|
riscv_pmp_set(index, cfg_val, addr_val);
|
||||||
|
} else {
|
||||||
|
uint8_t *u8_pmpcfg = (uint8_t *)pmpcfg;
|
||||||
|
|
||||||
|
u8_pmpcfg[index] = cfg_val;
|
||||||
|
pmpaddr[index] = addr_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = index+1;
|
||||||
|
} else if (region->mode == PMP_MODE_TOR) {
|
||||||
|
if ((index+1) >= CONFIG_PMP_SLOT) {
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
pmp_mode = PMP_TOR;
|
||||||
|
|
||||||
|
uint8_t cfg_val1 = PMP_NA4 | region->perm;
|
||||||
|
ulong_t addr_val1 = TO_PMP_ADDR(region->start);
|
||||||
|
uint8_t cfg_val2 = PMP_TOR | region->perm;
|
||||||
|
ulong_t addr_val2 = TO_PMP_ADDR(region->start + region->size);
|
||||||
|
|
||||||
|
if (to_csr) {
|
||||||
|
riscv_pmp_set(index, cfg_val1, addr_val1);
|
||||||
|
riscv_pmp_set(index+1, cfg_val2, addr_val2);
|
||||||
|
} else {
|
||||||
|
uint8_t *u8_pmpcfg = (uint8_t *)pmpcfg;
|
||||||
|
|
||||||
|
u8_pmpcfg[index] = cfg_val1;
|
||||||
|
pmpaddr[index] = addr_val1;
|
||||||
|
u8_pmpcfg[index+1] = cfg_val2;
|
||||||
|
pmpaddr[index+1] = addr_val2;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = index+2;
|
||||||
|
} else {
|
||||||
|
if (index >= CONFIG_PMP_SLOT) {
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((region->mode == PMP_MODE_NA4) || (region->size == 4)) {
|
||||||
|
pmp_mode = PMP_NA4;
|
||||||
|
} else {
|
||||||
|
pmp_mode = PMP_NAPOT;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t cfg_val = pmp_mode | region->perm;
|
||||||
|
ulong_t addr_val = TO_PMP_NAPOT(region->start, region->size);
|
||||||
|
|
||||||
|
if (to_csr) {
|
||||||
|
riscv_pmp_set(index, cfg_val, addr_val);
|
||||||
|
} else {
|
||||||
|
uint8_t *u8_pmpcfg = (uint8_t *)pmpcfg;
|
||||||
|
|
||||||
|
u8_pmpcfg[index] = cfg_val;
|
||||||
|
pmpaddr[index] = addr_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = index+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to_csr) {
|
||||||
|
LOG_DBG("Set PMP region %d: (" PR_ADDR ", " PR_ADDR
|
||||||
|
", %s%s%s, %s)", index, region->start, region->size,
|
||||||
|
((region->perm & PMP_R) ? "R" : " "),
|
||||||
|
((region->perm & PMP_W) ? "W" : " "),
|
||||||
|
((region->perm & PMP_X) ? "X" : " "),
|
||||||
|
((pmp_mode == PMP_TOR) ? "TOR" :
|
||||||
|
(pmp_mode == PMP_NAPOT) ? "NAPOT" : "NA4"));
|
||||||
|
} else {
|
||||||
|
LOG_DBG("PMP context " PR_ADDR " add region %d: (" PR_ADDR
|
||||||
|
", " PR_ADDR ", %s%s%s, %s)", (ulong_t) pmpcfg, index,
|
||||||
|
region->start, region->size,
|
||||||
|
((region->perm & PMP_R) ? "R" : " "),
|
||||||
|
((region->perm & PMP_W) ? "W" : " "),
|
||||||
|
((region->perm & PMP_X) ? "X" : " "),
|
||||||
|
((pmp_mode == PMP_TOR) ? "TOR" :
|
||||||
|
(pmp_mode == PMP_NAPOT) ? "NAPOT" : "NA4"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pmp_mode == PMP_TOR) {
|
||||||
|
LOG_DBG("TOR mode region also use entry %d", index+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_PMP_STACK_GUARD) || defined(CONFIG_USERSPACE)
|
||||||
|
static __unused int riscv_pmp_regions_translate(int start_reg_index,
|
||||||
|
const struct riscv_pmp_region regions[], uint8_t regions_num,
|
||||||
|
ulong_t pmpcfg[], ulong_t pmpaddr[])
|
||||||
|
{
|
||||||
|
int reg_index = start_reg_index;
|
||||||
|
|
||||||
|
for (int i = 0; i < regions_num; i++) {
|
||||||
|
/*
|
||||||
|
* Empty region.
|
||||||
|
*
|
||||||
|
* Note: start = size = 0 is valid region (special case).
|
||||||
|
*/
|
||||||
|
if ((regions[i].size == 0U) && (regions[i].start != 0)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Non-empty region. */
|
||||||
|
reg_index = riscv_pmp_region_translate(reg_index, ®ions[i],
|
||||||
|
false, pmpcfg, pmpaddr);
|
||||||
|
|
||||||
|
if (reg_index == -ENOSPC) {
|
||||||
|
LOG_ERR("no free PMP entry");
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return reg_index;
|
||||||
|
}
|
||||||
|
#endif /* defined(CONFIG_PMP_STACK_GUARD) || defined(CONFIG_USERSPACE) */
|
||||||
|
|
||||||
|
static int riscv_pmp_region_set(int index, const struct riscv_pmp_region *region)
|
||||||
|
{
|
||||||
|
/* Check 4 bytes alignment */
|
||||||
|
CHECKIF(!(((region->start & 0x3) == 0) &&
|
||||||
|
((region->size & 0x3) == 0) &&
|
||||||
|
region->size)) {
|
||||||
|
LOG_ERR("PMP address/size are not 4 bytes aligned");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return riscv_pmp_region_translate(index, region, true, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
void z_riscv_pmp_clear_config(void)
|
void z_riscv_pmp_clear_config(void)
|
||||||
{
|
{
|
||||||
|
LOG_DBG("Clear all dynamic PMP regions");
|
||||||
for (unsigned int i = 0; i < RISCV_PMP_CFG_NUM; i++)
|
for (unsigned int i = 0; i < RISCV_PMP_CFG_NUM; i++)
|
||||||
csr_write_enum(CSR_PMPCFG0 + i, 0);
|
csr_write_enum(CSR_PMPCFG0 + i, 0);
|
||||||
}
|
}
|
||||||
|
@ -189,48 +390,38 @@ void z_riscv_pmp_clear_config(void)
|
||||||
#include <linker/linker-defs.h>
|
#include <linker/linker-defs.h>
|
||||||
void z_riscv_init_user_accesses(struct k_thread *thread)
|
void z_riscv_init_user_accesses(struct k_thread *thread)
|
||||||
{
|
{
|
||||||
unsigned char index;
|
unsigned char index = 0U;
|
||||||
unsigned char *uchar_pmpcfg;
|
|
||||||
ulong_t rom_start = (ulong_t) __rom_region_start;
|
|
||||||
#if defined(CONFIG_PMP_POWER_OF_TWO_ALIGNMENT)
|
|
||||||
ulong_t rom_size = (ulong_t) __rom_region_size;
|
|
||||||
#else /* CONFIG_PMP_POWER_OF_TWO_ALIGNMENT */
|
|
||||||
ulong_t rom_end = (ulong_t) __rom_region_end;
|
|
||||||
#endif /* CONFIG_PMP_POWER_OF_TWO_ALIGNMENT */
|
|
||||||
index = 0U;
|
|
||||||
uchar_pmpcfg = (unsigned char *) thread->arch.u_pmpcfg;
|
|
||||||
|
|
||||||
#ifdef CONFIG_PMP_STACK_GUARD
|
#ifdef CONFIG_PMP_STACK_GUARD
|
||||||
index++;
|
index++;
|
||||||
#endif /* CONFIG_PMP_STACK_GUARD */
|
#endif /* CONFIG_PMP_STACK_GUARD */
|
||||||
|
|
||||||
/* MCU state */
|
struct riscv_pmp_region dynamic_regions[] = {
|
||||||
thread->arch.u_pmpaddr[index] = TO_PMP_ADDR((ulong_t) &is_user_mode);
|
{
|
||||||
uchar_pmpcfg[index++] = PMP_NA4 | PMP_R;
|
/* MCU state */
|
||||||
#if defined(CONFIG_PMP_POWER_OF_TWO_ALIGNMENT)
|
.start = (ulong_t) &is_user_mode,
|
||||||
/* Program and RO data */
|
.size = 4,
|
||||||
thread->arch.u_pmpaddr[index] = TO_PMP_NAPOT(rom_start, rom_size);
|
.perm = PMP_R,
|
||||||
uchar_pmpcfg[index++] = PMP_NAPOT | PMP_R | PMP_X;
|
.mode = PMP_MODE_NA4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* Program and RO data */
|
||||||
|
.start = (ulong_t) __rom_region_start,
|
||||||
|
.size = (ulong_t) __rom_region_size,
|
||||||
|
.perm = PMP_R | PMP_X,
|
||||||
|
.mode = PMP_MODE_DEFAULT,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
/* User-mode thread stack */
|
||||||
|
.start = thread->stack_info.start,
|
||||||
|
.size = thread->stack_info.size,
|
||||||
|
.perm = PMP_R | PMP_W,
|
||||||
|
.mode = PMP_MODE_DEFAULT,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/* RAM */
|
riscv_pmp_regions_translate(index, dynamic_regions,
|
||||||
thread->arch.u_pmpaddr[index] = TO_PMP_NAPOT(thread->stack_info.start,
|
ARRAY_SIZE(dynamic_regions), thread->arch.u_pmpcfg,
|
||||||
thread->stack_info.size);
|
thread->arch.u_pmpaddr);
|
||||||
|
|
||||||
uchar_pmpcfg[index++] = PMP_NAPOT | PMP_R | PMP_W;
|
|
||||||
#else /* CONFIG_PMP_POWER_OF_TWO_ALIGNMENT */
|
|
||||||
/* Program and RO data */
|
|
||||||
thread->arch.u_pmpaddr[index] = TO_PMP_ADDR(rom_start);
|
|
||||||
uchar_pmpcfg[index++] = PMP_NA4 | PMP_R | PMP_X;
|
|
||||||
thread->arch.u_pmpaddr[index] = TO_PMP_ADDR(rom_end);
|
|
||||||
uchar_pmpcfg[index++] = PMP_TOR | PMP_R | PMP_X;
|
|
||||||
|
|
||||||
/* RAM */
|
|
||||||
thread->arch.u_pmpaddr[index] = TO_PMP_ADDR(thread->stack_info.start);
|
|
||||||
uchar_pmpcfg[index++] = PMP_NA4 | PMP_R | PMP_W;
|
|
||||||
thread->arch.u_pmpaddr[index] = TO_PMP_ADDR(thread->stack_info.start +
|
|
||||||
thread->stack_info.size);
|
|
||||||
uchar_pmpcfg[index++] = PMP_TOR | PMP_R | PMP_W;
|
|
||||||
#endif /* CONFIG_PMP_POWER_OF_TWO_ALIGNMENT */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void z_riscv_configure_user_allowed_stack(struct k_thread *thread)
|
void z_riscv_configure_user_allowed_stack(struct k_thread *thread)
|
||||||
|
@ -244,6 +435,9 @@ void z_riscv_configure_user_allowed_stack(struct k_thread *thread)
|
||||||
|
|
||||||
for (i = 0U; i < RISCV_PMP_CFG_NUM; i++)
|
for (i = 0U; i < RISCV_PMP_CFG_NUM; i++)
|
||||||
csr_write_enum(CSR_PMPCFG0 + i, thread->arch.u_pmpcfg[i]);
|
csr_write_enum(CSR_PMPCFG0 + i, thread->arch.u_pmpcfg[i]);
|
||||||
|
|
||||||
|
LOG_DBG("Apply user PMP context " PR_ADDR " to dynamic PMP regions",
|
||||||
|
(ulong_t) thread->arch.u_pmpcfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int z_riscv_pmp_add_dynamic(struct k_thread *thread,
|
int z_riscv_pmp_add_dynamic(struct k_thread *thread,
|
||||||
|
@ -262,6 +456,12 @@ int z_riscv_pmp_add_dynamic(struct k_thread *thread,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct riscv_pmp_region pmp_region = {
|
||||||
|
.start = addr,
|
||||||
|
.size = size,
|
||||||
|
.perm = flags,
|
||||||
|
};
|
||||||
|
|
||||||
/* Get next free entry */
|
/* Get next free entry */
|
||||||
uchar_pmpcfg = (unsigned char *) thread->arch.u_pmpcfg;
|
uchar_pmpcfg = (unsigned char *) thread->arch.u_pmpcfg;
|
||||||
|
|
||||||
|
@ -271,35 +471,18 @@ int z_riscv_pmp_add_dynamic(struct k_thread *thread,
|
||||||
index++;
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
__ASSERT((index < CONFIG_PMP_SLOT), "no free PMP entry\n");
|
/* Select the best mode */
|
||||||
CHECKIF(!(index < CONFIG_PMP_SLOT)) {
|
|
||||||
ret = -ENOSPC;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Select the best type */
|
|
||||||
if (size == 4) {
|
if (size == 4) {
|
||||||
thread->arch.u_pmpaddr[index] = TO_PMP_ADDR(addr);
|
pmp_region.mode = PMP_MODE_NA4;
|
||||||
uchar_pmpcfg[index] = flags | PMP_NA4;
|
} else {
|
||||||
|
pmp_region.mode = PMP_MODE_DEFAULT;
|
||||||
}
|
}
|
||||||
#if !defined(CONFIG_PMP_POWER_OF_TWO_ALIGNMENT)
|
|
||||||
else if ((addr & (size - 1)) || (size & (size - 1))) {
|
|
||||||
__ASSERT(((index + 1) < CONFIG_PMP_SLOT),
|
|
||||||
"not enough free PMP entries\n");
|
|
||||||
CHECKIF(!((index + 1) < CONFIG_PMP_SLOT)) {
|
|
||||||
ret = -ENOSPC;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
thread->arch.u_pmpaddr[index] = TO_PMP_ADDR(addr);
|
index = riscv_pmp_region_translate(index, &pmp_region, false,
|
||||||
uchar_pmpcfg[index++] = flags | PMP_NA4;
|
thread->arch.u_pmpcfg, thread->arch.u_pmpaddr);
|
||||||
thread->arch.u_pmpaddr[index] = TO_PMP_ADDR(addr + size);
|
|
||||||
uchar_pmpcfg[index++] = flags | PMP_TOR;
|
if (index == -ENOSPC) {
|
||||||
}
|
ret = -ENOSPC;
|
||||||
#endif /* !CONFIG_PMP_POWER_OF_TWO_ALIGNMENT */
|
|
||||||
else {
|
|
||||||
thread->arch.u_pmpaddr[index] = TO_PMP_NAPOT(addr, size);
|
|
||||||
uchar_pmpcfg[index] = flags | PMP_NAPOT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -396,7 +579,7 @@ int arch_mem_domain_partition_remove(struct k_mem_domain *domain,
|
||||||
{
|
{
|
||||||
sys_dnode_t *node, *next_node;
|
sys_dnode_t *node, *next_node;
|
||||||
uint32_t index, i, num;
|
uint32_t index, i, num;
|
||||||
ulong_t pmp_type, pmp_addr;
|
ulong_t pmp_mode, pmp_addr;
|
||||||
unsigned char *uchar_pmpcfg;
|
unsigned char *uchar_pmpcfg;
|
||||||
struct k_thread *thread;
|
struct k_thread *thread;
|
||||||
ulong_t size = (ulong_t) domain->partitions[partition_id].size;
|
ulong_t size = (ulong_t) domain->partitions[partition_id].size;
|
||||||
|
@ -416,19 +599,19 @@ int arch_mem_domain_partition_remove(struct k_mem_domain *domain,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size == 4) {
|
if (size == 4) {
|
||||||
pmp_type = PMP_NA4;
|
pmp_mode = PMP_NA4;
|
||||||
pmp_addr = TO_PMP_ADDR(start);
|
pmp_addr = TO_PMP_ADDR(start);
|
||||||
num = 1U;
|
num = 1U;
|
||||||
}
|
}
|
||||||
#if !defined(CONFIG_PMP_POWER_OF_TWO_ALIGNMENT) || defined(CONFIG_PMP_STACK_GUARD)
|
#if !defined(CONFIG_PMP_POWER_OF_TWO_ALIGNMENT) || defined(CONFIG_PMP_STACK_GUARD)
|
||||||
else if ((start & (size - 1)) || (size & (size - 1))) {
|
else if ((start & (size - 1)) || (size & (size - 1))) {
|
||||||
pmp_type = PMP_TOR;
|
pmp_mode = PMP_TOR;
|
||||||
pmp_addr = TO_PMP_ADDR(start + size);
|
pmp_addr = TO_PMP_ADDR(start + size);
|
||||||
num = 2U;
|
num = 2U;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PMP_POWER_OF_TWO_ALIGNMENT || CONFIG_PMP_STACK_GUARD */
|
#endif /* CONFIG_PMP_POWER_OF_TWO_ALIGNMENT || CONFIG_PMP_STACK_GUARD */
|
||||||
else {
|
else {
|
||||||
pmp_type = PMP_NAPOT;
|
pmp_mode = PMP_NAPOT;
|
||||||
pmp_addr = TO_PMP_NAPOT(start, size);
|
pmp_addr = TO_PMP_NAPOT(start, size);
|
||||||
num = 1U;
|
num = 1U;
|
||||||
}
|
}
|
||||||
|
@ -442,7 +625,7 @@ int arch_mem_domain_partition_remove(struct k_mem_domain *domain,
|
||||||
for (index = PMP_REGION_NUM_FOR_U_THREAD;
|
for (index = PMP_REGION_NUM_FOR_U_THREAD;
|
||||||
index < CONFIG_PMP_SLOT;
|
index < CONFIG_PMP_SLOT;
|
||||||
index++) {
|
index++) {
|
||||||
if (((uchar_pmpcfg[index] & PMP_TYPE_MASK) == pmp_type) &&
|
if (((uchar_pmpcfg[index] & PMP_TYPE_MASK) == pmp_mode) &&
|
||||||
(pmp_addr == thread->arch.u_pmpaddr[index])) {
|
(pmp_addr == thread->arch.u_pmpaddr[index])) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -460,7 +643,7 @@ int arch_mem_domain_partition_remove(struct k_mem_domain *domain,
|
||||||
* using this memory domain.
|
* using this memory domain.
|
||||||
*/
|
*/
|
||||||
#if !defined(CONFIG_PMP_POWER_OF_TWO_ALIGNMENT) || defined(CONFIG_PMP_STACK_GUARD)
|
#if !defined(CONFIG_PMP_POWER_OF_TWO_ALIGNMENT) || defined(CONFIG_PMP_STACK_GUARD)
|
||||||
if (pmp_type == PMP_TOR) {
|
if (pmp_mode == PMP_TOR) {
|
||||||
index--;
|
index--;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PMP_POWER_OF_TWO_ALIGNMENT || CONFIG_PMP_STACK_GUARD */
|
#endif /* CONFIG_PMP_POWER_OF_TWO_ALIGNMENT || CONFIG_PMP_STACK_GUARD */
|
||||||
|
@ -554,24 +737,18 @@ int arch_mem_domain_thread_remove(struct k_thread *thread)
|
||||||
#endif /* CONFIG_USERSPACE */
|
#endif /* CONFIG_USERSPACE */
|
||||||
|
|
||||||
#ifdef CONFIG_PMP_STACK_GUARD
|
#ifdef CONFIG_PMP_STACK_GUARD
|
||||||
|
|
||||||
void z_riscv_init_stack_guard(struct k_thread *thread)
|
void z_riscv_init_stack_guard(struct k_thread *thread)
|
||||||
{
|
{
|
||||||
unsigned char index = 0U;
|
|
||||||
unsigned char *uchar_pmpcfg;
|
|
||||||
ulong_t stack_guard_addr;
|
ulong_t stack_guard_addr;
|
||||||
|
struct riscv_pmp_region dynamic_regions[4]; /* Maximum region_num is 4 */
|
||||||
uchar_pmpcfg = (unsigned char *) thread->arch.s_pmpcfg;
|
uint8_t region_num = 0U;
|
||||||
|
|
||||||
uchar_pmpcfg++;
|
|
||||||
|
|
||||||
/* stack guard: None */
|
/* stack guard: None */
|
||||||
thread->arch.s_pmpaddr[index] = TO_PMP_ADDR(thread->stack_info.start);
|
dynamic_regions[region_num].start = thread->stack_info.start;
|
||||||
uchar_pmpcfg[index++] = PMP_NA4;
|
dynamic_regions[region_num].size = PMP_GUARD_ALIGN_AND_SIZE;
|
||||||
thread->arch.s_pmpaddr[index] =
|
dynamic_regions[region_num].perm = 0;
|
||||||
TO_PMP_ADDR(thread->stack_info.start +
|
dynamic_regions[region_num].mode = PMP_MODE_TOR;
|
||||||
PMP_GUARD_ALIGN_AND_SIZE);
|
region_num++;
|
||||||
uchar_pmpcfg[index++] = PMP_TOR;
|
|
||||||
|
|
||||||
#ifdef CONFIG_USERSPACE
|
#ifdef CONFIG_USERSPACE
|
||||||
if (thread->arch.priv_stack_start) {
|
if (thread->arch.priv_stack_start) {
|
||||||
|
@ -580,28 +757,34 @@ void z_riscv_init_stack_guard(struct k_thread *thread)
|
||||||
#else
|
#else
|
||||||
stack_guard_addr = (ulong_t) thread->stack_obj;
|
stack_guard_addr = (ulong_t) thread->stack_obj;
|
||||||
#endif /* CONFIG_PMP_POWER_OF_TWO_ALIGNMENT */
|
#endif /* CONFIG_PMP_POWER_OF_TWO_ALIGNMENT */
|
||||||
thread->arch.s_pmpaddr[index] =
|
dynamic_regions[region_num].start = stack_guard_addr;
|
||||||
TO_PMP_ADDR(stack_guard_addr);
|
dynamic_regions[region_num].size = PMP_GUARD_ALIGN_AND_SIZE;
|
||||||
uchar_pmpcfg[index++] = PMP_NA4;
|
dynamic_regions[region_num].perm = 0;
|
||||||
thread->arch.s_pmpaddr[index] =
|
dynamic_regions[region_num].mode = PMP_MODE_TOR;
|
||||||
TO_PMP_ADDR(stack_guard_addr +
|
region_num++;
|
||||||
PMP_GUARD_ALIGN_AND_SIZE);
|
|
||||||
uchar_pmpcfg[index++] = PMP_TOR;
|
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_USERSPACE */
|
#endif /* CONFIG_USERSPACE */
|
||||||
|
|
||||||
/* RAM: RW */
|
/* RAM: RW */
|
||||||
thread->arch.s_pmpaddr[index] = TO_PMP_ADDR(CONFIG_SRAM_BASE_ADDRESS |
|
dynamic_regions[region_num].start = CONFIG_SRAM_BASE_ADDRESS;
|
||||||
TO_NAPOT_RANGE(KB(CONFIG_SRAM_SIZE)));
|
dynamic_regions[region_num].size = KB(CONFIG_SRAM_SIZE);
|
||||||
uchar_pmpcfg[index++] = (PMP_NAPOT | PMP_R | PMP_W);
|
dynamic_regions[region_num].perm = PMP_R | PMP_W;
|
||||||
|
dynamic_regions[region_num].mode = PMP_MODE_NAPOT;
|
||||||
|
region_num++;
|
||||||
|
|
||||||
/* All other memory: RWX */
|
/* All other memory: RWX */
|
||||||
#ifdef CONFIG_64BIT
|
/* special case: start = size = 0 means whole memory. */
|
||||||
thread->arch.s_pmpaddr[index] = 0x1FFFFFFFFFFFFFFF;
|
dynamic_regions[region_num].start = 0;
|
||||||
#else
|
dynamic_regions[region_num].size = 0;
|
||||||
thread->arch.s_pmpaddr[index] = 0x1FFFFFFF;
|
dynamic_regions[region_num].perm = PMP_R | PMP_W | PMP_X;
|
||||||
#endif /* CONFIG_64BIT */
|
dynamic_regions[region_num].mode = PMP_MODE_NAPOT;
|
||||||
uchar_pmpcfg[index] = PMP_NAPOT | PMP_R | PMP_W | PMP_X;
|
region_num++;
|
||||||
|
|
||||||
|
/* Reserve index 0 for PMP stack guard */
|
||||||
|
unsigned char index = 1;
|
||||||
|
|
||||||
|
riscv_pmp_regions_translate(index, dynamic_regions, region_num,
|
||||||
|
thread->arch.s_pmpcfg, thread->arch.s_pmpaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void z_riscv_configure_stack_guard(struct k_thread *thread)
|
void z_riscv_configure_stack_guard(struct k_thread *thread)
|
||||||
|
@ -613,8 +796,8 @@ void z_riscv_configure_stack_guard(struct k_thread *thread)
|
||||||
|
|
||||||
z_riscv_pmp_clear_config();
|
z_riscv_pmp_clear_config();
|
||||||
|
|
||||||
for (i = 0U; i < PMP_REGION_NUM_FOR_STACK_GUARD; i++)
|
for (i = 1U; i < PMP_REGION_NUM_FOR_STACK_GUARD; i++)
|
||||||
csr_write_enum(CSR_PMPADDR1 + i, thread->arch.s_pmpaddr[i]);
|
csr_write_enum(CSR_PMPADDR0 + i, thread->arch.s_pmpaddr[i]);
|
||||||
|
|
||||||
for (i = 0U; i < PMP_CFG_CSR_NUM_FOR_STACK_GUARD; i++)
|
for (i = 0U; i < PMP_CFG_CSR_NUM_FOR_STACK_GUARD; i++)
|
||||||
csr_write_enum(CSR_PMPCFG0 + i, thread->arch.s_pmpcfg[i]);
|
csr_write_enum(CSR_PMPCFG0 + i, thread->arch.s_pmpcfg[i]);
|
||||||
|
@ -625,13 +808,13 @@ void z_riscv_configure_stack_guard(struct k_thread *thread)
|
||||||
|
|
||||||
void z_riscv_configure_interrupt_stack_guard(void)
|
void z_riscv_configure_interrupt_stack_guard(void)
|
||||||
{
|
{
|
||||||
if (PMP_GUARD_ALIGN_AND_SIZE > 4) {
|
int index = 0, ret;
|
||||||
z_riscv_pmp_set(0, PMP_NAPOT | PMP_L,
|
|
||||||
(ulong_t) z_interrupt_stacks[0] |
|
LOG_DBG("Set static PMP region %d for IRQ stack guard", index);
|
||||||
TO_NAPOT_RANGE(PMP_GUARD_ALIGN_AND_SIZE));
|
ret = riscv_pmp_region_set(index, &irq_stack_guard_region);
|
||||||
} else {
|
if (ret == -EINVAL) {
|
||||||
z_riscv_pmp_set(0, PMP_NA4 | PMP_L,
|
LOG_ERR("Configure static PMP region of IRQ stack guard "
|
||||||
(ulong_t) z_interrupt_stacks[0]);
|
"failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PMP_STACK_GUARD */
|
#endif /* CONFIG_PMP_STACK_GUARD */
|
||||||
|
@ -640,6 +823,7 @@ void z_riscv_configure_interrupt_stack_guard(void)
|
||||||
|
|
||||||
void z_riscv_pmp_init_thread(struct k_thread *thread)
|
void z_riscv_pmp_init_thread(struct k_thread *thread)
|
||||||
{
|
{
|
||||||
|
/* Clear [u|s]_pmp[cfg|addr] field of k_thread */
|
||||||
unsigned char i;
|
unsigned char i;
|
||||||
ulong_t *pmpcfg;
|
ulong_t *pmpcfg;
|
||||||
|
|
||||||
|
|
|
@ -38,21 +38,6 @@
|
||||||
|
|
||||||
#ifdef CONFIG_RISCV_PMP
|
#ifdef CONFIG_RISCV_PMP
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief Set a Physical Memory Protection slot
|
|
||||||
*
|
|
||||||
* Configure a memory region to be secured by one of the 16 PMP entries.
|
|
||||||
*
|
|
||||||
* @param index Number of the targeted PMP entrie (0 to 15 only).
|
|
||||||
* @param cfg_val Configuration value (cf datasheet or defined flags)
|
|
||||||
* @param addr_val Address register value
|
|
||||||
*
|
|
||||||
* This function shall only be called from Secure state.
|
|
||||||
*
|
|
||||||
* @return -1 if bad argument, 0 otherwise.
|
|
||||||
*/
|
|
||||||
int z_riscv_pmp_set(unsigned int index, ulong_t cfg_val, ulong_t addr_val);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief Reset to 0 all PMP setup registers
|
* @brief Reset to 0 all PMP setup registers
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue