Blackfin: fix MPU page permission masks overflow when dealing with async memory
Attempting to use the MPU while doing XIP out of parallel flash hooked up to the async memory bus would often result in random crashes as the MPU slowly corrupted memory. The fallout here is that the async banks gain MPU protection from user space too. So any accesses have to go through the mmap() interface rather than just using hardcoded pointers. Signed-off-by: Barry Song <barry.song@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
This commit is contained in:
parent
c9784ebb23
commit
e18e7dd334
3 changed files with 38 additions and 11 deletions
|
@ -13,6 +13,7 @@
|
|||
#include <asm/page.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/cplbinit.h>
|
||||
#include <asm/sections.h>
|
||||
|
||||
/* Note: L1 stacks are CPU-private things, so we bluntly disable this
|
||||
feature in SMP mode, and use the per-CPU scratch SRAM bank only to
|
||||
|
@ -117,9 +118,16 @@ static inline void protect_page(struct mm_struct *mm, unsigned long addr,
|
|||
unsigned long flags)
|
||||
{
|
||||
unsigned long *mask = mm->context.page_rwx_mask;
|
||||
unsigned long page = addr >> 12;
|
||||
unsigned long idx = page >> 5;
|
||||
unsigned long bit = 1 << (page & 31);
|
||||
unsigned long page;
|
||||
unsigned long idx;
|
||||
unsigned long bit;
|
||||
|
||||
if (unlikely(addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE))
|
||||
page = (addr - (ASYNC_BANK0_BASE - _ramend)) >> 12;
|
||||
else
|
||||
page = addr >> 12;
|
||||
idx = page >> 5;
|
||||
bit = 1 << (page & 31);
|
||||
|
||||
if (flags & VM_READ)
|
||||
mask[idx] |= bit;
|
||||
|
|
|
@ -114,10 +114,15 @@ static noinline int dcplb_miss(unsigned int cpu)
|
|||
d_data = L2_DMEMORY;
|
||||
} else if (addr >= physical_mem_end) {
|
||||
if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) {
|
||||
addr &= ~(4 * 1024 * 1024 - 1);
|
||||
d_data &= ~PAGE_SIZE_4KB;
|
||||
d_data |= PAGE_SIZE_4MB;
|
||||
d_data |= CPLB_USER_RD | CPLB_USER_WR;
|
||||
mask = current_rwx_mask[cpu];
|
||||
if (mask) {
|
||||
int page = (addr - (ASYNC_BANK0_BASE - _ramend)) >> PAGE_SHIFT;
|
||||
int idx = page >> 5;
|
||||
int bit = 1 << (page & 31);
|
||||
|
||||
if (mask[idx] & bit)
|
||||
d_data |= CPLB_USER_RD;
|
||||
}
|
||||
} else if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH
|
||||
&& (status & (FAULT_RW | FAULT_USERSUPV)) == FAULT_USERSUPV) {
|
||||
addr &= ~(1 * 1024 * 1024 - 1);
|
||||
|
@ -204,10 +209,19 @@ static noinline int icplb_miss(unsigned int cpu)
|
|||
i_data = L2_IMEMORY;
|
||||
} else if (addr >= physical_mem_end) {
|
||||
if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) {
|
||||
addr &= ~(4 * 1024 * 1024 - 1);
|
||||
i_data &= ~PAGE_SIZE_4KB;
|
||||
i_data |= PAGE_SIZE_4MB;
|
||||
i_data |= CPLB_USER_RD;
|
||||
if (!(status & FAULT_USERSUPV)) {
|
||||
unsigned long *mask = current_rwx_mask[cpu];
|
||||
|
||||
if (mask) {
|
||||
int page = (addr - (ASYNC_BANK0_BASE - _ramend)) >> PAGE_SHIFT;
|
||||
int idx = page >> 5;
|
||||
int bit = 1 << (page & 31);
|
||||
|
||||
mask += 2 * page_mask_nelts;
|
||||
if (mask[idx] & bit)
|
||||
i_data |= CPLB_USER_RD;
|
||||
}
|
||||
}
|
||||
} else if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH
|
||||
&& (status & FAULT_USERSUPV)) {
|
||||
addr &= ~(1 * 1024 * 1024 - 1);
|
||||
|
|
|
@ -597,7 +597,12 @@ static __init void memory_setup(void)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_MPU
|
||||
#if defined(CONFIG_ROMFS_ON_MTD) && defined(CONFIG_MTD_ROM)
|
||||
page_mask_nelts = (((_ramend + ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE -
|
||||
ASYNC_BANK0_BASE) >> PAGE_SHIFT) + 31) / 32;
|
||||
#else
|
||||
page_mask_nelts = ((_ramend >> PAGE_SHIFT) + 31) / 32;
|
||||
#endif
|
||||
page_mask_order = get_order(3 * page_mask_nelts * sizeof(long));
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue