diff options
Diffstat (limited to 'arch/arm/mm')
-rw-r--r-- | arch/arm/mm/Makefile | 16 | ||||
-rw-r--r-- | arch/arm/mm/fault-armo.c | 44 | ||||
-rw-r--r-- | arch/arm/mm/fault-armv.c | 121 | ||||
-rw-r--r-- | arch/arm/mm/init.c | 6 | ||||
-rw-r--r-- | arch/arm/mm/mm-arc.c | 1 | ||||
-rw-r--r-- | arch/arm/mm/mm-ebsa110.c | 19 | ||||
-rw-r--r-- | arch/arm/mm/mm-ebsa285.c | 97 | ||||
-rw-r--r-- | arch/arm/mm/mm-nexuspci.c | 23 | ||||
-rw-r--r-- | arch/arm/mm/mm-rpc.c | 65 | ||||
-rw-r--r-- | arch/arm/mm/proc-arm6,7.S | 6 | ||||
-rw-r--r-- | arch/arm/mm/proc-sa110.S | 10 |
11 files changed, 375 insertions, 33 deletions
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile index 0488da561..be9be35f0 100644 --- a/arch/arm/mm/Makefile +++ b/arch/arm/mm/Makefile @@ -7,8 +7,14 @@ # # Note 2! The CFLAGS definition is now in the main makefile... +ifeq ($(MACHINE),a5k) +MMARCH=arc +else +MMARCH=$(MACHINE) +endif + O_TARGET := mm.o -O_OBJS := init.o extable.o fault-$(PROCESSOR).o mm-$(MACHINE).o +O_OBJS := init.o extable.o fault-$(PROCESSOR).o mm-$(MMARCH).o ifeq ($(PROCESSOR),armo) O_OBJS += proc-arm2,3.o @@ -28,9 +34,9 @@ proc-sa110.o: ../lib/constants.h ../lib/constants.h: @$(MAKE) -C ../lib constants.h +ifneq ($(CONFIG_BINUTILS_NEW),y) %.o: %.S -ifndef $(CONFIG_BINUTILS_NEW) - $(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..tmp.s - $(CC) $(CFLAGS:-pipe=) -c -o $@ ..tmp.s - $(RM) ..tmp.s + $(CC) $(CFLAGS) -D__ASSEMBLY__ -E $< | tr ';$$' '\n#' > ..$@.tmp.s + $(CC) $(CFLAGS:-pipe=) -c -o $@ ..$@.tmp.s + $(RM) ..$@.tmp.s endif diff --git a/arch/arm/mm/fault-armo.c b/arch/arm/mm/fault-armo.c index a0fd65df2..6e1024c30 100644 --- a/arch/arm/mm/fault-armo.c +++ b/arch/arm/mm/fault-armo.c @@ -27,6 +27,50 @@ #define FAULT_CODE_WRITE 0x02 #define FAULT_CODE_USER 0x01 +struct pgtable_cache_struct quicklists; + +void __bad_pte(pmd_t *pmd) +{ + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); + set_pmd(pmd, mk_pmd(BAD_PAGETABLE)); +} + +pgd_t *get_pgd_slow(void) +{ + pgd_t *pgd = (pgd_t *) kmalloc(PTRS_PER_PGD * BYTES_PER_PTR, GFP_KERNEL); + pgd_t *init; + + if (pgd) { + init = pgd_offset(&init_mm, 0); + memzero (pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); + memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR); + } + return pgd; +} + +pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *) kmalloc (PTRS_PER_PTE * BYTES_PER_PTR, GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR); + set_pmd(pmd, mk_pmd(pte)); + return pte + offset; + } + set_pmd(pmd, mk_pmd(BAD_PAGETABLE)); + return NULL; + } + kfree (pte); + if (pmd_bad(*pmd)) { + __bad_pte(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret); static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs, diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c index 2925761fb..051b336bf 100644 --- a/arch/arm/mm/fault-armv.c +++ b/arch/arm/mm/fault-armv.c @@ -25,8 +25,96 @@ #define FAULT_CODE_READ 0x02 #define FAULT_CODE_USER 0x01 +struct pgtable_cache_struct quicklists; + +void __bad_pmd(pmd_t *pmd) +{ + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); + set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE)); +} + +void __bad_pmd_kernel(pmd_t *pmd) +{ + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); + set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); +} + +pgd_t *get_pgd_slow(void) +{ + /* + * need to get a 16k page for level 1 + */ + pgd_t *pgd = (pgd_t *) __get_free_pages(GFP_KERNEL,2); + pgd_t *init; + + if (pgd) { + init = pgd_offset(&init_mm, 0); + memzero ((void *)pgd, USER_PTRS_PER_PGD * BYTES_PER_PTR); + memcpy (pgd + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD, + (PTRS_PER_PGD - USER_PTRS_PER_PGD) * BYTES_PER_PTR); + } + return pgd; +} + +pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *) get_small_page(GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR); + set_pmd(pmd, mk_user_pmd(pte)); + return pte + offset; + } + set_pmd(pmd, mk_user_pmd(BAD_PAGETABLE)); + return NULL; + } + free_small_page ((unsigned long) pte); + if (pmd_bad(*pmd)) { + __bad_pmd(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + +pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) +{ + pte_t *pte; + + pte = (pte_t *) get_small_page(GFP_KERNEL); + if (pmd_none(*pmd)) { + if (pte) { + memzero (pte, PTRS_PER_PTE * BYTES_PER_PTR); + set_pmd(pmd, mk_kernel_pmd(pte)); + return pte + offset; + } + set_pmd(pmd, mk_kernel_pmd(BAD_PAGETABLE)); + return NULL; + } + free_small_page ((unsigned long) pte); + if (pmd_bad(*pmd)) { + __bad_pmd_kernel(pmd); + return NULL; + } + return (pte_t *) pmd_page(*pmd) + offset; +} + extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret); +#ifdef DEBUG +static int sp_valid (unsigned long *sp) +{ + unsigned long addr = (unsigned long) sp; + + if (addr >= 0xb0000000 && addr < 0xd0000000) + return 1; + if (addr >= 0x03ff0000 && addr < 0x04000000) + return 1; + return 0; +} +#endif + static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs, struct task_struct *tsk, struct mm_struct *mm) { @@ -103,6 +191,16 @@ bad_area: printk ("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n", tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode); #ifdef DEBUG + { + unsigned int i, j; + unsigned long *sp = (unsigned long *) (regs->ARM_sp - 128); + for (j = 0; j < 20 && sp_valid (sp); j++) { + printk ("%p: ", sp); + for (i = 0; i < 8 && sp_valid (sp); i += 1, sp++) + printk ("%08lx ", *sp); + printk ("\n"); + } + } show_regs (regs); c_backtrace (regs->ARM_fp, regs->ARM_cpsr); #endif @@ -133,7 +231,6 @@ do_DataAbort (unsigned long addr, int fsr, int error_code, struct pt_regs *regs) { if (user_mode(regs)) error_code |= FAULT_CODE_USER; - #define DIE(signr,nam)\ force_sig(signr, current);\ die_if_kernel(nam, regs, fsr, signr);\ @@ -154,18 +251,22 @@ do_DataAbort (unsigned long addr, int fsr, int error_code, struct pt_regs *regs) case 11: DIE(SIGSEGV, "Domain fault") case 13:/* permission fault on section */ -#ifndef DEBUG +#ifdef DEBUG { - unsigned int i, j, a; -static int count=2; -if (count-- == 0) while (1); - a = regs->ARM_sp; - for (j = 0; j < 10; j++) { - printk ("%08x: ", a); - for (i = 0; i < 8; i += 1, a += 4) - printk ("%08lx ", *(unsigned long *)a); + unsigned int i, j; + unsigned long *sp; + + printk ("%s: section permission fault (bad address=0x%08lx, code %d)\n", + current->comm, addr, error_code); + sp = (unsigned long *) (regs->ARM_sp - 128); + for (j = 0; j < 20 && sp_valid (sp); j++) { + printk ("%p: ", sp); + for (i = 0; i < 8 && sp_valid (sp); i += 1, sp++) + printk ("%08lx ", *sp); printk ("\n"); } + show_regs (regs); + c_backtrace(regs->ARM_fp, regs->ARM_cpsr); } #endif DIE(SIGSEGV, "Permission fault") diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index b9e777a32..36b118eb2 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c @@ -17,6 +17,7 @@ #include <linux/mm.h> #include <linux/swap.h> #include <linux/smp.h> +#include <linux/init.h> #ifdef CONFIG_BLK_DEV_INITRD #include <linux/blk.h> #endif @@ -30,7 +31,6 @@ pgd_t swapper_pg_dir[PTRS_PER_PGD]; -const char bad_pmd_string[] = "Bad pmd in pte_alloc: %08lx\n"; extern char _etext, _stext, _edata, __bss_start, _end; extern char __init_begin, __init_end; @@ -103,7 +103,7 @@ void show_mem(void) /* * paging_init() sets up the page tables... */ -unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) +__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)) { extern unsigned long free_area_init(unsigned long, unsigned long); @@ -130,7 +130,7 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) * memory is free. This is done after various parts of the system have * claimed their memory after the kernel image. */ -void mem_init(unsigned long start_mem, unsigned long end_mem) +__initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) { extern void sound_init(void); int codepages = 0; diff --git a/arch/arm/mm/mm-arc.c b/arch/arm/mm/mm-arc.c index 4a4b4718c..ff447a6be 100644 --- a/arch/arm/mm/mm-arc.c +++ b/arch/arm/mm/mm-arc.c @@ -5,3 +5,4 @@ * * Copyright (C) 1998 Russell King */ +#include <asm/arch/mm-init.h> diff --git a/arch/arm/mm/mm-ebsa110.c b/arch/arm/mm/mm-ebsa110.c index 907a3f399..a937e098d 100644 --- a/arch/arm/mm/mm-ebsa110.c +++ b/arch/arm/mm/mm-ebsa110.c @@ -5,3 +5,22 @@ * * Copyright (C) 1998 Russell King */ + +#include <asm/io.h> + +/* map in IO */ +void setup_io_pagetables(void) +{ + unsigned long address = IO_START; + int spi = IO_BASE >> PGDIR_SHIFT; + + pgd_val(swapper_pg_dir[spi-1]) = 0xc0000000 | PMD_TYPE_SECT | + PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_AP_WRITE; + + while (address < IO_START + IO_SIZE && address) { + pgd_val(swapper_pg_dir[spi++]) = address | PMD_TYPE_SECT | + PMD_DOMAIN(DOMAIN_IO) | + PMD_SECT_AP_WRITE; + address += PGDIR_SIZE; + } +} diff --git a/arch/arm/mm/mm-ebsa285.c b/arch/arm/mm/mm-ebsa285.c new file mode 100644 index 000000000..eb5d7152a --- /dev/null +++ b/arch/arm/mm/mm-ebsa285.c @@ -0,0 +1,97 @@ +/* + * arch/arm/mm/mm-ebsa285.c + * + * Extra MM routines for the EBSA285 architecture + * + * Copyright (C) 1998 Russell King + */ +#include <linux/sched.h> +#include <linux/mm.h> + +#include <asm/pgtable.h> +#include <asm/page.h> +#include <asm/io.h> +#include <asm/proc/mm-init.h> + +/* Logical Physical + * 0xfff00000 0x40000000 X-Bus + * 0xffe00000 0x7c000000 PCI I/O space + * 0xfe000000 0x42000000 CSR + * 0xfd000000 0x78000000 Outbound write flush + * 0xfc000000 0x79000000 PCI IACK/special space + * 0xf9000000 0x7a000000 PCI Config type 1 + * 0xf8000000 0x7b000000 PCI Config type 0 + */ + +static struct mapping { + unsigned long virtual; + unsigned long physical; + unsigned long length; +} io_mapping[] = { + /* + * This is to allow us to fiddle with the EEPROM + * This entry will go away in time + */ + { 0xd8000000, 0x41000000, 0x00400000 }, + + /* + * These ones are so that we can fiddle + * with the various cards (eg VGA) + * until we're happy with them... + */ + { 0xdc000000, 0x7c000000, 0x00100000 }, + { 0xe0000000, 0x80000000, 0x10000000 }, + + { 0xf8000000, 0x7b000000, 0x01000000 }, /* Type 0 Config */ + + { 0xf9000000, 0x7a000000, 0x01000000 }, /* Type 1 Config */ + + { 0xfc000000, 0x79000000, 0x01000000 }, /* PCI IACK */ + { 0xfd000000, 0x78000000, 0x01000000 }, /* Outbound wflsh*/ + { 0xfe000000, 0x42000000, 0x01000000 }, /* CSR */ + { 0xffe00000, 0x7c000000, 0x00100000 }, /* PCI I/O */ + { 0xfff00000, 0x40000000, 0x00100000 }, /* X-Bus */ +}; + +#define SIZEOFIO (sizeof(io_mapping) / sizeof(io_mapping[0])) + +/* map in IO */ +unsigned long setup_io_pagetables(unsigned long start_mem) +{ + struct mapping *mp; + int i; + + for (i = 0, mp = io_mapping; i < SIZEOFIO; i++, mp++) { + while ((mp->virtual & 1048575 || mp->physical & 1048575) && mp->length >= PAGE_SIZE) { + alloc_init_page(&start_mem, mp->virtual, mp->physical, DOMAIN_IO, + PTE_AP_WRITE); + + mp->length -= PAGE_SIZE; + mp->virtual += PAGE_SIZE; + mp->physical += PAGE_SIZE; + } + + while (mp->length >= 1048576) { +if (mp->virtual > 0xf0000000) + alloc_init_section(&start_mem, mp->virtual, mp->physical, DOMAIN_IO, + PMD_SECT_AP_WRITE); +else +alloc_init_section(&start_mem, mp->virtual, mp->physical, DOMAIN_USER, PMD_SECT_AP_WRITE | PMD_SECT_AP_READ); + + mp->length -= 1048576; + mp->virtual += 1048576; + mp->physical += 1048576; + } + + while (mp->length >= PAGE_SIZE) { + alloc_init_page(&start_mem, mp->virtual, mp->physical, DOMAIN_IO, + PTE_AP_WRITE); + + mp->length -= PAGE_SIZE; + mp->virtual += PAGE_SIZE; + mp->physical += PAGE_SIZE; + } + } + return start_mem; +} + diff --git a/arch/arm/mm/mm-nexuspci.c b/arch/arm/mm/mm-nexuspci.c index bbae80b19..2bb2d0fab 100644 --- a/arch/arm/mm/mm-nexuspci.c +++ b/arch/arm/mm/mm-nexuspci.c @@ -1,7 +1,28 @@ /* * arch/arm/mm/mm-nexuspci.c + * from arch/arm/mm/mm-ebsa110.c * - * Extra MM routines for the Archimedes architecture + * Extra MM routines for the NexusPCI architecture * * Copyright (C) 1998 Russell King */ + +#include <asm/io.h> + +/* map in IO */ +void setup_io_pagetables(void) +{ + unsigned long address = IO_START; + int spi = IO_BASE >> PGDIR_SHIFT; + + pgd_val(swapper_pg_dir[spi-1]) = 0xc0000000 | PMD_TYPE_SECT | + PMD_DOMAIN(DOMAIN_KERNEL) | PMD_SECT_AP_WRITE; + + while (address < IO_START + IO_SIZE && address) { + pgd_val(swapper_pg_dir[spi++]) = address | PMD_TYPE_SECT | + PMD_DOMAIN(DOMAIN_IO) | + PMD_SECT_AP_WRITE; + address += PGDIR_SIZE; + } +} + diff --git a/arch/arm/mm/mm-rpc.c b/arch/arm/mm/mm-rpc.c index 5eccb1f81..f789b8f79 100644 --- a/arch/arm/mm/mm-rpc.c +++ b/arch/arm/mm/mm-rpc.c @@ -6,7 +6,14 @@ * Copyright (C) 1998 Russell King */ +#include <linux/sched.h> +#include <linux/slab.h> + +#include <asm/pgtable.h> #include <asm/setup.h> +#include <asm/io.h> +#include <asm/proc/mm-init.h> +#include <asm/arch/mm-init.h> #define NR_DRAM_BANKS 4 #define NR_VRAM_BANKS 1 @@ -21,8 +28,8 @@ #define FIRST_DRAM_ADDR 0x10000000 #define PHYS_TO_BANK(x) (((x) >> BANK_SHIFT) & (NR_DRAM_BANKS - 1)) -#define BANK_TO_PHYS(x) ((FIRST_DRAM_ADDR) + - (((x) - FIRST_DRAM_BANK) << BANK_SHIFT) +#define BANK_TO_PHYS(x) ((FIRST_DRAM_ADDR) + \ + (((x) - FIRST_DRAM_BANK) << BANK_SHIFT)) struct ram_bank { unsigned int virt_addr; /* virtual address of the *end* of this bank + 1 */ @@ -75,6 +82,56 @@ void init_dram_banks(struct param_struct *params) rambank[bank].virt_addr = PAGE_OFFSET + bytes; } - drambank[4].phys_offset = 0xd6000000; - drambank[4].virt_addr = 0xd8000000; + rambank[FIRST_VRAM_BANK].phys_offset = 0xd6000000; + rambank[FIRST_VRAM_BANK].virt_addr = 0xd8000000; + + current->tss.memmap = __virt_to_phys((unsigned long)swapper_pg_dir); +} + +static struct mapping { + unsigned long virtual; + unsigned long physical; + unsigned long length; +} io_mapping[] = { + { SCREEN2_BASE, SCREEN_START, 2*1048576 }, /* VRAM */ + { IO_BASE, IO_START, IO_SIZE } /* IO space */ +}; + +#define SIZEOFIO (sizeof(io_mapping) / sizeof(io_mapping[0])) + +/* map in IO */ +unsigned long setup_io_pagetables(unsigned long start_mem) +{ + struct mapping *mp; + int i; + + for (i = 0, mp = io_mapping; i < SIZEOFIO; i++, mp++) { + while ((mp->virtual & 1048575 || mp->physical & 1048575) && mp->length >= PAGE_SIZE) { + alloc_init_page(&start_mem, mp->virtual, mp->physical, DOMAIN_IO, + PTE_AP_WRITE); + + mp->length -= PAGE_SIZE; + mp->virtual += PAGE_SIZE; + mp->physical += PAGE_SIZE; + } + + while (mp->length >= 1048576) { + alloc_init_section(&start_mem, mp->virtual, mp->physical, DOMAIN_IO, + PMD_SECT_AP_WRITE); + mp->length -= 1048576; + mp->virtual += 1048576; + mp->physical += 1048576; + } + + while (mp->length >= PAGE_SIZE) { + alloc_init_page(&start_mem, mp->virtual, mp->physical, DOMAIN_IO, + PTE_AP_WRITE); + + mp->length -= PAGE_SIZE; + mp->virtual += PAGE_SIZE; + mp->physical += PAGE_SIZE; + } + } + + return start_mem; } diff --git a/arch/arm/mm/proc-arm6,7.S b/arch/arm/mm/proc-arm6,7.S index 776d0d57c..a853671fc 100644 --- a/arch/arm/mm/proc-arm6,7.S +++ b/arch/arm/mm/proc-arm6,7.S @@ -72,10 +72,10 @@ _arm6_7_switch_to: stmfd sp!, {ip} @ Save cpsr_SVC str sp, [r0, #TSS_SAVE] @ Save sp_SVC ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC - ldr r0, [r1, #ADDR_LIMIT] + ldr r0, [r1, #TSK_ADDR_LIMIT] teq r0, #0 - moveq r0, #KERNEL_DOMAIN - movne r0, #USER_DOMAIN + moveq r0, #DOM_KERNELDOMAIN + movne r0, #DOM_USERDOMAIN mcr p15, 0, r0, c3, c0 @ Set domain reg ldr r0, [r1, #TSS_MEMMAP] @ Page table pointer mov r1, #0 diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S index 7d53bf230..633e8c164 100644 --- a/arch/arm/mm/proc-sa110.S +++ b/arch/arm/mm/proc-sa110.S @@ -161,8 +161,6 @@ _sa110_flush_icache_area: blt 1b mcr p15, 0, r0, c7, c5, 0 @ flush I cache mov pc, lr - -@LC0: .word _current /* * Function: sa110_switch_to (struct task_struct *prev, struct task_struct *next) * @@ -183,10 +181,10 @@ _sa110_switch_to: stmfd sp!, {ip} @ Save cpsr_SVC str sp, [r0, #TSS_SAVE] @ Save sp_SVC ldr sp, [r1, #TSS_SAVE] @ Get saved sp_SVC - ldr r0, [r1, #ADDR_LIMIT] + ldr r0, [r1, #TSK_ADDR_LIMIT] teq r0, #0 - moveq r0, #KERNEL_DOMAIN - movne r0, #USER_DOMAIN + moveq r0, #DOM_KERNELDOMAIN + movne r0, #DOM_USERDOMAIN mcr p15, 0, r0, c3, c0 @ Set segment ldr r0, [r1, #TSS_MEMMAP] @ Page table pointer ldr r3, =Lclean_switch @@ -227,8 +225,6 @@ _sa110_data_abort: mov r2, r2, lsr #19 @ b1 = L and r3, r2, #0x69 << 2 and r2, r2, #2 -// teq r3, #0x21 << 2 -// orreq r2, r2, #1 @ b0 = {LD,ST}RT mrc p15, 0, r1, c5, c0, 0 @ get FSR and r1, r1, #255 mov pc, lr |