sparc: prepare mm/ for unification
authorSam Ravnborg <sam@ravnborg.org>
Mon, 17 Nov 2008 04:08:19 +0000 (20:08 -0800)
committerDavid S. Miller <davem@davemloft.net>
Thu, 4 Dec 2008 17:16:58 +0000 (09:16 -0800)
- rename files where sparc64 has similar files to _32.c
- Restructure Makefile
- Sneak in -Werror as we have for sparc64

Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
arch/sparc/mm/Makefile
arch/sparc/mm/fault.c [deleted file]
arch/sparc/mm/fault_32.c [new file with mode: 0644]
arch/sparc/mm/generic.c [deleted file]
arch/sparc/mm/generic_32.c [new file with mode: 0644]
arch/sparc/mm/init.c [deleted file]
arch/sparc/mm/init_32.c [new file with mode: 0644]

index ea88955d97ffe6f10ee6dd085e57ae593f0f54b1..3ad1b1f9953e8f2b865ac12e811805bf2cdb24c2 100644 (file)
@@ -1,17 +1,21 @@
 # Makefile for the linux Sparc-specific parts of the memory manager.
 #
 
-EXTRA_AFLAGS := -ansi
+asflags-y := -ansi
+ccflags-y := -Werror
 
-obj-y  := fault.o init.o loadmmu.o generic.o extable.o btfixup.o \
-           srmmu.o iommu.o io-unit.o hypersparc.o viking.o tsunami.o swift.o
+obj-y                   := fault_$(BITS).o
+obj-y                   += init_$(BITS).o
+obj-$(CONFIG_SPARC32)   += loadmmu.o
+obj-y                   += generic_$(BITS).o
+obj-$(CONFIG_SPARC32)   += extable.o btfixup.o srmmu.o iommu.o io-unit.o
+obj-$(CONFIG_SPARC32)   += hypersparc.o viking.o tsunami.o swift.o
 
-ifdef CONFIG_HIGHMEM
-obj-y  += highmem.o
-endif
+# Only used by sparc32
+obj-$(CONFIG_HIGHMEM)   += highmem.o
 
 ifdef CONFIG_SMP
-obj-y   += nosun4c.o
+obj-$(CONFIG_SPARC32) += nosun4c.o
 else
-obj-y   += sun4c.o
+obj-$(CONFIG_SPARC32) += sun4c.o
 endif
diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c
deleted file mode 100644 (file)
index a507e11..0000000
+++ /dev/null
@@ -1,543 +0,0 @@
-/*
- * fault.c:  Page fault handlers for the Sparc.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#include <asm/head.h>
-
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
-#include <linux/threads.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/kdebug.h>
-
-#include <asm/system.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/memreg.h>
-#include <asm/openprom.h>
-#include <asm/oplib.h>
-#include <asm/smp.h>
-#include <asm/traps.h>
-#include <asm/uaccess.h>
-
-extern int prom_node_root;
-
-/* At boot time we determine these two values necessary for setting
- * up the segment maps and page table entries (pte's).
- */
-
-int num_segmaps, num_contexts;
-int invalid_segment;
-
-/* various Virtual Address Cache parameters we find at boot time... */
-
-int vac_size, vac_linesize, vac_do_hw_vac_flushes;
-int vac_entries_per_context, vac_entries_per_segment;
-int vac_entries_per_page;
-
-/* Return how much physical memory we have.  */
-unsigned long probe_memory(void)
-{
-       unsigned long total = 0;
-       int i;
-
-       for (i = 0; sp_banks[i].num_bytes; i++)
-               total += sp_banks[i].num_bytes;
-
-       return total;
-}
-
-extern void sun4c_complete_all_stores(void);
-
-/* Whee, a level 15 NMI interrupt memory error.  Let's have fun... */
-asmlinkage void sparc_lvl15_nmi(struct pt_regs *regs, unsigned long serr,
-                               unsigned long svaddr, unsigned long aerr,
-                               unsigned long avaddr)
-{
-       sun4c_complete_all_stores();
-       printk("FAULT: NMI received\n");
-       printk("SREGS: Synchronous Error %08lx\n", serr);
-       printk("       Synchronous Vaddr %08lx\n", svaddr);
-       printk("      Asynchronous Error %08lx\n", aerr);
-       printk("      Asynchronous Vaddr %08lx\n", avaddr);
-       if (sun4c_memerr_reg)
-               printk("     Memory Parity Error %08lx\n", *sun4c_memerr_reg);
-       printk("REGISTER DUMP:\n");
-       show_regs(regs);
-       prom_halt();
-}
-
-static void unhandled_fault(unsigned long, struct task_struct *,
-               struct pt_regs *) __attribute__ ((noreturn));
-
-static void unhandled_fault(unsigned long address, struct task_struct *tsk,
-                     struct pt_regs *regs)
-{
-       if((unsigned long) address < PAGE_SIZE) {
-               printk(KERN_ALERT
-                   "Unable to handle kernel NULL pointer dereference\n");
-       } else {
-               printk(KERN_ALERT "Unable to handle kernel paging request "
-                      "at virtual address %08lx\n", address);
-       }
-       printk(KERN_ALERT "tsk->{mm,active_mm}->context = %08lx\n",
-               (tsk->mm ? tsk->mm->context : tsk->active_mm->context));
-       printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %08lx\n",
-               (tsk->mm ? (unsigned long) tsk->mm->pgd :
-                       (unsigned long) tsk->active_mm->pgd));
-       die_if_kernel("Oops", regs);
-}
-
-asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, 
-                           unsigned long address)
-{
-       struct pt_regs regs;
-       unsigned long g2;
-       unsigned int insn;
-       int i;
-       
-       i = search_extables_range(ret_pc, &g2);
-       switch (i) {
-       case 3:
-               /* load & store will be handled by fixup */
-               return 3;
-
-       case 1:
-               /* store will be handled by fixup, load will bump out */
-               /* for _to_ macros */
-               insn = *((unsigned int *) pc);
-               if ((insn >> 21) & 1)
-                       return 1;
-               break;
-
-       case 2:
-               /* load will be handled by fixup, store will bump out */
-               /* for _from_ macros */
-               insn = *((unsigned int *) pc);
-               if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15)
-                       return 2; 
-               break; 
-
-       default:
-               break;
-       };
-
-       memset(&regs, 0, sizeof (regs));
-       regs.pc = pc;
-       regs.npc = pc + 4;
-       __asm__ __volatile__(
-               "rd %%psr, %0\n\t"
-               "nop\n\t"
-               "nop\n\t"
-               "nop\n" : "=r" (regs.psr));
-       unhandled_fault(address, current, &regs);
-
-       /* Not reached */
-       return 0;
-}
-
-extern unsigned long safe_compute_effective_address(struct pt_regs *,
-                                                   unsigned int);
-
-static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault)
-{
-       unsigned int insn;
-
-       if (text_fault)
-               return regs->pc;
-
-       if (regs->psr & PSR_PS) {
-               insn = *(unsigned int *) regs->pc;
-       } else {
-               __get_user(insn, (unsigned int *) regs->pc);
-       }
-
-       return safe_compute_effective_address(regs, insn);
-}
-
-asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
-                              unsigned long address)
-{
-       struct vm_area_struct *vma;
-       struct task_struct *tsk = current;
-       struct mm_struct *mm = tsk->mm;
-       unsigned int fixup;
-       unsigned long g2;
-       siginfo_t info;
-       int from_user = !(regs->psr & PSR_PS);
-       int fault;
-
-       if(text_fault)
-               address = regs->pc;
-
-       /*
-        * We fault-in kernel-space virtual memory on-demand. The
-        * 'reference' page table is init_mm.pgd.
-        *
-        * NOTE! We MUST NOT take any locks for this case. We may
-        * be in an interrupt or a critical region, and should
-        * only copy the information from the master page table,
-        * nothing more.
-        */
-       if (!ARCH_SUN4C && address >= TASK_SIZE)
-               goto vmalloc_fault;
-
-       info.si_code = SEGV_MAPERR;
-
-       /*
-        * 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);
-
-       /*
-        * The kernel referencing a bad kernel pointer can lock up
-        * a sun4c machine completely, so we must attempt recovery.
-        */
-       if(!from_user && address >= PAGE_OFFSET)
-               goto bad_area;
-
-       vma = find_vma(mm, address);
-       if(!vma)
-               goto bad_area;
-       if(vma->vm_start <= address)
-               goto good_area;
-       if(!(vma->vm_flags & VM_GROWSDOWN))
-               goto bad_area;
-       if(expand_stack(vma, address))
-               goto bad_area;
-       /*
-        * Ok, we have a good vm_area for this memory access, so
-        * we can handle it..
-        */
-good_area:
-       info.si_code = SEGV_ACCERR;
-       if(write) {
-               if(!(vma->vm_flags & VM_WRITE))
-                       goto bad_area;
-       } else {
-               /* Allow reads even for write-only mappings */
-               if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
-                       goto bad_area;
-       }
-
-       /*
-        * If for any reason at all we couldn't handle the fault,
-        * make sure we exit gracefully rather than endlessly redo
-        * the fault.
-        */
-       fault = handle_mm_fault(mm, vma, address, write);
-       if (unlikely(fault & VM_FAULT_ERROR)) {
-               if (fault & VM_FAULT_OOM)
-                       goto out_of_memory;
-               else if (fault & VM_FAULT_SIGBUS)
-                       goto do_sigbus;
-               BUG();
-       }
-       if (fault & VM_FAULT_MAJOR)
-               current->maj_flt++;
-       else
-               current->min_flt++;
-       up_read(&mm->mmap_sem);
-       return;
-
-       /*
-        * Something tried to access memory that isn't in our memory map..
-        * Fix it, but check if it's kernel or user first..
-        */
-bad_area:
-       up_read(&mm->mmap_sem);
-
-bad_area_nosemaphore:
-       /* User mode accesses just cause a SIGSEGV */
-       if(from_user) {
-#if 0
-               printk("Fault whee %s [%d]: segfaults at %08lx pc=%08lx\n",
-                      tsk->comm, tsk->pid, address, regs->pc);
-#endif
-               info.si_signo = SIGSEGV;
-               info.si_errno = 0;
-               /* info.si_code set above to make clear whether
-                  this was a SEGV_MAPERR or SEGV_ACCERR fault.  */
-               info.si_addr = (void __user *)compute_si_addr(regs, text_fault);
-               info.si_trapno = 0;
-               force_sig_info (SIGSEGV, &info, tsk);
-               return;
-       }
-
-       /* Is this in ex_table? */
-no_context:
-       g2 = regs->u_regs[UREG_G2];
-       if (!from_user && (fixup = search_extables_range(regs->pc, &g2))) {
-               if (fixup > 10) { /* Values below are reserved for other things */
-                       extern const unsigned __memset_start[];
-                       extern const unsigned __memset_end[];
-                       extern const unsigned __csum_partial_copy_start[];
-                       extern const unsigned __csum_partial_copy_end[];
-
-#ifdef DEBUG_EXCEPTIONS
-                       printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address);
-                       printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n",
-                               regs->pc, fixup, g2);
-#endif
-                       if ((regs->pc >= (unsigned long)__memset_start &&
-                            regs->pc < (unsigned long)__memset_end) ||
-                           (regs->pc >= (unsigned long)__csum_partial_copy_start &&
-                            regs->pc < (unsigned long)__csum_partial_copy_end)) {
-                               regs->u_regs[UREG_I4] = address;
-                               regs->u_regs[UREG_I5] = regs->pc;
-                       }
-                       regs->u_regs[UREG_G2] = g2;
-                       regs->pc = fixup;
-                       regs->npc = regs->pc + 4;
-                       return;
-               }
-       }
-       
-       unhandled_fault (address, tsk, regs);
-       do_exit(SIGKILL);
-
-/*
- * We ran out of memory, or some other thing happened to us that made
- * us unable to handle the page fault gracefully.
- */
-out_of_memory:
-       up_read(&mm->mmap_sem);
-       printk("VM: killing process %s\n", tsk->comm);
-       if (from_user)
-               do_group_exit(SIGKILL);
-       goto no_context;
-
-do_sigbus:
-       up_read(&mm->mmap_sem);
-       info.si_signo = SIGBUS;
-       info.si_errno = 0;
-       info.si_code = BUS_ADRERR;
-       info.si_addr = (void __user *) compute_si_addr(regs, text_fault);
-       info.si_trapno = 0;
-       force_sig_info (SIGBUS, &info, tsk);
-       if (!from_user)
-               goto no_context;
-
-vmalloc_fault:
-       {
-               /*
-                * Synchronize this task's top level page-table
-                * with the 'reference' page table.
-                */
-               int offset = pgd_index(address);
-               pgd_t *pgd, *pgd_k;
-               pmd_t *pmd, *pmd_k;
-
-               pgd = tsk->active_mm->pgd + offset;
-               pgd_k = init_mm.pgd + offset;
-
-               if (!pgd_present(*pgd)) {
-                       if (!pgd_present(*pgd_k))
-                               goto bad_area_nosemaphore;
-                       pgd_val(*pgd) = pgd_val(*pgd_k);
-                       return;
-               }
-
-               pmd = pmd_offset(pgd, address);
-               pmd_k = pmd_offset(pgd_k, address);
-
-               if (pmd_present(*pmd) || !pmd_present(*pmd_k))
-                       goto bad_area_nosemaphore;
-               *pmd = *pmd_k;
-               return;
-       }
-}
-
-asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
-                              unsigned long address)
-{
-       extern void sun4c_update_mmu_cache(struct vm_area_struct *,
-                                          unsigned long,pte_t);
-       extern pte_t *sun4c_pte_offset_kernel(pmd_t *,unsigned long);
-       struct task_struct *tsk = current;
-       struct mm_struct *mm = tsk->mm;
-       pgd_t *pgdp;
-       pte_t *ptep;
-
-       if (text_fault) {
-               address = regs->pc;
-       } else if (!write &&
-                  !(regs->psr & PSR_PS)) {
-               unsigned int insn, __user *ip;
-
-               ip = (unsigned int __user *)regs->pc;
-               if (!get_user(insn, ip)) {
-                       if ((insn & 0xc1680000) == 0xc0680000)
-                               write = 1;
-               }
-       }
-
-       if (!mm) {
-               /* We are oopsing. */
-               do_sparc_fault(regs, text_fault, write, address);
-               BUG();  /* P3 Oops already, you bitch */
-       }
-
-       pgdp = pgd_offset(mm, address);
-       ptep = sun4c_pte_offset_kernel((pmd_t *) pgdp, address);
-
-       if (pgd_val(*pgdp)) {
-           if (write) {
-               if ((pte_val(*ptep) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT))
-                                  == (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT)) {
-                       unsigned long flags;
-
-                       *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
-                                     _SUN4C_PAGE_MODIFIED |
-                                     _SUN4C_PAGE_VALID |
-                                     _SUN4C_PAGE_DIRTY);
-
-                       local_irq_save(flags);
-                       if (sun4c_get_segmap(address) != invalid_segment) {
-                               sun4c_put_pte(address, pte_val(*ptep));
-                               local_irq_restore(flags);
-                               return;
-                       }
-                       local_irq_restore(flags);
-               }
-           } else {
-               if ((pte_val(*ptep) & (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT))
-                                  == (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT)) {
-                       unsigned long flags;
-
-                       *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
-                                     _SUN4C_PAGE_VALID);
-
-                       local_irq_save(flags);
-                       if (sun4c_get_segmap(address) != invalid_segment) {
-                               sun4c_put_pte(address, pte_val(*ptep));
-                               local_irq_restore(flags);
-                               return;
-                       }
-                       local_irq_restore(flags);
-               }
-           }
-       }
-
-       /* This conditional is 'interesting'. */
-       if (pgd_val(*pgdp) && !(write && !(pte_val(*ptep) & _SUN4C_PAGE_WRITE))
-           && (pte_val(*ptep) & _SUN4C_PAGE_VALID))
-               /* Note: It is safe to not grab the MMAP semaphore here because
-                *       we know that update_mmu_cache() will not sleep for
-                *       any reason (at least not in the current implementation)
-                *       and therefore there is no danger of another thread getting
-                *       on the CPU and doing a shrink_mmap() on this vma.
-                */
-               sun4c_update_mmu_cache (find_vma(current->mm, address), address,
-                                       *ptep);
-       else
-               do_sparc_fault(regs, text_fault, write, address);
-}
-
-/* This always deals with user addresses. */
-static void force_user_fault(unsigned long address, int write)
-{
-       struct vm_area_struct *vma;
-       struct task_struct *tsk = current;
-       struct mm_struct *mm = tsk->mm;
-       siginfo_t info;
-
-       info.si_code = SEGV_MAPERR;
-
-#if 0
-       printk("wf<pid=%d,wr=%d,addr=%08lx>\n",
-              tsk->pid, write, address);
-#endif
-       down_read(&mm->mmap_sem);
-       vma = find_vma(mm, address);
-       if(!vma)
-               goto bad_area;
-       if(vma->vm_start <= address)
-               goto good_area;
-       if(!(vma->vm_flags & VM_GROWSDOWN))
-               goto bad_area;
-       if(expand_stack(vma, address))
-               goto bad_area;
-good_area:
-       info.si_code = SEGV_ACCERR;
-       if(write) {
-               if(!(vma->vm_flags & VM_WRITE))
-                       goto bad_area;
-       } else {
-               if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
-                       goto bad_area;
-       }
-       switch (handle_mm_fault(mm, vma, address, write)) {
-       case VM_FAULT_SIGBUS:
-       case VM_FAULT_OOM:
-               goto do_sigbus;
-       }
-       up_read(&mm->mmap_sem);
-       return;
-bad_area:
-       up_read(&mm->mmap_sem);
-#if 0
-       printk("Window whee %s [%d]: segfaults at %08lx\n",
-              tsk->comm, tsk->pid, address);
-#endif
-       info.si_signo = SIGSEGV;
-       info.si_errno = 0;
-       /* info.si_code set above to make clear whether
-          this was a SEGV_MAPERR or SEGV_ACCERR fault.  */
-       info.si_addr = (void __user *) address;
-       info.si_trapno = 0;
-       force_sig_info (SIGSEGV, &info, tsk);
-       return;
-
-do_sigbus:
-       up_read(&mm->mmap_sem);
-       info.si_signo = SIGBUS;
-       info.si_errno = 0;
-       info.si_code = BUS_ADRERR;
-       info.si_addr = (void __user *) address;
-       info.si_trapno = 0;
-       force_sig_info (SIGBUS, &info, tsk);
-}
-
-void window_overflow_fault(void)
-{
-       unsigned long sp;
-
-       sp = current_thread_info()->rwbuf_stkptrs[0];
-       if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
-               force_user_fault(sp + 0x38, 1);
-       force_user_fault(sp, 1);
-}
-
-void window_underflow_fault(unsigned long sp)
-{
-       if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
-               force_user_fault(sp + 0x38, 0);
-       force_user_fault(sp, 0);
-}
-
-void window_ret_fault(struct pt_regs *regs)
-{
-       unsigned long sp;
-
-       sp = regs->u_regs[UREG_FP];
-       if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
-               force_user_fault(sp + 0x38, 0);
-       force_user_fault(sp, 0);
-}
diff --git a/arch/sparc/mm/fault_32.c b/arch/sparc/mm/fault_32.c
new file mode 100644 (file)
index 0000000..a507e11
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * fault.c:  Page fault handlers for the Sparc.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <asm/head.h>
+
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/threads.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kdebug.h>
+
+#include <asm/system.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/memreg.h>
+#include <asm/openprom.h>
+#include <asm/oplib.h>
+#include <asm/smp.h>
+#include <asm/traps.h>
+#include <asm/uaccess.h>
+
+extern int prom_node_root;
+
+/* At boot time we determine these two values necessary for setting
+ * up the segment maps and page table entries (pte's).
+ */
+
+int num_segmaps, num_contexts;
+int invalid_segment;
+
+/* various Virtual Address Cache parameters we find at boot time... */
+
+int vac_size, vac_linesize, vac_do_hw_vac_flushes;
+int vac_entries_per_context, vac_entries_per_segment;
+int vac_entries_per_page;
+
+/* Return how much physical memory we have.  */
+unsigned long probe_memory(void)
+{
+       unsigned long total = 0;
+       int i;
+
+       for (i = 0; sp_banks[i].num_bytes; i++)
+               total += sp_banks[i].num_bytes;
+
+       return total;
+}
+
+extern void sun4c_complete_all_stores(void);
+
+/* Whee, a level 15 NMI interrupt memory error.  Let's have fun... */
+asmlinkage void sparc_lvl15_nmi(struct pt_regs *regs, unsigned long serr,
+                               unsigned long svaddr, unsigned long aerr,
+                               unsigned long avaddr)
+{
+       sun4c_complete_all_stores();
+       printk("FAULT: NMI received\n");
+       printk("SREGS: Synchronous Error %08lx\n", serr);
+       printk("       Synchronous Vaddr %08lx\n", svaddr);
+       printk("      Asynchronous Error %08lx\n", aerr);
+       printk("      Asynchronous Vaddr %08lx\n", avaddr);
+       if (sun4c_memerr_reg)
+               printk("     Memory Parity Error %08lx\n", *sun4c_memerr_reg);
+       printk("REGISTER DUMP:\n");
+       show_regs(regs);
+       prom_halt();
+}
+
+static void unhandled_fault(unsigned long, struct task_struct *,
+               struct pt_regs *) __attribute__ ((noreturn));
+
+static void unhandled_fault(unsigned long address, struct task_struct *tsk,
+                     struct pt_regs *regs)
+{
+       if((unsigned long) address < PAGE_SIZE) {
+               printk(KERN_ALERT
+                   "Unable to handle kernel NULL pointer dereference\n");
+       } else {
+               printk(KERN_ALERT "Unable to handle kernel paging request "
+                      "at virtual address %08lx\n", address);
+       }
+       printk(KERN_ALERT "tsk->{mm,active_mm}->context = %08lx\n",
+               (tsk->mm ? tsk->mm->context : tsk->active_mm->context));
+       printk(KERN_ALERT "tsk->{mm,active_mm}->pgd = %08lx\n",
+               (tsk->mm ? (unsigned long) tsk->mm->pgd :
+                       (unsigned long) tsk->active_mm->pgd));
+       die_if_kernel("Oops", regs);
+}
+
+asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc, 
+                           unsigned long address)
+{
+       struct pt_regs regs;
+       unsigned long g2;
+       unsigned int insn;
+       int i;
+       
+       i = search_extables_range(ret_pc, &g2);
+       switch (i) {
+       case 3:
+               /* load & store will be handled by fixup */
+               return 3;
+
+       case 1:
+               /* store will be handled by fixup, load will bump out */
+               /* for _to_ macros */
+               insn = *((unsigned int *) pc);
+               if ((insn >> 21) & 1)
+                       return 1;
+               break;
+
+       case 2:
+               /* load will be handled by fixup, store will bump out */
+               /* for _from_ macros */
+               insn = *((unsigned int *) pc);
+               if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15)
+                       return 2; 
+               break; 
+
+       default:
+               break;
+       };
+
+       memset(&regs, 0, sizeof (regs));
+       regs.pc = pc;
+       regs.npc = pc + 4;
+       __asm__ __volatile__(
+               "rd %%psr, %0\n\t"
+               "nop\n\t"
+               "nop\n\t"
+               "nop\n" : "=r" (regs.psr));
+       unhandled_fault(address, current, &regs);
+
+       /* Not reached */
+       return 0;
+}
+
+extern unsigned long safe_compute_effective_address(struct pt_regs *,
+                                                   unsigned int);
+
+static unsigned long compute_si_addr(struct pt_regs *regs, int text_fault)
+{
+       unsigned int insn;
+
+       if (text_fault)
+               return regs->pc;
+
+       if (regs->psr & PSR_PS) {
+               insn = *(unsigned int *) regs->pc;
+       } else {
+               __get_user(insn, (unsigned int *) regs->pc);
+       }
+
+       return safe_compute_effective_address(regs, insn);
+}
+
+asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
+                              unsigned long address)
+{
+       struct vm_area_struct *vma;
+       struct task_struct *tsk = current;
+       struct mm_struct *mm = tsk->mm;
+       unsigned int fixup;
+       unsigned long g2;
+       siginfo_t info;
+       int from_user = !(regs->psr & PSR_PS);
+       int fault;
+
+       if(text_fault)
+               address = regs->pc;
+
+       /*
+        * We fault-in kernel-space virtual memory on-demand. The
+        * 'reference' page table is init_mm.pgd.
+        *
+        * NOTE! We MUST NOT take any locks for this case. We may
+        * be in an interrupt or a critical region, and should
+        * only copy the information from the master page table,
+        * nothing more.
+        */
+       if (!ARCH_SUN4C && address >= TASK_SIZE)
+               goto vmalloc_fault;
+
+       info.si_code = SEGV_MAPERR;
+
+       /*
+        * 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);
+
+       /*
+        * The kernel referencing a bad kernel pointer can lock up
+        * a sun4c machine completely, so we must attempt recovery.
+        */
+       if(!from_user && address >= PAGE_OFFSET)
+               goto bad_area;
+
+       vma = find_vma(mm, address);
+       if(!vma)
+               goto bad_area;
+       if(vma->vm_start <= address)
+               goto good_area;
+       if(!(vma->vm_flags & VM_GROWSDOWN))
+               goto bad_area;
+       if(expand_stack(vma, address))
+               goto bad_area;
+       /*
+        * Ok, we have a good vm_area for this memory access, so
+        * we can handle it..
+        */
+good_area:
+       info.si_code = SEGV_ACCERR;
+       if(write) {
+               if(!(vma->vm_flags & VM_WRITE))
+                       goto bad_area;
+       } else {
+               /* Allow reads even for write-only mappings */
+               if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
+                       goto bad_area;
+       }
+
+       /*
+        * If for any reason at all we couldn't handle the fault,
+        * make sure we exit gracefully rather than endlessly redo
+        * the fault.
+        */
+       fault = handle_mm_fault(mm, vma, address, write);
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               if (fault & VM_FAULT_OOM)
+                       goto out_of_memory;
+               else if (fault & VM_FAULT_SIGBUS)
+                       goto do_sigbus;
+               BUG();
+       }
+       if (fault & VM_FAULT_MAJOR)
+               current->maj_flt++;
+       else
+               current->min_flt++;
+       up_read(&mm->mmap_sem);
+       return;
+
+       /*
+        * Something tried to access memory that isn't in our memory map..
+        * Fix it, but check if it's kernel or user first..
+        */
+bad_area:
+       up_read(&mm->mmap_sem);
+
+bad_area_nosemaphore:
+       /* User mode accesses just cause a SIGSEGV */
+       if(from_user) {
+#if 0
+               printk("Fault whee %s [%d]: segfaults at %08lx pc=%08lx\n",
+                      tsk->comm, tsk->pid, address, regs->pc);
+#endif
+               info.si_signo = SIGSEGV;
+               info.si_errno = 0;
+               /* info.si_code set above to make clear whether
+                  this was a SEGV_MAPERR or SEGV_ACCERR fault.  */
+               info.si_addr = (void __user *)compute_si_addr(regs, text_fault);
+               info.si_trapno = 0;
+               force_sig_info (SIGSEGV, &info, tsk);
+               return;
+       }
+
+       /* Is this in ex_table? */
+no_context:
+       g2 = regs->u_regs[UREG_G2];
+       if (!from_user && (fixup = search_extables_range(regs->pc, &g2))) {
+               if (fixup > 10) { /* Values below are reserved for other things */
+                       extern const unsigned __memset_start[];
+                       extern const unsigned __memset_end[];
+                       extern const unsigned __csum_partial_copy_start[];
+                       extern const unsigned __csum_partial_copy_end[];
+
+#ifdef DEBUG_EXCEPTIONS
+                       printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address);
+                       printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n",
+                               regs->pc, fixup, g2);
+#endif
+                       if ((regs->pc >= (unsigned long)__memset_start &&
+                            regs->pc < (unsigned long)__memset_end) ||
+                           (regs->pc >= (unsigned long)__csum_partial_copy_start &&
+                            regs->pc < (unsigned long)__csum_partial_copy_end)) {
+                               regs->u_regs[UREG_I4] = address;
+                               regs->u_regs[UREG_I5] = regs->pc;
+                       }
+                       regs->u_regs[UREG_G2] = g2;
+                       regs->pc = fixup;
+                       regs->npc = regs->pc + 4;
+                       return;
+               }
+       }
+       
+       unhandled_fault (address, tsk, regs);
+       do_exit(SIGKILL);
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+out_of_memory:
+       up_read(&mm->mmap_sem);
+       printk("VM: killing process %s\n", tsk->comm);
+       if (from_user)
+               do_group_exit(SIGKILL);
+       goto no_context;
+
+do_sigbus:
+       up_read(&mm->mmap_sem);
+       info.si_signo = SIGBUS;
+       info.si_errno = 0;
+       info.si_code = BUS_ADRERR;
+       info.si_addr = (void __user *) compute_si_addr(regs, text_fault);
+       info.si_trapno = 0;
+       force_sig_info (SIGBUS, &info, tsk);
+       if (!from_user)
+               goto no_context;
+
+vmalloc_fault:
+       {
+               /*
+                * Synchronize this task's top level page-table
+                * with the 'reference' page table.
+                */
+               int offset = pgd_index(address);
+               pgd_t *pgd, *pgd_k;
+               pmd_t *pmd, *pmd_k;
+
+               pgd = tsk->active_mm->pgd + offset;
+               pgd_k = init_mm.pgd + offset;
+
+               if (!pgd_present(*pgd)) {
+                       if (!pgd_present(*pgd_k))
+                               goto bad_area_nosemaphore;
+                       pgd_val(*pgd) = pgd_val(*pgd_k);
+                       return;
+               }
+
+               pmd = pmd_offset(pgd, address);
+               pmd_k = pmd_offset(pgd_k, address);
+
+               if (pmd_present(*pmd) || !pmd_present(*pmd_k))
+                       goto bad_area_nosemaphore;
+               *pmd = *pmd_k;
+               return;
+       }
+}
+
+asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
+                              unsigned long address)
+{
+       extern void sun4c_update_mmu_cache(struct vm_area_struct *,
+                                          unsigned long,pte_t);
+       extern pte_t *sun4c_pte_offset_kernel(pmd_t *,unsigned long);
+       struct task_struct *tsk = current;
+       struct mm_struct *mm = tsk->mm;
+       pgd_t *pgdp;
+       pte_t *ptep;
+
+       if (text_fault) {
+               address = regs->pc;
+       } else if (!write &&
+                  !(regs->psr & PSR_PS)) {
+               unsigned int insn, __user *ip;
+
+               ip = (unsigned int __user *)regs->pc;
+               if (!get_user(insn, ip)) {
+                       if ((insn & 0xc1680000) == 0xc0680000)
+                               write = 1;
+               }
+       }
+
+       if (!mm) {
+               /* We are oopsing. */
+               do_sparc_fault(regs, text_fault, write, address);
+               BUG();  /* P3 Oops already, you bitch */
+       }
+
+       pgdp = pgd_offset(mm, address);
+       ptep = sun4c_pte_offset_kernel((pmd_t *) pgdp, address);
+
+       if (pgd_val(*pgdp)) {
+           if (write) {
+               if ((pte_val(*ptep) & (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT))
+                                  == (_SUN4C_PAGE_WRITE|_SUN4C_PAGE_PRESENT)) {
+                       unsigned long flags;
+
+                       *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
+                                     _SUN4C_PAGE_MODIFIED |
+                                     _SUN4C_PAGE_VALID |
+                                     _SUN4C_PAGE_DIRTY);
+
+                       local_irq_save(flags);
+                       if (sun4c_get_segmap(address) != invalid_segment) {
+                               sun4c_put_pte(address, pte_val(*ptep));
+                               local_irq_restore(flags);
+                               return;
+                       }
+                       local_irq_restore(flags);
+               }
+           } else {
+               if ((pte_val(*ptep) & (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT))
+                                  == (_SUN4C_PAGE_READ|_SUN4C_PAGE_PRESENT)) {
+                       unsigned long flags;
+
+                       *ptep = __pte(pte_val(*ptep) | _SUN4C_PAGE_ACCESSED |
+                                     _SUN4C_PAGE_VALID);
+
+                       local_irq_save(flags);
+                       if (sun4c_get_segmap(address) != invalid_segment) {
+                               sun4c_put_pte(address, pte_val(*ptep));
+                               local_irq_restore(flags);
+                               return;
+                       }
+                       local_irq_restore(flags);
+               }
+           }
+       }
+
+       /* This conditional is 'interesting'. */
+       if (pgd_val(*pgdp) && !(write && !(pte_val(*ptep) & _SUN4C_PAGE_WRITE))
+           && (pte_val(*ptep) & _SUN4C_PAGE_VALID))
+               /* Note: It is safe to not grab the MMAP semaphore here because
+                *       we know that update_mmu_cache() will not sleep for
+                *       any reason (at least not in the current implementation)
+                *       and therefore there is no danger of another thread getting
+                *       on the CPU and doing a shrink_mmap() on this vma.
+                */
+               sun4c_update_mmu_cache (find_vma(current->mm, address), address,
+                                       *ptep);
+       else
+               do_sparc_fault(regs, text_fault, write, address);
+}
+
+/* This always deals with user addresses. */
+static void force_user_fault(unsigned long address, int write)
+{
+       struct vm_area_struct *vma;
+       struct task_struct *tsk = current;
+       struct mm_struct *mm = tsk->mm;
+       siginfo_t info;
+
+       info.si_code = SEGV_MAPERR;
+
+#if 0
+       printk("wf<pid=%d,wr=%d,addr=%08lx>\n",
+              tsk->pid, write, address);
+#endif
+       down_read(&mm->mmap_sem);
+       vma = find_vma(mm, address);
+       if(!vma)
+               goto bad_area;
+       if(vma->vm_start <= address)
+               goto good_area;
+       if(!(vma->vm_flags & VM_GROWSDOWN))
+               goto bad_area;
+       if(expand_stack(vma, address))
+               goto bad_area;
+good_area:
+       info.si_code = SEGV_ACCERR;
+       if(write) {
+               if(!(vma->vm_flags & VM_WRITE))
+                       goto bad_area;
+       } else {
+               if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
+                       goto bad_area;
+       }
+       switch (handle_mm_fault(mm, vma, address, write)) {
+       case VM_FAULT_SIGBUS:
+       case VM_FAULT_OOM:
+               goto do_sigbus;
+       }
+       up_read(&mm->mmap_sem);
+       return;
+bad_area:
+       up_read(&mm->mmap_sem);
+#if 0
+       printk("Window whee %s [%d]: segfaults at %08lx\n",
+              tsk->comm, tsk->pid, address);
+#endif
+       info.si_signo = SIGSEGV;
+       info.si_errno = 0;
+       /* info.si_code set above to make clear whether
+          this was a SEGV_MAPERR or SEGV_ACCERR fault.  */
+       info.si_addr = (void __user *) address;
+       info.si_trapno = 0;
+       force_sig_info (SIGSEGV, &info, tsk);
+       return;
+
+do_sigbus:
+       up_read(&mm->mmap_sem);
+       info.si_signo = SIGBUS;
+       info.si_errno = 0;
+       info.si_code = BUS_ADRERR;
+       info.si_addr = (void __user *) address;
+       info.si_trapno = 0;
+       force_sig_info (SIGBUS, &info, tsk);
+}
+
+void window_overflow_fault(void)
+{
+       unsigned long sp;
+
+       sp = current_thread_info()->rwbuf_stkptrs[0];
+       if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
+               force_user_fault(sp + 0x38, 1);
+       force_user_fault(sp, 1);
+}
+
+void window_underflow_fault(unsigned long sp)
+{
+       if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
+               force_user_fault(sp + 0x38, 0);
+       force_user_fault(sp, 0);
+}
+
+void window_ret_fault(struct pt_regs *regs)
+{
+       unsigned long sp;
+
+       sp = regs->u_regs[UREG_FP];
+       if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
+               force_user_fault(sp + 0x38, 0);
+       force_user_fault(sp, 0);
+}
diff --git a/arch/sparc/mm/generic.c b/arch/sparc/mm/generic.c
deleted file mode 100644 (file)
index a289261..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * generic.c: Generic Sparc mm routines that are not dependent upon
- *            MMU type but are Sparc specific.
- *
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/swap.h>
-#include <linux/pagemap.h>
-
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
-
-/* Remap IO memory, the same way as remap_pfn_range(), but use
- * the obio memory space.
- *
- * They use a pgprot that sets PAGE_IO and does not check the
- * mem_map table as this is independent of normal memory.
- */
-static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte, unsigned long address, unsigned long size,
-       unsigned long offset, pgprot_t prot, int space)
-{
-       unsigned long end;
-
-       address &= ~PMD_MASK;
-       end = address + size;
-       if (end > PMD_SIZE)
-               end = PMD_SIZE;
-       do {
-               set_pte_at(mm, address, pte, mk_pte_io(offset, prot, space));
-               address += PAGE_SIZE;
-               offset += PAGE_SIZE;
-               pte++;
-       } while (address < end);
-}
-
-static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
-       unsigned long offset, pgprot_t prot, int space)
-{
-       unsigned long end;
-
-       address &= ~PGDIR_MASK;
-       end = address + size;
-       if (end > PGDIR_SIZE)
-               end = PGDIR_SIZE;
-       offset -= address;
-       do {
-               pte_t * pte = pte_alloc_map(mm, pmd, address);
-               if (!pte)
-                       return -ENOMEM;
-               io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space);
-               address = (address + PMD_SIZE) & PMD_MASK;
-               pmd++;
-       } while (address < end);
-       return 0;
-}
-
-int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
-                      unsigned long pfn, unsigned long size, pgprot_t prot)
-{
-       int error = 0;
-       pgd_t * dir;
-       unsigned long beg = from;
-       unsigned long end = from + size;
-       struct mm_struct *mm = vma->vm_mm;
-       int space = GET_IOSPACE(pfn);
-       unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
-
-       /* See comment in mm/memory.c remap_pfn_range */
-       vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
-       vma->vm_pgoff = (offset >> PAGE_SHIFT) |
-               ((unsigned long)space << 28UL);
-
-       offset -= from;
-       dir = pgd_offset(mm, from);
-       flush_cache_range(vma, beg, end);
-
-       while (from < end) {
-               pmd_t *pmd = pmd_alloc(mm, dir, from);
-               error = -ENOMEM;
-               if (!pmd)
-                       break;
-               error = io_remap_pmd_range(mm, pmd, from, end - from, offset + from, prot, space);
-               if (error)
-                       break;
-               from = (from + PGDIR_SIZE) & PGDIR_MASK;
-               dir++;
-       }
-
-       flush_tlb_range(vma, beg, end);
-       return error;
-}
diff --git a/arch/sparc/mm/generic_32.c b/arch/sparc/mm/generic_32.c
new file mode 100644 (file)
index 0000000..a289261
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * generic.c: Generic Sparc mm routines that are not dependent upon
+ *            MMU type but are Sparc specific.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/pagemap.h>
+
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+
+/* Remap IO memory, the same way as remap_pfn_range(), but use
+ * the obio memory space.
+ *
+ * They use a pgprot that sets PAGE_IO and does not check the
+ * mem_map table as this is independent of normal memory.
+ */
+static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte, unsigned long address, unsigned long size,
+       unsigned long offset, pgprot_t prot, int space)
+{
+       unsigned long end;
+
+       address &= ~PMD_MASK;
+       end = address + size;
+       if (end > PMD_SIZE)
+               end = PMD_SIZE;
+       do {
+               set_pte_at(mm, address, pte, mk_pte_io(offset, prot, space));
+               address += PAGE_SIZE;
+               offset += PAGE_SIZE;
+               pte++;
+       } while (address < end);
+}
+
+static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
+       unsigned long offset, pgprot_t prot, int space)
+{
+       unsigned long end;
+
+       address &= ~PGDIR_MASK;
+       end = address + size;
+       if (end > PGDIR_SIZE)
+               end = PGDIR_SIZE;
+       offset -= address;
+       do {
+               pte_t * pte = pte_alloc_map(mm, pmd, address);
+               if (!pte)
+                       return -ENOMEM;
+               io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space);
+               address = (address + PMD_SIZE) & PMD_MASK;
+               pmd++;
+       } while (address < end);
+       return 0;
+}
+
+int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
+                      unsigned long pfn, unsigned long size, pgprot_t prot)
+{
+       int error = 0;
+       pgd_t * dir;
+       unsigned long beg = from;
+       unsigned long end = from + size;
+       struct mm_struct *mm = vma->vm_mm;
+       int space = GET_IOSPACE(pfn);
+       unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
+
+       /* See comment in mm/memory.c remap_pfn_range */
+       vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
+       vma->vm_pgoff = (offset >> PAGE_SHIFT) |
+               ((unsigned long)space << 28UL);
+
+       offset -= from;
+       dir = pgd_offset(mm, from);
+       flush_cache_range(vma, beg, end);
+
+       while (from < end) {
+               pmd_t *pmd = pmd_alloc(mm, dir, from);
+               error = -ENOMEM;
+               if (!pmd)
+                       break;
+               error = io_remap_pmd_range(mm, pmd, from, end - from, offset + from, prot, space);
+               if (error)
+                       break;
+               from = (from + PGDIR_SIZE) & PGDIR_MASK;
+               dir++;
+       }
+
+       flush_tlb_range(vma, beg, end);
+       return error;
+}
diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
deleted file mode 100644 (file)
index 677c1e1..0000000
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- *  linux/arch/sparc/mm/init.c
- *
- *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- *  Copyright (C) 1995 Eddie C. Dost (ecd@skynet.be)
- *  Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- *  Copyright (C) 2000 Anton Blanchard (anton@samba.org)
- */
-
-#include <linux/module.h>
-#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/initrd.h>
-#include <linux/init.h>
-#include <linux/highmem.h>
-#include <linux/bootmem.h>
-#include <linux/pagemap.h>
-#include <linux/poison.h>
-
-#include <asm/system.h>
-#include <asm/vac-ops.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/vaddrs.h>
-#include <asm/pgalloc.h>       /* bug in asm-generic/tlb.h: check_pgt_cache */
-#include <asm/tlb.h>
-#include <asm/prom.h>
-
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
-unsigned long *sparc_valid_addr_bitmap;
-
-unsigned long phys_base;
-unsigned long pfn_base;
-
-unsigned long page_kernel;
-
-struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS+1];
-unsigned long sparc_unmapped_base;
-
-struct pgtable_cache_struct pgt_quicklists;
-
-/* References to section boundaries */
-extern char __init_begin, __init_end, _start, _end, etext , edata;
-
-/* Initial ramdisk setup */
-extern unsigned int sparc_ramdisk_image;
-extern unsigned int sparc_ramdisk_size;
-
-unsigned long highstart_pfn, highend_pfn;
-
-pte_t *kmap_pte;
-pgprot_t kmap_prot;
-
-#define kmap_get_fixmap_pte(vaddr) \
-       pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
-
-void __init kmap_init(void)
-{
-       /* cache the first kmap pte */
-       kmap_pte = kmap_get_fixmap_pte(__fix_to_virt(FIX_KMAP_BEGIN));
-       kmap_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV | SRMMU_CACHE);
-}
-
-void show_mem(void)
-{
-       printk("Mem-info:\n");
-       show_free_areas();
-       printk("Free swap:       %6ldkB\n",
-              nr_swap_pages << (PAGE_SHIFT-10));
-       printk("%ld pages of RAM\n", totalram_pages);
-       printk("%ld free pages\n", nr_free_pages());
-#if 0 /* undefined pgtable_cache_size, pgd_cache_size */
-       printk("%ld pages in page table cache\n",pgtable_cache_size);
-#ifndef CONFIG_SMP
-       if (sparc_cpu_model == sun4m || sparc_cpu_model == sun4d)
-               printk("%ld entries in page dir cache\n",pgd_cache_size);
-#endif 
-#endif
-}
-
-void __init sparc_context_init(int numctx)
-{
-       int ctx;
-
-       ctx_list_pool = __alloc_bootmem(numctx * sizeof(struct ctx_list), SMP_CACHE_BYTES, 0UL);
-
-       for(ctx = 0; ctx < numctx; ctx++) {
-               struct ctx_list *clist;
-
-               clist = (ctx_list_pool + ctx);
-               clist->ctx_number = ctx;
-               clist->ctx_mm = NULL;
-       }
-       ctx_free.next = ctx_free.prev = &ctx_free;
-       ctx_used.next = ctx_used.prev = &ctx_used;
-       for(ctx = 0; ctx < numctx; ctx++)
-               add_to_free_ctxlist(ctx_list_pool + ctx);
-}
-
-extern unsigned long cmdline_memory_size;
-unsigned long last_valid_pfn;
-
-unsigned long calc_highpages(void)
-{
-       int i;
-       int nr = 0;
-
-       for (i = 0; sp_banks[i].num_bytes != 0; i++) {
-               unsigned long start_pfn = sp_banks[i].base_addr >> PAGE_SHIFT;
-               unsigned long end_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT;
-
-               if (end_pfn <= max_low_pfn)
-                       continue;
-
-               if (start_pfn < max_low_pfn)
-                       start_pfn = max_low_pfn;
-
-               nr += end_pfn - start_pfn;
-       }
-
-       return nr;
-}
-
-static unsigned long calc_max_low_pfn(void)
-{
-       int i;
-       unsigned long tmp = pfn_base + (SRMMU_MAXMEM >> PAGE_SHIFT);
-       unsigned long curr_pfn, last_pfn;
-
-       last_pfn = (sp_banks[0].base_addr + sp_banks[0].num_bytes) >> PAGE_SHIFT;
-       for (i = 1; sp_banks[i].num_bytes != 0; i++) {
-               curr_pfn = sp_banks[i].base_addr >> PAGE_SHIFT;
-
-               if (curr_pfn >= tmp) {
-                       if (last_pfn < tmp)
-                               tmp = last_pfn;
-                       break;
-               }
-
-               last_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT;
-       }
-
-       return tmp;
-}
-
-unsigned long __init bootmem_init(unsigned long *pages_avail)
-{
-       unsigned long bootmap_size, start_pfn;
-       unsigned long end_of_phys_memory = 0UL;
-       unsigned long bootmap_pfn, bytes_avail, size;
-       int i;
-
-       bytes_avail = 0UL;
-       for (i = 0; sp_banks[i].num_bytes != 0; i++) {
-               end_of_phys_memory = sp_banks[i].base_addr +
-                       sp_banks[i].num_bytes;
-               bytes_avail += sp_banks[i].num_bytes;
-               if (cmdline_memory_size) {
-                       if (bytes_avail > cmdline_memory_size) {
-                               unsigned long slack = bytes_avail - cmdline_memory_size;
-
-                               bytes_avail -= slack;
-                               end_of_phys_memory -= slack;
-
-                               sp_banks[i].num_bytes -= slack;
-                               if (sp_banks[i].num_bytes == 0) {
-                                       sp_banks[i].base_addr = 0xdeadbeef;
-                               } else {
-                                       sp_banks[i+1].num_bytes = 0;
-                                       sp_banks[i+1].base_addr = 0xdeadbeef;
-                               }
-                               break;
-                       }
-               }
-       }
-
-       /* Start with page aligned address of last symbol in kernel
-        * image.  
-        */
-       start_pfn  = (unsigned long)__pa(PAGE_ALIGN((unsigned long) &_end));
-
-       /* Now shift down to get the real physical page frame number. */
-       start_pfn >>= PAGE_SHIFT;
-
-       bootmap_pfn = start_pfn;
-
-       max_pfn = end_of_phys_memory >> PAGE_SHIFT;
-
-       max_low_pfn = max_pfn;
-       highstart_pfn = highend_pfn = max_pfn;
-
-       if (max_low_pfn > pfn_base + (SRMMU_MAXMEM >> PAGE_SHIFT)) {
-               highstart_pfn = pfn_base + (SRMMU_MAXMEM >> PAGE_SHIFT);
-               max_low_pfn = calc_max_low_pfn();
-               printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
-                   calc_highpages() >> (20 - PAGE_SHIFT));
-       }
-
-#ifdef CONFIG_BLK_DEV_INITRD
-       /* Now have to check initial ramdisk, so that bootmap does not overwrite it */
-       if (sparc_ramdisk_image) {
-               if (sparc_ramdisk_image >= (unsigned long)&_end - 2 * PAGE_SIZE)
-                       sparc_ramdisk_image -= KERNBASE;
-               initrd_start = sparc_ramdisk_image + phys_base;
-               initrd_end = initrd_start + sparc_ramdisk_size;
-               if (initrd_end > end_of_phys_memory) {
-                       printk(KERN_CRIT "initrd extends beyond end of memory "
-                                        "(0x%016lx > 0x%016lx)\ndisabling initrd\n",
-                              initrd_end, end_of_phys_memory);
-                       initrd_start = 0;
-               }
-               if (initrd_start) {
-                       if (initrd_start >= (start_pfn << PAGE_SHIFT) &&
-                           initrd_start < (start_pfn << PAGE_SHIFT) + 2 * PAGE_SIZE)
-                               bootmap_pfn = PAGE_ALIGN (initrd_end) >> PAGE_SHIFT;
-               }
-       }
-#endif 
-       /* Initialize the boot-time allocator. */
-       bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn, pfn_base,
-                                        max_low_pfn);
-
-       /* Now register the available physical memory with the
-        * allocator.
-        */
-       *pages_avail = 0;
-       for (i = 0; sp_banks[i].num_bytes != 0; i++) {
-               unsigned long curr_pfn, last_pfn;
-
-               curr_pfn = sp_banks[i].base_addr >> PAGE_SHIFT;
-               if (curr_pfn >= max_low_pfn)
-                       break;
-
-               last_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT;
-               if (last_pfn > max_low_pfn)
-                       last_pfn = max_low_pfn;
-
-               /*
-                * .. finally, did all the rounding and playing
-                * around just make the area go away?
-                */
-               if (last_pfn <= curr_pfn)
-                       continue;
-
-               size = (last_pfn - curr_pfn) << PAGE_SHIFT;
-               *pages_avail += last_pfn - curr_pfn;
-
-               free_bootmem(sp_banks[i].base_addr, size);
-       }
-
-#ifdef CONFIG_BLK_DEV_INITRD
-       if (initrd_start) {
-               /* Reserve the initrd image area. */
-               size = initrd_end - initrd_start;
-               reserve_bootmem(initrd_start, size, BOOTMEM_DEFAULT);
-               *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
-
-               initrd_start = (initrd_start - phys_base) + PAGE_OFFSET;
-               initrd_end = (initrd_end - phys_base) + PAGE_OFFSET;            
-       }
-#endif
-       /* Reserve the kernel text/data/bss. */
-       size = (start_pfn << PAGE_SHIFT) - phys_base;
-       reserve_bootmem(phys_base, size, BOOTMEM_DEFAULT);
-       *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
-
-       /* Reserve the bootmem map.   We do not account for it
-        * in pages_avail because we will release that memory
-        * in free_all_bootmem.
-        */
-       size = bootmap_size;
-       reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size, BOOTMEM_DEFAULT);
-       *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
-
-       return max_pfn;
-}
-
-/*
- * check_pgt_cache
- *
- * This is called at the end of unmapping of VMA (zap_page_range),
- * to rescan the page cache for architecture specific things,
- * presumably something like sun4/sun4c PMEGs. Most architectures
- * define check_pgt_cache empty.
- *
- * We simply copy the 2.4 implementation for now.
- */
-static int pgt_cache_water[2] = { 25, 50 };
-
-void check_pgt_cache(void)
-{
-       do_check_pgt_cache(pgt_cache_water[0], pgt_cache_water[1]);
-}
-
-/*
- * paging_init() sets up the page tables: We call the MMU specific
- * init routine based upon the Sun model type on the Sparc.
- *
- */
-extern void sun4c_paging_init(void);
-extern void srmmu_paging_init(void);
-extern void device_scan(void);
-
-pgprot_t PAGE_SHARED __read_mostly;
-EXPORT_SYMBOL(PAGE_SHARED);
-
-void __init paging_init(void)
-{
-       switch(sparc_cpu_model) {
-       case sun4c:
-       case sun4e:
-       case sun4:
-               sun4c_paging_init();
-               sparc_unmapped_base = 0xe0000000;
-               BTFIXUPSET_SETHI(sparc_unmapped_base, 0xe0000000);
-               break;
-       case sun4m:
-       case sun4d:
-               srmmu_paging_init();
-               sparc_unmapped_base = 0x50000000;
-               BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000);
-               break;
-       default:
-               prom_printf("paging_init: Cannot init paging on this Sparc\n");
-               prom_printf("paging_init: sparc_cpu_model = %d\n", sparc_cpu_model);
-               prom_printf("paging_init: Halting...\n");
-               prom_halt();
-       };
-
-       /* Initialize the protection map with non-constant, MMU dependent values. */
-       protection_map[0] = PAGE_NONE;
-       protection_map[1] = PAGE_READONLY;
-       protection_map[2] = PAGE_COPY;
-       protection_map[3] = PAGE_COPY;
-       protection_map[4] = PAGE_READONLY;
-       protection_map[5] = PAGE_READONLY;
-       protection_map[6] = PAGE_COPY;
-       protection_map[7] = PAGE_COPY;
-       protection_map[8] = PAGE_NONE;
-       protection_map[9] = PAGE_READONLY;
-       protection_map[10] = PAGE_SHARED;
-       protection_map[11] = PAGE_SHARED;
-       protection_map[12] = PAGE_READONLY;
-       protection_map[13] = PAGE_READONLY;
-       protection_map[14] = PAGE_SHARED;
-       protection_map[15] = PAGE_SHARED;
-       btfixup();
-       prom_build_devicetree();
-       device_scan();
-}
-
-static void __init taint_real_pages(void)
-{
-       int i;
-
-       for (i = 0; sp_banks[i].num_bytes; i++) {
-               unsigned long start, end;
-
-               start = sp_banks[i].base_addr;
-               end = start + sp_banks[i].num_bytes;
-
-               while (start < end) {
-                       set_bit(start >> 20, sparc_valid_addr_bitmap);
-                       start += PAGE_SIZE;
-               }
-       }
-}
-
-static void map_high_region(unsigned long start_pfn, unsigned long end_pfn)
-{
-       unsigned long tmp;
-
-#ifdef CONFIG_DEBUG_HIGHMEM
-       printk("mapping high region %08lx - %08lx\n", start_pfn, end_pfn);
-#endif
-
-       for (tmp = start_pfn; tmp < end_pfn; tmp++) {
-               struct page *page = pfn_to_page(tmp);
-
-               ClearPageReserved(page);
-               init_page_count(page);
-               __free_page(page);
-               totalhigh_pages++;
-       }
-}
-
-void __init mem_init(void)
-{
-       int codepages = 0;
-       int datapages = 0;
-       int initpages = 0; 
-       int reservedpages = 0;
-       int i;
-
-       if (PKMAP_BASE+LAST_PKMAP*PAGE_SIZE >= FIXADDR_START) {
-               prom_printf("BUG: fixmap and pkmap areas overlap\n");
-               prom_printf("pkbase: 0x%lx pkend: 0x%lx fixstart 0x%lx\n",
-                      PKMAP_BASE,
-                      (unsigned long)PKMAP_BASE+LAST_PKMAP*PAGE_SIZE,
-                      FIXADDR_START);
-               prom_printf("Please mail sparclinux@vger.kernel.org.\n");
-               prom_halt();
-       }
-
-
-       /* Saves us work later. */
-       memset((void *)&empty_zero_page, 0, PAGE_SIZE);
-
-       i = last_valid_pfn >> ((20 - PAGE_SHIFT) + 5);
-       i += 1;
-       sparc_valid_addr_bitmap = (unsigned long *)
-               __alloc_bootmem(i << 2, SMP_CACHE_BYTES, 0UL);
-
-       if (sparc_valid_addr_bitmap == NULL) {
-               prom_printf("mem_init: Cannot alloc valid_addr_bitmap.\n");
-               prom_halt();
-       }
-       memset(sparc_valid_addr_bitmap, 0, i << 2);
-
-       taint_real_pages();
-
-       max_mapnr = last_valid_pfn - pfn_base;
-       high_memory = __va(max_low_pfn << PAGE_SHIFT);
-
-       totalram_pages = free_all_bootmem();
-
-       for (i = 0; sp_banks[i].num_bytes != 0; i++) {
-               unsigned long start_pfn = sp_banks[i].base_addr >> PAGE_SHIFT;
-               unsigned long end_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT;
-
-               num_physpages += sp_banks[i].num_bytes >> PAGE_SHIFT;
-
-               if (end_pfn <= highstart_pfn)
-                       continue;
-
-               if (start_pfn < highstart_pfn)
-                       start_pfn = highstart_pfn;
-
-               map_high_region(start_pfn, end_pfn);
-       }
-       
-       totalram_pages += totalhigh_pages;
-
-       codepages = (((unsigned long) &etext) - ((unsigned long)&_start));
-       codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT;
-       datapages = (((unsigned long) &edata) - ((unsigned long)&etext));
-       datapages = PAGE_ALIGN(datapages) >> PAGE_SHIFT;
-       initpages = (((unsigned long) &__init_end) - ((unsigned long) &__init_begin));
-       initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT;
-
-       /* Ignore memory holes for the purpose of counting reserved pages */
-       for (i=0; i < max_low_pfn; i++)
-               if (test_bit(i >> (20 - PAGE_SHIFT), sparc_valid_addr_bitmap)
-                   && PageReserved(pfn_to_page(i)))
-                       reservedpages++;
-
-       printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
-              (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
-              num_physpages << (PAGE_SHIFT - 10),
-              codepages << (PAGE_SHIFT-10),
-              reservedpages << (PAGE_SHIFT - 10),
-              datapages << (PAGE_SHIFT-10), 
-              initpages << (PAGE_SHIFT-10),
-              totalhigh_pages << (PAGE_SHIFT-10));
-}
-
-void free_initmem (void)
-{
-       unsigned long addr;
-
-       addr = (unsigned long)(&__init_begin);
-       for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
-               struct page *p;
-
-               memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
-               p = virt_to_page(addr);
-
-               ClearPageReserved(p);
-               init_page_count(p);
-               __free_page(p);
-               totalram_pages++;
-               num_physpages++;
-       }
-       printk(KERN_INFO "Freeing unused kernel memory: %dk freed\n",
-               (&__init_end - &__init_begin) >> 10);
-}
-
-#ifdef CONFIG_BLK_DEV_INITRD
-void free_initrd_mem(unsigned long start, unsigned long end)
-{
-       if (start < end)
-               printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
-                       (end - start) >> 10);
-       for (; start < end; start += PAGE_SIZE) {
-               struct page *p;
-
-               memset((void *)start, POISON_FREE_INITMEM, PAGE_SIZE);
-               p = virt_to_page(start);
-
-               ClearPageReserved(p);
-               init_page_count(p);
-               __free_page(p);
-               totalram_pages++;
-               num_physpages++;
-       }
-}
-#endif
-
-void sparc_flush_page_to_ram(struct page *page)
-{
-       unsigned long vaddr = (unsigned long)page_address(page);
-
-       if (vaddr)
-               __flush_page_to_ram(vaddr);
-}
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
new file mode 100644 (file)
index 0000000..677c1e1
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+ *  linux/arch/sparc/mm/init.c
+ *
+ *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *  Copyright (C) 1995 Eddie C. Dost (ecd@skynet.be)
+ *  Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *  Copyright (C) 2000 Anton Blanchard (anton@samba.org)
+ */
+
+#include <linux/module.h>
+#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/initrd.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <linux/bootmem.h>
+#include <linux/pagemap.h>
+#include <linux/poison.h>
+
+#include <asm/system.h>
+#include <asm/vac-ops.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/vaddrs.h>
+#include <asm/pgalloc.h>       /* bug in asm-generic/tlb.h: check_pgt_cache */
+#include <asm/tlb.h>
+#include <asm/prom.h>
+
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+unsigned long *sparc_valid_addr_bitmap;
+
+unsigned long phys_base;
+unsigned long pfn_base;
+
+unsigned long page_kernel;
+
+struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS+1];
+unsigned long sparc_unmapped_base;
+
+struct pgtable_cache_struct pgt_quicklists;
+
+/* References to section boundaries */
+extern char __init_begin, __init_end, _start, _end, etext , edata;
+
+/* Initial ramdisk setup */
+extern unsigned int sparc_ramdisk_image;
+extern unsigned int sparc_ramdisk_size;
+
+unsigned long highstart_pfn, highend_pfn;
+
+pte_t *kmap_pte;
+pgprot_t kmap_prot;
+
+#define kmap_get_fixmap_pte(vaddr) \
+       pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr))
+
+void __init kmap_init(void)
+{
+       /* cache the first kmap pte */
+       kmap_pte = kmap_get_fixmap_pte(__fix_to_virt(FIX_KMAP_BEGIN));
+       kmap_prot = __pgprot(SRMMU_ET_PTE | SRMMU_PRIV | SRMMU_CACHE);
+}
+
+void show_mem(void)
+{
+       printk("Mem-info:\n");
+       show_free_areas();
+       printk("Free swap:       %6ldkB\n",
+              nr_swap_pages << (PAGE_SHIFT-10));
+       printk("%ld pages of RAM\n", totalram_pages);
+       printk("%ld free pages\n", nr_free_pages());
+#if 0 /* undefined pgtable_cache_size, pgd_cache_size */
+       printk("%ld pages in page table cache\n",pgtable_cache_size);
+#ifndef CONFIG_SMP
+       if (sparc_cpu_model == sun4m || sparc_cpu_model == sun4d)
+               printk("%ld entries in page dir cache\n",pgd_cache_size);
+#endif 
+#endif
+}
+
+void __init sparc_context_init(int numctx)
+{
+       int ctx;
+
+       ctx_list_pool = __alloc_bootmem(numctx * sizeof(struct ctx_list), SMP_CACHE_BYTES, 0UL);
+
+       for(ctx = 0; ctx < numctx; ctx++) {
+               struct ctx_list *clist;
+
+               clist = (ctx_list_pool + ctx);
+               clist->ctx_number = ctx;
+               clist->ctx_mm = NULL;
+       }
+       ctx_free.next = ctx_free.prev = &ctx_free;
+       ctx_used.next = ctx_used.prev = &ctx_used;
+       for(ctx = 0; ctx < numctx; ctx++)
+               add_to_free_ctxlist(ctx_list_pool + ctx);
+}
+
+extern unsigned long cmdline_memory_size;
+unsigned long last_valid_pfn;
+
+unsigned long calc_highpages(void)
+{
+       int i;
+       int nr = 0;
+
+       for (i = 0; sp_banks[i].num_bytes != 0; i++) {
+               unsigned long start_pfn = sp_banks[i].base_addr >> PAGE_SHIFT;
+               unsigned long end_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT;
+
+               if (end_pfn <= max_low_pfn)
+                       continue;
+
+               if (start_pfn < max_low_pfn)
+                       start_pfn = max_low_pfn;
+
+               nr += end_pfn - start_pfn;
+       }
+
+       return nr;
+}
+
+static unsigned long calc_max_low_pfn(void)
+{
+       int i;
+       unsigned long tmp = pfn_base + (SRMMU_MAXMEM >> PAGE_SHIFT);
+       unsigned long curr_pfn, last_pfn;
+
+       last_pfn = (sp_banks[0].base_addr + sp_banks[0].num_bytes) >> PAGE_SHIFT;
+       for (i = 1; sp_banks[i].num_bytes != 0; i++) {
+               curr_pfn = sp_banks[i].base_addr >> PAGE_SHIFT;
+
+               if (curr_pfn >= tmp) {
+                       if (last_pfn < tmp)
+                               tmp = last_pfn;
+                       break;
+               }
+
+               last_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT;
+       }
+
+       return tmp;
+}
+
+unsigned long __init bootmem_init(unsigned long *pages_avail)
+{
+       unsigned long bootmap_size, start_pfn;
+       unsigned long end_of_phys_memory = 0UL;
+       unsigned long bootmap_pfn, bytes_avail, size;
+       int i;
+
+       bytes_avail = 0UL;
+       for (i = 0; sp_banks[i].num_bytes != 0; i++) {
+               end_of_phys_memory = sp_banks[i].base_addr +
+                       sp_banks[i].num_bytes;
+               bytes_avail += sp_banks[i].num_bytes;
+               if (cmdline_memory_size) {
+                       if (bytes_avail > cmdline_memory_size) {
+                               unsigned long slack = bytes_avail - cmdline_memory_size;
+
+                               bytes_avail -= slack;
+                               end_of_phys_memory -= slack;
+
+                               sp_banks[i].num_bytes -= slack;
+                               if (sp_banks[i].num_bytes == 0) {
+                                       sp_banks[i].base_addr = 0xdeadbeef;
+                               } else {
+                                       sp_banks[i+1].num_bytes = 0;
+                                       sp_banks[i+1].base_addr = 0xdeadbeef;
+                               }
+                               break;
+                       }
+               }
+       }
+
+       /* Start with page aligned address of last symbol in kernel
+        * image.  
+        */
+       start_pfn  = (unsigned long)__pa(PAGE_ALIGN((unsigned long) &_end));
+
+       /* Now shift down to get the real physical page frame number. */
+       start_pfn >>= PAGE_SHIFT;
+
+       bootmap_pfn = start_pfn;
+
+       max_pfn = end_of_phys_memory >> PAGE_SHIFT;
+
+       max_low_pfn = max_pfn;
+       highstart_pfn = highend_pfn = max_pfn;
+
+       if (max_low_pfn > pfn_base + (SRMMU_MAXMEM >> PAGE_SHIFT)) {
+               highstart_pfn = pfn_base + (SRMMU_MAXMEM >> PAGE_SHIFT);
+               max_low_pfn = calc_max_low_pfn();
+               printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
+                   calc_highpages() >> (20 - PAGE_SHIFT));
+       }
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       /* Now have to check initial ramdisk, so that bootmap does not overwrite it */
+       if (sparc_ramdisk_image) {
+               if (sparc_ramdisk_image >= (unsigned long)&_end - 2 * PAGE_SIZE)
+                       sparc_ramdisk_image -= KERNBASE;
+               initrd_start = sparc_ramdisk_image + phys_base;
+               initrd_end = initrd_start + sparc_ramdisk_size;
+               if (initrd_end > end_of_phys_memory) {
+                       printk(KERN_CRIT "initrd extends beyond end of memory "
+                                        "(0x%016lx > 0x%016lx)\ndisabling initrd\n",
+                              initrd_end, end_of_phys_memory);
+                       initrd_start = 0;
+               }
+               if (initrd_start) {
+                       if (initrd_start >= (start_pfn << PAGE_SHIFT) &&
+                           initrd_start < (start_pfn << PAGE_SHIFT) + 2 * PAGE_SIZE)
+                               bootmap_pfn = PAGE_ALIGN (initrd_end) >> PAGE_SHIFT;
+               }
+       }
+#endif 
+       /* Initialize the boot-time allocator. */
+       bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn, pfn_base,
+                                        max_low_pfn);
+
+       /* Now register the available physical memory with the
+        * allocator.
+        */
+       *pages_avail = 0;
+       for (i = 0; sp_banks[i].num_bytes != 0; i++) {
+               unsigned long curr_pfn, last_pfn;
+
+               curr_pfn = sp_banks[i].base_addr >> PAGE_SHIFT;
+               if (curr_pfn >= max_low_pfn)
+                       break;
+
+               last_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT;
+               if (last_pfn > max_low_pfn)
+                       last_pfn = max_low_pfn;
+
+               /*
+                * .. finally, did all the rounding and playing
+                * around just make the area go away?
+                */
+               if (last_pfn <= curr_pfn)
+                       continue;
+
+               size = (last_pfn - curr_pfn) << PAGE_SHIFT;
+               *pages_avail += last_pfn - curr_pfn;
+
+               free_bootmem(sp_banks[i].base_addr, size);
+       }
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (initrd_start) {
+               /* Reserve the initrd image area. */
+               size = initrd_end - initrd_start;
+               reserve_bootmem(initrd_start, size, BOOTMEM_DEFAULT);
+               *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
+
+               initrd_start = (initrd_start - phys_base) + PAGE_OFFSET;
+               initrd_end = (initrd_end - phys_base) + PAGE_OFFSET;            
+       }
+#endif
+       /* Reserve the kernel text/data/bss. */
+       size = (start_pfn << PAGE_SHIFT) - phys_base;
+       reserve_bootmem(phys_base, size, BOOTMEM_DEFAULT);
+       *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
+
+       /* Reserve the bootmem map.   We do not account for it
+        * in pages_avail because we will release that memory
+        * in free_all_bootmem.
+        */
+       size = bootmap_size;
+       reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size, BOOTMEM_DEFAULT);
+       *pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
+
+       return max_pfn;
+}
+
+/*
+ * check_pgt_cache
+ *
+ * This is called at the end of unmapping of VMA (zap_page_range),
+ * to rescan the page cache for architecture specific things,
+ * presumably something like sun4/sun4c PMEGs. Most architectures
+ * define check_pgt_cache empty.
+ *
+ * We simply copy the 2.4 implementation for now.
+ */
+static int pgt_cache_water[2] = { 25, 50 };
+
+void check_pgt_cache(void)
+{
+       do_check_pgt_cache(pgt_cache_water[0], pgt_cache_water[1]);
+}
+
+/*
+ * paging_init() sets up the page tables: We call the MMU specific
+ * init routine based upon the Sun model type on the Sparc.
+ *
+ */
+extern void sun4c_paging_init(void);
+extern void srmmu_paging_init(void);
+extern void device_scan(void);
+
+pgprot_t PAGE_SHARED __read_mostly;
+EXPORT_SYMBOL(PAGE_SHARED);
+
+void __init paging_init(void)
+{
+       switch(sparc_cpu_model) {
+       case sun4c:
+       case sun4e:
+       case sun4:
+               sun4c_paging_init();
+               sparc_unmapped_base = 0xe0000000;
+               BTFIXUPSET_SETHI(sparc_unmapped_base, 0xe0000000);
+               break;
+       case sun4m:
+       case sun4d:
+               srmmu_paging_init();
+               sparc_unmapped_base = 0x50000000;
+               BTFIXUPSET_SETHI(sparc_unmapped_base, 0x50000000);
+               break;
+       default:
+               prom_printf("paging_init: Cannot init paging on this Sparc\n");
+               prom_printf("paging_init: sparc_cpu_model = %d\n", sparc_cpu_model);
+               prom_printf("paging_init: Halting...\n");
+               prom_halt();
+       };
+
+       /* Initialize the protection map with non-constant, MMU dependent values. */
+       protection_map[0] = PAGE_NONE;
+       protection_map[1] = PAGE_READONLY;
+       protection_map[2] = PAGE_COPY;
+       protection_map[3] = PAGE_COPY;
+       protection_map[4] = PAGE_READONLY;
+       protection_map[5] = PAGE_READONLY;
+       protection_map[6] = PAGE_COPY;
+       protection_map[7] = PAGE_COPY;
+       protection_map[8] = PAGE_NONE;
+       protection_map[9] = PAGE_READONLY;
+       protection_map[10] = PAGE_SHARED;
+       protection_map[11] = PAGE_SHARED;
+       protection_map[12] = PAGE_READONLY;
+       protection_map[13] = PAGE_READONLY;
+       protection_map[14] = PAGE_SHARED;
+       protection_map[15] = PAGE_SHARED;
+       btfixup();
+       prom_build_devicetree();
+       device_scan();
+}
+
+static void __init taint_real_pages(void)
+{
+       int i;
+
+       for (i = 0; sp_banks[i].num_bytes; i++) {
+               unsigned long start, end;
+
+               start = sp_banks[i].base_addr;
+               end = start + sp_banks[i].num_bytes;
+
+               while (start < end) {
+                       set_bit(start >> 20, sparc_valid_addr_bitmap);
+                       start += PAGE_SIZE;
+               }
+       }
+}
+
+static void map_high_region(unsigned long start_pfn, unsigned long end_pfn)
+{
+       unsigned long tmp;
+
+#ifdef CONFIG_DEBUG_HIGHMEM
+       printk("mapping high region %08lx - %08lx\n", start_pfn, end_pfn);
+#endif
+
+       for (tmp = start_pfn; tmp < end_pfn; tmp++) {
+               struct page *page = pfn_to_page(tmp);
+
+               ClearPageReserved(page);
+               init_page_count(page);
+               __free_page(page);
+               totalhigh_pages++;
+       }
+}
+
+void __init mem_init(void)
+{
+       int codepages = 0;
+       int datapages = 0;
+       int initpages = 0; 
+       int reservedpages = 0;
+       int i;
+
+       if (PKMAP_BASE+LAST_PKMAP*PAGE_SIZE >= FIXADDR_START) {
+               prom_printf("BUG: fixmap and pkmap areas overlap\n");
+               prom_printf("pkbase: 0x%lx pkend: 0x%lx fixstart 0x%lx\n",
+                      PKMAP_BASE,
+                      (unsigned long)PKMAP_BASE+LAST_PKMAP*PAGE_SIZE,
+                      FIXADDR_START);
+               prom_printf("Please mail sparclinux@vger.kernel.org.\n");
+               prom_halt();
+       }
+
+
+       /* Saves us work later. */
+       memset((void *)&empty_zero_page, 0, PAGE_SIZE);
+
+       i = last_valid_pfn >> ((20 - PAGE_SHIFT) + 5);
+       i += 1;
+       sparc_valid_addr_bitmap = (unsigned long *)
+               __alloc_bootmem(i << 2, SMP_CACHE_BYTES, 0UL);
+
+       if (sparc_valid_addr_bitmap == NULL) {
+               prom_printf("mem_init: Cannot alloc valid_addr_bitmap.\n");
+               prom_halt();
+       }
+       memset(sparc_valid_addr_bitmap, 0, i << 2);
+
+       taint_real_pages();
+
+       max_mapnr = last_valid_pfn - pfn_base;
+       high_memory = __va(max_low_pfn << PAGE_SHIFT);
+
+       totalram_pages = free_all_bootmem();
+
+       for (i = 0; sp_banks[i].num_bytes != 0; i++) {
+               unsigned long start_pfn = sp_banks[i].base_addr >> PAGE_SHIFT;
+               unsigned long end_pfn = (sp_banks[i].base_addr + sp_banks[i].num_bytes) >> PAGE_SHIFT;
+
+               num_physpages += sp_banks[i].num_bytes >> PAGE_SHIFT;
+
+               if (end_pfn <= highstart_pfn)
+                       continue;
+
+               if (start_pfn < highstart_pfn)
+                       start_pfn = highstart_pfn;
+
+               map_high_region(start_pfn, end_pfn);
+       }
+       
+       totalram_pages += totalhigh_pages;
+
+       codepages = (((unsigned long) &etext) - ((unsigned long)&_start));
+       codepages = PAGE_ALIGN(codepages) >> PAGE_SHIFT;
+       datapages = (((unsigned long) &edata) - ((unsigned long)&etext));
+       datapages = PAGE_ALIGN(datapages) >> PAGE_SHIFT;
+       initpages = (((unsigned long) &__init_end) - ((unsigned long) &__init_begin));
+       initpages = PAGE_ALIGN(initpages) >> PAGE_SHIFT;
+
+       /* Ignore memory holes for the purpose of counting reserved pages */
+       for (i=0; i < max_low_pfn; i++)
+               if (test_bit(i >> (20 - PAGE_SHIFT), sparc_valid_addr_bitmap)
+                   && PageReserved(pfn_to_page(i)))
+                       reservedpages++;
+
+       printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init, %ldk highmem)\n",
+              (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
+              num_physpages << (PAGE_SHIFT - 10),
+              codepages << (PAGE_SHIFT-10),
+              reservedpages << (PAGE_SHIFT - 10),
+              datapages << (PAGE_SHIFT-10), 
+              initpages << (PAGE_SHIFT-10),
+              totalhigh_pages << (PAGE_SHIFT-10));
+}
+
+void free_initmem (void)
+{
+       unsigned long addr;
+
+       addr = (unsigned long)(&__init_begin);
+       for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) {
+               struct page *p;
+
+               memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
+               p = virt_to_page(addr);
+
+               ClearPageReserved(p);
+               init_page_count(p);
+               __free_page(p);
+               totalram_pages++;
+               num_physpages++;
+       }
+       printk(KERN_INFO "Freeing unused kernel memory: %dk freed\n",
+               (&__init_end - &__init_begin) >> 10);
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+       if (start < end)
+               printk(KERN_INFO "Freeing initrd memory: %ldk freed\n",
+                       (end - start) >> 10);
+       for (; start < end; start += PAGE_SIZE) {
+               struct page *p;
+
+               memset((void *)start, POISON_FREE_INITMEM, PAGE_SIZE);
+               p = virt_to_page(start);
+
+               ClearPageReserved(p);
+               init_page_count(p);
+               __free_page(p);
+               totalram_pages++;
+               num_physpages++;
+       }
+}
+#endif
+
+void sparc_flush_page_to_ram(struct page *page)
+{
+       unsigned long vaddr = (unsigned long)page_address(page);
+
+       if (vaddr)
+               __flush_page_to_ram(vaddr);
+}