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>
|
||||
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
|
||||
extern ulong_t is_user_mode;
|
||||
#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 {
|
||||
CSR_PMPCFG0,
|
||||
CSR_PMPCFG1,
|
||||
|
@ -44,7 +86,7 @@ enum {
|
|||
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;
|
||||
|
||||
|
@ -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 shift, mask;
|
||||
int pmpcfg_csr;
|
||||
int pmpaddr_csr;
|
||||
|
||||
if (index >= PMP_SLOT_NUMBER) {
|
||||
if (index >= CONFIG_PMP_SLOT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Calculate PMP config/addr register, shift and mask */
|
||||
#ifdef CONFIG_64BIT
|
||||
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 */
|
||||
pmpcfg_csr = CSR_PMPCFG0 + PMPCFG_NUM(index);
|
||||
pmpaddr_csr = CSR_PMPADDR0 + index;
|
||||
|
||||
/* Mask = 0x000000FF<<((index%4)*8) */
|
||||
mask = 0x000000FF << shift;
|
||||
|
||||
cfg_val = cfg_val << shift;
|
||||
addr_val = TO_PMP_ADDR(addr_val);
|
||||
shift = PMPCFG_SHIFT(index);
|
||||
mask = 0xFF << shift;
|
||||
|
||||
reg_val = csr_read_enum(pmpcfg_csr);
|
||||
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(pmpcfg_csr, reg_val);
|
||||
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)
|
||||
{
|
||||
LOG_DBG("Clear all dynamic PMP regions");
|
||||
for (unsigned int i = 0; i < RISCV_PMP_CFG_NUM; i++)
|
||||
csr_write_enum(CSR_PMPCFG0 + i, 0);
|
||||
}
|
||||
|
@ -189,48 +390,38 @@ void z_riscv_pmp_clear_config(void)
|
|||
#include <linker/linker-defs.h>
|
||||
void z_riscv_init_user_accesses(struct k_thread *thread)
|
||||
{
|
||||
unsigned char index;
|
||||
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;
|
||||
|
||||
unsigned char index = 0U;
|
||||
#ifdef CONFIG_PMP_STACK_GUARD
|
||||
index++;
|
||||
#endif /* CONFIG_PMP_STACK_GUARD */
|
||||
|
||||
struct riscv_pmp_region dynamic_regions[] = {
|
||||
{
|
||||
/* MCU state */
|
||||
thread->arch.u_pmpaddr[index] = TO_PMP_ADDR((ulong_t) &is_user_mode);
|
||||
uchar_pmpcfg[index++] = PMP_NA4 | PMP_R;
|
||||
#if defined(CONFIG_PMP_POWER_OF_TWO_ALIGNMENT)
|
||||
.start = (ulong_t) &is_user_mode,
|
||||
.size = 4,
|
||||
.perm = PMP_R,
|
||||
.mode = PMP_MODE_NA4,
|
||||
},
|
||||
{
|
||||
/* Program and RO data */
|
||||
thread->arch.u_pmpaddr[index] = TO_PMP_NAPOT(rom_start, rom_size);
|
||||
uchar_pmpcfg[index++] = PMP_NAPOT | PMP_R | PMP_X;
|
||||
.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 */
|
||||
thread->arch.u_pmpaddr[index] = TO_PMP_NAPOT(thread->stack_info.start,
|
||||
thread->stack_info.size);
|
||||
|
||||
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 */
|
||||
riscv_pmp_regions_translate(index, dynamic_regions,
|
||||
ARRAY_SIZE(dynamic_regions), thread->arch.u_pmpcfg,
|
||||
thread->arch.u_pmpaddr);
|
||||
}
|
||||
|
||||
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++)
|
||||
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,
|
||||
|
@ -262,6 +456,12 @@ int z_riscv_pmp_add_dynamic(struct k_thread *thread,
|
|||
goto out;
|
||||
}
|
||||
|
||||
struct riscv_pmp_region pmp_region = {
|
||||
.start = addr,
|
||||
.size = size,
|
||||
.perm = flags,
|
||||
};
|
||||
|
||||
/* Get next free entry */
|
||||
uchar_pmpcfg = (unsigned char *) thread->arch.u_pmpcfg;
|
||||
|
||||
|
@ -271,35 +471,18 @@ int z_riscv_pmp_add_dynamic(struct k_thread *thread,
|
|||
index++;
|
||||
}
|
||||
|
||||
__ASSERT((index < CONFIG_PMP_SLOT), "no free PMP entry\n");
|
||||
CHECKIF(!(index < CONFIG_PMP_SLOT)) {
|
||||
ret = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Select the best type */
|
||||
/* Select the best mode */
|
||||
if (size == 4) {
|
||||
thread->arch.u_pmpaddr[index] = TO_PMP_ADDR(addr);
|
||||
uchar_pmpcfg[index] = flags | PMP_NA4;
|
||||
}
|
||||
#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;
|
||||
pmp_region.mode = PMP_MODE_NA4;
|
||||
} else {
|
||||
pmp_region.mode = PMP_MODE_DEFAULT;
|
||||
}
|
||||
|
||||
thread->arch.u_pmpaddr[index] = TO_PMP_ADDR(addr);
|
||||
uchar_pmpcfg[index++] = flags | PMP_NA4;
|
||||
thread->arch.u_pmpaddr[index] = TO_PMP_ADDR(addr + size);
|
||||
uchar_pmpcfg[index++] = flags | PMP_TOR;
|
||||
}
|
||||
#endif /* !CONFIG_PMP_POWER_OF_TWO_ALIGNMENT */
|
||||
else {
|
||||
thread->arch.u_pmpaddr[index] = TO_PMP_NAPOT(addr, size);
|
||||
uchar_pmpcfg[index] = flags | PMP_NAPOT;
|
||||
index = riscv_pmp_region_translate(index, &pmp_region, false,
|
||||
thread->arch.u_pmpcfg, thread->arch.u_pmpaddr);
|
||||
|
||||
if (index == -ENOSPC) {
|
||||
ret = -ENOSPC;
|
||||
}
|
||||
|
||||
out:
|
||||
|
@ -396,7 +579,7 @@ int arch_mem_domain_partition_remove(struct k_mem_domain *domain,
|
|||
{
|
||||
sys_dnode_t *node, *next_node;
|
||||
uint32_t index, i, num;
|
||||
ulong_t pmp_type, pmp_addr;
|
||||
ulong_t pmp_mode, pmp_addr;
|
||||
unsigned char *uchar_pmpcfg;
|
||||
struct k_thread *thread;
|
||||
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) {
|
||||
pmp_type = PMP_NA4;
|
||||
pmp_mode = PMP_NA4;
|
||||
pmp_addr = TO_PMP_ADDR(start);
|
||||
num = 1U;
|
||||
}
|
||||
#if !defined(CONFIG_PMP_POWER_OF_TWO_ALIGNMENT) || defined(CONFIG_PMP_STACK_GUARD)
|
||||
else if ((start & (size - 1)) || (size & (size - 1))) {
|
||||
pmp_type = PMP_TOR;
|
||||
pmp_mode = PMP_TOR;
|
||||
pmp_addr = TO_PMP_ADDR(start + size);
|
||||
num = 2U;
|
||||
}
|
||||
#endif /* CONFIG_PMP_POWER_OF_TWO_ALIGNMENT || CONFIG_PMP_STACK_GUARD */
|
||||
else {
|
||||
pmp_type = PMP_NAPOT;
|
||||
pmp_mode = PMP_NAPOT;
|
||||
pmp_addr = TO_PMP_NAPOT(start, size);
|
||||
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;
|
||||
index < CONFIG_PMP_SLOT;
|
||||
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])) {
|
||||
break;
|
||||
}
|
||||
|
@ -460,7 +643,7 @@ int arch_mem_domain_partition_remove(struct k_mem_domain *domain,
|
|||
* using this memory domain.
|
||||
*/
|
||||
#if !defined(CONFIG_PMP_POWER_OF_TWO_ALIGNMENT) || defined(CONFIG_PMP_STACK_GUARD)
|
||||
if (pmp_type == PMP_TOR) {
|
||||
if (pmp_mode == PMP_TOR) {
|
||||
index--;
|
||||
}
|
||||
#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 */
|
||||
|
||||
#ifdef CONFIG_PMP_STACK_GUARD
|
||||
|
||||
void z_riscv_init_stack_guard(struct k_thread *thread)
|
||||
{
|
||||
unsigned char index = 0U;
|
||||
unsigned char *uchar_pmpcfg;
|
||||
ulong_t stack_guard_addr;
|
||||
|
||||
uchar_pmpcfg = (unsigned char *) thread->arch.s_pmpcfg;
|
||||
|
||||
uchar_pmpcfg++;
|
||||
struct riscv_pmp_region dynamic_regions[4]; /* Maximum region_num is 4 */
|
||||
uint8_t region_num = 0U;
|
||||
|
||||
/* stack guard: None */
|
||||
thread->arch.s_pmpaddr[index] = TO_PMP_ADDR(thread->stack_info.start);
|
||||
uchar_pmpcfg[index++] = PMP_NA4;
|
||||
thread->arch.s_pmpaddr[index] =
|
||||
TO_PMP_ADDR(thread->stack_info.start +
|
||||
PMP_GUARD_ALIGN_AND_SIZE);
|
||||
uchar_pmpcfg[index++] = PMP_TOR;
|
||||
dynamic_regions[region_num].start = thread->stack_info.start;
|
||||
dynamic_regions[region_num].size = PMP_GUARD_ALIGN_AND_SIZE;
|
||||
dynamic_regions[region_num].perm = 0;
|
||||
dynamic_regions[region_num].mode = PMP_MODE_TOR;
|
||||
region_num++;
|
||||
|
||||
#ifdef CONFIG_USERSPACE
|
||||
if (thread->arch.priv_stack_start) {
|
||||
|
@ -580,28 +757,34 @@ void z_riscv_init_stack_guard(struct k_thread *thread)
|
|||
#else
|
||||
stack_guard_addr = (ulong_t) thread->stack_obj;
|
||||
#endif /* CONFIG_PMP_POWER_OF_TWO_ALIGNMENT */
|
||||
thread->arch.s_pmpaddr[index] =
|
||||
TO_PMP_ADDR(stack_guard_addr);
|
||||
uchar_pmpcfg[index++] = PMP_NA4;
|
||||
thread->arch.s_pmpaddr[index] =
|
||||
TO_PMP_ADDR(stack_guard_addr +
|
||||
PMP_GUARD_ALIGN_AND_SIZE);
|
||||
uchar_pmpcfg[index++] = PMP_TOR;
|
||||
dynamic_regions[region_num].start = stack_guard_addr;
|
||||
dynamic_regions[region_num].size = PMP_GUARD_ALIGN_AND_SIZE;
|
||||
dynamic_regions[region_num].perm = 0;
|
||||
dynamic_regions[region_num].mode = PMP_MODE_TOR;
|
||||
region_num++;
|
||||
}
|
||||
#endif /* CONFIG_USERSPACE */
|
||||
|
||||
/* RAM: RW */
|
||||
thread->arch.s_pmpaddr[index] = TO_PMP_ADDR(CONFIG_SRAM_BASE_ADDRESS |
|
||||
TO_NAPOT_RANGE(KB(CONFIG_SRAM_SIZE)));
|
||||
uchar_pmpcfg[index++] = (PMP_NAPOT | PMP_R | PMP_W);
|
||||
dynamic_regions[region_num].start = CONFIG_SRAM_BASE_ADDRESS;
|
||||
dynamic_regions[region_num].size = KB(CONFIG_SRAM_SIZE);
|
||||
dynamic_regions[region_num].perm = PMP_R | PMP_W;
|
||||
dynamic_regions[region_num].mode = PMP_MODE_NAPOT;
|
||||
region_num++;
|
||||
|
||||
/* All other memory: RWX */
|
||||
#ifdef CONFIG_64BIT
|
||||
thread->arch.s_pmpaddr[index] = 0x1FFFFFFFFFFFFFFF;
|
||||
#else
|
||||
thread->arch.s_pmpaddr[index] = 0x1FFFFFFF;
|
||||
#endif /* CONFIG_64BIT */
|
||||
uchar_pmpcfg[index] = PMP_NAPOT | PMP_R | PMP_W | PMP_X;
|
||||
/* special case: start = size = 0 means whole memory. */
|
||||
dynamic_regions[region_num].start = 0;
|
||||
dynamic_regions[region_num].size = 0;
|
||||
dynamic_regions[region_num].perm = PMP_R | PMP_W | PMP_X;
|
||||
dynamic_regions[region_num].mode = PMP_MODE_NAPOT;
|
||||
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)
|
||||
|
@ -613,8 +796,8 @@ void z_riscv_configure_stack_guard(struct k_thread *thread)
|
|||
|
||||
z_riscv_pmp_clear_config();
|
||||
|
||||
for (i = 0U; i < PMP_REGION_NUM_FOR_STACK_GUARD; i++)
|
||||
csr_write_enum(CSR_PMPADDR1 + i, thread->arch.s_pmpaddr[i]);
|
||||
for (i = 1U; i < PMP_REGION_NUM_FOR_STACK_GUARD; i++)
|
||||
csr_write_enum(CSR_PMPADDR0 + i, thread->arch.s_pmpaddr[i]);
|
||||
|
||||
for (i = 0U; i < PMP_CFG_CSR_NUM_FOR_STACK_GUARD; 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)
|
||||
{
|
||||
if (PMP_GUARD_ALIGN_AND_SIZE > 4) {
|
||||
z_riscv_pmp_set(0, PMP_NAPOT | PMP_L,
|
||||
(ulong_t) z_interrupt_stacks[0] |
|
||||
TO_NAPOT_RANGE(PMP_GUARD_ALIGN_AND_SIZE));
|
||||
} else {
|
||||
z_riscv_pmp_set(0, PMP_NA4 | PMP_L,
|
||||
(ulong_t) z_interrupt_stacks[0]);
|
||||
int index = 0, ret;
|
||||
|
||||
LOG_DBG("Set static PMP region %d for IRQ stack guard", index);
|
||||
ret = riscv_pmp_region_set(index, &irq_stack_guard_region);
|
||||
if (ret == -EINVAL) {
|
||||
LOG_ERR("Configure static PMP region of IRQ stack guard "
|
||||
"failed");
|
||||
}
|
||||
}
|
||||
#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)
|
||||
{
|
||||
/* Clear [u|s]_pmp[cfg|addr] field of k_thread */
|
||||
unsigned char i;
|
||||
ulong_t *pmpcfg;
|
||||
|
||||
|
|
|
@ -38,21 +38,6 @@
|
|||
|
||||
#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
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue