[Blackfin] arch: Initial checkin of the memory protection support.
Enable it with CONFIG_MPU. Signed-off-by: Bernd Schmidt <bernd.schmidt@analog.com> Signed-off-by: Bryan Wu <bryan.wu@analog.com>
This commit is contained in:
parent
2047e40d72
commit
b97b8a9983
|
@ -765,6 +765,15 @@ config L1_MAX_PIECE
|
||||||
Set the max memory pieces for the L1 SRAM allocation algorithm.
|
Set the max memory pieces for the L1 SRAM allocation algorithm.
|
||||||
Min value is 16. Max value is 1024.
|
Min value is 16. Max value is 1024.
|
||||||
|
|
||||||
|
|
||||||
|
config MPU
|
||||||
|
bool "Enable the memory protection unit (EXPERIMENTAL)"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Use the processor's MPU to protect applications from accessing
|
||||||
|
memory they do not own. This comes at a performance penalty
|
||||||
|
and is recommended only for debugging.
|
||||||
|
|
||||||
comment "Asynchonous Memory Configuration"
|
comment "Asynchonous Memory Configuration"
|
||||||
|
|
||||||
menu "EBIU_AMGCTL Global Control"
|
menu "EBIU_AMGCTL Global Control"
|
||||||
|
|
|
@ -82,7 +82,11 @@ core-y += arch/$(ARCH)/mach-$(MACHINE)/
|
||||||
core-y += arch/$(ARCH)/mach-$(MACHINE)/boards/
|
core-y += arch/$(ARCH)/mach-$(MACHINE)/boards/
|
||||||
endif
|
endif
|
||||||
|
|
||||||
core-y += arch/$(ARCH)/kernel/cplb-nompu/
|
ifeq ($(CONFIG_MPU),y)
|
||||||
|
core-y += arch/$(ARCH)/kernel/cplb-mpu/
|
||||||
|
else
|
||||||
|
core-y += arch/$(ARCH)/kernel/cplb-nompu/
|
||||||
|
endif
|
||||||
|
|
||||||
libs-y += arch/$(ARCH)/lib/
|
libs-y += arch/$(ARCH)/lib/
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
#
|
||||||
|
# arch/blackfin/kernel/cplb-nompu/Makefile
|
||||||
|
#
|
||||||
|
|
||||||
|
obj-y := cplbinit.o cacheinit.o cplbmgr.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_CPLB_INFO) += cplbinfo.o
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2004-2007 Analog Devices Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see the file COPYING, or write
|
||||||
|
* to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/cpu.h>
|
||||||
|
|
||||||
|
#include <asm/cacheflush.h>
|
||||||
|
#include <asm/blackfin.h>
|
||||||
|
#include <asm/cplb.h>
|
||||||
|
#include <asm/cplbinit.h>
|
||||||
|
|
||||||
|
#if defined(CONFIG_BFIN_ICACHE)
|
||||||
|
void bfin_icache_init(void)
|
||||||
|
{
|
||||||
|
unsigned long ctrl;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
SSYNC();
|
||||||
|
for (i = 0; i < MAX_CPLBS; i++) {
|
||||||
|
bfin_write32(ICPLB_ADDR0 + i * 4, icplb_tbl[i].addr);
|
||||||
|
bfin_write32(ICPLB_DATA0 + i * 4, icplb_tbl[i].data);
|
||||||
|
}
|
||||||
|
ctrl = bfin_read_IMEM_CONTROL();
|
||||||
|
ctrl |= IMC | ENICPLB;
|
||||||
|
bfin_write_IMEM_CONTROL(ctrl);
|
||||||
|
SSYNC();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CONFIG_BFIN_DCACHE)
|
||||||
|
void bfin_dcache_init(void)
|
||||||
|
{
|
||||||
|
unsigned long ctrl;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
SSYNC();
|
||||||
|
for (i = 0; i < MAX_CPLBS; i++) {
|
||||||
|
bfin_write32(DCPLB_ADDR0 + i * 4, dcplb_tbl[i].addr);
|
||||||
|
bfin_write32(DCPLB_DATA0 + i * 4, dcplb_tbl[i].data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl = bfin_read_DMEM_CONTROL();
|
||||||
|
ctrl |= DMEM_CNTR;
|
||||||
|
bfin_write_DMEM_CONTROL(ctrl);
|
||||||
|
SSYNC();
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,144 @@
|
||||||
|
/*
|
||||||
|
* File: arch/blackfin/mach-common/cplbinfo.c
|
||||||
|
* Based on:
|
||||||
|
* Author: Sonic Zhang <sonic.zhang@analog.com>
|
||||||
|
*
|
||||||
|
* Created: Jan. 2005
|
||||||
|
* Description: Display CPLB status
|
||||||
|
*
|
||||||
|
* Modified:
|
||||||
|
* Copyright 2004-2006 Analog Devices Inc.
|
||||||
|
*
|
||||||
|
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see the file COPYING, or write
|
||||||
|
* to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/proc_fs.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
|
#include <asm/current.h>
|
||||||
|
#include <asm/system.h>
|
||||||
|
#include <asm/cplb.h>
|
||||||
|
#include <asm/cplbinit.h>
|
||||||
|
#include <asm/blackfin.h>
|
||||||
|
|
||||||
|
#define CPLB_I 1
|
||||||
|
#define CPLB_D 2
|
||||||
|
|
||||||
|
#define SYNC_SYS SSYNC()
|
||||||
|
#define SYNC_CORE CSYNC()
|
||||||
|
|
||||||
|
#define CPLB_BIT_PAGESIZE 0x30000
|
||||||
|
|
||||||
|
static char page_size_string_table[][4] = { "1K", "4K", "1M", "4M" };
|
||||||
|
|
||||||
|
static char *cplb_print_entry(char *buf, struct cplb_entry *tbl, int switched)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
buf += sprintf(buf, "Index\tAddress\t\tData\tSize\tU/RD\tU/WR\tS/WR\tSwitch\n");
|
||||||
|
for (i = 0; i < MAX_CPLBS; i++) {
|
||||||
|
unsigned long data = tbl[i].data;
|
||||||
|
unsigned long addr = tbl[i].addr;
|
||||||
|
if (!(data & CPLB_VALID))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
buf +=
|
||||||
|
sprintf(buf,
|
||||||
|
"%d\t0x%08lx\t%06lx\t%s\t%c\t%c\t%c\t%c\n",
|
||||||
|
i, addr, data,
|
||||||
|
page_size_string_table[(data & 0x30000) >> 16],
|
||||||
|
(data & CPLB_USER_RD) ? 'Y' : 'N',
|
||||||
|
(data & CPLB_USER_WR) ? 'Y' : 'N',
|
||||||
|
(data & CPLB_SUPV_WR) ? 'Y' : 'N',
|
||||||
|
i < switched ? 'N' : 'Y');
|
||||||
|
}
|
||||||
|
buf += sprintf(buf, "\n");
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cplbinfo_proc_output(char *buf)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
|
||||||
|
p += sprintf(p, "------------------ CPLB Information ------------------\n\n");
|
||||||
|
|
||||||
|
if (bfin_read_IMEM_CONTROL() & ENICPLB) {
|
||||||
|
p += sprintf(p, "Instruction CPLB entry:\n");
|
||||||
|
p = cplb_print_entry(p, icplb_tbl, first_switched_icplb);
|
||||||
|
} else
|
||||||
|
p += sprintf(p, "Instruction CPLB is disabled.\n\n");
|
||||||
|
|
||||||
|
if (1 || bfin_read_DMEM_CONTROL() & ENDCPLB) {
|
||||||
|
p += sprintf(p, "Data CPLB entry:\n");
|
||||||
|
p = cplb_print_entry(p, dcplb_tbl, first_switched_dcplb);
|
||||||
|
} else
|
||||||
|
p += sprintf(p, "Data CPLB is disabled.\n");
|
||||||
|
|
||||||
|
p += sprintf(p, "ICPLB miss: %d\nICPLB supervisor miss: %d\n",
|
||||||
|
nr_icplb_miss, nr_icplb_supv_miss);
|
||||||
|
p += sprintf(p, "DCPLB miss: %d\nDCPLB protection fault:%d\n",
|
||||||
|
nr_dcplb_miss, nr_dcplb_prot);
|
||||||
|
p += sprintf(p, "CPLB flushes: %d\n",
|
||||||
|
nr_cplb_flush);
|
||||||
|
|
||||||
|
return p - buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cplbinfo_read_proc(char *page, char **start, off_t off,
|
||||||
|
int count, int *eof, void *data)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = cplbinfo_proc_output(page);
|
||||||
|
if (len <= off + count)
|
||||||
|
*eof = 1;
|
||||||
|
*start = page + off;
|
||||||
|
len -= off;
|
||||||
|
if (len > count)
|
||||||
|
len = count;
|
||||||
|
if (len < 0)
|
||||||
|
len = 0;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init cplbinfo_init(void)
|
||||||
|
{
|
||||||
|
struct proc_dir_entry *entry;
|
||||||
|
|
||||||
|
entry = create_proc_entry("cplbinfo", 0, NULL);
|
||||||
|
if (!entry)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
entry->read_proc = cplbinfo_read_proc;
|
||||||
|
entry->data = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit cplbinfo_exit(void)
|
||||||
|
{
|
||||||
|
remove_proc_entry("cplbinfo", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(cplbinfo_init);
|
||||||
|
module_exit(cplbinfo_exit);
|
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* Blackfin CPLB initialization
|
||||||
|
*
|
||||||
|
* Copyright 2004-2007 Analog Devices Inc.
|
||||||
|
*
|
||||||
|
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see the file COPYING, or write
|
||||||
|
* to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#include <linux/module.h>
|
||||||
|
|
||||||
|
#include <asm/blackfin.h>
|
||||||
|
#include <asm/cplb.h>
|
||||||
|
#include <asm/cplbinit.h>
|
||||||
|
|
||||||
|
struct cplb_entry icplb_tbl[MAX_CPLBS];
|
||||||
|
struct cplb_entry dcplb_tbl[MAX_CPLBS];
|
||||||
|
|
||||||
|
int first_switched_icplb, first_switched_dcplb;
|
||||||
|
int first_mask_dcplb;
|
||||||
|
|
||||||
|
void __init generate_cpl_tables(void)
|
||||||
|
{
|
||||||
|
int i_d, i_i;
|
||||||
|
unsigned long addr;
|
||||||
|
unsigned long d_data, i_data;
|
||||||
|
unsigned long d_cache = 0, i_cache = 0;
|
||||||
|
|
||||||
|
#ifdef CONFIG_BFIN_ICACHE
|
||||||
|
i_cache = CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_BFIN_DCACHE
|
||||||
|
d_cache = CPLB_L1_CHBL;
|
||||||
|
#ifdef CONFIG_BLKFIN_WT
|
||||||
|
d_cache |= CPLB_L1_AOW | CPLB_WT;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
i_d = i_i = 0;
|
||||||
|
|
||||||
|
/* Set up the zero page. */
|
||||||
|
dcplb_tbl[i_d].addr = 0;
|
||||||
|
dcplb_tbl[i_d++].data = SDRAM_OOPS | PAGE_SIZE_1KB;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
icplb_tbl[i_i].addr = 0;
|
||||||
|
icplb_tbl[i_i++].data = i_cache | CPLB_USER_RD | PAGE_SIZE_4KB;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Cover kernel memory with 4M pages. */
|
||||||
|
addr = 0;
|
||||||
|
d_data = d_cache | CPLB_SUPV_WR | CPLB_VALID | PAGE_SIZE_4MB | CPLB_DIRTY;
|
||||||
|
i_data = i_cache | CPLB_VALID | CPLB_PORTPRIO | PAGE_SIZE_4MB;
|
||||||
|
|
||||||
|
for (; addr < memory_start; addr += 4 * 1024 * 1024) {
|
||||||
|
dcplb_tbl[i_d].addr = addr;
|
||||||
|
dcplb_tbl[i_d++].data = d_data;
|
||||||
|
icplb_tbl[i_i].addr = addr;
|
||||||
|
icplb_tbl[i_i++].data = i_data | (addr == 0 ? CPLB_USER_RD : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cover L1 memory. One 4M area for code and data each is enough. */
|
||||||
|
#if L1_DATA_A_LENGTH > 0 || L1_DATA_B_LENGTH > 0
|
||||||
|
dcplb_tbl[i_d].addr = L1_DATA_A_START;
|
||||||
|
dcplb_tbl[i_d++].data = L1_DMEMORY | PAGE_SIZE_4MB;
|
||||||
|
#endif
|
||||||
|
icplb_tbl[i_i].addr = L1_CODE_START;
|
||||||
|
icplb_tbl[i_i++].data = L1_IMEMORY | PAGE_SIZE_4MB;
|
||||||
|
|
||||||
|
first_mask_dcplb = i_d;
|
||||||
|
first_switched_dcplb = i_d + (1 << page_mask_order);
|
||||||
|
first_switched_icplb = i_i;
|
||||||
|
|
||||||
|
while (i_d < MAX_CPLBS)
|
||||||
|
dcplb_tbl[i_d++].data = 0;
|
||||||
|
while (i_i < MAX_CPLBS)
|
||||||
|
icplb_tbl[i_i++].data = 0;
|
||||||
|
}
|
|
@ -0,0 +1,338 @@
|
||||||
|
/*
|
||||||
|
* Blackfin CPLB exception handling.
|
||||||
|
* Copyright 2004-2007 Analog Devices Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see the file COPYING, or write
|
||||||
|
* to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
|
||||||
|
#include <asm/blackfin.h>
|
||||||
|
#include <asm/cplbinit.h>
|
||||||
|
#include <asm/mmu_context.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_BFIN_ICACHE
|
||||||
|
|
||||||
|
#define FAULT_RW (1 << 16)
|
||||||
|
#define FAULT_USERSUPV (1 << 17)
|
||||||
|
|
||||||
|
int page_mask_nelts;
|
||||||
|
int page_mask_order;
|
||||||
|
unsigned long *current_rwx_mask;
|
||||||
|
|
||||||
|
int nr_dcplb_miss, nr_icplb_miss, nr_icplb_supv_miss, nr_dcplb_prot;
|
||||||
|
int nr_cplb_flush;
|
||||||
|
|
||||||
|
static inline void disable_dcplb(void)
|
||||||
|
{
|
||||||
|
unsigned long ctrl;
|
||||||
|
SSYNC();
|
||||||
|
ctrl = bfin_read_DMEM_CONTROL();
|
||||||
|
ctrl &= ~ENDCPLB;
|
||||||
|
bfin_write_DMEM_CONTROL(ctrl);
|
||||||
|
SSYNC();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void enable_dcplb(void)
|
||||||
|
{
|
||||||
|
unsigned long ctrl;
|
||||||
|
SSYNC();
|
||||||
|
ctrl = bfin_read_DMEM_CONTROL();
|
||||||
|
ctrl |= ENDCPLB;
|
||||||
|
bfin_write_DMEM_CONTROL(ctrl);
|
||||||
|
SSYNC();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void disable_icplb(void)
|
||||||
|
{
|
||||||
|
unsigned long ctrl;
|
||||||
|
SSYNC();
|
||||||
|
ctrl = bfin_read_IMEM_CONTROL();
|
||||||
|
ctrl &= ~ENICPLB;
|
||||||
|
bfin_write_IMEM_CONTROL(ctrl);
|
||||||
|
SSYNC();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void enable_icplb(void)
|
||||||
|
{
|
||||||
|
unsigned long ctrl;
|
||||||
|
SSYNC();
|
||||||
|
ctrl = bfin_read_IMEM_CONTROL();
|
||||||
|
ctrl |= ENICPLB;
|
||||||
|
bfin_write_IMEM_CONTROL(ctrl);
|
||||||
|
SSYNC();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given the contents of the status register, return the index of the
|
||||||
|
* CPLB that caused the fault.
|
||||||
|
*/
|
||||||
|
static inline int faulting_cplb_index(int status)
|
||||||
|
{
|
||||||
|
int signbits = __builtin_bfin_norm_fr1x32(status & 0xFFFF);
|
||||||
|
return 30 - signbits;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given the contents of the status register and the DCPLB_DATA contents,
|
||||||
|
* return true if a write access should be permitted.
|
||||||
|
*/
|
||||||
|
static inline int write_permitted(int status, unsigned long data)
|
||||||
|
{
|
||||||
|
if (status & FAULT_USERSUPV)
|
||||||
|
return !!(data & CPLB_SUPV_WR);
|
||||||
|
else
|
||||||
|
return !!(data & CPLB_USER_WR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Counters to implement round-robin replacement. */
|
||||||
|
static int icplb_rr_index, dcplb_rr_index;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find an ICPLB entry to be evicted and return its index.
|
||||||
|
*/
|
||||||
|
static int evict_one_icplb(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = first_switched_icplb; i < MAX_CPLBS; i++)
|
||||||
|
if ((icplb_tbl[i].data & CPLB_VALID) == 0)
|
||||||
|
return i;
|
||||||
|
i = first_switched_icplb + icplb_rr_index;
|
||||||
|
if (i >= MAX_CPLBS) {
|
||||||
|
i -= MAX_CPLBS - first_switched_icplb;
|
||||||
|
icplb_rr_index -= MAX_CPLBS - first_switched_icplb;
|
||||||
|
}
|
||||||
|
icplb_rr_index++;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int evict_one_dcplb(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = first_switched_dcplb; i < MAX_CPLBS; i++)
|
||||||
|
if ((dcplb_tbl[i].data & CPLB_VALID) == 0)
|
||||||
|
return i;
|
||||||
|
i = first_switched_dcplb + dcplb_rr_index;
|
||||||
|
if (i >= MAX_CPLBS) {
|
||||||
|
i -= MAX_CPLBS - first_switched_dcplb;
|
||||||
|
dcplb_rr_index -= MAX_CPLBS - first_switched_dcplb;
|
||||||
|
}
|
||||||
|
dcplb_rr_index++;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static noinline int dcplb_miss(void)
|
||||||
|
{
|
||||||
|
unsigned long addr = bfin_read_DCPLB_FAULT_ADDR();
|
||||||
|
int status = bfin_read_DCPLB_STATUS();
|
||||||
|
unsigned long *mask;
|
||||||
|
int idx;
|
||||||
|
unsigned long d_data;
|
||||||
|
|
||||||
|
nr_dcplb_miss++;
|
||||||
|
if (addr >= _ramend)
|
||||||
|
return CPLB_PROT_VIOL;
|
||||||
|
|
||||||
|
d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
|
||||||
|
#ifdef CONFIG_BFIN_DCACHE
|
||||||
|
d_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
|
||||||
|
#ifdef CONFIG_BLKFIN_WT
|
||||||
|
d_data |= CPLB_L1_AOW | CPLB_WT;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
mask = current_rwx_mask;
|
||||||
|
if (mask) {
|
||||||
|
int page = addr >> PAGE_SHIFT;
|
||||||
|
int offs = page >> 5;
|
||||||
|
int bit = 1 << (page & 31);
|
||||||
|
|
||||||
|
if (mask[offs] & bit)
|
||||||
|
d_data |= CPLB_USER_RD;
|
||||||
|
|
||||||
|
mask += page_mask_nelts;
|
||||||
|
if (mask[offs] & bit)
|
||||||
|
d_data |= CPLB_USER_WR;
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = evict_one_dcplb();
|
||||||
|
|
||||||
|
addr &= PAGE_MASK;
|
||||||
|
dcplb_tbl[idx].addr = addr;
|
||||||
|
dcplb_tbl[idx].data = d_data;
|
||||||
|
|
||||||
|
disable_dcplb();
|
||||||
|
bfin_write32(DCPLB_DATA0 + idx * 4, d_data);
|
||||||
|
bfin_write32(DCPLB_ADDR0 + idx * 4, addr);
|
||||||
|
enable_dcplb();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static noinline int icplb_miss(void)
|
||||||
|
{
|
||||||
|
unsigned long addr = bfin_read_ICPLB_FAULT_ADDR();
|
||||||
|
int status = bfin_read_ICPLB_STATUS();
|
||||||
|
int idx;
|
||||||
|
unsigned long i_data;
|
||||||
|
|
||||||
|
nr_icplb_miss++;
|
||||||
|
if (status & FAULT_USERSUPV)
|
||||||
|
nr_icplb_supv_miss++;
|
||||||
|
|
||||||
|
if (addr >= _ramend)
|
||||||
|
return CPLB_PROT_VIOL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First, try to find a CPLB that matches this address. If we
|
||||||
|
* find one, then the fact that we're in the miss handler means
|
||||||
|
* that the instruction crosses a page boundary.
|
||||||
|
*/
|
||||||
|
for (idx = first_switched_icplb; idx < MAX_CPLBS; idx++) {
|
||||||
|
if (icplb_tbl[idx].data & CPLB_VALID) {
|
||||||
|
unsigned long this_addr = icplb_tbl[idx].addr;
|
||||||
|
if (this_addr <= addr && this_addr + PAGE_SIZE > addr) {
|
||||||
|
addr += PAGE_SIZE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i_data = CPLB_VALID | CPLB_PORTPRIO | PAGE_SIZE_4KB;
|
||||||
|
#ifdef CONFIG_BFIN_ICACHE
|
||||||
|
i_data |= CPLB_L1_CHBL | ANOMALY_05000158_WORKAROUND;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Two cases to distinguish - a supervisor access must necessarily
|
||||||
|
* be for a module page; we grant it unconditionally (could do better
|
||||||
|
* here in the future). Otherwise, check the x bitmap of the current
|
||||||
|
* process.
|
||||||
|
*/
|
||||||
|
if (!(status & FAULT_USERSUPV)) {
|
||||||
|
unsigned long *mask = current_rwx_mask;
|
||||||
|
|
||||||
|
if (mask) {
|
||||||
|
int page = addr >> PAGE_SHIFT;
|
||||||
|
int offs = page >> 5;
|
||||||
|
int bit = 1 << (page & 31);
|
||||||
|
|
||||||
|
mask += 2 * page_mask_nelts;
|
||||||
|
if (mask[offs] & bit)
|
||||||
|
i_data |= CPLB_USER_RD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
idx = evict_one_icplb();
|
||||||
|
addr &= PAGE_MASK;
|
||||||
|
icplb_tbl[idx].addr = addr;
|
||||||
|
icplb_tbl[idx].data = i_data;
|
||||||
|
|
||||||
|
disable_icplb();
|
||||||
|
bfin_write32(ICPLB_DATA0 + idx * 4, i_data);
|
||||||
|
bfin_write32(ICPLB_ADDR0 + idx * 4, addr);
|
||||||
|
enable_icplb();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static noinline int dcplb_protection_fault(void)
|
||||||
|
{
|
||||||
|
unsigned long addr = bfin_read_DCPLB_FAULT_ADDR();
|
||||||
|
int status = bfin_read_DCPLB_STATUS();
|
||||||
|
|
||||||
|
nr_dcplb_prot++;
|
||||||
|
|
||||||
|
if (status & FAULT_RW) {
|
||||||
|
int idx = faulting_cplb_index(status);
|
||||||
|
unsigned long data = dcplb_tbl[idx].data;
|
||||||
|
if (!(data & CPLB_WT) && !(data & CPLB_DIRTY) &&
|
||||||
|
write_permitted(status, data)) {
|
||||||
|
data |= CPLB_DIRTY;
|
||||||
|
dcplb_tbl[idx].data = data;
|
||||||
|
bfin_write32(DCPLB_DATA0 + idx * 4, data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CPLB_PROT_VIOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cplb_hdr(int seqstat, struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
int cause = seqstat & 0x3f;
|
||||||
|
switch (cause) {
|
||||||
|
case 0x23:
|
||||||
|
return dcplb_protection_fault();
|
||||||
|
case 0x2C:
|
||||||
|
return icplb_miss();
|
||||||
|
case 0x26:
|
||||||
|
return dcplb_miss();
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
panic_cplb_error(seqstat, regs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_switched_cplbs(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
nr_cplb_flush++;
|
||||||
|
|
||||||
|
disable_icplb();
|
||||||
|
for (i = first_switched_icplb; i < MAX_CPLBS; i++) {
|
||||||
|
icplb_tbl[i].data = 0;
|
||||||
|
bfin_write32(ICPLB_DATA0 + i * 4, 0);
|
||||||
|
}
|
||||||
|
enable_icplb();
|
||||||
|
|
||||||
|
disable_dcplb();
|
||||||
|
for (i = first_mask_dcplb; i < MAX_CPLBS; i++) {
|
||||||
|
dcplb_tbl[i].data = 0;
|
||||||
|
bfin_write32(DCPLB_DATA0 + i * 4, 0);
|
||||||
|
}
|
||||||
|
enable_dcplb();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_mask_dcplbs(unsigned long *masks)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned long addr = (unsigned long)masks;
|
||||||
|
unsigned long d_data;
|
||||||
|
current_rwx_mask = masks;
|
||||||
|
|
||||||
|
if (!masks)
|
||||||
|
return;
|
||||||
|
|
||||||
|
d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB;
|
||||||
|
#ifdef CONFIG_BFIN_DCACHE
|
||||||
|
d_data |= CPLB_L1_CHBL;
|
||||||
|
#ifdef CONFIG_BLKFIN_WT
|
||||||
|
d_data |= CPLB_L1_AOW | CPLB_WT;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
disable_dcplb();
|
||||||
|
for (i = first_mask_dcplb; i < first_switched_dcplb; i++) {
|
||||||
|
dcplb_tbl[i].addr = addr;
|
||||||
|
dcplb_tbl[i].data = d_data;
|
||||||
|
bfin_write32(DCPLB_DATA0 + i * 4, d_data);
|
||||||
|
bfin_write32(DCPLB_ADDR0 + i * 4, addr);
|
||||||
|
addr += PAGE_SIZE;
|
||||||
|
}
|
||||||
|
enable_dcplb();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -238,7 +238,12 @@ void __init setup_arch(char **cmdline_p)
|
||||||
memory_end = _ramend - DMA_UNCACHED_REGION;
|
memory_end = _ramend - DMA_UNCACHED_REGION;
|
||||||
|
|
||||||
_ramstart = (unsigned long)__bss_stop;
|
_ramstart = (unsigned long)__bss_stop;
|
||||||
|
#ifdef CONFIG_MPU
|
||||||
|
/* Round up to multiple of 4MB. */
|
||||||
|
memory_start = (_ramstart + 0x3fffff) & ~0x3fffff;
|
||||||
|
#else
|
||||||
memory_start = PAGE_ALIGN(_ramstart);
|
memory_start = PAGE_ALIGN(_ramstart);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_MTD_UCLINUX)
|
#if defined(CONFIG_MTD_UCLINUX)
|
||||||
/* generic memory mapped MTD driver */
|
/* generic memory mapped MTD driver */
|
||||||
|
@ -307,6 +312,11 @@ void __init setup_arch(char **cmdline_p)
|
||||||
printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20);
|
printk(KERN_NOTICE "Warning: limiting memory to %liMB due to hardware anomaly 05000263\n", memory_end >> 20);
|
||||||
#endif /* ANOMALY_05000263 */
|
#endif /* ANOMALY_05000263 */
|
||||||
|
|
||||||
|
#ifdef CONFIG_MPU
|
||||||
|
page_mask_nelts = ((_ramend >> PAGE_SHIFT) + 31) / 32;
|
||||||
|
page_mask_order = get_order(3 * page_mask_nelts * sizeof(long));
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(CONFIG_MTD_UCLINUX)
|
#if !defined(CONFIG_MTD_UCLINUX)
|
||||||
memory_end -= SIZE_4K; /*In case there is no valid CPLB behind memory_end make sure we don't get to close*/
|
memory_end -= SIZE_4K; /*In case there is no valid CPLB behind memory_end make sure we don't get to close*/
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -95,24 +95,43 @@ ENTRY(_ex_workaround_261)
|
||||||
R6 = 0x26; /* Data CPLB Miss */
|
R6 = 0x26; /* Data CPLB Miss */
|
||||||
cc = R6 == R7;
|
cc = R6 == R7;
|
||||||
if cc jump _ex_dcplb_miss (BP);
|
if cc jump _ex_dcplb_miss (BP);
|
||||||
|
R6 = 0x23; /* Data CPLB Miss */
|
||||||
|
cc = R6 == R7;
|
||||||
|
if cc jump _ex_dcplb_viol (BP);
|
||||||
/* Handle 0x23 Data CPLB Protection Violation
|
/* Handle 0x23 Data CPLB Protection Violation
|
||||||
* and Data CPLB Multiple Hits - Linux Trap Zero
|
* and Data CPLB Multiple Hits - Linux Trap Zero
|
||||||
*/
|
*/
|
||||||
jump _ex_trap_c;
|
jump _ex_trap_c;
|
||||||
ENDPROC(_ex_workaround_261)
|
ENDPROC(_ex_workaround_261)
|
||||||
|
|
||||||
|
#else
|
||||||
|
#ifdef CONFIG_MPU
|
||||||
|
#define _ex_dviol _ex_dcplb_viol
|
||||||
#else
|
#else
|
||||||
#define _ex_dviol _ex_trap_c
|
#define _ex_dviol _ex_trap_c
|
||||||
|
#endif
|
||||||
#define _ex_dmiss _ex_dcplb_miss
|
#define _ex_dmiss _ex_dcplb_miss
|
||||||
#define _ex_dmult _ex_trap_c
|
#define _ex_dmult _ex_trap_c
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
ENTRY(_ex_dcplb_viol)
|
||||||
ENTRY(_ex_dcplb_miss)
|
ENTRY(_ex_dcplb_miss)
|
||||||
ENTRY(_ex_icplb_miss)
|
ENTRY(_ex_icplb_miss)
|
||||||
(R7:6,P5:4) = [sp++];
|
(R7:6,P5:4) = [sp++];
|
||||||
ASTAT = [sp++];
|
ASTAT = [sp++];
|
||||||
SAVE_ALL_SYS
|
SAVE_ALL_SYS
|
||||||
|
#ifdef CONFIG_MPU
|
||||||
|
R0 = SEQSTAT;
|
||||||
|
R1 = SP;
|
||||||
|
sp += -12;
|
||||||
|
call _cplb_hdr;
|
||||||
|
sp += 12;
|
||||||
|
CC = R0 == 0;
|
||||||
|
IF !CC JUMP _handle_bad_cplb;
|
||||||
|
#else
|
||||||
call __cplb_hdr;
|
call __cplb_hdr;
|
||||||
|
#endif
|
||||||
DEBUG_START_HWTRACE(p5, r7)
|
DEBUG_START_HWTRACE(p5, r7)
|
||||||
RESTORE_ALL_SYS
|
RESTORE_ALL_SYS
|
||||||
SP = EX_SCRATCH_REG;
|
SP = EX_SCRATCH_REG;
|
||||||
|
|
|
@ -184,13 +184,15 @@ static __init void free_init_pages(const char *what, unsigned long begin, unsign
|
||||||
#ifdef CONFIG_BLK_DEV_INITRD
|
#ifdef CONFIG_BLK_DEV_INITRD
|
||||||
void __init free_initrd_mem(unsigned long start, unsigned long end)
|
void __init free_initrd_mem(unsigned long start, unsigned long end)
|
||||||
{
|
{
|
||||||
|
#ifndef CONFIG_MPU
|
||||||
free_init_pages("initrd memory", start, end);
|
free_init_pages("initrd memory", start, end);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void __init free_initmem(void)
|
void __init free_initmem(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_RAMKERNEL
|
#if defined CONFIG_RAMKERNEL && !defined CONFIG_MPU
|
||||||
free_init_pages("unused kernel memory",
|
free_init_pages("unused kernel memory",
|
||||||
(unsigned long)(&__init_begin),
|
(unsigned long)(&__init_begin),
|
||||||
(unsigned long)(&__init_end));
|
(unsigned long)(&__init_end));
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* File: include/asm-blackfin/cplbinit.h
|
||||||
|
* Based on:
|
||||||
|
* Author:
|
||||||
|
*
|
||||||
|
* Created:
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Modified:
|
||||||
|
* Copyright 2004-2006 Analog Devices Inc.
|
||||||
|
*
|
||||||
|
* Bugs: Enter bugs at http://blackfin.uclinux.org/
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see the file COPYING, or write
|
||||||
|
* to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
#ifndef __ASM_BFIN_CPLB_MPU_H
|
||||||
|
#define __ASM_BFIN_CPLB_MPU_H
|
||||||
|
|
||||||
|
struct cplb_entry {
|
||||||
|
unsigned long data, addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mem_region {
|
||||||
|
unsigned long start, end;
|
||||||
|
unsigned long dcplb_data;
|
||||||
|
unsigned long icplb_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct cplb_entry dcplb_tbl[MAX_CPLBS];
|
||||||
|
extern struct cplb_entry icplb_tbl[MAX_CPLBS];
|
||||||
|
extern int first_switched_icplb;
|
||||||
|
extern int first_mask_dcplb;
|
||||||
|
extern int first_switched_dcplb;
|
||||||
|
|
||||||
|
extern int nr_dcplb_miss, nr_icplb_miss, nr_icplb_supv_miss, nr_dcplb_prot;
|
||||||
|
extern int nr_cplb_flush;
|
||||||
|
|
||||||
|
extern int page_mask_order;
|
||||||
|
extern int page_mask_nelts;
|
||||||
|
|
||||||
|
extern unsigned long *current_rwx_mask;
|
||||||
|
|
||||||
|
extern void flush_switched_cplbs(void);
|
||||||
|
extern void set_mask_dcplbs(unsigned long *);
|
||||||
|
|
||||||
|
extern void __noreturn panic_cplb_error(int seqstat, struct pt_regs *);
|
||||||
|
|
||||||
|
#endif /* __ASM_BFIN_CPLB_MPU_H */
|
|
@ -65,7 +65,11 @@
|
||||||
#define SIZE_1M 0x00100000 /* 1M */
|
#define SIZE_1M 0x00100000 /* 1M */
|
||||||
#define SIZE_4M 0x00400000 /* 4M */
|
#define SIZE_4M 0x00400000 /* 4M */
|
||||||
|
|
||||||
|
#ifdef CONFIG_MPU
|
||||||
|
#define MAX_CPLBS 16
|
||||||
|
#else
|
||||||
#define MAX_CPLBS (16 * 2)
|
#define MAX_CPLBS (16 * 2)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ASYNC_MEMORY_CPLB_COVERAGE ((ASYNC_BANK0_SIZE + ASYNC_BANK1_SIZE + \
|
#define ASYNC_MEMORY_CPLB_COVERAGE ((ASYNC_BANK0_SIZE + ASYNC_BANK1_SIZE + \
|
||||||
ASYNC_BANK2_SIZE + ASYNC_BANK3_SIZE) / SIZE_4M)
|
ASYNC_BANK2_SIZE + ASYNC_BANK3_SIZE) / SIZE_4M)
|
||||||
|
|
|
@ -33,6 +33,12 @@
|
||||||
#include <asm/blackfin.h>
|
#include <asm/blackfin.h>
|
||||||
#include <asm/cplb.h>
|
#include <asm/cplb.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_MPU
|
||||||
|
|
||||||
|
#include <asm/cplb-mpu.h>
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
#define INITIAL_T 0x1
|
#define INITIAL_T 0x1
|
||||||
#define SWITCH_T 0x2
|
#define SWITCH_T 0x2
|
||||||
#define I_CPLB 0x4
|
#define I_CPLB 0x4
|
||||||
|
@ -79,6 +85,8 @@ extern u_long ipdt_swapcount_table[];
|
||||||
extern u_long dpdt_swapcount_table[];
|
extern u_long dpdt_swapcount_table[];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif /* CONFIG_MPU */
|
||||||
|
|
||||||
extern unsigned long reserved_mem_dcache_on;
|
extern unsigned long reserved_mem_dcache_on;
|
||||||
extern unsigned long reserved_mem_icache_on;
|
extern unsigned long reserved_mem_icache_on;
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,9 @@ typedef struct {
|
||||||
unsigned long exec_fdpic_loadmap;
|
unsigned long exec_fdpic_loadmap;
|
||||||
unsigned long interp_fdpic_loadmap;
|
unsigned long interp_fdpic_loadmap;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_MPU
|
||||||
|
unsigned long *page_rwx_mask;
|
||||||
|
#endif
|
||||||
} mm_context_t;
|
} mm_context_t;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,9 +30,12 @@
|
||||||
#ifndef __BLACKFIN_MMU_CONTEXT_H__
|
#ifndef __BLACKFIN_MMU_CONTEXT_H__
|
||||||
#define __BLACKFIN_MMU_CONTEXT_H__
|
#define __BLACKFIN_MMU_CONTEXT_H__
|
||||||
|
|
||||||
|
#include <linux/gfp.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
#include <asm/pgalloc.h>
|
#include <asm/pgalloc.h>
|
||||||
|
#include <asm/cplbinit.h>
|
||||||
|
|
||||||
extern void *current_l1_stack_save;
|
extern void *current_l1_stack_save;
|
||||||
extern int nr_l1stack_tasks;
|
extern int nr_l1stack_tasks;
|
||||||
|
@ -50,6 +53,12 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
|
||||||
static inline int
|
static inline int
|
||||||
init_new_context(struct task_struct *tsk, struct mm_struct *mm)
|
init_new_context(struct task_struct *tsk, struct mm_struct *mm)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_MPU
|
||||||
|
unsigned long p = __get_free_pages(GFP_KERNEL, page_mask_order);
|
||||||
|
mm->context.page_rwx_mask = (unsigned long *)p;
|
||||||
|
memset(mm->context.page_rwx_mask, 0,
|
||||||
|
page_mask_nelts * 3 * sizeof(long));
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +82,11 @@ static inline void destroy_context(struct mm_struct *mm)
|
||||||
sram_free(tmp->addr);
|
sram_free(tmp->addr);
|
||||||
kfree(tmp);
|
kfree(tmp);
|
||||||
}
|
}
|
||||||
|
#ifdef CONFIG_MPU
|
||||||
|
if (current_rwx_mask == mm->context.page_rwx_mask)
|
||||||
|
current_rwx_mask = NULL;
|
||||||
|
free_pages((unsigned long)mm->context.page_rwx_mask, page_mask_order);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned long
|
static inline unsigned long
|
||||||
|
@ -106,9 +120,21 @@ activate_l1stack(struct mm_struct *mm, unsigned long sp_base)
|
||||||
|
|
||||||
#define deactivate_mm(tsk,mm) do { } while (0)
|
#define deactivate_mm(tsk,mm) do { } while (0)
|
||||||
|
|
||||||
static inline void activate_mm(struct mm_struct *prev_mm,
|
#define activate_mm(prev, next) switch_mm(prev, next, NULL)
|
||||||
struct mm_struct *next_mm)
|
|
||||||
|
static inline void switch_mm(struct mm_struct *prev_mm, struct mm_struct *next_mm,
|
||||||
|
struct task_struct *tsk)
|
||||||
{
|
{
|
||||||
|
if (prev_mm == next_mm)
|
||||||
|
return;
|
||||||
|
#ifdef CONFIG_MPU
|
||||||
|
if (prev_mm->context.page_rwx_mask == current_rwx_mask) {
|
||||||
|
flush_switched_cplbs();
|
||||||
|
set_mask_dcplbs(next_mm->context.page_rwx_mask);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* L1 stack switching. */
|
||||||
if (!next_mm->context.l1_stack_save)
|
if (!next_mm->context.l1_stack_save)
|
||||||
return;
|
return;
|
||||||
if (next_mm->context.l1_stack_save == current_l1_stack_save)
|
if (next_mm->context.l1_stack_save == current_l1_stack_save)
|
||||||
|
@ -120,10 +146,36 @@ static inline void activate_mm(struct mm_struct *prev_mm,
|
||||||
memcpy(l1_stack_base, current_l1_stack_save, l1_stack_len);
|
memcpy(l1_stack_base, current_l1_stack_save, l1_stack_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
|
#ifdef CONFIG_MPU
|
||||||
struct task_struct *tsk)
|
static inline void protect_page(struct mm_struct *mm, unsigned long addr,
|
||||||
|
unsigned long flags)
|
||||||
{
|
{
|
||||||
activate_mm(prev, next);
|
unsigned long *mask = mm->context.page_rwx_mask;
|
||||||
|
unsigned long page = addr >> 12;
|
||||||
|
unsigned long idx = page >> 5;
|
||||||
|
unsigned long bit = 1 << (page & 31);
|
||||||
|
|
||||||
|
if (flags & VM_MAYREAD)
|
||||||
|
mask[idx] |= bit;
|
||||||
|
else
|
||||||
|
mask[idx] &= ~bit;
|
||||||
|
mask += page_mask_nelts;
|
||||||
|
if (flags & VM_MAYWRITE)
|
||||||
|
mask[idx] |= bit;
|
||||||
|
else
|
||||||
|
mask[idx] &= ~bit;
|
||||||
|
mask += page_mask_nelts;
|
||||||
|
if (flags & VM_MAYEXEC)
|
||||||
|
mask[idx] |= bit;
|
||||||
|
else
|
||||||
|
mask[idx] &= ~bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void update_protections(struct mm_struct *mm)
|
||||||
|
{
|
||||||
|
flush_switched_cplbs();
|
||||||
|
set_mask_dcplbs(mm->context.page_rwx_mask);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue