diff options
Diffstat (limited to 'arch/arm26/mm')
-rw-r--r-- | arch/arm26/mm/Makefile | 6 | ||||
-rw-r--r-- | arch/arm26/mm/extable.c | 24 | ||||
-rw-r--r-- | arch/arm26/mm/fault.c | 312 | ||||
-rw-r--r-- | arch/arm26/mm/fault.h | 5 | ||||
-rw-r--r-- | arch/arm26/mm/init.c | 403 | ||||
-rw-r--r-- | arch/arm26/mm/memc.c | 184 | ||||
-rw-r--r-- | arch/arm26/mm/proc-funcs.S | 359 | ||||
-rw-r--r-- | arch/arm26/mm/small_page.c | 192 |
8 files changed, 0 insertions, 1485 deletions
diff --git a/arch/arm26/mm/Makefile b/arch/arm26/mm/Makefile deleted file mode 100644 index a8fb166..0000000 --- a/arch/arm26/mm/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# Makefile for the linux arm26-specific parts of the memory manager. -# - -obj-y := init.o extable.o proc-funcs.o memc.o fault.o \ - small_page.o diff --git a/arch/arm26/mm/extable.c b/arch/arm26/mm/extable.c deleted file mode 100644 index 38e1958..0000000 --- a/arch/arm26/mm/extable.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * linux/arch/arm26/mm/extable.c - */ - -#include <linux/module.h> -#include <asm/uaccess.h> - -int fixup_exception(struct pt_regs *regs) -{ - const struct exception_table_entry *fixup; - - fixup = search_exception_tables(instruction_pointer(regs)); - - /* - * The kernel runs in SVC mode - make sure we keep running in SVC mode - * by frobbing the PSR appropriately (PSR and PC are in the same reg. - * on ARM26) - */ - if (fixup) - regs->ARM_pc = fixup->fixup | PSR_I_BIT | MODE_SVC26; - - return fixup != NULL; -} - diff --git a/arch/arm26/mm/fault.c b/arch/arm26/mm/fault.c deleted file mode 100644 index dec638a..0000000 --- a/arch/arm26/mm/fault.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * linux/arch/arm26/mm/fault.c - * - * Copyright (C) 1995 Linus Torvalds - * Modifications for ARM processor (c) 1995-2001 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/types.h> -#include <linux/ptrace.h> -#include <linux/mman.h> -#include <linux/mm.h> -#include <linux/interrupt.h> -#include <linux/proc_fs.h> -#include <linux/init.h> - -#include <asm/system.h> -#include <asm/pgtable.h> -#include <asm/uaccess.h> //FIXME this header may be bogusly included - -#include "fault.h" - -#define FAULT_CODE_LDRSTRPOST 0x80 -#define FAULT_CODE_LDRSTRPRE 0x40 -#define FAULT_CODE_LDRSTRREG 0x20 -#define FAULT_CODE_LDMSTM 0x10 -#define FAULT_CODE_LDCSTC 0x08 -#define FAULT_CODE_PREFETCH 0x04 -#define FAULT_CODE_WRITE 0x02 -#define FAULT_CODE_FORCECOW 0x01 - -#define DO_COW(m) ((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW)) -#define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE)) -#define DEBUG -/* - * This is useful to dump out the page tables associated with - * 'addr' in mm 'mm'. - */ -void show_pte(struct mm_struct *mm, unsigned long addr) -{ - pgd_t *pgd; - - if (!mm) - mm = &init_mm; - - printk(KERN_ALERT "pgd = %p\n", mm->pgd); - pgd = pgd_offset(mm, addr); - printk(KERN_ALERT "[%08lx] *pgd=%08lx", addr, pgd_val(*pgd)); - - do { - pmd_t *pmd; - pte_t *pte; - - pmd = pmd_offset(pgd, addr); - - if (pmd_none(*pmd)) - break; - - if (pmd_bad(*pmd)) { - printk("(bad)"); - break; - } - - /* We must not map this if we have highmem enabled */ - /* FIXME */ - pte = pte_offset_map(pmd, addr); - printk(", *pte=%08lx", pte_val(*pte)); - pte_unmap(pte); - } while(0); - - printk("\n"); -} - -/* - * Oops. The kernel tried to access some page that wasn't present. - */ -static void -__do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, - struct pt_regs *regs) -{ - /* - * Are we prepared to handle this kernel fault? - */ - if (fixup_exception(regs)) - return; - - /* - * No handler, we'll have to terminate things with extreme prejudice. - */ - bust_spinlocks(1); - printk(KERN_ALERT - "Unable to handle kernel %s at virtual address %08lx\n", - (addr < PAGE_SIZE) ? "NULL pointer dereference" : - "paging request", addr); - - show_pte(mm, addr); - die("Oops", regs, fsr); - bust_spinlocks(0); - do_exit(SIGKILL); -} - -/* - * Something tried to access memory that isn't in our memory map.. - * User mode accesses just cause a SIGSEGV - */ -static void -__do_user_fault(struct task_struct *tsk, unsigned long addr, - unsigned int fsr, int code, struct pt_regs *regs) -{ - struct siginfo si; - -#ifdef CONFIG_DEBUG_USER - printk("%s: unhandled page fault at 0x%08lx, code 0x%03x\n", - tsk->comm, addr, fsr); - show_pte(tsk->mm, addr); - show_regs(regs); - //dump_backtrace(regs, tsk); // FIXME ARM32 dropped this - why? - while(1); //FIXME - hack to stop debug going nutso -#endif - - tsk->thread.address = addr; - tsk->thread.error_code = fsr; - tsk->thread.trap_no = 14; - si.si_signo = SIGSEGV; - si.si_errno = 0; - si.si_code = code; - si.si_addr = (void *)addr; - force_sig_info(SIGSEGV, &si, tsk); -} - -static int -__do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, - struct task_struct *tsk) -{ - struct vm_area_struct *vma; - int fault, mask; - - vma = find_vma(mm, addr); - fault = -2; /* bad map area */ - if (!vma) - goto out; - if (vma->vm_start > addr) - goto check_stack; - - /* - * Ok, we have a good vm_area for this - * memory access, so we can handle it. - */ -good_area: - if (READ_FAULT(fsr)) /* read? */ - mask = VM_READ|VM_EXEC|VM_WRITE; - else - mask = VM_WRITE; - - fault = -1; /* bad access type */ - if (!(vma->vm_flags & mask)) - goto out; - - /* - * If for any reason at all we couldn't handle - * the fault, make sure we exit gracefully rather - * than endlessly redo the fault. - */ -survive: - fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(fsr)); - if (unlikely(fault & VM_FAULT_ERROR)) { - if (fault & VM_FAULT_OOM) - goto out_of_memory; - else if (fault & VM_FAULT_SIGBUS) - return fault; - BUG(); - } - if (fault & VM_FAULT_MAJOR) - tsk->maj_flt++; - else - tsk->min_flt++; - return fault; - -out_of_memory: - fault = -3; /* out of memory */ - if (!is_init(tsk)) - goto out; - - /* - * If we are out of memory for pid1, - * sleep for a while and retry - */ - yield(); - goto survive; - -check_stack: - if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr)) - goto good_area; -out: - return fault; -} - -int do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) -{ - struct task_struct *tsk; - struct mm_struct *mm; - int fault; - - tsk = current; - mm = tsk->mm; - - /* - * If we're in an interrupt or have no user - * context, we must not take the fault.. - */ - if (in_atomic() || !mm) - goto no_context; - - down_read(&mm->mmap_sem); - fault = __do_page_fault(mm, addr, fsr, tsk); - up_read(&mm->mmap_sem); - - /* - * Handle the "normal" case first - */ - if (likely(!(fault & VM_FAULT_ERROR))) - return 0; - if (fault & VM_FAULT_SIGBUS) - goto do_sigbus; - /* else VM_FAULT_OOM */ - - /* - * If we are in kernel mode at this point, we - * have no context to handle this fault with. - * FIXME - is this test right? - */ - if (!user_mode(regs)){ - goto no_context; - } - - if (fault == -3) { - /* - * We ran out of memory, or some other thing happened to - * us that made us unable to handle the page fault gracefully. - */ - printk("VM: killing process %s\n", tsk->comm); - do_exit(SIGKILL); - } - else{ - __do_user_fault(tsk, addr, fsr, fault == -1 ? SEGV_ACCERR : SEGV_MAPERR, regs); - } - - return 0; - - -/* - * We ran out of memory, or some other thing happened to us that made - * us unable to handle the page fault gracefully. - */ -do_sigbus: - /* - * Send a sigbus, regardless of whether we were in kernel - * or user mode. - */ - tsk->thread.address = addr; //FIXME - need other bits setting? - tsk->thread.error_code = fsr; - tsk->thread.trap_no = 14; - force_sig(SIGBUS, tsk); -#ifdef CONFIG_DEBUG_USER - printk(KERN_DEBUG "%s: sigbus at 0x%08lx, pc=0x%08lx\n", - current->comm, addr, instruction_pointer(regs)); -#endif - - /* Kernel mode? Handle exceptions or die */ - if (user_mode(regs)) - return 0; - -no_context: - __do_kernel_fault(mm, addr, fsr, regs); - return 0; -} - -/* - * Handle a data abort. Note that we have to handle a range of addresses - * on ARM2/3 for ldm. If both pages are zero-mapped, then we have to force - * a copy-on-write. However, on the second page, we always force COW. - */ -asmlinkage void -do_DataAbort(unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs) -{ - do_page_fault(min_addr, mode, regs); - - if ((min_addr ^ max_addr) >> PAGE_SHIFT){ - do_page_fault(max_addr, mode | FAULT_CODE_FORCECOW, regs); - } -} - -asmlinkage int -do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) -{ -#if 0 - if (the memc mapping for this page exists) { - printk ("Page in, but got abort (undefined instruction?)\n"); - return 0; - } -#endif - do_page_fault(addr, FAULT_CODE_PREFETCH, regs); - return 1; -} - diff --git a/arch/arm26/mm/fault.h b/arch/arm26/mm/fault.h deleted file mode 100644 index 4442d00..0000000 --- a/arch/arm26/mm/fault.h +++ /dev/null @@ -1,5 +0,0 @@ -void show_pte(struct mm_struct *mm, unsigned long addr); - -int do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs); - -unsigned long search_extable(unsigned long addr); //FIXME - is it right? diff --git a/arch/arm26/mm/init.c b/arch/arm26/mm/init.c deleted file mode 100644 index 36e7ee3..0000000 --- a/arch/arm26/mm/init.c +++ /dev/null @@ -1,403 +0,0 @@ -/* - * linux/arch/arm26/mm/init.c - * - * Copyright (C) 1995-2002 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/types.h> -#include <linux/ptrace.h> -#include <linux/mman.h> -#include <linux/mm.h> -#include <linux/swap.h> -#include <linux/smp.h> -#include <linux/init.h> -#include <linux/initrd.h> -#include <linux/bootmem.h> -#include <linux/blkdev.h> -#include <linux/pfn.h> - -#include <asm/segment.h> -#include <asm/mach-types.h> -#include <asm/dma.h> -#include <asm/hardware.h> -#include <asm/setup.h> -#include <asm/tlb.h> - -#include <asm/map.h> - -struct mmu_gather mmu_gathers[NR_CPUS]; - -extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; -extern char _stext, _text, _etext, _end, __init_begin, __init_end; -#ifdef CONFIG_XIP_KERNEL -extern char _endtext, _sdata; -#endif -extern unsigned long phys_initrd_start; -extern unsigned long phys_initrd_size; - -/* - * The sole use of this is to pass memory configuration - * data from paging_init to mem_init. - */ -static struct meminfo meminfo __initdata = { 0, }; - -/* - * empty_zero_page is a special page that is used for - * zero-initialized data and COW. - */ -struct page *empty_zero_page; - -void show_mem(void) -{ - int free = 0, total = 0, reserved = 0; - int shared = 0, cached = 0, slab = 0; - struct page *page, *end; - - printk("Mem-info:\n"); - show_free_areas(); - printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); - - - page = NODE_MEM_MAP(0); - end = page + NODE_DATA(0)->node_spanned_pages; - - do { - total++; - if (PageReserved(page)) - reserved++; - else if (PageSwapCache(page)) - cached++; - else if (PageSlab(page)) - slab++; - else if (!page_count(page)) - free++; - else - shared += page_count(page) - 1; - page++; - } while (page < end); - - printk("%d pages of RAM\n", total); - printk("%d free pages\n", free); - printk("%d reserved pages\n", reserved); - printk("%d slab pages\n", slab); - printk("%d pages shared\n", shared); - printk("%d pages swap cached\n", cached); -} - -struct node_info { - unsigned int start; - unsigned int end; - int bootmap_pages; -}; - -/* - * FIXME: We really want to avoid allocating the bootmap bitmap - * over the top of the initrd. Hopefully, this is located towards - * the start of a bank, so if we allocate the bootmap bitmap at - * the end, we won't clash. - */ -static unsigned int __init -find_bootmap_pfn(struct meminfo *mi, unsigned int bootmap_pages) -{ - unsigned int start_pfn, bootmap_pfn; - unsigned int start, end; - - start_pfn = PFN_UP((unsigned long)&_end); - bootmap_pfn = 0; - - /* ARM26 machines only have one node */ - if (mi->bank->node != 0) - BUG(); - - start = PFN_UP(mi->bank->start); - end = PFN_DOWN(mi->bank->size + mi->bank->start); - - if (start < start_pfn) - start = start_pfn; - - if (end <= start) - BUG(); - - if (end - start >= bootmap_pages) - bootmap_pfn = start; - else - BUG(); - - return bootmap_pfn; -} - -/* - * Scan the memory info structure and pull out: - * - the end of memory - * - the number of nodes - * - the pfn range of each node - * - the number of bootmem bitmap pages - */ -static void __init -find_memend_and_nodes(struct meminfo *mi, struct node_info *np) -{ - unsigned int memend_pfn = 0; - - nodes_clear(node_online_map); - node_set_online(0); - - np->bootmap_pages = 0; - - if (mi->bank->size == 0) { - BUG(); - } - - /* - * Get the start and end pfns for this bank - */ - np->start = PFN_UP(mi->bank->start); - np->end = PFN_DOWN(mi->bank->start + mi->bank->size); - - if (memend_pfn < np->end) - memend_pfn = np->end; - - /* - * Calculate the number of pages we require to - * store the bootmem bitmaps. - */ - np->bootmap_pages = bootmem_bootmap_pages(np->end - np->start); - - /* - * This doesn't seem to be used by the Linux memory - * manager any more. If we can get rid of it, we - * also get rid of some of the stuff above as well. - */ - max_low_pfn = memend_pfn - PFN_DOWN(PHYS_OFFSET); - max_pfn = memend_pfn - PFN_DOWN(PHYS_OFFSET); - mi->end = memend_pfn << PAGE_SHIFT; - -} - -/* - * Initialise the bootmem allocator for all nodes. This is called - * early during the architecture specific initialisation. - */ -void __init bootmem_init(struct meminfo *mi) -{ - struct node_info node_info; - unsigned int bootmap_pfn; - pg_data_t *pgdat = NODE_DATA(0); - - find_memend_and_nodes(mi, &node_info); - - bootmap_pfn = find_bootmap_pfn(mi, node_info.bootmap_pages); - - /* - * Note that node 0 must always have some pages. - */ - if (node_info.end == 0) - BUG(); - - /* - * Initialise the bootmem allocator. - */ - init_bootmem_node(pgdat, bootmap_pfn, node_info.start, node_info.end); - - /* - * Register all available RAM in this node with the bootmem allocator. - */ - free_bootmem_node(pgdat, mi->bank->start, mi->bank->size); - - /* - * Register the kernel text and data with bootmem. - * Note: with XIP we dont register .text since - * its in ROM. - */ -#ifdef CONFIG_XIP_KERNEL - reserve_bootmem_node(pgdat, __pa(&_sdata), &_end - &_sdata); -#else - reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext); -#endif - - /* - * And don't forget to reserve the allocator bitmap, - * which will be freed later. - */ - reserve_bootmem_node(pgdat, bootmap_pfn << PAGE_SHIFT, - node_info.bootmap_pages << PAGE_SHIFT); - - /* - * These should likewise go elsewhere. They pre-reserve - * the screen memory region at the start of main system - * memory. FIXME - screen RAM is not 512K! - */ - reserve_bootmem_node(pgdat, 0x02000000, 0x00080000); - -#ifdef CONFIG_BLK_DEV_INITRD - initrd_start = phys_initrd_start; - initrd_end = initrd_start + phys_initrd_size; - - /* Achimedes machines only have one node, so initrd is in node 0 */ -#ifdef CONFIG_XIP_KERNEL - /* Only reserve initrd space if it is in RAM */ - if(initrd_start && initrd_start < 0x03000000){ -#else - if(initrd_start){ -#endif - reserve_bootmem_node(pgdat, __pa(initrd_start), - initrd_end - initrd_start); - } -#endif /* CONFIG_BLK_DEV_INITRD */ - - -} - -/* - * paging_init() sets up the page tables, initialises the zone memory - * maps, and sets up the zero page, bad page and bad page tables. - */ -void __init paging_init(struct meminfo *mi) -{ - void *zero_page; - unsigned long zone_size[MAX_NR_ZONES]; - unsigned long zhole_size[MAX_NR_ZONES]; - struct bootmem_data *bdata; - pg_data_t *pgdat; - int i; - - memcpy(&meminfo, mi, sizeof(meminfo)); - - /* - * allocate the zero page. Note that we count on this going ok. - */ - zero_page = alloc_bootmem_low_pages(PAGE_SIZE); - - /* - * initialise the page tables. - */ - memtable_init(mi); - flush_tlb_all(); - - /* - * initialise the zones in node 0 (archimedes have only 1 node) - */ - - for (i = 0; i < MAX_NR_ZONES; i++) { - zone_size[i] = 0; - zhole_size[i] = 0; - } - - pgdat = NODE_DATA(0); - bdata = pgdat->bdata; - zone_size[0] = bdata->node_low_pfn - - (bdata->node_boot_start >> PAGE_SHIFT); - if (!zone_size[0]) - BUG(); - pgdat->node_mem_map = NULL; - free_area_init_node(0, pgdat, zone_size, - bdata->node_boot_start >> PAGE_SHIFT, zhole_size); - - /* - * finish off the bad pages once - * the mem_map is initialised - */ - memzero(zero_page, PAGE_SIZE); - empty_zero_page = virt_to_page(zero_page); -} - -static inline void free_area(unsigned long addr, unsigned long end, char *s) -{ - unsigned int size = (end - addr) >> 10; - - for (; addr < end; addr += PAGE_SIZE) { - struct page *page = virt_to_page(addr); - ClearPageReserved(page); - init_page_count(page); - free_page(addr); - totalram_pages++; - } - - if (size && s) - printk(KERN_INFO "Freeing %s memory: %dK\n", s, size); -} - -/* - * mem_init() marks the free areas in the mem_map and tells us how much - * memory is free. This is done after various parts of the system have - * claimed their memory after the kernel image. - */ -void __init mem_init(void) -{ - unsigned int codepages, datapages, initpages; - pg_data_t *pgdat = NODE_DATA(0); - extern int sysctl_overcommit_memory; - - - /* Note: data pages includes BSS */ -#ifdef CONFIG_XIP_KERNEL - codepages = &_endtext - &_text; - datapages = &_end - &_sdata; -#else - codepages = &_etext - &_text; - datapages = &_end - &_etext; -#endif - initpages = &__init_end - &__init_begin; - - high_memory = (void *)__va(meminfo.end); - max_mapnr = virt_to_page(high_memory) - mem_map; - - /* this will put all unused low memory onto the freelists */ - if (pgdat->node_spanned_pages != 0) - totalram_pages += free_all_bootmem_node(pgdat); - - num_physpages = meminfo.bank[0].size >> PAGE_SHIFT; - - printk(KERN_INFO "Memory: %luMB total\n", num_physpages >> (20 - PAGE_SHIFT)); - printk(KERN_NOTICE "Memory: %luKB available (%dK code, " - "%dK data, %dK init)\n", - (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), - codepages >> 10, datapages >> 10, initpages >> 10); - - /* - * Turn on overcommit on tiny machines - */ - if (PAGE_SIZE >= 16384 && num_physpages <= 128) { - sysctl_overcommit_memory = OVERCOMMIT_ALWAYS; - printk("Turning on overcommit\n"); - } -} - -void free_initmem(void){ -#ifndef CONFIG_XIP_KERNEL - free_area((unsigned long)(&__init_begin), - (unsigned long)(&__init_end), - "init"); -#endif -} - -#ifdef CONFIG_BLK_DEV_INITRD - -static int keep_initrd; - -void free_initrd_mem(unsigned long start, unsigned long end) -{ -#ifdef CONFIG_XIP_KERNEL - /* Only bin initrd if it is in RAM... */ - if(!keep_initrd && start < 0x03000000) -#else - if (!keep_initrd) -#endif - free_area(start, end, "initrd"); -} - -static int __init keepinitrd_setup(char *__unused) -{ - keep_initrd = 1; - return 1; -} - -__setup("keepinitrd", keepinitrd_setup); -#endif diff --git a/arch/arm26/mm/memc.c b/arch/arm26/mm/memc.c deleted file mode 100644 index ffecd85..0000000 --- a/arch/arm26/mm/memc.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * linux/arch/arm26/mm/memc.c - * - * Copyright (C) 1998-2000 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Page table sludge for older ARM processor architectures. - */ -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/init.h> -#include <linux/bootmem.h> - -#include <asm/pgtable.h> -#include <asm/pgalloc.h> -#include <asm/page.h> -#include <asm/memory.h> -#include <asm/hardware.h> - -#include <asm/map.h> - -#define MEMC_TABLE_SIZE (256*sizeof(unsigned long)) - -struct kmem_cache *pte_cache, *pgd_cache; -int page_nr; - -/* - * Allocate space for a page table and a MEMC table. - * Note that we place the MEMC - * table before the page directory. This means we can - * easily get to both tightly-associated data structures - * with a single pointer. - */ -static inline pgd_t *alloc_pgd_table(void) -{ - void *pg2k = kmem_cache_alloc(pgd_cache, GFP_KERNEL); - - if (pg2k) - pg2k += MEMC_TABLE_SIZE; - - return (pgd_t *)pg2k; -} - -/* - * Free a page table. this function is the counterpart to get_pgd_slow - * below, not alloc_pgd_table above. - */ -void free_pgd_slow(pgd_t *pgd) -{ - unsigned long tbl = (unsigned long)pgd; - - tbl -= MEMC_TABLE_SIZE; - - kmem_cache_free(pgd_cache, (void *)tbl); -} - -/* - * Allocate a new pgd and fill it in ready for use - * - * A new tasks pgd is completely empty (all pages !present) except for: - * - * o The machine vectors at virtual address 0x0 - * o The vmalloc region at the top of address space - * - */ -#define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD) - -pgd_t *get_pgd_slow(struct mm_struct *mm) -{ - pgd_t *new_pgd, *init_pgd; - pmd_t *new_pmd, *init_pmd; - pte_t *new_pte, *init_pte; - - new_pgd = alloc_pgd_table(); - if (!new_pgd) - goto no_pgd; - - /* - * On ARM, first page must always be allocated since it contains - * the machine vectors. - */ - new_pmd = pmd_alloc(mm, new_pgd, 0); - if (!new_pmd) - goto no_pmd; - - new_pte = pte_alloc_map(mm, new_pmd, 0); - if (!new_pte) - goto no_pte; - - init_pgd = pgd_offset(&init_mm, 0); - init_pmd = pmd_offset(init_pgd, 0); - init_pte = pte_offset(init_pmd, 0); - - set_pte(new_pte, *init_pte); - pte_unmap(new_pte); - - /* - * the page table entries are zeroed - * when the table is created. (see the cache_ctor functions below) - * Now we need to plonk the kernel (vmalloc) area at the end of - * the address space. We copy this from the init thread, just like - * the init_pte we copied above... - */ - memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR, - (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t)); - - /* update MEMC tables */ - cpu_memc_update_all(new_pgd); - return new_pgd; - -no_pte: - pmd_free(new_pmd); -no_pmd: - free_pgd_slow(new_pgd); -no_pgd: - return NULL; -} - -/* - * No special code is required here. - */ -void setup_mm_for_reboot(char mode) -{ -} - -/* - * This contains the code to setup the memory map on an ARM2/ARM250/ARM3 - * o swapper_pg_dir = 0x0207d000 - * o kernel proper starts at 0x0208000 - * o create (allocate) a pte to contain the machine vectors - * o populate the pte (points to 0x02078000) (FIXME - is it zeroed?) - * o populate the init tasks page directory (pgd) with the new pte - * o zero the rest of the init tasks pgdir (FIXME - what about vmalloc?!) - */ -void __init memtable_init(struct meminfo *mi) -{ - pte_t *pte; - int i; - - page_nr = max_low_pfn; - - pte = alloc_bootmem_low_pages(PTRS_PER_PTE * sizeof(pte_t)); - pte[0] = mk_pte_phys(PAGE_OFFSET + SCREEN_SIZE, PAGE_READONLY); - pmd_populate(&init_mm, pmd_offset(swapper_pg_dir, 0), pte); - - for (i = 1; i < PTRS_PER_PGD; i++) - pgd_val(swapper_pg_dir[i]) = 0; -} - -void __init iotable_init(struct map_desc *io_desc) -{ - /* nothing to do */ -} - -/* - * We never have holes in the memmap - */ -void __init create_memmap_holes(struct meminfo *mi) -{ -} - -static void pte_cache_ctor(void *pte, struct kmem_cache *cache, unsigned long flags) -{ - memzero(pte, sizeof(pte_t) * PTRS_PER_PTE); -} - -static void pgd_cache_ctor(void *pgd, struct kmem_cache *cache, unsigned long flags) -{ - memzero(pgd + MEMC_TABLE_SIZE, USER_PTRS_PER_PGD * sizeof(pgd_t)); -} - -void __init pgtable_cache_init(void) -{ - pte_cache = kmem_cache_create("pte-cache", - sizeof(pte_t) * PTRS_PER_PTE, - 0, SLAB_PANIC, pte_cache_ctor); - - pgd_cache = kmem_cache_create("pgd-cache", MEMC_TABLE_SIZE + - sizeof(pgd_t) * PTRS_PER_PGD, - 0, SLAB_PANIC, pgd_cache_ctor); -} diff --git a/arch/arm26/mm/proc-funcs.S b/arch/arm26/mm/proc-funcs.S deleted file mode 100644 index f9fca52..0000000 --- a/arch/arm26/mm/proc-funcs.S +++ /dev/null @@ -1,359 +0,0 @@ -/* - * linux/arch/arm26/mm/proc-arm2,3.S - * - * Copyright (C) 1997-1999 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * MMU functions for ARM2,3 - * - * These are the low level assembler for performing cache - * and memory functions on ARM2, ARM250 and ARM3 processors. - */ -#include <linux/linkage.h> -#include <asm/assembler.h> -#include <asm/asm-offsets.h> -#include <asm/procinfo.h> -#include <asm/ptrace.h> - -/* - * MEMC workhorse code. It's both a horse which things it's a pig. - */ -/* - * Function: cpu_memc_update_entry(pgd_t *pgd, unsigned long phys_pte, unsigned long addr) - * Params : pgd Page tables/MEMC mapping - * : phys_pte physical address, or PTE - * : addr virtual address - */ -ENTRY(cpu_memc_update_entry) - tst r1, #PAGE_PRESENT @ is the page present - orreq r1, r1, #PAGE_OLD | PAGE_CLEAN - moveq r2, #0x01f00000 - mov r3, r1, lsr #13 @ convert to physical page nr - and r3, r3, #0x3fc - adr ip, memc_phys_table_32 - ldr r3, [ip, r3] - tst r1, #PAGE_OLD | PAGE_NOT_USER - biceq r3, r3, #0x200 - tsteq r1, #PAGE_READONLY | PAGE_CLEAN - biceq r3, r3, #0x300 - mov r2, r2, lsr #15 @ virtual -> nr - orr r3, r3, r2, lsl #15 - and r2, r2, #0x300 - orr r3, r3, r2, lsl #2 - and r2, r3, #255 - sub r0, r0, #256 * 4 - str r3, [r0, r2, lsl #2] - strb r3, [r3] - movs pc, lr -/* - * Params : r0 = preserved - * : r1 = memc table base (preserved) - * : r2 = page table entry - * : r3 = preserved - * : r4 = unused - * : r5 = memc physical address translation table - * : ip = virtual address (preserved) - */ -update_pte: - mov r4, r2, lsr #13 - and r4, r4, #0x3fc - ldr r4, [r5, r4] @ covert to MEMC page - - tst r2, #PAGE_OLD | PAGE_NOT_USER @ check for MEMC read - biceq r4, r4, #0x200 - tsteq r2, #PAGE_READONLY | PAGE_CLEAN @ check for MEMC write - biceq r4, r4, #0x300 - - orr r4, r4, ip - and r2, ip, #0x01800000 - orr r4, r4, r2, lsr #13 - - and r2, r4, #255 - str r4, [r1, r2, lsl #2] - movs pc, lr - -/* - * Params : r0 = preserved - * : r1 = memc table base (preserved) - * : r2 = page table base - * : r3 = preserved - * : r4 = unused - * : r5 = memc physical address translation table - * : ip = virtual address (updated) - */ -update_pte_table: - stmfd sp!, {r0, lr} - bic r0, r2, #3 -1: ldr r2, [r0], #4 @ get entry - tst r2, #PAGE_PRESENT @ page present - blne update_pte @ process pte - add ip, ip, #32768 @ increment virt addr - ldr r2, [r0], #4 @ get entry - tst r2, #PAGE_PRESENT @ page present - blne update_pte @ process pte - add ip, ip, #32768 @ increment virt addr - ldr r2, [r0], #4 @ get entry - tst r2, #PAGE_PRESENT @ page present - blne update_pte @ process pte - add ip, ip, #32768 @ increment virt addr - ldr r2, [r0], #4 @ get entry - tst r2, #PAGE_PRESENT @ page present - blne update_pte @ process pte - add ip, ip, #32768 @ increment virt addr - tst ip, #32768 * 31 @ finished? - bne 1b - ldmfd sp!, {r0, pc}^ - -/* - * Function: cpu_memc_update_all(pgd_t *pgd) - * Params : pgd Page tables/MEMC mapping - * Notes : this is optimised for 32k pages - */ -ENTRY(cpu_memc_update_all) - stmfd sp!, {r4, r5, lr} - bl clear_tables - sub r1, r0, #256 * 4 @ start of MEMC tables - adr r5, memc_phys_table_32 @ Convert to logical page number - mov ip, #0 @ virtual address -1: ldmia r0!, {r2, r3} @ load two pgd entries - tst r2, #PAGE_PRESENT @ is pgd entry present? - addeq ip, ip, #1048576 @FIXME - PAGE_PRESENT is for PTEs technically... - blne update_pte_table - mov r2, r3 - tst r2, #PAGE_PRESENT @ is pgd entry present? - addeq ip, ip, #1048576 - blne update_pte_table - teq ip, #32 * 1048576 - bne 1b - ldmfd sp!, {r4, r5, pc}^ - -/* - * Build the table to map from physical page number to memc page number - */ - .type memc_phys_table_32, #object -memc_phys_table_32: - .irp b7, 0x00, 0x80 - .irp b6, 0x00, 0x02 - .irp b5, 0x00, 0x04 - .irp b4, 0x00, 0x01 - - .irp b3, 0x00, 0x40 - .irp b2, 0x00, 0x20 - .irp b1, 0x00, 0x10 - .irp b0, 0x00, 0x08 - .long 0x03800300 + \b7 + \b6 + \b5 + \b4 + \b3 + \b2 + \b1 + \b0 - .endr - .endr - .endr - .endr - - .endr - .endr - .endr - .endr - .size memc_phys_table_32, . - memc_phys_table_32 - -/* - * helper for cpu_memc_update_all, this clears out all - * mappings, setting them close to the top of memory, - * and inaccessible (0x01f00000). - * Params : r0 = page table pointer - */ -clear_tables: ldr r1, _arm3_set_pgd - 4 - ldr r2, [r1] - sub r1, r0, #256 * 4 @ start of MEMC tables - add r2, r1, r2, lsl #2 @ end of tables - mov r3, #0x03f00000 @ Default mapping (null mapping) - orr r3, r3, #0x00000f00 - orr r4, r3, #1 - orr r5, r3, #2 - orr ip, r3, #3 -1: stmia r1!, {r3, r4, r5, ip} - add r3, r3, #4 - add r4, r4, #4 - add r5, r5, #4 - add ip, ip, #4 - stmia r1!, {r3, r4, r5, ip} - add r3, r3, #4 - add r4, r4, #4 - add r5, r5, #4 - add ip, ip, #4 - teq r1, r2 - bne 1b - mov pc, lr - -/* - * Function: *_set_pgd(pgd_t *pgd) - * Params : pgd New page tables/MEMC mapping - * Purpose : update MEMC hardware with new mapping - */ - .word page_nr @ extern - declared in mm-memc.c -_arm3_set_pgd: mcr p15, 0, r1, c1, c0, 0 @ flush cache -_arm2_set_pgd: stmfd sp!, {lr} - ldr r1, _arm3_set_pgd - 4 - ldr r2, [r1] - sub r0, r0, #256 * 4 @ start of MEMC tables - add r1, r0, r2, lsl #2 @ end of tables -1: ldmia r0!, {r2, r3, ip, lr} - strb r2, [r2] - strb r3, [r3] - strb ip, [ip] - strb lr, [lr] - ldmia r0!, {r2, r3, ip, lr} - strb r2, [r2] - strb r3, [r3] - strb ip, [ip] - strb lr, [lr] - teq r0, r1 - bne 1b - ldmfd sp!, {pc}^ - -/* - * Function: *_proc_init (void) - * Purpose : Initialise the cache control registers - */ -_arm3_proc_init: - mov r0, #0x001f0000 - orr r0, r0, #0x0000ff00 - orr r0, r0, #0x000000ff - mcr p15, 0, r0, c3, c0 @ ARM3 Cacheable - mcr p15, 0, r0, c4, c0 @ ARM3 Updateable - mov r0, #0 - mcr p15, 0, r0, c5, c0 @ ARM3 Disruptive - mcr p15, 0, r0, c1, c0 @ ARM3 Flush - mov r0, #3 - mcr p15, 0, r0, c2, c0 @ ARM3 Control -_arm2_proc_init: - movs pc, lr - -/* - * Function: *_proc_fin (void) - * Purpose : Finalise processor (disable caches) - */ -_arm3_proc_fin: mov r0, #2 - mcr p15, 0, r0, c2, c0 -_arm2_proc_fin: orrs pc, lr, #PSR_I_BIT|PSR_F_BIT - -/* - * Function: *_xchg_1 (int new, volatile void *ptr) - * Params : new New value to store at... - * : ptr pointer to byte-wide location - * Purpose : Performs an exchange operation - * Returns : Original byte data at 'ptr' - */ -_arm2_xchg_1: mov r2, pc - orr r2, r2, #PSR_I_BIT - teqp r2, #0 - ldrb r2, [r1] - strb r0, [r1] - mov r0, r2 - movs pc, lr - -_arm3_xchg_1: swpb r0, r0, [r1] - movs pc, lr - -/* - * Function: *_xchg_4 (int new, volatile void *ptr) - * Params : new New value to store at... - * : ptr pointer to word-wide location - * Purpose : Performs an exchange operation - * Returns : Original word data at 'ptr' - */ -_arm2_xchg_4: mov r2, pc - orr r2, r2, #PSR_I_BIT - teqp r2, #0 - ldr r2, [r1] - str r0, [r1] - mov r0, r2 - movs pc, lr - -_arm3_xchg_4: swp r0, r0, [r1] - movs pc, lr - -_arm2_3_check_bugs: - bics pc, lr, #PSR_F_BIT @ Clear FIQ disable bit - -armvlsi_name: .asciz "ARM/VLSI" -_arm2_name: .asciz "ARM 2" -_arm250_name: .asciz "ARM 250" -_arm3_name: .asciz "ARM 3" - - .section ".init.text", #alloc, #execinstr -/* - * Purpose : Function pointers used to access above functions - all calls - * come through these - */ - .globl arm2_processor_functions -arm2_processor_functions: - .word _arm2_3_check_bugs - .word _arm2_proc_init - .word _arm2_proc_fin - .word _arm2_set_pgd - .word _arm2_xchg_1 - .word _arm2_xchg_4 - -cpu_arm2_info: - .long armvlsi_name - .long _arm2_name - - .globl arm250_processor_functions -arm250_processor_functions: - .word _arm2_3_check_bugs - .word _arm2_proc_init - .word _arm2_proc_fin - .word _arm2_set_pgd - .word _arm3_xchg_1 - .word _arm3_xchg_4 - -cpu_arm250_info: - .long armvlsi_name - .long _arm250_name - - .globl arm3_processor_functions -arm3_processor_functions: - .word _arm2_3_check_bugs - .word _arm3_proc_init - .word _arm3_proc_fin - .word _arm3_set_pgd - .word _arm3_xchg_1 - .word _arm3_xchg_4 - -cpu_arm3_info: - .long armvlsi_name - .long _arm3_name - -arm2_arch_name: .asciz "armv1" -arm3_arch_name: .asciz "armv2" -arm2_elf_name: .asciz "v1" -arm3_elf_name: .asciz "v2" - .align - - .section ".proc.info", #alloc, #execinstr - - .long 0x41560200 - .long 0xfffffff0 - .long arm2_arch_name - .long arm2_elf_name - .long 0 - .long cpu_arm2_info - .long arm2_processor_functions - - .long 0x41560250 - .long 0xfffffff0 - .long arm3_arch_name - .long arm3_elf_name - .long 0 - .long cpu_arm250_info - .long arm250_processor_functions - - .long 0x41560300 - .long 0xfffffff0 - .long arm3_arch_name - .long arm3_elf_name - .long 0 - .long cpu_arm3_info - .long arm3_processor_functions - diff --git a/arch/arm26/mm/small_page.c b/arch/arm26/mm/small_page.c deleted file mode 100644 index 3044710..0000000 --- a/arch/arm26/mm/small_page.c +++ /dev/null @@ -1,192 +0,0 @@ -/* - * linux/arch/arm26/mm/small_page.c - * - * Copyright (C) 1996 Russell King - * Copyright (C) 2003 Ian Molton - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Changelog: - * 26/01/1996 RMK Cleaned up various areas to make little more generic - * 07/02/1999 RMK Support added for 16K and 32K page sizes - * containing 8K blocks - * 23/05/2004 IM Fixed to use struct page->lru (thanks wli) - * - */ -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/types.h> -#include <linux/ptrace.h> -#include <linux/mman.h> -#include <linux/mm.h> -#include <linux/swap.h> -#include <linux/smp.h> -#include <linux/bitops.h> - -#include <asm/pgtable.h> - -#define PEDANTIC - -/* - * Requirement: - * We need to be able to allocate naturally aligned memory of finer - * granularity than the page size. This is typically used for the - * second level page tables on 32-bit ARMs. - * - * FIXME - this comment is *out of date* - * Theory: - * We "misuse" the Linux memory management system. We use alloc_page - * to allocate a page and then mark it as reserved. The Linux memory - * management system will then ignore the "offset", "next_hash" and - * "pprev_hash" entries in the mem_map for this page. - * - * We then use a bitstring in the "offset" field to mark which segments - * of the page are in use, and manipulate this as required during the - * allocation and freeing of these small pages. - * - * We also maintain a queue of pages being used for this purpose using - * the "next_hash" and "pprev_hash" entries of mem_map; - */ - -struct order { - struct list_head queue; - unsigned int mask; /* (1 << shift) - 1 */ - unsigned int shift; /* (1 << shift) size of page */ - unsigned int block_mask; /* nr_blocks - 1 */ - unsigned int all_used; /* (1 << nr_blocks) - 1 */ -}; - - -static struct order orders[] = { -#if PAGE_SIZE == 32768 - { LIST_HEAD_INIT(orders[0].queue), 2047, 11, 15, 0x0000ffff }, - { LIST_HEAD_INIT(orders[1].queue), 8191, 13, 3, 0x0000000f } -#else -#error unsupported page size (ARGH!) -#endif -}; - -#define USED_MAP(pg) ((pg)->index) -#define TEST_AND_CLEAR_USED(pg,off) (test_and_clear_bit(off, &USED_MAP(pg))) -#define SET_USED(pg,off) (set_bit(off, &USED_MAP(pg))) - -static DEFINE_SPINLOCK(small_page_lock); - -static unsigned long __get_small_page(int priority, struct order *order) -{ - unsigned long flags; - struct page *page; - int offset; - - do { - spin_lock_irqsave(&small_page_lock, flags); - - if (list_empty(&order->queue)) - goto need_new_page; - - page = list_entry(order->queue.next, struct page, lru); -again: -#ifdef PEDANTIC - BUG_ON(USED_MAP(page) & ~order->all_used); -#endif - offset = ffz(USED_MAP(page)); - SET_USED(page, offset); - if (USED_MAP(page) == order->all_used) - list_del_init(&page->lru); - spin_unlock_irqrestore(&small_page_lock, flags); - - return (unsigned long) page_address(page) + (offset << order->shift); - -need_new_page: - spin_unlock_irqrestore(&small_page_lock, flags); - page = alloc_page(priority); - spin_lock_irqsave(&small_page_lock, flags); - - if (list_empty(&order->queue)) { - if (!page) - goto no_page; - SetPageReserved(page); - USED_MAP(page) = 0; - list_add(&page->lru, &order->queue); - goto again; - } - - spin_unlock_irqrestore(&small_page_lock, flags); - __free_page(page); - } while (1); - -no_page: - spin_unlock_irqrestore(&small_page_lock, flags); - return 0; -} - -static void __free_small_page(unsigned long spage, struct order *order) -{ - unsigned long flags; - struct page *page; - - if (virt_addr_valid(spage)) { - page = virt_to_page(spage); - - /* - * The container-page must be marked Reserved - */ - if (!PageReserved(page) || spage & order->mask) - goto non_small; - -#ifdef PEDANTIC - BUG_ON(USED_MAP(page) & ~order->all_used); -#endif - - spage = spage >> order->shift; - spage &= order->block_mask; - - /* - * the following must be atomic wrt get_page - */ - spin_lock_irqsave(&small_page_lock, flags); - - if (USED_MAP(page) == order->all_used) - list_add(&page->lru, &order->queue); - - if (!TEST_AND_CLEAR_USED(page, spage)) - goto already_free; - - if (USED_MAP(page) == 0) - goto free_page; - - spin_unlock_irqrestore(&small_page_lock, flags); - } - return; - -free_page: - /* - * unlink the page from the small page queue and free it - */ - list_del_init(&page->lru); - spin_unlock_irqrestore(&small_page_lock, flags); - ClearPageReserved(page); - __free_page(page); - return; - -non_small: - printk("Trying to free non-small page from %p\n", __builtin_return_address(0)); - return; -already_free: - printk("Trying to free free small page from %p\n", __builtin_return_address(0)); -} - -unsigned long get_page_8k(int priority) -{ - return __get_small_page(priority, orders+1); -} - -void free_page_8k(unsigned long spage) -{ - __free_small_page(spage, orders+1); -} |