bl30: rtos_sdk fix pmp addr config omissions [1/1]
PD#SWPL-140705
Problem:
pmp_addr register need address aligned, for base address
which pmp protect matches conditions as follows:
If base address is 4K aligned, then pmp entry could protect
4K region from base address to base address + 4K.
If base address is 8K aligned, then pmp entry could protect
8K region from base address to base address + 8K.
And so on...
If do not config like this, the region which pmp protect
would have some bias, causing pmp config error and text
could not run ok.
Solution:
Make pmp_addr config aligned to size.
.text/rodata permission: R/X
other region permission: R/W
application to both M and U mode.
Verify:
t3x_bc302
Change-Id: Ic18e033cc1ca41ae2ba13e2d1bc244982d7459a8
Signed-off-by: bangzheng.liu <bangzheng.liu@amlogic.com>
diff --git a/n200_func.c b/n200_func.c
index e7532e9..0ae0bf0 100644
--- a/n200_func.c
+++ b/n200_func.c
@@ -36,85 +36,104 @@
}
#ifndef CONFIG_N200_REVA
+static uint32_t pmpcfg_order_get(uint32_t pmp_size)
+{
+ int pmpcfg_order = 0;
+
+ if ((pmp_size & (pmp_size - 1)) != 0) {
+ printf("error: pmp_size is not 2^n\n");
+ return 0;
+ }
+
+ while (pmp_size > 1) {
+ pmp_size >>= 1;
+ pmpcfg_order++;
+ }
+
+ return pmpcfg_order;
+}
+
+static uint32_t pmpaddr_encode(uint32_t pmp_base_addr, uint32_t pmp_cfg_order)
+{
+ uint32_t addrmask, pmpaddr;
+
+ addrmask = (1UL << (pmp_cfg_order - PMP_SHIFT)) - 1;
+ pmpaddr = ((pmp_base_addr >> PMP_SHIFT) & ~addrmask);
+ pmpaddr |= (addrmask >> 1);
+
+ return pmpaddr;
+}
+
+
/*
* -- Configure PMP --
* For both Machine and User mode.
* To make aocpu text/ro data space readable and executable.
- * To make aocpu data space readable and writable.
- * To make 4G space readable and writable.
* Note:
- * If config_pmp is called, pmp_open_all_space is invalid.
+ * If config_pmp is called, pmp_open_all_space is invalid.
*/
uint32_t config_pmp(void)
{
uint32_t start_text_addr = (uint32_t)&_text;
uint32_t end_text_addr = (uint32_t)&_etext;
uint32_t text_len_left = end_text_addr - start_text_addr;
- uint32_t next_seg_len;
- uint32_t pmp_cfg[8] = {0};
+ uint32_t next_seg_len = 0;
+ uint32_t pmp_cfg[8] = {0}, pmp_addr[8] = {0};
int pmp_entry_used = 0;
uint32_t pmp_region_base = start_text_addr;
- uint32_t ao_ram_end = configMEM_START + configMEM_LEN;
- uint32_t all_region_size = 0x1fffffff;
PMP_PRINT("AOCPU: configure PMP for memory 0x%lx ~ 0x%lx\n",
start_text_addr, end_text_addr);
while (text_len_left > 0) {
- for (next_seg_len = 1024; next_seg_len*2 <= text_len_left; next_seg_len *= 2)
- ;
+ if ((text_len_left >= SIZE_32K) && ((pmp_region_base & (SIZE_32K - 1)) == 0))
+ next_seg_len = SIZE_32K;
+ else if ((text_len_left >= SIZE_16K) && ((pmp_region_base & (SIZE_16K - 1)) == 0))
+ next_seg_len = SIZE_16K;
+ else if ((text_len_left >= SIZE_8K) && ((pmp_region_base & (SIZE_8K - 1)) == 0))
+ next_seg_len = SIZE_8K;
+ else if ((text_len_left >= SIZE_4K) && ((pmp_region_base & (SIZE_4K - 1)) == 0))
+ next_seg_len = SIZE_4K;
+ else if ((text_len_left >= SIZE_2K) && ((pmp_region_base & (SIZE_2K - 1)) == 0))
+ next_seg_len = SIZE_2K;
+ else if ((text_len_left >= SIZE_1K) && ((pmp_region_base & (SIZE_1K - 1)) == 0))
+ next_seg_len = SIZE_1K;
- text_len_left -= next_seg_len;
- PMP_PRINT_DEBUG("segment length: %lx\n", next_seg_len);
- PMP_PRINT_DEBUG("length left : %lx\n", text_len_left);
-
- /* Configure text/ro data space access privilege */
- switch (pmp_entry_used) {
- case 0:
- write_csr(pmpaddr0, (pmp_region_base >> 2) | NAPOT_SIZE(next_seg_len));
- pmp_cfg[0] = (PMP_CFG_R_EN | PMP_CFG_X_EN | PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
- break;
- case 1:
- write_csr(pmpaddr1, (pmp_region_base >> 2) | NAPOT_SIZE(next_seg_len));
- pmp_cfg[1] = (PMP_CFG_R_EN | PMP_CFG_X_EN | PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
- break;
- case 2:
- write_csr(pmpaddr2, (pmp_region_base >> 2) | NAPOT_SIZE(next_seg_len));
- pmp_cfg[2] = (PMP_CFG_R_EN | PMP_CFG_X_EN | PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
- break;
- case 3:
- write_csr(pmpaddr3, (pmp_region_base >> 2) | NAPOT_SIZE(next_seg_len));
- pmp_cfg[3] = (PMP_CFG_R_EN | PMP_CFG_X_EN | PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
- break;
- case 4:
- write_csr(pmpaddr4, (pmp_region_base >> 2) | NAPOT_SIZE(next_seg_len));
- pmp_cfg[4] = (PMP_CFG_R_EN | PMP_CFG_X_EN | PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
- break;
- case 5:
- write_csr(pmpaddr5, (pmp_region_base >> 2) | NAPOT_SIZE(next_seg_len));
- pmp_cfg[5] = (PMP_CFG_R_EN | PMP_CFG_X_EN | PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
- break;
- default:
+ if (next_seg_len == 0) {
+ PMP_PRINT("pmp config error: not aligned.\n");
+ PMP_PRINT("pmp base: 0x%x, segment left: 0x%x\n",
+ pmp_region_base, text_len_left);
break;
}
+
+ text_len_left -= next_seg_len;
+ PMP_PRINT_DEBUG("pm pregion base: %lx\n", pmp_region_base);
+ PMP_PRINT_DEBUG("segment length : %lx\n", next_seg_len);
+ PMP_PRINT_DEBUG("length left : %lx\n", text_len_left);
+
+ pmp_addr[pmp_entry_used] = pmpaddr_encode(pmp_region_base,
+ pmpcfg_order_get(next_seg_len));
+ pmp_cfg[pmp_entry_used] = (PMP_CFG_R_EN | PMP_CFG_X_EN |
+ PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
pmp_entry_used++;
pmp_region_base += next_seg_len;
PMP_PRINT_DEBUG("pmp_entry_used : %d\n", pmp_entry_used);
- PMP_PRINT_DEBUG("pmp_region_base: %lx\n", pmp_region_base);
+ next_seg_len = 0;
+
+ if (pmp_entry_used >= 8) {
+ PMP_PRINT_DEBUG("Note: pmp entry has been full used\n");
+ break;
+ }
}
- /* Configure data space access privilege */
- write_csr(pmpaddr6, (pmp_region_base >> 2) | NAPOT_SIZE(ao_ram_end - pmp_region_base));
- pmp_cfg[6] = (PMP_CFG_R_EN | PMP_CFG_W_EN | PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
- /* Configure all 32-bit (4G) address space access privilege */
- write_csr(pmpaddr7, (0x0) | all_region_size);
- pmp_cfg[7] = (PMP_CFG_R_EN | PMP_CFG_W_EN | PMP_CFG_A_NAPOT | PMP_CFG_L_EN);
- /* Set Configuration for text/ro data/data/4G space */
- write_csr(pmpcfg0, (pmp_cfg[3] << 24) | (pmp_cfg[2] << 16) |
- (pmp_cfg[1] << 8) | (pmp_cfg[0] << 0));
- write_csr(pmpcfg1, (pmp_cfg[7] << 24) | (pmp_cfg[6] << 16) |
- (pmp_cfg[5] << 8) | (pmp_cfg[4] << 0));
-
+ write_csr(pmpaddr0, pmp_addr[0]);
+ write_csr(pmpaddr1, pmp_addr[1]);
+ write_csr(pmpaddr2, pmp_addr[2]);
+ write_csr(pmpaddr3, pmp_addr[3]);
+ write_csr(pmpaddr4, pmp_addr[4]);
+ write_csr(pmpaddr5, pmp_addr[5]);
+ write_csr(pmpaddr6, pmp_addr[6]);
+ write_csr(pmpaddr7, pmp_addr[7]);
PMP_PRINT_DEBUG("pmpaddr0 : %lx\n", read_csr(pmpaddr0));
PMP_PRINT_DEBUG("pmpaddr1 : %lx\n", read_csr(pmpaddr1));
PMP_PRINT_DEBUG("pmpaddr2 : %lx\n", read_csr(pmpaddr2));
@@ -123,8 +142,15 @@
PMP_PRINT_DEBUG("pmpaddr5 : %lx\n", read_csr(pmpaddr5));
PMP_PRINT_DEBUG("pmpaddr6 : %lx\n", read_csr(pmpaddr6));
PMP_PRINT_DEBUG("pmpaddr7 : %lx\n", read_csr(pmpaddr7));
+
+ write_csr(pmpcfg0, (pmp_cfg[3] << 24) | (pmp_cfg[2] << 16) |
+ (pmp_cfg[1] << 8) | (pmp_cfg[0] << 0));
PMP_PRINT_DEBUG("pmpcfg0 : %lx\n", read_csr(pmpcfg0));
+
+ write_csr(pmpcfg1, (pmp_cfg[7] << 24) | (pmp_cfg[6] << 16) |
+ (pmp_cfg[5] << 8) | (pmp_cfg[4] << 0));
PMP_PRINT_DEBUG("pmpcfg1 : %lx\n", read_csr(pmpcfg1));
+
PMP_PRINT("AOCPU: configure PMP end\n");
return 0;