aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin
diff options
context:
space:
mode:
authorBarry Song <barry.song@analog.com>2009-12-07 05:05:58 -0500
committerMike Frysinger <vapier@gentoo.org>2010-03-09 00:30:46 -0500
commite18e7dd33454f277b9438af66d25984362278021 (patch)
tree3c809ab2ebf8ad6276570f7eab238bd45e7216e8 /arch/blackfin
parentc9784ebb23be1e2ef23f537d6df04e0ea0206802 (diff)
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>
Diffstat (limited to 'arch/blackfin')
-rw-r--r--arch/blackfin/include/asm/mmu_context.h14
-rw-r--r--arch/blackfin/kernel/cplb-mpu/cplbmgr.c30
-rw-r--r--arch/blackfin/kernel/setup.c5
3 files changed, 38 insertions, 11 deletions
diff --git a/arch/blackfin/include/asm/mmu_context.h b/arch/blackfin/include/asm/mmu_context.h
index ae8ef4ffd806..7f363d7e43a5 100644
--- a/arch/blackfin/include/asm/mmu_context.h
+++ b/arch/blackfin/include/asm/mmu_context.h
@@ -13,6 +13,7 @@
13#include <asm/page.h> 13#include <asm/page.h>
14#include <asm/pgalloc.h> 14#include <asm/pgalloc.h>
15#include <asm/cplbinit.h> 15#include <asm/cplbinit.h>
16#include <asm/sections.h>
16 17
17/* Note: L1 stacks are CPU-private things, so we bluntly disable this 18/* Note: L1 stacks are CPU-private things, so we bluntly disable this
18 feature in SMP mode, and use the per-CPU scratch SRAM bank only to 19 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,
117 unsigned long flags) 118 unsigned long flags)
118{ 119{
119 unsigned long *mask = mm->context.page_rwx_mask; 120 unsigned long *mask = mm->context.page_rwx_mask;
120 unsigned long page = addr >> 12; 121 unsigned long page;
121 unsigned long idx = page >> 5; 122 unsigned long idx;
122 unsigned long bit = 1 << (page & 31); 123 unsigned long bit;
124
125 if (unlikely(addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE))
126 page = (addr - (ASYNC_BANK0_BASE - _ramend)) >> 12;
127 else
128 page = addr >> 12;
129 idx = page >> 5;
130 bit = 1 << (page & 31);
123 131
124 if (flags & VM_READ) 132 if (flags & VM_READ)
125 mask[idx] |= bit; 133 mask[idx] |= bit;
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
index 930c01c06813..d4cc53a0ef89 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
@@ -114,10 +114,15 @@ static noinline int dcplb_miss(unsigned int cpu)
114 d_data = L2_DMEMORY; 114 d_data = L2_DMEMORY;
115 } else if (addr >= physical_mem_end) { 115 } else if (addr >= physical_mem_end) {
116 if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) { 116 if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) {
117 addr &= ~(4 * 1024 * 1024 - 1); 117 mask = current_rwx_mask[cpu];
118 d_data &= ~PAGE_SIZE_4KB; 118 if (mask) {
119 d_data |= PAGE_SIZE_4MB; 119 int page = (addr - (ASYNC_BANK0_BASE - _ramend)) >> PAGE_SHIFT;
120 d_data |= CPLB_USER_RD | CPLB_USER_WR; 120 int idx = page >> 5;
121 int bit = 1 << (page & 31);
122
123 if (mask[idx] & bit)
124 d_data |= CPLB_USER_RD;
125 }
121 } else if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH 126 } else if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH
122 && (status & (FAULT_RW | FAULT_USERSUPV)) == FAULT_USERSUPV) { 127 && (status & (FAULT_RW | FAULT_USERSUPV)) == FAULT_USERSUPV) {
123 addr &= ~(1 * 1024 * 1024 - 1); 128 addr &= ~(1 * 1024 * 1024 - 1);
@@ -204,10 +209,19 @@ static noinline int icplb_miss(unsigned int cpu)
204 i_data = L2_IMEMORY; 209 i_data = L2_IMEMORY;
205 } else if (addr >= physical_mem_end) { 210 } else if (addr >= physical_mem_end) {
206 if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) { 211 if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) {
207 addr &= ~(4 * 1024 * 1024 - 1); 212 if (!(status & FAULT_USERSUPV)) {
208 i_data &= ~PAGE_SIZE_4KB; 213 unsigned long *mask = current_rwx_mask[cpu];
209 i_data |= PAGE_SIZE_4MB; 214
210 i_data |= CPLB_USER_RD; 215 if (mask) {
216 int page = (addr - (ASYNC_BANK0_BASE - _ramend)) >> PAGE_SHIFT;
217 int idx = page >> 5;
218 int bit = 1 << (page & 31);
219
220 mask += 2 * page_mask_nelts;
221 if (mask[idx] & bit)
222 i_data |= CPLB_USER_RD;
223 }
224 }
211 } else if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH 225 } else if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH
212 && (status & FAULT_USERSUPV)) { 226 && (status & FAULT_USERSUPV)) {
213 addr &= ~(1 * 1024 * 1024 - 1); 227 addr &= ~(1 * 1024 * 1024 - 1);
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
index 69cbc1a81201..8dc7ee1ef336 100644
--- a/arch/blackfin/kernel/setup.c
+++ b/arch/blackfin/kernel/setup.c
@@ -597,7 +597,12 @@ static __init void memory_setup(void)
597 } 597 }
598 598
599#ifdef CONFIG_MPU 599#ifdef CONFIG_MPU
600#if defined(CONFIG_ROMFS_ON_MTD) && defined(CONFIG_MTD_ROM)
601 page_mask_nelts = (((_ramend + ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE -
602 ASYNC_BANK0_BASE) >> PAGE_SHIFT) + 31) / 32;
603#else
600 page_mask_nelts = ((_ramend >> PAGE_SHIFT) + 31) / 32; 604 page_mask_nelts = ((_ramend >> PAGE_SHIFT) + 31) / 32;
605#endif
601 page_mask_order = get_order(3 * page_mask_nelts * sizeof(long)); 606 page_mask_order = get_order(3 * page_mask_nelts * sizeof(long));
602#endif 607#endif
603 608