Skip to content

Commit

Permalink
Blackfin: fix MPU page permission masks overflow when dealing with as…
Browse files Browse the repository at this point in the history
…ync 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>
  • Loading branch information
Barry Song authored and Mike Frysinger committed Mar 9, 2010
1 parent c9784eb commit e18e7dd
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 11 deletions.
14 changes: 11 additions & 3 deletions arch/blackfin/include/asm/mmu_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
30 changes: 22 additions & 8 deletions arch/blackfin/kernel/cplb-mpu/cplbmgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions arch/blackfin/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit e18e7dd

Please sign in to comment.