Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mmu2 #4

Open
wants to merge 3 commits into
base: pre_mmu2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build/configs/rtl8730e/loadable_apps/defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1206,7 +1206,7 @@ CONFIG_ELF_CACHE_READ=y
CONFIG_ELF_CACHE_BLOCK_SIZE=2048
CONFIG_ELF_CACHE_BLOCKS_COUNT=60
# CONFIG_SYMTAB_ORDEREDBYNAME is not set
# CONFIG_OPTIMIZE_APP_RELOAD_TIME is not set
CONFIG_OPTIMIZE_APP_RELOAD_TIME=y
# CONFIG_SAVE_BIN_SECTION_ADDR is not set

#
Expand Down
2 changes: 1 addition & 1 deletion docs/MPURegionsUsageGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
```c
void mpu_region_initialize(struct mpu_usages_s *mpu)

offset += MPU_NUM_REGIONS;
offset += NUM_APP_REGIONS;
mpu->nregion_xxx_xx = offset;
```
2. **Board specific MPU region reservation**
Expand Down
2 changes: 1 addition & 1 deletion os/arch/arm/src/amebasmart/Make.defs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ CMN_CSRCS += arm_doirq.c arm_gicv2.c arm_gicv2_dump.c
CMN_CSRCS += arm_initialstate.c arm_mmu.c arm_prefetchabort.c
CMN_CSRCS += arm_schedulesigaction.c arm_sigdeliver.c
CMN_CSRCS += arm_syscall.c arm_tcbinfo.c arm_undefinedinsn.c
CMN_CSRCS += arm_perf.c up_checkspace.c
CMN_CSRCS += arm_perf.c up_checkspace.c up_restoretask.c

ifeq ($(CONFIG_ARMV7A_L2CC_PL310),y)
CMN_CSRCS += arm_l2cc_pl310.c
Expand Down
1 change: 1 addition & 0 deletions os/arch/arm/src/armv7-a/arm_blocktask.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ void up_block_task(struct tcb_s *tcb, tstate_t task_state)
/* Reset scheduler parameters */

// sched_resume_scheduler(rtcb);
up_restoretask(rtcb);

/* Then switch contexts. Any necessary address environment
* changes will be made when the interrupt returns.
Expand Down
4 changes: 4 additions & 0 deletions os/arch/arm/src/armv7-a/arm_head.S
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,11 @@ __start:
.LCptinfo:
.long (PGTABLE_BASE_PADDR & 0xfff00000) /* Physical base address */
.long (PGTABLE_BASE_VADDR & 0xfff00000) /* Virtual base address */
#ifdef CONFIG_APP_BINARY_SEPARATION
.long MMU_USR_PGTBL_MAPPING /* MMU flags for text section in RAM */
#else
.long MMU_MEMFLAGS /* MMU flags for text section in RAM */
#endif
.size .LCptinfo, . -.LCptinfo
#endif

Expand Down
311 changes: 311 additions & 0 deletions os/arch/arm/src/armv7-a/arm_mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,41 @@
#include "cp15_cacheops.h"
#include "mmu.h"

#ifdef CONFIG_APP_BINARY_SEPARATION
#include <tinyara/mm/mm.h>
#endif
/****************************************************************************
* Private Functions
****************************************************************************/
static void mmu_set_flags(uint32_t *val, bool ro, bool exec, uint8_t isL1, uint8_t isGlobal)
{
if (isL1) {
if (ro && exec) {
*val |= MMU_APP_L1_ROX;
} else if (ro) {
*val |= MMU_APP_L1_RO;
} else {
*val |= MMU_APP_L1_RW;
}

if (!isGlobal) {
*val |= PMD_SECT_NG;
}
} else {
if (ro && exec) {
*val |= MMU_APP_L2_ROX;
} else if (ro) {
*val |= MMU_APP_L2_RO;
} else {
*val |= MMU_APP_L2_RW;
}

if (!isGlobal) {
// *val |= PTE_NG; disable non global bit for now, will check later if required to use asid..
}
}
}

/****************************************************************************
* Public Functions
****************************************************************************/
Expand Down Expand Up @@ -254,3 +289,279 @@ void mmu_invalidate_region(uint32_t vstart, size_t size)
}
}
#endif

#ifdef CONFIG_APP_BINARY_SEPARATION
/****************************************************************************
* Name: mmu_get_os_l1_pgtbl
*
* Description:
* Returns the virtual address of the kernel L1 page table.
*
* Input Parameters:
*
* Returned Value:
* Page table address
****************************************************************************/
uint32_t *mmu_get_os_l1_pgtbl(void)
{
return (uint32_t *)PGTABLE_BASE_VADDR;
}

/****************************************************************************
* Name: mmu_allocate_app_l1_pgtbl
*
* Description:
* Allocate space for L1 page table of application, in accordance with
* the requirements of the arch specific mmu.
*
* Input Parameters:
*
* Returned Value:
* L1 Page table address
****************************************************************************/
uint32_t *mmu_allocate_app_l1_pgtbl(int app_id)
{
uint32_t *addr = (uint32_t *)(PGTABLE_BASE_VADDR + (app_id * 16384));
// uint32_t *addr = (uint32_t *)kmm_memalign(L1_PGTBL_ALIGNMENT, L1_PGTBL_SIZE);
// ASSERT(addr);
// memset(addr, 0, L1_PGTBL_SIZE);
return addr;
}

/****************************************************************************
* Name: mmu_allocate_app_l2_pgtbl
*
* Description:
* Allocate space for L2 page table of application, in accordance with
* the requirements of the arch specific mmu.
*
* Input Parameters:
*
* Returned Value:
* L2 Page table address
****************************************************************************/
uint32_t *mmu_allocate_app_l2_pgtbl(int app_id, int l2_idx)
{
app_id--;
uint32_t *addr = (uint32_t *)(PGTABLE_BASE_VADDR + (2 * 16384) + (app_id * l2_idx * 1024));
// uint32_t *addr = (uint32_t *)kmm_memalign(L2_PGTBL_ALIGNMENT, L2_PGTBL_SIZE);
// ASSERT(addr);
// memset(addr, 0, L2_PGTBL_SIZE);
return addr;
}

/****************************************************************************
* Name: mmu_update_app_l1_pgtbl_ospgtbl
*
* Description:
* Loop through the L1 page table.
* Copy kernel L1 page table to app page table.
* If the entry is pointing to a L2 page table
* Allocate L2 page table for app.
* Copy entries from kernel to app L2 table.
* Update the L2 page table address in L1 table.
*
* Input Parameters:
* app_pgtbl: Pointer to L1 page table of app
*
****************************************************************************/
void mmu_update_app_l1_pgtbl_ospgtbl(uint32_t *app_l1_pgtbl)
{
uint32_t *os_l1_pgtbl = (uint32_t *)PGTABLE_BASE_VADDR;

memcpy((void *)app_l1_pgtbl, (void *)os_l1_pgtbl, L1_PGTBL_SIZE);
cp15_flush_dcache((uintptr_t)app_l1_pgtbl, (uintptr_t)app_l1_pgtbl + L1_PGTBL_SIZE);

#ifdef CONFIG_SUPPORT_COMMON_BINARY
for (int i = 0; i < L1_PGTBL_NENTRIES; i++) {
if ((os_l1_pgtbl[i] & PMD_TYPE_MASK) == PMD_TYPE_PTE) {
//Found a L2 page table.
uint32_t *os_l2_pgtbl = (uint32_t *)(os_l1_pgtbl[i] & PMD_PTE_PADDR_MASK);
uint32_t *app_l2_pgtbl = mmu_allocate_app_l2_pgtbl();
memcpy(app_l2_pgtbl, os_l2_pgtbl, L2_PGTBL_SIZE);
app_l1_pgtbl[i] &= ~PMD_PTE_PADDR_MASK;
app_l1_pgtbl[i] |= (uint32_t)app_l2_pgtbl & PMD_PTE_PADDR_MASK;
}
}
#endif
}

/****************************************************************************
* Name: mmu_map_app_region
*
* Description
*
* Input Parameters:
*
* Returned Value:
****************************************************************************/
void mmu_map_app_region(int app_id, uint32_t *l1_pgtbl, uint32_t start, uint32_t size, bool ro, bool exec, bool global)
{
uint32_t idx;
uint32_t val;
uint32_t end = start + size;
irqstate_t flags;

lldbg("start = 0x%08x end = 0x%08x size = %x\n", start, end, size);

// Run a loop until the entire region is mapped.
while (start < end) {
// Check if this address can be mapped to a section.
if (!(start & SECTION_MASK) && !(size & SECTION_MASK)) {
// Yes. Update the section entry in the the L1 page table.
idx = start >> 20;
val = start & PMD_PTE_PADDR_MASK;
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not required at present, but may be needed to change the mask to section instead of PTE

mmu_set_flags(&val, ro, exec, true, global);

lldbg("Add section for addr 0x%08x idx = %d\n", start, idx);

if (global) {
// If this update is for the common binary, then it is done
// in the kernel page tables and so the cache and tlbs need
// to be flushed and invalidated.
flags = enter_critical_section();
l1_pgtbl[idx] = val;
cp15_clean_dcache_bymva((uint32_t)&l1_pgtbl[idx]);
mmu_invalidate_region(start, SECTION_SIZE);
leave_critical_section(flags);
} else {
l1_pgtbl[idx] = val;
cp15_clean_dcache_bymva((uint32_t)&l1_pgtbl[idx]);
}

// Advance the memory region address.
start += SECTION_SIZE;
} else { // Check if this address can be mapped to a small page.

// Check if L2 page table is not created.
idx = (start & 0xfff00000) >> 20;
int l2_idx = 0;
uint32_t *l2_pgtbl = (uint32_t *)(l1_pgtbl[idx] & PMD_PTE_PADDR_MASK);
if ((l1_pgtbl[idx] & PMD_TYPE_MASK) != PMD_TYPE_PTE) {
// Yes. Allocate L2 page table for app.
l2_pgtbl = mmu_allocate_app_l2_pgtbl(app_id, l2_idx++);

/* fill the newly allocated l2 page table with default kernel flags */
uint32_t l2_start = start & PMD_SECT_PADDR_MASK;
lldbg("start address %x l2 page\n", l2_start);
for (int i = 0; i < L2_PGTBL_NENTRIES; i++) {
l2_pgtbl[i] = l2_start | (1<<10) | PTE_AP_RW1 | PTE_TYPE_SMALL | PMD_CACHEABLE;
lldbg("l2[%d] = %x\n", i, l2_pgtbl[i]);
l2_start += 0x1000;
}
lldbg("end address %x l2 page\n", l2_start);
val = l2_pgtbl;
lldbg("setting l2 pg tbl in l1 , %x\n", val);
l1_pgtbl[idx] = (val & PMD_PTE_PADDR_MASK) | PMD_SECT_DOM(0) | PMD_TYPE_PTE | (1 << 3);

lldbg("Allocated L2 pgtbl at 0x%08x\n", l2_pgtbl);

if (global) {
// If this update is for the common binary, then it is done
// in the kernel page tables and so the cache and tlbs need
// to be flushed and invalidated.

flags = enter_critical_section();

// Fill default entries into L2 page table.
uint32_t tmp = start;
for (idx = 0; idx < L2_PGTBL_NENTRIES; idx++) {
val = tmp & PTE_SMALL_PADDR_MASK;
val |= MMU_MEMFLAGS;
l2_pgtbl[idx] = val;
cp15_clean_dcache_bymva((uint32_t)&l2_pgtbl[idx]);
tmp += 4096;
}

// Update L2 page table address in L1 page table.
val = (uint32_t)l2_pgtbl & PMD_PTE_PADDR_MASK;
val |= MMU_L1_DATAFLAGS;
l1_pgtbl[idx] = val;

cp15_clean_dcache_bymva((uint32_t)&l1_pgtbl[idx]);
cp15_invalidate_tlb_bymva(start);
leave_critical_section(flags);
} else {
//already updated above
// Update L2 page table address in L1 page table.
//val = (uint32_t)l2_pgtbl & PMD_PTE_PADDR_MASK;
//val |= MMU_L1_PGTABFLAGS;
//l1_pgtbl[idx] = val;
// dbg("Set l1 pte at 0x%08x = 0x%08x\n", &l1_pgtbl[idx], val);
//cp15_clean_dcache_bymva((uint32_t)&l1_pgtbl[idx]);
}
}

// Update the L2 page table entry.
idx = (start & 0x000ff000) >> 12;
val = start & PTE_SMALL_PADDR_MASK;
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are filling the addresses from only the start in the page table, it will miss some entries before start and after end. I think it might not be right?? (May cause prefetch abort when fetching the address that does not have an entry in secondary page table?)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I will change it. But it will not affect our current issue.

mmu_set_flags(&val, ro, exec, false, global);

if (global) {
flags = enter_critical_section();
l2_pgtbl[idx] = val;
// If this update is for the common binary, then it is done
// in the kernel page tables and so the cache and tlbs need
// to be flushed and invalidated.
cp15_clean_dcache_bymva((uint32_t)&l2_pgtbl[idx]);
cp15_invalidate_tlb_bymva(start);
leave_critical_section(flags);
} else {
l2_pgtbl[idx] = val;
// dbg("Set l2 pte at 0x%08x = 0x%08x\n", &l2_pgtbl[idx], val);
//cp15_clean_dcache_bymva((uint32_t)&l2_pgtbl[idx]);
}

// Advance the memory region address.
start += SMALL_PAGE_SIZE;
}
}
}

#endif // CONFIG_APP_BINARY_SEPARATION


void mmu_dump_pgtbl(void)
{
struct tcb_s *rtcb = sched_self();
if (rtcb->app_id < 1) {
return;
}

uint32_t *l1tbl = mmu_l1_pgtable();

lldbg("L1 page table base addr = 0x%08x\n", l1tbl);

lldbg("================================================\n");
lldbg("ENTRY TYPE OUT NG AP XN\n");
lldbg("ADDR ADDR \n");
lldbg("================================================\n");
for (int i = 0; i < L1_PGTBL_NENTRIES; i++) {
bool ng = (l1tbl[i] & PMD_SECT_NG) ? 1 : 0;
if (ng && (l1tbl[i] & PMD_TYPE_MASK) == PMD_TYPE_SECT) {
lldbg("0x%08x SECT 0x%08x %d %1x%1x %d\n",
&l1tbl[i],
l1tbl[i] & PMD_SECT_PADDR_MASK,
(l1tbl[i] & PMD_SECT_NG) ? 1 : 0,
(l1tbl[i] & PMD_SECT_AP2) ? 1 : 0,
(l1tbl[i] & PMD_SECT_AP_MASK) >> PMD_SECT_AP_SHIFT,
(l1tbl[i] & PMD_SECT_XN) ? 1 : 0);
} else if((l1tbl[i] & PMD_TYPE_MASK) == PMD_TYPE_PTE) {
lldbg("0x%08x L1PTE 0x%08x\n", &l1tbl[i], l1tbl[i] & PMD_PTE_PADDR_MASK);
uint32_t *l2tbl = (uint32_t)l1tbl[i] & PMD_PTE_PADDR_MASK;
for (int j = 0; j < L2_PGTBL_NENTRIES; j++) {
bool ng = (l2tbl[j] & PTE_NG) ? 1 : 0;
if (ng && ((l2tbl[j] & PTE_TYPE_MASK) != PTE_TYPE_FAULT)) {
lldbg("0x%08x PAGE 0x%08x %d %1x%1x %d\n",
&l2tbl[j],
l2tbl[j] & PTE_SMALL_PADDR_MASK,
(l2tbl[j] & PTE_NG) ? 1 : 0,
(l2tbl[j] & PTE_AP2) ? 1 : 0,
(l2tbl[j] & PTE_AP_MASK) >> PTE_AP_SHIFT,
(l2tbl[j] & PTE_SMALL_XN) ? 1 : 0);
}
}
}
}
lldbg("=============================================\n");
}
5 changes: 5 additions & 0 deletions os/arch/arm/src/armv7-a/arm_prefetchabort.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@

#include "sched/sched.h"
#include "arm_internal.h"
#include "mmu.h"

/****************************************************************************
* Public Functions
Expand Down Expand Up @@ -148,6 +149,10 @@ uint32_t *arm_prefetchabort(uint32_t *regs, uint32_t ifar, uint32_t ifsr)

_alert("Prefetch abort. PC: %08x IFAR: %08x IFSR: %08x\n",
regs[REG_PC], ifar, ifsr);

_alert("MMU L1 Entry for 0x%08x = 0x%08x\n", ifar, mmu_l1_getentry(ifar));
mmu_dump_pgtbl();

PANIC();
return regs; /* To keep the compiler happy */
}
Expand Down
1 change: 1 addition & 0 deletions os/arch/arm/src/armv7-a/arm_releasepending.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ void up_release_pending(void)
/* Update scheduler parameters */

// sched_resume_scheduler(rtcb);
up_restoretask(rtcb);

/* Then switch contexts. Any necessary address environment
* changes will be made when the interrupt returns.
Expand Down
Loading