diff options
author | Paul Mackerras <paulus@samba.org> | 2008-06-09 14:01:46 +1000 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2008-06-10 21:40:22 +1000 |
commit | 917f0af9e5a9ceecf9e72537fabb501254ba321d (patch) | |
tree | 1ef207755c6d83ce4af93ef2b5e4645eebd65886 /arch/ppc/kernel | |
parent | 0f3d6bcd391b058c619fc30e8022e8a29fbf4bef (diff) |
powerpc: Remove arch/ppc and include/asm-ppc
All the maintained platforms are now in arch/powerpc, so the old
arch/ppc stuff can now go away.
Acked-by: Adrian Bunk <bunk@kernel.org>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Becky Bruce <becky.bruce@freescale.com>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Acked-by: Jochen Friedrich <jochen@scram.de>
Acked-by: John Linn <john.linn@xilinx.com>
Acked-by: Jon Loeliger <jdl@freescale.com>
Acked-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Acked-by: Kumar Gala <galak@kernel.crashing.org>
Acked-by: Olof Johansson <olof@lixom.net>
Acked-by: Peter Korsgaard <jacmet@sunsite.dk>
Acked-by: Scott Wood <scottwood@freescale.com>
Acked-by: Sean MacLennan <smaclennan@pikatech.com>
Acked-by: Segher Boessenkool <segher@kernel.crashing.org>
Acked-by: Stefan Roese <sr@denx.de>
Acked-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com>
Acked-by: Wolfgang Denk <wd@denx.de>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/ppc/kernel')
-rw-r--r-- | arch/ppc/kernel/Makefile | 21 | ||||
-rw-r--r-- | arch/ppc/kernel/asm-offsets.c | 164 | ||||
-rw-r--r-- | arch/ppc/kernel/cpu_setup_power4.S | 197 | ||||
-rw-r--r-- | arch/ppc/kernel/entry.S | 960 | ||||
-rw-r--r-- | arch/ppc/kernel/head.S | 1220 | ||||
-rw-r--r-- | arch/ppc/kernel/head_44x.S | 769 | ||||
-rw-r--r-- | arch/ppc/kernel/head_4xx.S | 1021 | ||||
-rw-r--r-- | arch/ppc/kernel/head_8xx.S | 959 | ||||
-rw-r--r-- | arch/ppc/kernel/head_booke.h | 308 | ||||
-rw-r--r-- | arch/ppc/kernel/machine_kexec.c | 118 | ||||
-rw-r--r-- | arch/ppc/kernel/misc.S | 868 | ||||
-rw-r--r-- | arch/ppc/kernel/pci.c | 1233 | ||||
-rw-r--r-- | arch/ppc/kernel/ppc-stub.c | 866 | ||||
-rw-r--r-- | arch/ppc/kernel/ppc_htab.c | 464 | ||||
-rw-r--r-- | arch/ppc/kernel/ppc_ksyms.c | 258 | ||||
-rw-r--r-- | arch/ppc/kernel/relocate_kernel.S | 123 | ||||
-rw-r--r-- | arch/ppc/kernel/setup.c | 572 | ||||
-rw-r--r-- | arch/ppc/kernel/smp-tbsync.c | 180 | ||||
-rw-r--r-- | arch/ppc/kernel/smp.c | 414 | ||||
-rw-r--r-- | arch/ppc/kernel/softemu8xx.c | 147 | ||||
-rw-r--r-- | arch/ppc/kernel/time.c | 445 | ||||
-rw-r--r-- | arch/ppc/kernel/traps.c | 826 | ||||
-rw-r--r-- | arch/ppc/kernel/vmlinux.lds.S | 164 |
23 files changed, 0 insertions, 12297 deletions
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile deleted file mode 100644 index 7b739054968..00000000000 --- a/arch/ppc/kernel/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# -# Makefile for the linux kernel. -# -extra-$(CONFIG_PPC_STD_MMU) := head.o -extra-$(CONFIG_40x) := head_4xx.o -extra-$(CONFIG_44x) := head_44x.o -extra-$(CONFIG_8xx) := head_8xx.o -extra-y += vmlinux.lds - -obj-y := entry.o traps.o time.o misc.o \ - setup.o \ - ppc_htab.o -obj-$(CONFIG_MODULES) += ppc_ksyms.o -obj-$(CONFIG_PCI) += pci.o -obj-$(CONFIG_KGDB) += ppc-stub.o -obj-$(CONFIG_SMP) += smp.o smp-tbsync.o -obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o - -ifndef CONFIG_MATH_EMULATION -obj-$(CONFIG_8xx) += softemu8xx.o -endif diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c deleted file mode 100644 index 8dcbdd6c2d2..00000000000 --- a/arch/ppc/kernel/asm-offsets.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * This program is used to generate definitions needed by - * assembly language modules. - * - * We use the technique used in the OSF Mach kernel code: - * generate asm statements containing #defines, - * compile this file to assembler, and then extract the - * #defines from the assembly-language output. - */ - -#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/suspend.h> -#include <linux/mman.h> -#include <linux/mm.h> -#include <linux/kbuild.h> - -#include <asm/io.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/processor.h> -#include <asm/cputable.h> -#include <asm/thread_info.h> -#include <asm/vdso_datapage.h> - -int -main(void) -{ - DEFINE(THREAD, offsetof(struct task_struct, thread)); - DEFINE(THREAD_INFO, offsetof(struct task_struct, stack)); - DEFINE(MM, offsetof(struct task_struct, mm)); - DEFINE(PTRACE, offsetof(struct task_struct, ptrace)); - DEFINE(KSP, offsetof(struct thread_struct, ksp)); - DEFINE(PGDIR, offsetof(struct thread_struct, pgdir)); - DEFINE(PT_REGS, offsetof(struct thread_struct, regs)); - DEFINE(THREAD_FPEXC_MODE, offsetof(struct thread_struct, fpexc_mode)); - DEFINE(THREAD_FPR0, offsetof(struct thread_struct, fpr[0])); - DEFINE(THREAD_FPSCR, offsetof(struct thread_struct, fpscr)); -#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) - DEFINE(THREAD_DBCR0, offsetof(struct thread_struct, dbcr0)); - DEFINE(PT_PTRACED, PT_PTRACED); -#endif -#ifdef CONFIG_ALTIVEC - DEFINE(THREAD_VR0, offsetof(struct thread_struct, vr[0])); - DEFINE(THREAD_VRSAVE, offsetof(struct thread_struct, vrsave)); - DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr)); - DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr)); -#endif /* CONFIG_ALTIVEC */ - /* Interrupt register frame */ - DEFINE(STACK_FRAME_OVERHEAD, STACK_FRAME_OVERHEAD); - DEFINE(INT_FRAME_SIZE, STACK_FRAME_OVERHEAD + sizeof(struct pt_regs)); - /* in fact we only use gpr0 - gpr9 and gpr20 - gpr23 */ - DEFINE(GPR0, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[0])); - DEFINE(GPR1, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[1])); - DEFINE(GPR2, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[2])); - DEFINE(GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[3])); - DEFINE(GPR4, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[4])); - DEFINE(GPR5, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[5])); - DEFINE(GPR6, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[6])); - DEFINE(GPR7, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[7])); - DEFINE(GPR8, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[8])); - DEFINE(GPR9, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[9])); - DEFINE(GPR10, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[10])); - DEFINE(GPR11, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[11])); - DEFINE(GPR12, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[12])); - DEFINE(GPR13, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[13])); - DEFINE(GPR14, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[14])); - DEFINE(GPR15, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[15])); - DEFINE(GPR16, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[16])); - DEFINE(GPR17, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[17])); - DEFINE(GPR18, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[18])); - DEFINE(GPR19, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[19])); - DEFINE(GPR20, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[20])); - DEFINE(GPR21, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[21])); - DEFINE(GPR22, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[22])); - DEFINE(GPR23, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[23])); - DEFINE(GPR24, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[24])); - DEFINE(GPR25, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[25])); - DEFINE(GPR26, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[26])); - DEFINE(GPR27, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[27])); - DEFINE(GPR28, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[28])); - DEFINE(GPR29, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[29])); - DEFINE(GPR30, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[30])); - DEFINE(GPR31, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, gpr[31])); - /* Note: these symbols include _ because they overlap with special - * register names - */ - DEFINE(_NIP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, nip)); - DEFINE(_MSR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, msr)); - DEFINE(_CTR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ctr)); - DEFINE(_LINK, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, link)); - DEFINE(_CCR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, ccr)); - DEFINE(_MQ, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, mq)); - DEFINE(_XER, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, xer)); - DEFINE(_DAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar)); - DEFINE(_DSISR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); - /* The PowerPC 400-class & Book-E processors have neither the DAR nor the DSISR - * SPRs. Hence, we overload them to hold the similar DEAR and ESR SPRs - * for such processors. For critical interrupts we use them to - * hold SRR0 and SRR1. - */ - DEFINE(_DEAR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dar)); - DEFINE(_ESR, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, dsisr)); - DEFINE(ORIG_GPR3, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, orig_gpr3)); - DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result)); - DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); - DEFINE(CLONE_VM, CLONE_VM); - DEFINE(CLONE_UNTRACED, CLONE_UNTRACED); - DEFINE(MM_PGD, offsetof(struct mm_struct, pgd)); - - /* About the CPU features table */ - DEFINE(CPU_SPEC_ENTRY_SIZE, sizeof(struct cpu_spec)); - DEFINE(CPU_SPEC_PVR_MASK, offsetof(struct cpu_spec, pvr_mask)); - DEFINE(CPU_SPEC_PVR_VALUE, offsetof(struct cpu_spec, pvr_value)); - DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); - DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); - - DEFINE(TI_TASK, offsetof(struct thread_info, task)); - DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); - DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); - DEFINE(TI_LOCAL_FLAGS, offsetof(struct thread_info, local_flags)); - DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); - DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); - - DEFINE(pbe_address, offsetof(struct pbe, address)); - DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address)); - DEFINE(pbe_next, offsetof(struct pbe, next)); - - DEFINE(TASK_SIZE, TASK_SIZE); - DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); - - /* datapage offsets for use by vdso */ - DEFINE(CFG_TB_ORIG_STAMP, offsetof(struct vdso_data, tb_orig_stamp)); - DEFINE(CFG_TB_TICKS_PER_SEC, offsetof(struct vdso_data, tb_ticks_per_sec)); - DEFINE(CFG_TB_TO_XS, offsetof(struct vdso_data, tb_to_xs)); - DEFINE(CFG_STAMP_XSEC, offsetof(struct vdso_data, stamp_xsec)); - DEFINE(CFG_TB_UPDATE_COUNT, offsetof(struct vdso_data, tb_update_count)); - DEFINE(CFG_TZ_MINUTEWEST, offsetof(struct vdso_data, tz_minuteswest)); - DEFINE(CFG_TZ_DSTTIME, offsetof(struct vdso_data, tz_dsttime)); - DEFINE(CFG_SYSCALL_MAP32, offsetof(struct vdso_data, syscall_map_32)); - DEFINE(WTOM_CLOCK_SEC, offsetof(struct vdso_data, wtom_clock_sec)); - DEFINE(WTOM_CLOCK_NSEC, offsetof(struct vdso_data, wtom_clock_nsec)); - DEFINE(TVAL32_TV_SEC, offsetof(struct timeval, tv_sec)); - DEFINE(TVAL32_TV_USEC, offsetof(struct timeval, tv_usec)); - DEFINE(TSPEC32_TV_SEC, offsetof(struct timespec, tv_sec)); - DEFINE(TSPEC32_TV_NSEC, offsetof(struct timespec, tv_nsec)); - - /* timeval/timezone offsets for use by vdso */ - DEFINE(TZONE_TZ_MINWEST, offsetof(struct timezone, tz_minuteswest)); - DEFINE(TZONE_TZ_DSTTIME, offsetof(struct timezone, tz_dsttime)); - - /* Other bits used by the vdso */ - DEFINE(CLOCK_REALTIME, CLOCK_REALTIME); - DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC); - DEFINE(NSEC_PER_SEC, NSEC_PER_SEC); - DEFINE(CLOCK_REALTIME_RES, TICK_NSEC); - - return 0; -} diff --git a/arch/ppc/kernel/cpu_setup_power4.S b/arch/ppc/kernel/cpu_setup_power4.S deleted file mode 100644 index 6a674e834ee..00000000000 --- a/arch/ppc/kernel/cpu_setup_power4.S +++ /dev/null @@ -1,197 +0,0 @@ -/* - * This file contains low level CPU setup functions. - * Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include <asm/processor.h> -#include <asm/page.h> -#include <asm/ppc_asm.h> -#include <asm/cputable.h> -#include <asm/asm-offsets.h> -#include <asm/cache.h> - -_GLOBAL(__970_cpu_preinit) - /* - * Deal only with PPC970 and PPC970FX. - */ - mfspr r0,SPRN_PVR - srwi r0,r0,16 - cmpwi cr0,r0,0x39 - cmpwi cr1,r0,0x3c - cror 4*cr0+eq,4*cr0+eq,4*cr1+eq - bnelr - - /* Make sure HID4:rm_ci is off before MMU is turned off, that large - * pages are enabled with HID4:61 and clear HID5:DCBZ_size and - * HID5:DCBZ32_ill - */ - li r0,0 - mfspr r11,SPRN_HID4 - rldimi r11,r0,40,23 /* clear bit 23 (rm_ci) */ - rldimi r11,r0,2,61 /* clear bit 61 (lg_pg_en) */ - sync - mtspr SPRN_HID4,r11 - isync - sync - mfspr r11,SPRN_HID5 - rldimi r11,r0,6,56 /* clear bits 56 & 57 (DCBZ*) */ - sync - mtspr SPRN_HID5,r11 - isync - sync - - /* Setup some basic HID1 features */ - mfspr r0,SPRN_HID1 - li r11,0x1200 /* enable i-fetch cacheability */ - sldi r11,r11,44 /* and prefetch */ - or r0,r0,r11 - mtspr SPRN_HID1,r0 - mtspr SPRN_HID1,r0 - isync - - /* Clear HIOR */ - li r0,0 - sync - mtspr SPRN_HIOR,0 /* Clear interrupt prefix */ - isync - blr - -_GLOBAL(__setup_cpu_ppc970) - mfspr r0,SPRN_HID0 - li r11,5 /* clear DOZE and SLEEP */ - rldimi r0,r11,52,8 /* set NAP and DPM */ - mtspr SPRN_HID0,r0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - mfspr r0,SPRN_HID0 - sync - isync - blr - -/* Definitions for the table use to save CPU states */ -#define CS_HID0 0 -#define CS_HID1 8 -#define CS_HID4 16 -#define CS_HID5 24 -#define CS_SIZE 32 - - .data - .balign L1_CACHE_BYTES -cpu_state_storage: - .space CS_SIZE - .balign L1_CACHE_BYTES,0 - .text - -/* Called in normal context to backup CPU 0 state. This - * does not include cache settings. This function is also - * called for machine sleep. This does not include the MMU - * setup, BATs, etc... but rather the "special" registers - * like HID0, HID1, HID4, etc... - */ -_GLOBAL(__save_cpu_setup) - /* Some CR fields are volatile, we back it up all */ - mfcr r7 - - /* Get storage ptr */ - lis r5,cpu_state_storage@h - ori r5,r5,cpu_state_storage@l - - /* We only deal with 970 for now */ - mfspr r0,SPRN_PVR - srwi r0,r0,16 - cmpwi cr0,r0,0x39 - cmpwi cr1,r0,0x3c - cror 4*cr0+eq,4*cr0+eq,4*cr1+eq - bne 1f - - /* Save HID0,1,4 and 5 */ - mfspr r3,SPRN_HID0 - std r3,CS_HID0(r5) - mfspr r3,SPRN_HID1 - std r3,CS_HID1(r5) - mfspr r3,SPRN_HID4 - std r3,CS_HID4(r5) - mfspr r3,SPRN_HID5 - std r3,CS_HID5(r5) - -1: - mtcr r7 - blr - -/* Called with no MMU context (typically MSR:IR/DR off) to - * restore CPU state as backed up by the previous - * function. This does not include cache setting - */ -_GLOBAL(__restore_cpu_setup) - /* Some CR fields are volatile, we back it up all */ - mfcr r7 - - /* Get storage ptr */ - lis r5,(cpu_state_storage-KERNELBASE)@h - ori r5,r5,cpu_state_storage@l - - /* We only deal with 970 for now */ - mfspr r0,SPRN_PVR - srwi r0,r0,16 - cmpwi cr0,r0,0x39 - cmpwi cr1,r0,0x3c - cror 4*cr0+eq,4*cr0+eq,4*cr1+eq - bne 1f - - /* Clear interrupt prefix */ - li r0,0 - sync - mtspr SPRN_HIOR,0 - isync - - /* Restore HID0 */ - ld r3,CS_HID0(r5) - sync - isync - mtspr SPRN_HID0,r3 - mfspr r3,SPRN_HID0 - mfspr r3,SPRN_HID0 - mfspr r3,SPRN_HID0 - mfspr r3,SPRN_HID0 - mfspr r3,SPRN_HID0 - mfspr r3,SPRN_HID0 - sync - isync - - /* Restore HID1 */ - ld r3,CS_HID1(r5) - sync - isync - mtspr SPRN_HID1,r3 - mtspr SPRN_HID1,r3 - sync - isync - - /* Restore HID4 */ - ld r3,CS_HID4(r5) - sync - isync - mtspr SPRN_HID4,r3 - sync - isync - - /* Restore HID5 */ - ld r3,CS_HID5(r5) - sync - isync - mtspr SPRN_HID5,r3 - sync - isync -1: - mtcr r7 - blr - diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S deleted file mode 100644 index fcd830a292e..00000000000 --- a/arch/ppc/kernel/entry.S +++ /dev/null @@ -1,960 +0,0 @@ -/* - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * Rewritten by Cort Dougan (cort@fsmlabs.com) for PReP - * Copyright (C) 1996 Cort Dougan <cort@fsmlabs.com> - * Adapted for Power Macintosh by Paul Mackerras. - * Low-level exception handlers and MMU support - * rewritten by Paul Mackerras. - * Copyright (C) 1996 Paul Mackerras. - * MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net). - * - * This file contains the system call entry code, context switch - * code, and exception/interrupt return code for PowerPC. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include <linux/errno.h> -#include <linux/sys.h> -#include <linux/threads.h> -#include <asm/processor.h> -#include <asm/page.h> -#include <asm/mmu.h> -#include <asm/cputable.h> -#include <asm/thread_info.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> -#include <asm/unistd.h> - -#undef SHOW_SYSCALLS -#undef SHOW_SYSCALLS_TASK - -/* - * MSR_KERNEL is > 0x10000 on 4xx/Book-E since it include MSR_CE. - */ -#if MSR_KERNEL >= 0x10000 -#define LOAD_MSR_KERNEL(r, x) lis r,(x)@h; ori r,r,(x)@l -#else -#define LOAD_MSR_KERNEL(r, x) li r,(x) -#endif - -#ifdef CONFIG_BOOKE -#include "head_booke.h" -#define TRANSFER_TO_HANDLER_EXC_LEVEL(exc_level) \ - mtspr exc_level##_SPRG,r8; \ - BOOKE_LOAD_EXC_LEVEL_STACK(exc_level); \ - lwz r0,GPR10-INT_FRAME_SIZE(r8); \ - stw r0,GPR10(r11); \ - lwz r0,GPR11-INT_FRAME_SIZE(r8); \ - stw r0,GPR11(r11); \ - mfspr r8,exc_level##_SPRG - - .globl mcheck_transfer_to_handler -mcheck_transfer_to_handler: - TRANSFER_TO_HANDLER_EXC_LEVEL(MCHECK) - b transfer_to_handler_full - - .globl debug_transfer_to_handler -debug_transfer_to_handler: - TRANSFER_TO_HANDLER_EXC_LEVEL(DEBUG) - b transfer_to_handler_full - - .globl crit_transfer_to_handler -crit_transfer_to_handler: - TRANSFER_TO_HANDLER_EXC_LEVEL(CRIT) - /* fall through */ -#endif - -#ifdef CONFIG_40x - .globl crit_transfer_to_handler -crit_transfer_to_handler: - lwz r0,crit_r10@l(0) - stw r0,GPR10(r11) - lwz r0,crit_r11@l(0) - stw r0,GPR11(r11) - /* fall through */ -#endif - -/* - * This code finishes saving the registers to the exception frame - * and jumps to the appropriate handler for the exception, turning - * on address translation. - * Note that we rely on the caller having set cr0.eq iff the exception - * occurred in kernel mode (i.e. MSR:PR = 0). - */ - .globl transfer_to_handler_full -transfer_to_handler_full: - SAVE_NVGPRS(r11) - /* fall through */ - - .globl transfer_to_handler -transfer_to_handler: - stw r2,GPR2(r11) - stw r12,_NIP(r11) - stw r9,_MSR(r11) - andi. r2,r9,MSR_PR - mfctr r12 - mfspr r2,SPRN_XER - stw r12,_CTR(r11) - stw r2,_XER(r11) - mfspr r12,SPRN_SPRG3 - addi r2,r12,-THREAD - tovirt(r2,r2) /* set r2 to current */ - beq 2f /* if from user, fix up THREAD.regs */ - addi r11,r1,STACK_FRAME_OVERHEAD - stw r11,PT_REGS(r12) -#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) - /* Check to see if the dbcr0 register is set up to debug. Use the - single-step bit to do this. */ - lwz r12,THREAD_DBCR0(r12) - andis. r12,r12,DBCR0_IC@h - beq+ 3f - /* From user and task is ptraced - load up global dbcr0 */ - li r12,-1 /* clear all pending debug events */ - mtspr SPRN_DBSR,r12 - lis r11,global_dbcr0@ha - tophys(r11,r11) - addi r11,r11,global_dbcr0@l - lwz r12,0(r11) - mtspr SPRN_DBCR0,r12 - lwz r12,4(r11) - addi r12,r12,-1 - stw r12,4(r11) -#endif - b 3f - -2: /* if from kernel, check interrupted DOZE/NAP mode and - * check for stack overflow - */ - lwz r9,THREAD_INFO-THREAD(r12) - cmplw r1,r9 /* if r1 <= current->thread_info */ - ble- stack_ovf /* then the kernel stack overflowed */ -5: -#ifdef CONFIG_6xx - tophys(r9,r9) /* check local flags */ - lwz r12,TI_LOCAL_FLAGS(r9) - mtcrf 0x01,r12 - bt- 31-TLF_NAPPING,4f -#endif /* CONFIG_6xx */ - .globl transfer_to_handler_cont -transfer_to_handler_cont: -3: - mflr r9 - lwz r11,0(r9) /* virtual address of handler */ - lwz r9,4(r9) /* where to go when done */ - mtspr SPRN_SRR0,r11 - mtspr SPRN_SRR1,r10 - mtlr r9 - SYNC - RFI /* jump to handler, enable MMU */ - -#ifdef CONFIG_6xx -4: rlwinm r12,r12,0,~_TLF_NAPPING - stw r12,TI_LOCAL_FLAGS(r9) - b power_save_6xx_restore -#endif - -/* - * On kernel stack overflow, load up an initial stack pointer - * and call StackOverflow(regs), which should not return. - */ -stack_ovf: - /* sometimes we use a statically-allocated stack, which is OK. */ - lis r12,_end@h - ori r12,r12,_end@l - cmplw r1,r12 - ble 5b /* r1 <= &_end is OK */ - SAVE_NVGPRS(r11) - addi r3,r1,STACK_FRAME_OVERHEAD - lis r1,init_thread_union@ha - addi r1,r1,init_thread_union@l - addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD - lis r9,StackOverflow@ha - addi r9,r9,StackOverflow@l - LOAD_MSR_KERNEL(r10,MSR_KERNEL) - FIX_SRR1(r10,r12) - mtspr SPRN_SRR0,r9 - mtspr SPRN_SRR1,r10 - SYNC - RFI - -/* - * Handle a system call. - */ - .stabs "arch/ppc/kernel/",N_SO,0,0,0f - .stabs "entry.S",N_SO,0,0,0f -0: - -_GLOBAL(DoSyscall) - stw r3,ORIG_GPR3(r1) - li r12,0 - stw r12,RESULT(r1) - lwz r11,_CCR(r1) /* Clear SO bit in CR */ - rlwinm r11,r11,0,4,2 - stw r11,_CCR(r1) -#ifdef SHOW_SYSCALLS - bl do_show_syscall -#endif /* SHOW_SYSCALLS */ - rlwinm r10,r1,0,0,18 /* current_thread_info() */ - lwz r11,TI_FLAGS(r10) - andi. r11,r11,_TIF_SYSCALL_T_OR_A - bne- syscall_dotrace -syscall_dotrace_cont: - cmplwi 0,r0,NR_syscalls - lis r10,sys_call_table@h - ori r10,r10,sys_call_table@l - slwi r0,r0,2 - bge- 66f - lwzx r10,r10,r0 /* Fetch system call handler [ptr] */ - mtlr r10 - addi r9,r1,STACK_FRAME_OVERHEAD - PPC440EP_ERR42 - blrl /* Call handler */ - .globl ret_from_syscall -ret_from_syscall: -#ifdef SHOW_SYSCALLS - bl do_show_syscall_exit -#endif - mr r6,r3 - rlwinm r12,r1,0,0,18 /* current_thread_info() */ - /* disable interrupts so current_thread_info()->flags can't change */ - LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ - SYNC - MTMSRD(r10) - lwz r9,TI_FLAGS(r12) - li r8,-_LAST_ERRNO - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_USER_WORK_MASK|_TIF_PERSYSCALL_MASK) - bne- syscall_exit_work - cmplw 0,r3,r8 - blt+ syscall_exit_cont - lwz r11,_CCR(r1) /* Load CR */ - neg r3,r3 - oris r11,r11,0x1000 /* Set SO bit in CR */ - stw r11,_CCR(r1) -syscall_exit_cont: -#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) - /* If the process has its own DBCR0 value, load it up. The single - step bit tells us that dbcr0 should be loaded. */ - lwz r0,THREAD+THREAD_DBCR0(r2) - andis. r10,r0,DBCR0_IC@h - bnel- load_dbcr0 -#endif -#ifdef CONFIG_44x - lis r4,icache_44x_need_flush@ha - lwz r5,icache_44x_need_flush@l(r4) - cmplwi cr0,r5,0 - bne- 2f -1: -#endif /* CONFIG_44x */ -BEGIN_FTR_SECTION - lwarx r7,0,r1 -END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX) - stwcx. r0,0,r1 /* to clear the reservation */ - lwz r4,_LINK(r1) - lwz r5,_CCR(r1) - mtlr r4 - mtcr r5 - lwz r7,_NIP(r1) - lwz r8,_MSR(r1) - FIX_SRR1(r8, r0) - lwz r2,GPR2(r1) - lwz r1,GPR1(r1) - mtspr SPRN_SRR0,r7 - mtspr SPRN_SRR1,r8 - SYNC - RFI -#ifdef CONFIG_44x -2: li r7,0 - iccci r0,r0 - stw r7,icache_44x_need_flush@l(r4) - b 1b -#endif /* CONFIG_44x */ - -66: li r3,-ENOSYS - b ret_from_syscall - - .globl ret_from_fork -ret_from_fork: - REST_NVGPRS(r1) - bl schedule_tail - li r3,0 - b ret_from_syscall - -/* Traced system call support */ -syscall_dotrace: - SAVE_NVGPRS(r1) - li r0,0xc00 - stw r0,TRAP(r1) - addi r3,r1,STACK_FRAME_OVERHEAD - bl do_syscall_trace_enter - lwz r0,GPR0(r1) /* Restore original registers */ - lwz r3,GPR3(r1) - lwz r4,GPR4(r1) - lwz r5,GPR5(r1) - lwz r6,GPR6(r1) - lwz r7,GPR7(r1) - lwz r8,GPR8(r1) - REST_NVGPRS(r1) - b syscall_dotrace_cont - -syscall_exit_work: - andi. r0,r9,_TIF_RESTOREALL - beq+ 0f - REST_NVGPRS(r1) - b 2f -0: cmplw 0,r3,r8 - blt+ 1f - andi. r0,r9,_TIF_NOERROR - bne- 1f - lwz r11,_CCR(r1) /* Load CR */ - neg r3,r3 - oris r11,r11,0x1000 /* Set SO bit in CR */ - stw r11,_CCR(r1) - -1: stw r6,RESULT(r1) /* Save result */ - stw r3,GPR3(r1) /* Update return value */ -2: andi. r0,r9,(_TIF_PERSYSCALL_MASK) - beq 4f - - /* Clear per-syscall TIF flags if any are set. */ - - li r11,_TIF_PERSYSCALL_MASK - addi r12,r12,TI_FLAGS -3: lwarx r8,0,r12 - andc r8,r8,r11 -#ifdef CONFIG_IBM405_ERR77 - dcbt 0,r12 -#endif - stwcx. r8,0,r12 - bne- 3b - subi r12,r12,TI_FLAGS - -4: /* Anything which requires enabling interrupts? */ - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) - beq ret_from_except - - /* Re-enable interrupts */ - ori r10,r10,MSR_EE - SYNC - MTMSRD(r10) - - /* Save NVGPRS if they're not saved already */ - lwz r4,TRAP(r1) - andi. r4,r4,1 - beq 5f - SAVE_NVGPRS(r1) - li r4,0xc00 - stw r4,TRAP(r1) -5: - addi r3,r1,STACK_FRAME_OVERHEAD - bl do_syscall_trace_leave - b ret_from_except_full - -#ifdef SHOW_SYSCALLS -do_show_syscall: -#ifdef SHOW_SYSCALLS_TASK - lis r11,show_syscalls_task@ha - lwz r11,show_syscalls_task@l(r11) - cmp 0,r2,r11 - bnelr -#endif - stw r31,GPR31(r1) - mflr r31 - lis r3,7f@ha - addi r3,r3,7f@l - lwz r4,GPR0(r1) - lwz r5,GPR3(r1) - lwz r6,GPR4(r1) - lwz r7,GPR5(r1) - lwz r8,GPR6(r1) - lwz r9,GPR7(r1) - bl printk - lis r3,77f@ha - addi r3,r3,77f@l - lwz r4,GPR8(r1) - mr r5,r2 - bl printk - lwz r0,GPR0(r1) - lwz r3,GPR3(r1) - lwz r4,GPR4(r1) - lwz r5,GPR5(r1) - lwz r6,GPR6(r1) - lwz r7,GPR7(r1) - lwz r8,GPR8(r1) - mtlr r31 - lwz r31,GPR31(r1) - blr - -do_show_syscall_exit: -#ifdef SHOW_SYSCALLS_TASK - lis r11,show_syscalls_task@ha - lwz r11,show_syscalls_task@l(r11) - cmp 0,r2,r11 - bnelr -#endif - stw r31,GPR31(r1) - mflr r31 - stw r3,RESULT(r1) /* Save result */ - mr r4,r3 - lis r3,79f@ha - addi r3,r3,79f@l - bl printk - lwz r3,RESULT(r1) - mtlr r31 - lwz r31,GPR31(r1) - blr - -7: .string "syscall %d(%x, %x, %x, %x, %x, " -77: .string "%x), current=%p\n" -79: .string " -> %x\n" - .align 2,0 - -#ifdef SHOW_SYSCALLS_TASK - .data - .globl show_syscalls_task -show_syscalls_task: - .long -1 - .text -#endif -#endif /* SHOW_SYSCALLS */ - -/* - * The fork/clone functions need to copy the full register set into - * the child process. Therefore we need to save all the nonvolatile - * registers (r13 - r31) before calling the C code. - */ - .globl ppc_fork -ppc_fork: - SAVE_NVGPRS(r1) - lwz r0,TRAP(r1) - rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ - stw r0,TRAP(r1) /* register set saved */ - b sys_fork - - .globl ppc_vfork -ppc_vfork: - SAVE_NVGPRS(r1) - lwz r0,TRAP(r1) - rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ - stw r0,TRAP(r1) /* register set saved */ - b sys_vfork - - .globl ppc_clone -ppc_clone: - SAVE_NVGPRS(r1) - lwz r0,TRAP(r1) - rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ - stw r0,TRAP(r1) /* register set saved */ - b sys_clone - - .globl ppc_swapcontext -ppc_swapcontext: - SAVE_NVGPRS(r1) - lwz r0,TRAP(r1) - rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ - stw r0,TRAP(r1) /* register set saved */ - b sys_swapcontext - -/* - * Top-level page fault handling. - * This is in assembler because if do_page_fault tells us that - * it is a bad kernel page fault, we want to save the non-volatile - * registers before calling bad_page_fault. - */ - .globl handle_page_fault -handle_page_fault: - stw r4,_DAR(r1) - addi r3,r1,STACK_FRAME_OVERHEAD - bl do_page_fault - cmpwi r3,0 - beq+ ret_from_except - SAVE_NVGPRS(r1) - lwz r0,TRAP(r1) - clrrwi r0,r0,1 - stw r0,TRAP(r1) - mr r5,r3 - addi r3,r1,STACK_FRAME_OVERHEAD - lwz r4,_DAR(r1) - bl bad_page_fault - b ret_from_except_full - -/* - * This routine switches between two different tasks. The process - * state of one is saved on its kernel stack. Then the state - * of the other is restored from its kernel stack. The memory - * management hardware is updated to the second process's state. - * Finally, we can return to the second process. - * On entry, r3 points to the THREAD for the current task, r4 - * points to the THREAD for the new task. - * - * This routine is always called with interrupts disabled. - * - * Note: there are two ways to get to the "going out" portion - * of this code; either by coming in via the entry (_switch) - * or via "fork" which must set up an environment equivalent - * to the "_switch" path. If you change this , you'll have to - * change the fork code also. - * - * The code which creates the new task context is in 'copy_thread' - * in arch/ppc/kernel/process.c - */ -_GLOBAL(_switch) - stwu r1,-INT_FRAME_SIZE(r1) - mflr r0 - stw r0,INT_FRAME_SIZE+4(r1) - /* r3-r12 are caller saved -- Cort */ - SAVE_NVGPRS(r1) - stw r0,_NIP(r1) /* Return to switch caller */ - mfmsr r11 - li r0,MSR_FP /* Disable floating-point */ -#ifdef CONFIG_ALTIVEC -BEGIN_FTR_SECTION - oris r0,r0,MSR_VEC@h /* Disable altivec */ - mfspr r12,SPRN_VRSAVE /* save vrsave register value */ - stw r12,THREAD+THREAD_VRSAVE(r2) -END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) -#endif /* CONFIG_ALTIVEC */ - and. r0,r0,r11 /* FP or altivec enabled? */ - beq+ 1f - andc r11,r11,r0 - MTMSRD(r11) - isync -1: stw r11,_MSR(r1) - mfcr r10 - stw r10,_CCR(r1) - stw r1,KSP(r3) /* Set old stack pointer */ - -#ifdef CONFIG_SMP - /* We need a sync somewhere here to make sure that if the - * previous task gets rescheduled on another CPU, it sees all - * stores it has performed on this one. - */ - sync -#endif /* CONFIG_SMP */ - - tophys(r0,r4) - CLR_TOP32(r0) - mtspr SPRN_SPRG3,r0 /* Update current THREAD phys addr */ - lwz r1,KSP(r4) /* Load new stack pointer */ - - /* save the old current 'last' for return value */ - mr r3,r2 - addi r2,r4,-THREAD /* Update current */ - -#ifdef CONFIG_ALTIVEC -BEGIN_FTR_SECTION - lwz r0,THREAD+THREAD_VRSAVE(r2) - mtspr SPRN_VRSAVE,r0 /* if G4, restore VRSAVE reg */ -END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) -#endif /* CONFIG_ALTIVEC */ - lwz r0,_CCR(r1) - mtcrf 0xFF,r0 - /* r3-r12 are destroyed -- Cort */ - REST_NVGPRS(r1) - - lwz r4,_NIP(r1) /* Return to _switch caller in new task */ - mtlr r4 - addi r1,r1,INT_FRAME_SIZE - blr - - .globl fast_exception_return -fast_exception_return: -#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) - andi. r10,r9,MSR_RI /* check for recoverable interrupt */ - beq 1f /* if not, we've got problems */ -#endif - -2: REST_4GPRS(3, r11) - lwz r10,_CCR(r11) - REST_GPR(1, r11) - mtcr r10 - lwz r10,_LINK(r11) - mtlr r10 - REST_GPR(10, r11) - mtspr SPRN_SRR1,r9 - mtspr SPRN_SRR0,r12 - REST_GPR(9, r11) - REST_GPR(12, r11) - lwz r11,GPR11(r11) - SYNC - RFI - -#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) -/* check if the exception happened in a restartable section */ -1: lis r3,exc_exit_restart_end@ha - addi r3,r3,exc_exit_restart_end@l - cmplw r12,r3 - bge 3f - lis r4,exc_exit_restart@ha - addi r4,r4,exc_exit_restart@l - cmplw r12,r4 - blt 3f - lis r3,fee_restarts@ha - tophys(r3,r3) - lwz r5,fee_restarts@l(r3) - addi r5,r5,1 - stw r5,fee_restarts@l(r3) - mr r12,r4 /* restart at exc_exit_restart */ - b 2b - - .section .bss - .align 2 -fee_restarts: - .space 4 - .previous - -/* aargh, a nonrecoverable interrupt, panic */ -/* aargh, we don't know which trap this is */ -/* but the 601 doesn't implement the RI bit, so assume it's OK */ -3: -BEGIN_FTR_SECTION - b 2b -END_FTR_SECTION_IFSET(CPU_FTR_601) - li r10,-1 - stw r10,TRAP(r11) - addi r3,r1,STACK_FRAME_OVERHEAD - lis r10,MSR_KERNEL@h - ori r10,r10,MSR_KERNEL@l - bl transfer_to_handler_full - .long nonrecoverable_exception - .long ret_from_except -#endif - - .globl ret_from_except_full -ret_from_except_full: - REST_NVGPRS(r1) - /* fall through */ - - .globl ret_from_except -ret_from_except: - /* Hard-disable interrupts so that current_thread_info()->flags - * can't change between when we test it and when we return - * from the interrupt. */ - LOAD_MSR_KERNEL(r10,MSR_KERNEL) - SYNC /* Some chip revs have problems here... */ - MTMSRD(r10) /* disable interrupts */ - - lwz r3,_MSR(r1) /* Returning to user mode? */ - andi. r0,r3,MSR_PR - beq resume_kernel - -user_exc_return: /* r10 contains MSR_KERNEL here */ - /* Check current_thread_info()->flags */ - rlwinm r9,r1,0,0,18 - lwz r9,TI_FLAGS(r9) - andi. r0,r9,_TIF_USER_WORK_MASK - bne do_work - -restore_user: -#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) - /* Check whether this process has its own DBCR0 value. The single - step bit tells us that dbcr0 should be loaded. */ - lwz r0,THREAD+THREAD_DBCR0(r2) - andis. r10,r0,DBCR0_IC@h - bnel- load_dbcr0 -#endif - -#ifdef CONFIG_PREEMPT - b restore - -/* N.B. the only way to get here is from the beq following ret_from_except. */ -resume_kernel: - /* check current_thread_info->preempt_count */ - rlwinm r9,r1,0,0,18 - lwz r0,TI_PREEMPT(r9) - cmpwi 0,r0,0 /* if non-zero, just restore regs and return */ - bne restore - lwz r0,TI_FLAGS(r9) - andi. r0,r0,_TIF_NEED_RESCHED - beq+ restore - andi. r0,r3,MSR_EE /* interrupts off? */ - beq restore /* don't schedule if so */ -1: bl preempt_schedule_irq - rlwinm r9,r1,0,0,18 - lwz r3,TI_FLAGS(r9) - andi. r0,r3,_TIF_NEED_RESCHED - bne- 1b -#else -resume_kernel: -#endif /* CONFIG_PREEMPT */ - - /* interrupts are hard-disabled at this point */ -restore: -#ifdef CONFIG_44x - lis r4,icache_44x_need_flush@ha - lwz r5,icache_44x_need_flush@l(r4) - cmplwi cr0,r5,0 - beq+ 1f - li r6,0 - iccci r0,r0 - stw r6,icache_44x_need_flush@l(r4) -1: -#endif /* CONFIG_44x */ - lwz r0,GPR0(r1) - lwz r2,GPR2(r1) - REST_4GPRS(3, r1) - REST_2GPRS(7, r1) - - lwz r10,_XER(r1) - lwz r11,_CTR(r1) - mtspr SPRN_XER,r10 - mtctr r11 - - PPC405_ERR77(0,r1) -BEGIN_FTR_SECTION - lwarx r11,0,r1 -END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX) - stwcx. r0,0,r1 /* to clear the reservation */ - -#if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) - lwz r9,_MSR(r1) - andi. r10,r9,MSR_RI /* check if this exception occurred */ - beql nonrecoverable /* at a bad place (MSR:RI = 0) */ - - lwz r10,_CCR(r1) - lwz r11,_LINK(r1) - mtcrf 0xFF,r10 - mtlr r11 - - /* - * Once we put values in SRR0 and SRR1, we are in a state - * where exceptions are not recoverable, since taking an - * exception will trash SRR0 and SRR1. Therefore we clear the - * MSR:RI bit to indicate this. If we do take an exception, - * we can't return to the point of the exception but we - * can restart the exception exit path at the label - * exc_exit_restart below. -- paulus - */ - LOAD_MSR_KERNEL(r10,MSR_KERNEL & ~MSR_RI) - SYNC - MTMSRD(r10) /* clear the RI bit */ - .globl exc_exit_restart -exc_exit_restart: - lwz r9,_MSR(r1) - lwz r12,_NIP(r1) - FIX_SRR1(r9,r10) - mtspr SPRN_SRR0,r12 - mtspr SPRN_SRR1,r9 - REST_4GPRS(9, r1) - lwz r1,GPR1(r1) - .globl exc_exit_restart_end -exc_exit_restart_end: - SYNC - RFI - -#else /* !(CONFIG_4xx || CONFIG_BOOKE) */ - /* - * This is a bit different on 4xx/Book-E because it doesn't have - * the RI bit in the MSR. - * The TLB miss handler checks if we have interrupted - * the exception exit path and restarts it if so - * (well maybe one day it will... :). - */ - lwz r11,_LINK(r1) - mtlr r11 - lwz r10,_CCR(r1) - mtcrf 0xff,r10 - REST_2GPRS(9, r1) - .globl exc_exit_restart -exc_exit_restart: - lwz r11,_NIP(r1) - lwz r12,_MSR(r1) -exc_exit_start: - mtspr SPRN_SRR0,r11 - mtspr SPRN_SRR1,r12 - REST_2GPRS(11, r1) - lwz r1,GPR1(r1) - .globl exc_exit_restart_end -exc_exit_restart_end: - PPC405_ERR77_SYNC - rfi - b . /* prevent prefetch past rfi */ - -/* - * Returning from a critical interrupt in user mode doesn't need - * to be any different from a normal exception. For a critical - * interrupt in the kernel, we just return (without checking for - * preemption) since the interrupt may have happened at some crucial - * place (e.g. inside the TLB miss handler), and because we will be - * running with r1 pointing into critical_stack, not the current - * process's kernel stack (and therefore current_thread_info() will - * give the wrong answer). - * We have to restore various SPRs that may have been in use at the - * time of the critical interrupt. - * - */ -#ifdef CONFIG_40x -#define PPC_40x_TURN_OFF_MSR_DR \ - /* avoid any possible TLB misses here by turning off MSR.DR, we \ - * assume the instructions here are mapped by a pinned TLB entry */ \ - li r10,MSR_IR; \ - mtmsr r10; \ - isync; \ - tophys(r1, r1); -#else -#define PPC_40x_TURN_OFF_MSR_DR -#endif - -#define RET_FROM_EXC_LEVEL(exc_lvl_srr0, exc_lvl_srr1, exc_lvl_rfi) \ - REST_NVGPRS(r1); \ - lwz r3,_MSR(r1); \ - andi. r3,r3,MSR_PR; \ - LOAD_MSR_KERNEL(r10,MSR_KERNEL); \ - bne user_exc_return; \ - lwz r0,GPR0(r1); \ - lwz r2,GPR2(r1); \ - REST_4GPRS(3, r1); \ - REST_2GPRS(7, r1); \ - lwz r10,_XER(r1); \ - lwz r11,_CTR(r1); \ - mtspr SPRN_XER,r10; \ - mtctr r11; \ - PPC405_ERR77(0,r1); \ - stwcx. r0,0,r1; /* to clear the reservation */ \ - lwz r11,_LINK(r1); \ - mtlr r11; \ - lwz r10,_CCR(r1); \ - mtcrf 0xff,r10; \ - PPC_40x_TURN_OFF_MSR_DR; \ - lwz r9,_DEAR(r1); \ - lwz r10,_ESR(r1); \ - mtspr SPRN_DEAR,r9; \ - mtspr SPRN_ESR,r10; \ - lwz r11,_NIP(r1); \ - lwz r12,_MSR(r1); \ - mtspr exc_lvl_srr0,r11; \ - mtspr exc_lvl_srr1,r12; \ - lwz r9,GPR9(r1); \ - lwz r12,GPR12(r1); \ - lwz r10,GPR10(r1); \ - lwz r11,GPR11(r1); \ - lwz r1,GPR1(r1); \ - PPC405_ERR77_SYNC; \ - exc_lvl_rfi; \ - b .; /* prevent prefetch past exc_lvl_rfi */ - - .globl ret_from_crit_exc -ret_from_crit_exc: - RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI) - -#ifdef CONFIG_BOOKE - .globl ret_from_debug_exc -ret_from_debug_exc: - RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, RFDI) - - .globl ret_from_mcheck_exc -ret_from_mcheck_exc: - RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI) -#endif /* CONFIG_BOOKE */ - -/* - * Load the DBCR0 value for a task that is being ptraced, - * having first saved away the global DBCR0. Note that r0 - * has the dbcr0 value to set upon entry to this. - */ -load_dbcr0: - mfmsr r10 /* first disable debug exceptions */ - rlwinm r10,r10,0,~MSR_DE - mtmsr r10 - isync - mfspr r10,SPRN_DBCR0 - lis r11,global_dbcr0@ha - addi r11,r11,global_dbcr0@l - stw r10,0(r11) - mtspr SPRN_DBCR0,r0 - lwz r10,4(r11) - addi r10,r10,1 - stw r10,4(r11) - li r11,-1 - mtspr SPRN_DBSR,r11 /* clear all pending debug events */ - blr - - .section .bss - .align 4 -global_dbcr0: - .space 8 - .previous -#endif /* !(CONFIG_4xx || CONFIG_BOOKE) */ - -do_work: /* r10 contains MSR_KERNEL here */ - andi. r0,r9,_TIF_NEED_RESCHED - beq do_user_signal - -do_resched: /* r10 contains MSR_KERNEL here */ - ori r10,r10,MSR_EE - SYNC - MTMSRD(r10) /* hard-enable interrupts */ - bl schedule -recheck: - LOAD_MSR_KERNEL(r10,MSR_KERNEL) - SYNC - MTMSRD(r10) /* disable interrupts */ - rlwinm r9,r1,0,0,18 - lwz r9,TI_FLAGS(r9) - andi. r0,r9,_TIF_NEED_RESCHED - bne- do_resched - andi. r0,r9,_TIF_USER_WORK_MASK - beq restore_user -do_user_signal: /* r10 contains MSR_KERNEL here */ - ori r10,r10,MSR_EE - SYNC - MTMSRD(r10) /* hard-enable interrupts */ - /* save r13-r31 in the exception frame, if not already done */ - lwz r3,TRAP(r1) - andi. r0,r3,1 - beq 2f - SAVE_NVGPRS(r1) - rlwinm r3,r3,0,0,30 - stw r3,TRAP(r1) -2: li r3,0 - addi r4,r1,STACK_FRAME_OVERHEAD - bl do_signal - REST_NVGPRS(r1) - b recheck - -/* - * We come here when we are at the end of handling an exception - * that occurred at a place where taking an exception will lose - * state information, such as the contents of SRR0 and SRR1. - */ -nonrecoverable: - lis r10,exc_exit_restart_end@ha - addi r10,r10,exc_exit_restart_end@l - cmplw r12,r10 - bge 3f - lis r11,exc_exit_restart@ha - addi r11,r11,exc_exit_restart@l - cmplw r12,r11 - blt 3f - lis r10,ee_restarts@ha - lwz r12,ee_restarts@l(r10) - addi r12,r12,1 - stw r12,ee_restarts@l(r10) - mr r12,r11 /* restart at exc_exit_restart */ - blr -3: /* OK, we can't recover, kill this process */ - /* but the 601 doesn't implement the RI bit, so assume it's OK */ -BEGIN_FTR_SECTION - blr -END_FTR_SECTION_IFSET(CPU_FTR_601) - lwz r3,TRAP(r1) - andi. r0,r3,1 - beq 4f - SAVE_NVGPRS(r1) - rlwinm r3,r3,0,0,30 - stw r3,TRAP(r1) -4: addi r3,r1,STACK_FRAME_OVERHEAD - bl nonrecoverable_exception - /* shouldn't return */ - b 4b - - .section .bss - .align 2 -ee_restarts: - .space 4 - .previous diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S deleted file mode 100644 index e7e642b9513..00000000000 --- a/arch/ppc/kernel/head.S +++ /dev/null @@ -1,1220 +0,0 @@ -/* - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP - * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> - * Adapted for Power Macintosh by Paul Mackerras. - * Low-level exception handlers and MMU support - * rewritten by Paul Mackerras. - * Copyright (C) 1996 Paul Mackerras. - * MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net). - * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). - * - * This file contains the low-level support and setup for the - * PowerPC platform, including trap and interrupt dispatch. - * (The PPC 8xx embedded CPUs use head_8xx.S instead.) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include <asm/processor.h> -#include <asm/page.h> -#include <asm/mmu.h> -#include <asm/pgtable.h> -#include <asm/cputable.h> -#include <asm/cache.h> -#include <asm/thread_info.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> - -/* 601 only have IBAT; cr0.eq is set on 601 when using this macro */ -#define LOAD_BAT(n, reg, RA, RB) \ - /* see the comment for clear_bats() -- Cort */ \ - li RA,0; \ - mtspr SPRN_IBAT##n##U,RA; \ - mtspr SPRN_DBAT##n##U,RA; \ - lwz RA,(n*16)+0(reg); \ - lwz RB,(n*16)+4(reg); \ - mtspr SPRN_IBAT##n##U,RA; \ - mtspr SPRN_IBAT##n##L,RB; \ - beq 1f; \ - lwz RA,(n*16)+8(reg); \ - lwz RB,(n*16)+12(reg); \ - mtspr SPRN_DBAT##n##U,RA; \ - mtspr SPRN_DBAT##n##L,RB; \ -1: - - .text - .stabs "arch/ppc/kernel/",N_SO,0,0,0f - .stabs "head.S",N_SO,0,0,0f -0: - .globl _stext -_stext: - -/* - * _start is defined this way because the XCOFF loader in the OpenFirmware - * on the powermac expects the entry point to be a procedure descriptor. - */ - .text - .globl _start -_start: - /* - * These are here for legacy reasons, the kernel used to - * need to look like a coff function entry for the pmac - * but we're always started by some kind of bootloader now. - * -- Cort - */ - nop /* used by __secondary_hold on prep (mtx) and chrp smp */ - nop /* used by __secondary_hold on prep (mtx) and chrp smp */ - nop - -/* PMAC - * Enter here with the kernel text, data and bss loaded starting at - * 0, running with virtual == physical mapping. - * r5 points to the prom entry point (the client interface handler - * address). Address translation is turned on, with the prom - * managing the hash table. Interrupts are disabled. The stack - * pointer (r1) points to just below the end of the half-meg region - * from 0x380000 - 0x400000, which is mapped in already. - * - * If we are booted from MacOS via BootX, we enter with the kernel - * image loaded somewhere, and the following values in registers: - * r3: 'BooX' (0x426f6f58) - * r4: virtual address of boot_infos_t - * r5: 0 - * - * APUS - * r3: 'APUS' - * r4: physical address of memory base - * Linux/m68k style BootInfo structure at &_end. - * - * PREP - * This is jumped to on prep systems right after the kernel is relocated - * to its proper place in memory by the boot loader. The expected layout - * of the regs is: - * r3: ptr to residual data - * r4: initrd_start or if no initrd then 0 - * r5: initrd_end - unused if r4 is 0 - * r6: Start of command line string - * r7: End of command line string - * - * This just gets a minimal mmu environment setup so we can call - * start_here() to do the real work. - * -- Cort - */ - - .globl __start -__start: - mr r31,r3 /* save parameters */ - mr r30,r4 - mr r29,r5 - mr r28,r6 - mr r27,r7 - li r24,0 /* cpu # */ - -/* - * early_init() does the early machine identification and does - * the necessary low-level setup and clears the BSS - * -- Cort <cort@fsmlabs.com> - */ - bl early_init - -/* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains - * the physical address we are running at, returned by early_init() - */ - bl mmu_off -__after_mmu_off: - bl clear_bats - bl flush_tlbs - - bl initial_bats -#ifdef CONFIG_BOOTX_TEXT - bl setup_disp_bat -#endif - -/* - * Call setup_cpu for CPU 0 and initialize 6xx Idle - */ - bl reloc_offset - li r24,0 /* cpu# */ - bl call_setup_cpu /* Call setup_cpu for this CPU */ -#ifdef CONFIG_6xx - bl reloc_offset - bl init_idle_6xx -#endif /* CONFIG_6xx */ - - -/* - * We need to run with _start at physical address 0. - * If the MMU is already turned on, we copy stuff to KERNELBASE, - * otherwise we copy it to 0. - */ - bl reloc_offset - mr r26,r3 - addis r4,r3,KERNELBASE@h /* current address of _start */ - cmpwi 0,r4,0 /* are we already running at 0? */ - bne relocate_kernel - -/* - * we now have the 1st 16M of ram mapped with the bats. - * prep needs the mmu to be turned on here, but pmac already has it on. - * this shouldn't bother the pmac since it just gets turned on again - * as we jump to our code at KERNELBASE. -- Cort - * Actually no, pmac doesn't have it on any more. BootX enters with MMU - * off, and in other cases, we now turn it off before changing BATs above. - */ -turn_on_mmu: - mfmsr r0 - ori r0,r0,MSR_DR|MSR_IR - mtspr SPRN_SRR1,r0 - lis r0,start_here@h - ori r0,r0,start_here@l - mtspr SPRN_SRR0,r0 - SYNC - RFI /* enables MMU */ - -/* - * We need __secondary_hold as a place to hold the other cpus on - * an SMP machine, even when we are running a UP kernel. - */ - . = 0xc0 /* for prep bootloader */ - li r3,1 /* MTX only has 1 cpu */ - .globl __secondary_hold -__secondary_hold: - /* tell the master we're here */ - stw r3,4(0) -#ifdef CONFIG_SMP -100: lwz r4,0(0) - /* wait until we're told to start */ - cmpw 0,r4,r3 - bne 100b - /* our cpu # was at addr 0 - go */ - mr r24,r3 /* cpu # */ - b __secondary_start -#else - b . -#endif /* CONFIG_SMP */ - -/* - * Exception entry code. This code runs with address translation - * turned off, i.e. using physical addresses. - * We assume sprg3 has the physical address of the current - * task's thread_struct. - */ -#define EXCEPTION_PROLOG \ - mtspr SPRN_SPRG0,r10; \ - mtspr SPRN_SPRG1,r11; \ - mfcr r10; \ - EXCEPTION_PROLOG_1; \ - EXCEPTION_PROLOG_2 - -#define EXCEPTION_PROLOG_1 \ - mfspr r11,SPRN_SRR1; /* check whether user or kernel */ \ - andi. r11,r11,MSR_PR; \ - tophys(r11,r1); /* use tophys(r1) if kernel */ \ - beq 1f; \ - mfspr r11,SPRN_SPRG3; \ - lwz r11,THREAD_INFO-THREAD(r11); \ - addi r11,r11,THREAD_SIZE; \ - tophys(r11,r11); \ -1: subi r11,r11,INT_FRAME_SIZE /* alloc exc. frame */ - - -#define EXCEPTION_PROLOG_2 \ - CLR_TOP32(r11); \ - stw r10,_CCR(r11); /* save registers */ \ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mfspr r10,SPRN_SPRG0; \ - stw r10,GPR10(r11); \ - mfspr r12,SPRN_SPRG1; \ - stw r12,GPR11(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r12,SPRN_SRR0; \ - mfspr r9,SPRN_SRR1; \ - stw r1,GPR1(r11); \ - stw r1,0(r11); \ - tovirt(r1,r11); /* set new kernel sp */ \ - li r10,MSR_KERNEL & ~(MSR_IR|MSR_DR); /* can take exceptions */ \ - MTMSRD(r10); /* (except for mach check in rtas) */ \ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -/* - * Note: code which follows this uses cr0.eq (set if from kernel), - * r11, r12 (SRR0), and r9 (SRR1). - * - * Note2: once we have set r1 we are in a position to take exceptions - * again, and we could thus set MSR:RI at that point. - */ - -/* - * Exception vectors. - */ -#define EXCEPTION(n, label, hdlr, xfer) \ - . = n; \ -label: \ - EXCEPTION_PROLOG; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - xfer(n, hdlr) - -#define EXC_XFER_TEMPLATE(n, hdlr, trap, copyee, tfer, ret) \ - li r10,trap; \ - stw r10,TRAP(r11); \ - li r10,MSR_KERNEL; \ - copyee(r10, r9); \ - bl tfer; \ -i##n: \ - .long hdlr; \ - .long ret - -#define COPY_EE(d, s) rlwimi d,s,0,16,16 -#define NOCOPY(d, s) - -#define EXC_XFER_STD(n, hdlr) \ - EXC_XFER_TEMPLATE(n, hdlr, n, NOCOPY, transfer_to_handler_full, \ - ret_from_except_full) - -#define EXC_XFER_LITE(n, hdlr) \ - EXC_XFER_TEMPLATE(n, hdlr, n+1, NOCOPY, transfer_to_handler, \ - ret_from_except) - -#define EXC_XFER_EE(n, hdlr) \ - EXC_XFER_TEMPLATE(n, hdlr, n, COPY_EE, transfer_to_handler_full, \ - ret_from_except_full) - -#define EXC_XFER_EE_LITE(n, hdlr) \ - EXC_XFER_TEMPLATE(n, hdlr, n+1, COPY_EE, transfer_to_handler, \ - ret_from_except) - -/* System reset */ -/* core99 pmac starts the seconary here by changing the vector, and - putting it back to what it was (unknown_exception) when done. */ - EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD) - -/* Machine check */ - . = 0x200 - mtspr SPRN_SPRG0,r10 - mtspr SPRN_SPRG1,r11 - mfcr r10 - EXCEPTION_PROLOG_1 -7: EXCEPTION_PROLOG_2 - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_STD(0x200, machine_check_exception) - -/* Data access exception. */ - . = 0x300 -DataAccess: - EXCEPTION_PROLOG - mfspr r10,SPRN_DSISR - andis. r0,r10,0xa470 /* weird error? */ - bne 1f /* if not, try to put a PTE */ - mfspr r4,SPRN_DAR /* into the hash table */ - rlwinm r3,r10,32-15,21,21 /* DSISR_STORE -> _PAGE_RW */ - bl hash_page -1: stw r10,_DSISR(r11) - mr r5,r10 - mfspr r4,SPRN_DAR - EXC_XFER_EE_LITE(0x300, handle_page_fault) - -/* Instruction access exception. */ - . = 0x400 -InstructionAccess: - EXCEPTION_PROLOG - andis. r0,r9,0x4000 /* no pte found? */ - beq 1f /* if so, try to put a PTE */ - li r3,0 /* into the hash table */ - mr r4,r12 /* SRR0 is fault address */ - bl hash_page -1: mr r4,r12 - mr r5,r9 - EXC_XFER_EE_LITE(0x400, handle_page_fault) - -/* External interrupt */ - EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) - -/* Alignment exception */ - . = 0x600 -Alignment: - EXCEPTION_PROLOG - mfspr r4,SPRN_DAR - stw r4,_DAR(r11) - mfspr r5,SPRN_DSISR - stw r5,_DSISR(r11) - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE(0x600, alignment_exception) - -/* Program check exception */ - EXCEPTION(0x700, ProgramCheck, program_check_exception, EXC_XFER_STD) - -/* Floating-point unavailable */ - . = 0x800 -FPUnavailable: - EXCEPTION_PROLOG - bne load_up_fpu /* if from user, just load it up */ - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception) - -/* Decrementer */ - EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE) - - EXCEPTION(0xa00, Trap_0a, unknown_exception, EXC_XFER_EE) - EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_EE) - -/* System call */ - . = 0xc00 -SystemCall: - EXCEPTION_PROLOG - EXC_XFER_EE_LITE(0xc00, DoSyscall) - -/* Single step - not used on 601 */ - EXCEPTION(0xd00, SingleStep, single_step_exception, EXC_XFER_STD) - EXCEPTION(0xe00, Trap_0e, unknown_exception, EXC_XFER_EE) - -/* - * The Altivec unavailable trap is at 0x0f20. Foo. - * We effectively remap it to 0x3000. - * We include an altivec unavailable exception vector even if - * not configured for Altivec, so that you can't panic a - * non-altivec kernel running on a machine with altivec just - * by executing an altivec instruction. - */ - . = 0xf00 - b Trap_0f - - . = 0xf20 - b AltiVecUnavailable - -Trap_0f: - EXCEPTION_PROLOG - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE(0xf00, unknown_exception) - -/* - * Handle TLB miss for instruction on 603/603e. - * Note: we get an alternate set of r0 - r3 to use automatically. - */ - . = 0x1000 -InstructionTLBMiss: -/* - * r0: stored ctr - * r1: linux style pte ( later becomes ppc hardware pte ) - * r2: ptr to linux-style pte - * r3: scratch - */ - mfctr r0 - /* Get PTE (linux-style) and check access */ - mfspr r3,SPRN_IMISS - lis r1,KERNELBASE@h /* check if kernel address */ - cmplw 0,r3,r1 - mfspr r2,SPRN_SPRG3 - li r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */ - lwz r2,PGDIR(r2) - blt+ 112f - lis r2,swapper_pg_dir@ha /* if kernel address, use */ - addi r2,r2,swapper_pg_dir@l /* kernel page table */ - mfspr r1,SPRN_SRR1 /* and MSR_PR bit from SRR1 */ - rlwinm r1,r1,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ -112: tophys(r2,r2) - rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ - lwz r2,0(r2) /* get pmd entry */ - rlwinm. r2,r2,0,0,19 /* extract address of pte page */ - beq- InstructionAddressInvalid /* return if no mapping */ - rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ - lwz r3,0(r2) /* get linux-style pte */ - andc. r1,r1,r3 /* check access & ~permission */ - bne- InstructionAddressInvalid /* return if access not permitted */ - ori r3,r3,_PAGE_ACCESSED /* set _PAGE_ACCESSED in pte */ - /* - * NOTE! We are assuming this is not an SMP system, otherwise - * we would need to update the pte atomically with lwarx/stwcx. - */ - stw r3,0(r2) /* update PTE (accessed bit) */ - /* Convert linux-style PTE to low word of PPC-style PTE */ - rlwinm r1,r3,32-10,31,31 /* _PAGE_RW -> PP lsb */ - rlwinm r2,r3,32-7,31,31 /* _PAGE_DIRTY -> PP lsb */ - and r1,r1,r2 /* writable if _RW and _DIRTY */ - rlwimi r3,r3,32-1,30,30 /* _PAGE_USER -> PP msb */ - rlwimi r3,r3,32-1,31,31 /* _PAGE_USER -> PP lsb */ - ori r1,r1,0xe14 /* clear out reserved bits and M */ - andc r1,r3,r1 /* PP = user? (rw&dirty? 2: 3): 0 */ - mtspr SPRN_RPA,r1 - mfspr r3,SPRN_IMISS - tlbli r3 - mfspr r3,SPRN_SRR1 /* Need to restore CR0 */ - mtcrf 0x80,r3 - rfi -InstructionAddressInvalid: - mfspr r3,SPRN_SRR1 - rlwinm r1,r3,9,6,6 /* Get load/store bit */ - - addis r1,r1,0x2000 - mtspr SPRN_DSISR,r1 /* (shouldn't be needed) */ - mtctr r0 /* Restore CTR */ - andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */ - or r2,r2,r1 - mtspr SPRN_SRR1,r2 - mfspr r1,SPRN_IMISS /* Get failing address */ - rlwinm. r2,r2,0,31,31 /* Check for little endian access */ - rlwimi r2,r2,1,30,30 /* change 1 -> 3 */ - xor r1,r1,r2 - mtspr SPRN_DAR,r1 /* Set fault address */ - mfmsr r0 /* Restore "normal" registers */ - xoris r0,r0,MSR_TGPR>>16 - mtcrf 0x80,r3 /* Restore CR0 */ - mtmsr r0 - b InstructionAccess - -/* - * Handle TLB miss for DATA Load operation on 603/603e - */ - . = 0x1100 -DataLoadTLBMiss: -/* - * r0: stored ctr - * r1: linux style pte ( later becomes ppc hardware pte ) - * r2: ptr to linux-style pte - * r3: scratch - */ - mfctr r0 - /* Get PTE (linux-style) and check access */ - mfspr r3,SPRN_DMISS - lis r1,KERNELBASE@h /* check if kernel address */ - cmplw 0,r3,r1 - mfspr r2,SPRN_SPRG3 - li r1,_PAGE_USER|_PAGE_PRESENT /* low addresses tested as user */ - lwz r2,PGDIR(r2) - blt+ 112f - lis r2,swapper_pg_dir@ha /* if kernel address, use */ - addi r2,r2,swapper_pg_dir@l /* kernel page table */ - mfspr r1,SPRN_SRR1 /* and MSR_PR bit from SRR1 */ - rlwinm r1,r1,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ -112: tophys(r2,r2) - rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ - lwz r2,0(r2) /* get pmd entry */ - rlwinm. r2,r2,0,0,19 /* extract address of pte page */ - beq- DataAddressInvalid /* return if no mapping */ - rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ - lwz r3,0(r2) /* get linux-style pte */ - andc. r1,r1,r3 /* check access & ~permission */ - bne- DataAddressInvalid /* return if access not permitted */ - ori r3,r3,_PAGE_ACCESSED /* set _PAGE_ACCESSED in pte */ - /* - * NOTE! We are assuming this is not an SMP system, otherwise - * we would need to update the pte atomically with lwarx/stwcx. - */ - stw r3,0(r2) /* update PTE (accessed bit) */ - /* Convert linux-style PTE to low word of PPC-style PTE */ - rlwinm r1,r3,32-10,31,31 /* _PAGE_RW -> PP lsb */ - rlwinm r2,r3,32-7,31,31 /* _PAGE_DIRTY -> PP lsb */ - and r1,r1,r2 /* writable if _RW and _DIRTY */ - rlwimi r3,r3,32-1,30,30 /* _PAGE_USER -> PP msb */ - rlwimi r3,r3,32-1,31,31 /* _PAGE_USER -> PP lsb */ - ori r1,r1,0xe14 /* clear out reserved bits and M */ - andc r1,r3,r1 /* PP = user? (rw&dirty? 2: 3): 0 */ - mtspr SPRN_RPA,r1 - mfspr r3,SPRN_DMISS - tlbld r3 - mfspr r3,SPRN_SRR1 /* Need to restore CR0 */ - mtcrf 0x80,r3 - rfi -DataAddressInvalid: - mfspr r3,SPRN_SRR1 - rlwinm r1,r3,9,6,6 /* Get load/store bit */ - addis r1,r1,0x2000 - mtspr SPRN_DSISR,r1 - mtctr r0 /* Restore CTR */ - andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */ - mtspr SPRN_SRR1,r2 - mfspr r1,SPRN_DMISS /* Get failing address */ - rlwinm. r2,r2,0,31,31 /* Check for little endian access */ - beq 20f /* Jump if big endian */ - xori r1,r1,3 -20: mtspr SPRN_DAR,r1 /* Set fault address */ - mfmsr r0 /* Restore "normal" registers */ - xoris r0,r0,MSR_TGPR>>16 - mtcrf 0x80,r3 /* Restore CR0 */ - mtmsr r0 - b DataAccess - -/* - * Handle TLB miss for DATA Store on 603/603e - */ - . = 0x1200 -DataStoreTLBMiss: -/* - * r0: stored ctr - * r1: linux style pte ( later becomes ppc hardware pte ) - * r2: ptr to linux-style pte - * r3: scratch - */ - mfctr r0 - /* Get PTE (linux-style) and check access */ - mfspr r3,SPRN_DMISS - lis r1,KERNELBASE@h /* check if kernel address */ - cmplw 0,r3,r1 - mfspr r2,SPRN_SPRG3 - li r1,_PAGE_RW|_PAGE_USER|_PAGE_PRESENT /* access flags */ - lwz r2,PGDIR(r2) - blt+ 112f - lis r2,swapper_pg_dir@ha /* if kernel address, use */ - addi r2,r2,swapper_pg_dir@l /* kernel page table */ - mfspr r1,SPRN_SRR1 /* and MSR_PR bit from SRR1 */ - rlwinm r1,r1,32-12,29,29 /* shift MSR_PR to _PAGE_USER posn */ -112: tophys(r2,r2) - rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ - lwz r2,0(r2) /* get pmd entry */ - rlwinm. r2,r2,0,0,19 /* extract address of pte page */ - beq- DataAddressInvalid /* return if no mapping */ - rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ - lwz r3,0(r2) /* get linux-style pte */ - andc. r1,r1,r3 /* check access & ~permission */ - bne- DataAddressInvalid /* return if access not permitted */ - ori r3,r3,_PAGE_ACCESSED|_PAGE_DIRTY - /* - * NOTE! We are assuming this is not an SMP system, otherwise - * we would need to update the pte atomically with lwarx/stwcx. - */ - stw r3,0(r2) /* update PTE (accessed/dirty bits) */ - /* Convert linux-style PTE to low word of PPC-style PTE */ - rlwimi r3,r3,32-1,30,30 /* _PAGE_USER -> PP msb */ - li r1,0xe15 /* clear out reserved bits and M */ - andc r1,r3,r1 /* PP = user? 2: 0 */ - mtspr SPRN_RPA,r1 - mfspr r3,SPRN_DMISS - tlbld r3 - mfspr r3,SPRN_SRR1 /* Need to restore CR0 */ - mtcrf 0x80,r3 - rfi - -#ifndef CONFIG_ALTIVEC -#define altivec_assist_exception unknown_exception -#endif - - EXCEPTION(0x1300, Trap_13, instruction_breakpoint_exception, EXC_XFER_EE) - EXCEPTION(0x1400, SMI, SMIException, EXC_XFER_EE) - EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1600, Trap_16, altivec_assist_exception, EXC_XFER_EE) - EXCEPTION(0x1700, Trap_17, TAUException, EXC_XFER_STD) - EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1a00, Trap_1a, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1b00, Trap_1b, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1c00, Trap_1c, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1d00, Trap_1d, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1e00, Trap_1e, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1f00, Trap_1f, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x2000, RunMode, RunModeException, EXC_XFER_EE) - EXCEPTION(0x2100, Trap_21, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x2200, Trap_22, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x2300, Trap_23, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x2400, Trap_24, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x2500, Trap_25, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x2600, Trap_26, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x2700, Trap_27, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x2800, Trap_28, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x2900, Trap_29, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x2a00, Trap_2a, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x2b00, Trap_2b, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x2c00, Trap_2c, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x2d00, Trap_2d, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x2e00, Trap_2e, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x2f00, MOLTrampoline, unknown_exception, EXC_XFER_EE_LITE) - - .globl mol_trampoline - .set mol_trampoline, i0x2f00 - - . = 0x3000 - -AltiVecUnavailable: - EXCEPTION_PROLOG -#ifdef CONFIG_ALTIVEC - bne load_up_altivec /* if from user, just load it up */ -#endif /* CONFIG_ALTIVEC */ - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE_LITE(0xf20, altivec_unavailable_exception) - -#ifdef CONFIG_ALTIVEC -/* Note that the AltiVec support is closely modeled after the FP - * support. Changes to one are likely to be applicable to the - * other! */ -load_up_altivec: -/* - * Disable AltiVec for the task which had AltiVec previously, - * and save its AltiVec registers in its thread_struct. - * Enables AltiVec for use in the kernel on return. - * On SMP we know the AltiVec units are free, since we give it up every - * switch. -- Kumar - */ - mfmsr r5 - oris r5,r5,MSR_VEC@h - MTMSRD(r5) /* enable use of AltiVec now */ - isync -/* - * For SMP, we don't do lazy AltiVec switching because it just gets too - * horrendously complex, especially when a task switches from one CPU - * to another. Instead we call giveup_altivec in switch_to. - */ -#ifndef CONFIG_SMP - tophys(r6,0) - addis r3,r6,last_task_used_altivec@ha - lwz r4,last_task_used_altivec@l(r3) - cmpwi 0,r4,0 - beq 1f - add r4,r4,r6 - addi r4,r4,THREAD /* want THREAD of last_task_used_altivec */ - SAVE_32VRS(0,r10,r4) - mfvscr vr0 - li r10,THREAD_VSCR - stvx vr0,r10,r4 - lwz r5,PT_REGS(r4) - add r5,r5,r6 - lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) - lis r10,MSR_VEC@h - andc r4,r4,r10 /* disable altivec for previous task */ - stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) -1: -#endif /* CONFIG_SMP */ - /* enable use of AltiVec after return */ - oris r9,r9,MSR_VEC@h - mfspr r5,SPRN_SPRG3 /* current task's THREAD (phys) */ - li r4,1 - li r10,THREAD_VSCR - stw r4,THREAD_USED_VR(r5) - lvx vr0,r10,r5 - mtvscr vr0 - REST_32VRS(0,r10,r5) -#ifndef CONFIG_SMP - subi r4,r5,THREAD - sub r4,r4,r6 - stw r4,last_task_used_altivec@l(r3) -#endif /* CONFIG_SMP */ - /* restore registers and return */ - /* we haven't used ctr or xer or lr */ - b fast_exception_return - -/* - * giveup_altivec(tsk) - * Disable AltiVec for the task given as the argument, - * and save the AltiVec registers in its thread_struct. - * Enables AltiVec for use in the kernel on return. - */ - - .globl giveup_altivec -giveup_altivec: - mfmsr r5 - oris r5,r5,MSR_VEC@h - SYNC - MTMSRD(r5) /* enable use of AltiVec now */ - isync - cmpwi 0,r3,0 - beqlr- /* if no previous owner, done */ - addi r3,r3,THREAD /* want THREAD of task */ - lwz r5,PT_REGS(r3) - cmpwi 0,r5,0 - SAVE_32VRS(0, r4, r3) - mfvscr vr0 - li r4,THREAD_VSCR - stvx vr0,r4,r3 - beq 1f - lwz r4,_MSR-STACK_FRAME_OVERHEAD(r5) - lis r3,MSR_VEC@h - andc r4,r4,r3 /* disable AltiVec for previous task */ - stw r4,_MSR-STACK_FRAME_OVERHEAD(r5) -1: -#ifndef CONFIG_SMP - li r5,0 - lis r4,last_task_used_altivec@ha - stw r5,last_task_used_altivec@l(r4) -#endif /* CONFIG_SMP */ - blr -#endif /* CONFIG_ALTIVEC */ - -/* - * This code is jumped to from the startup code to copy - * the kernel image to physical address 0. - */ -relocate_kernel: - addis r9,r26,klimit@ha /* fetch klimit */ - lwz r25,klimit@l(r9) - addis r25,r25,-KERNELBASE@h - li r3,0 /* Destination base address */ - li r6,0 /* Destination offset */ - li r5,0x4000 /* # bytes of memory to copy */ - bl copy_and_flush /* copy the first 0x4000 bytes */ - addi r0,r3,4f@l /* jump to the address of 4f */ - mtctr r0 /* in copy and do the rest. */ - bctr /* jump to the copy */ -4: mr r5,r25 - bl copy_and_flush /* copy the rest */ - b turn_on_mmu - -/* - * Copy routine used to copy the kernel to start at physical address 0 - * and flush and invalidate the caches as needed. - * r3 = dest addr, r4 = source addr, r5 = copy limit, r6 = start offset - * on exit, r3, r4, r5 are unchanged, r6 is updated to be >= r5. - */ -copy_and_flush: - addi r5,r5,-4 - addi r6,r6,-4 -4: li r0,L1_CACHE_BYTES/4 - mtctr r0 -3: addi r6,r6,4 /* copy a cache line */ - lwzx r0,r6,r4 - stwx r0,r6,r3 - bdnz 3b - dcbst r6,r3 /* write it to memory */ - sync - icbi r6,r3 /* flush the icache line */ - cmplw 0,r6,r5 - blt 4b - sync /* additional sync needed on g4 */ - isync - addi r5,r5,4 - addi r6,r6,4 - blr - -#ifdef CONFIG_SMP - .globl __secondary_start_pmac_0 -__secondary_start_pmac_0: - /* NB the entries for cpus 0, 1, 2 must each occupy 8 bytes. */ - li r24,0 - b 1f - li r24,1 - b 1f - li r24,2 - b 1f - li r24,3 -1: - /* on powersurge, we come in here with IR=0 and DR=1, and DBAT 0 - set to map the 0xf0000000 - 0xffffffff region */ - mfmsr r0 - rlwinm r0,r0,0,28,26 /* clear DR (0x10) */ - SYNC - mtmsr r0 - isync - - .globl __secondary_start -__secondary_start: - /* Copy some CPU settings from CPU 0 */ - bl __restore_cpu_setup - - lis r3,-KERNELBASE@h - mr r4,r24 - bl call_setup_cpu /* Call setup_cpu for this CPU */ -#ifdef CONFIG_6xx - lis r3,-KERNELBASE@h - bl init_idle_6xx -#endif /* CONFIG_6xx */ - - /* get current_thread_info and current */ - lis r1,secondary_ti@ha - tophys(r1,r1) - lwz r1,secondary_ti@l(r1) - tophys(r2,r1) - lwz r2,TI_TASK(r2) - - /* stack */ - addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD - li r0,0 - tophys(r3,r1) - stw r0,0(r3) - - /* load up the MMU */ - bl load_up_mmu - - /* ptr to phys current thread */ - tophys(r4,r2) - addi r4,r4,THREAD /* phys address of our thread_struct */ - CLR_TOP32(r4) - mtspr SPRN_SPRG3,r4 - li r3,0 - mtspr SPRN_SPRG2,r3 /* 0 => not in RTAS */ - - /* enable MMU and jump to start_secondary */ - li r4,MSR_KERNEL - FIX_SRR1(r4,r5) - lis r3,start_secondary@h - ori r3,r3,start_secondary@l - mtspr SPRN_SRR0,r3 - mtspr SPRN_SRR1,r4 - SYNC - RFI -#endif /* CONFIG_SMP */ - -/* - * Those generic dummy functions are kept for CPUs not - * included in CONFIG_6xx - */ -#if !defined(CONFIG_6xx) -_GLOBAL(__save_cpu_setup) - blr -_GLOBAL(__restore_cpu_setup) - blr -#endif /* !defined(CONFIG_6xx) */ - - -/* - * Load stuff into the MMU. Intended to be called with - * IR=0 and DR=0. - */ -load_up_mmu: - sync /* Force all PTE updates to finish */ - isync - tlbia /* Clear all TLB entries */ - sync /* wait for tlbia/tlbie to finish */ - TLBSYNC /* ... on all CPUs */ - /* Load the SDR1 register (hash table base & size) */ - lis r6,_SDR1@ha - tophys(r6,r6) - lwz r6,_SDR1@l(r6) - mtspr SPRN_SDR1,r6 - li r0,16 /* load up segment register values */ - mtctr r0 /* for context 0 */ - lis r3,0x2000 /* Ku = 1, VSID = 0 */ - li r4,0 -3: mtsrin r3,r4 - addi r3,r3,0x111 /* increment VSID */ - addis r4,r4,0x1000 /* address of next segment */ - bdnz 3b - -/* Load the BAT registers with the values set up by MMU_init. - MMU_init takes care of whether we're on a 601 or not. */ - mfpvr r3 - srwi r3,r3,16 - cmpwi r3,1 - lis r3,BATS@ha - addi r3,r3,BATS@l - tophys(r3,r3) - LOAD_BAT(0,r3,r4,r5) - LOAD_BAT(1,r3,r4,r5) - LOAD_BAT(2,r3,r4,r5) - LOAD_BAT(3,r3,r4,r5) - - blr - -/* - * This is where the main kernel code starts. - */ -start_here: - /* ptr to current */ - lis r2,init_task@h - ori r2,r2,init_task@l - /* Set up for using our exception vectors */ - /* ptr to phys current thread */ - tophys(r4,r2) - addi r4,r4,THREAD /* init task's THREAD */ - CLR_TOP32(r4) - mtspr SPRN_SPRG3,r4 - li r3,0 - mtspr SPRN_SPRG2,r3 /* 0 => not in RTAS */ - - /* stack */ - lis r1,init_thread_union@ha - addi r1,r1,init_thread_union@l - li r0,0 - stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1) -/* - * Do early bootinfo parsing, platform-specific initialization, - * and set up the MMU. - */ - mr r3,r31 - mr r4,r30 - mr r5,r29 - mr r6,r28 - mr r7,r27 - bl machine_init - bl MMU_init - -/* - * Go back to running unmapped so we can load up new values - * for SDR1 (hash table pointer) and the segment registers - * and change to using our exception vectors. - */ - lis r4,2f@h - ori r4,r4,2f@l - tophys(r4,r4) - li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) - FIX_SRR1(r3,r5) - mtspr SPRN_SRR0,r4 - mtspr SPRN_SRR1,r3 - SYNC - RFI -/* Load up the kernel context */ -2: bl load_up_mmu - -#ifdef CONFIG_BDI_SWITCH - /* Add helper information for the Abatron bdiGDB debugger. - * We do this here because we know the mmu is disabled, and - * will be enabled for real in just a few instructions. - */ - lis r5, abatron_pteptrs@h - ori r5, r5, abatron_pteptrs@l - stw r5, 0xf0(r0) /* This much match your Abatron config */ - lis r6, swapper_pg_dir@h - ori r6, r6, swapper_pg_dir@l - tophys(r5, r5) - stw r6, 0(r5) -#endif /* CONFIG_BDI_SWITCH */ - -/* Now turn on the MMU for real! */ - li r4,MSR_KERNEL - FIX_SRR1(r4,r5) - lis r3,start_kernel@h - ori r3,r3,start_kernel@l - mtspr SPRN_SRR0,r3 - mtspr SPRN_SRR1,r4 - SYNC - RFI - -/* - * Set up the segment registers for a new context. - */ -_GLOBAL(set_context) - mulli r3,r3,897 /* multiply context by skew factor */ - rlwinm r3,r3,4,8,27 /* VSID = (context & 0xfffff) << 4 */ - addis r3,r3,0x6000 /* Set Ks, Ku bits */ - li r0,NUM_USER_SEGMENTS - mtctr r0 - -#ifdef CONFIG_BDI_SWITCH - /* Context switch the PTE pointer for the Abatron BDI2000. - * The PGDIR is passed as second argument. - */ - lis r5, KERNELBASE@h - lwz r5, 0xf0(r5) - stw r4, 0x4(r5) -#endif - li r4,0 - isync -3: - mtsrin r3,r4 - addi r3,r3,0x111 /* next VSID */ - rlwinm r3,r3,0,8,3 /* clear out any overflow from VSID field */ - addis r4,r4,0x1000 /* address of next segment */ - bdnz 3b - sync - isync - blr - -/* - * An undocumented "feature" of 604e requires that the v bit - * be cleared before changing BAT values. - * - * Also, newer IBM firmware does not clear bat3 and 4 so - * this makes sure it's done. - * -- Cort - */ -clear_bats: - li r10,0 - mfspr r9,SPRN_PVR - rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ - cmpwi r9, 1 - beq 1f - - mtspr SPRN_DBAT0U,r10 - mtspr SPRN_DBAT0L,r10 - mtspr SPRN_DBAT1U,r10 - mtspr SPRN_DBAT1L,r10 - mtspr SPRN_DBAT2U,r10 - mtspr SPRN_DBAT2L,r10 - mtspr SPRN_DBAT3U,r10 - mtspr SPRN_DBAT3L,r10 -1: - mtspr SPRN_IBAT0U,r10 - mtspr SPRN_IBAT0L,r10 - mtspr SPRN_IBAT1U,r10 - mtspr SPRN_IBAT1L,r10 - mtspr SPRN_IBAT2U,r10 - mtspr SPRN_IBAT2L,r10 - mtspr SPRN_IBAT3U,r10 - mtspr SPRN_IBAT3L,r10 -BEGIN_FTR_SECTION - /* Here's a tweak: at this point, CPU setup have - * not been called yet, so HIGH_BAT_EN may not be - * set in HID0 for the 745x processors. However, it - * seems that doesn't affect our ability to actually - * write to these SPRs. - */ - mtspr SPRN_DBAT4U,r10 - mtspr SPRN_DBAT4L,r10 - mtspr SPRN_DBAT5U,r10 - mtspr SPRN_DBAT5L,r10 - mtspr SPRN_DBAT6U,r10 - mtspr SPRN_DBAT6L,r10 - mtspr SPRN_DBAT7U,r10 - mtspr SPRN_DBAT7L,r10 - mtspr SPRN_IBAT4U,r10 - mtspr SPRN_IBAT4L,r10 - mtspr SPRN_IBAT5U,r10 - mtspr SPRN_IBAT5L,r10 - mtspr SPRN_IBAT6U,r10 - mtspr SPRN_IBAT6L,r10 - mtspr SPRN_IBAT7U,r10 - mtspr SPRN_IBAT7L,r10 -END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS) - blr - -flush_tlbs: - lis r10, 0x40 -1: addic. r10, r10, -0x1000 - tlbie r10 - blt 1b - sync - blr - -mmu_off: - addi r4, r3, __after_mmu_off - _start - mfmsr r3 - andi. r0,r3,MSR_DR|MSR_IR /* MMU enabled? */ - beqlr - andc r3,r3,r0 - mtspr SPRN_SRR0,r4 - mtspr SPRN_SRR1,r3 - sync - RFI - -/* - * Use the first pair of BAT registers to map the 1st 16MB - * of RAM to KERNELBASE. From this point on we can't safely - * call OF any more. - */ -initial_bats: - lis r11,KERNELBASE@h - mfspr r9,SPRN_PVR - rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ - cmpwi 0,r9,1 - bne 4f - ori r11,r11,4 /* set up BAT registers for 601 */ - li r8,0x7f /* valid, block length = 8MB */ - oris r9,r11,0x800000@h /* set up BAT reg for 2nd 8M */ - oris r10,r8,0x800000@h /* set up BAT reg for 2nd 8M */ - mtspr SPRN_IBAT0U,r11 /* N.B. 601 has valid bit in */ - mtspr SPRN_IBAT0L,r8 /* lower BAT register */ - mtspr SPRN_IBAT1U,r9 - mtspr SPRN_IBAT1L,r10 - isync - blr - -4: tophys(r8,r11) -#ifdef CONFIG_SMP - ori r8,r8,0x12 /* R/W access, M=1 */ -#else - ori r8,r8,2 /* R/W access */ -#endif /* CONFIG_SMP */ - ori r11,r11,BL_256M<<2|0x2 /* set up BAT registers for 604 */ - - mtspr SPRN_DBAT0L,r8 /* N.B. 6xx (not 601) have valid */ - mtspr SPRN_DBAT0U,r11 /* bit in upper BAT register */ - mtspr SPRN_IBAT0L,r8 - mtspr SPRN_IBAT0U,r11 - isync - blr - -#ifdef CONFIG_BOOTX_TEXT -setup_disp_bat: - /* - * setup the display bat prepared for us in prom.c - */ - mflr r8 - bl reloc_offset - mtlr r8 - addis r8,r3,disp_BAT@ha - addi r8,r8,disp_BAT@l - lwz r11,0(r8) - lwz r8,4(r8) - mfspr r9,SPRN_PVR - rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */ - cmpwi 0,r9,1 - beq 1f - mtspr SPRN_DBAT3L,r8 - mtspr SPRN_DBAT3U,r11 - blr -1: mtspr SPRN_IBAT3L,r8 - mtspr SPRN_IBAT3U,r11 - blr - -#endif /* defined(CONFIG_BOOTX_TEXT) */ - -#ifdef CONFIG_8260 -/* Jump into the system reset for the rom. - * We first disable the MMU, and then jump to the ROM reset address. - * - * r3 is the board info structure, r4 is the location for starting. - * I use this for building a small kernel that can load other kernels, - * rather than trying to write or rely on a rom monitor that can tftp load. - */ - .globl m8260_gorom -m8260_gorom: - mfmsr r0 - rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ - sync - mtmsr r0 - sync - mfspr r11, SPRN_HID0 - lis r10, 0 - ori r10,r10,HID0_ICE|HID0_DCE - andc r11, r11, r10 - mtspr SPRN_HID0, r11 - isync - li r5, MSR_ME|MSR_RI - lis r6,2f@h - addis r6,r6,-KERNELBASE@h - ori r6,r6,2f@l - mtspr SPRN_SRR0,r6 - mtspr SPRN_SRR1,r5 - isync - sync - rfi -2: - mtlr r4 - blr -#endif - - -/* - * We put a few things here that have to be page-aligned. - * This stuff goes at the beginning of the data segment, - * which is page-aligned. - */ - .data - .globl sdata -sdata: - .globl empty_zero_page -empty_zero_page: - .space 4096 - - .globl swapper_pg_dir -swapper_pg_dir: - .space 4096 - -/* - * This space gets a copy of optional info passed to us by the bootstrap - * Used to pass parameters into the kernel like root=/dev/sda1, etc. - */ - .globl cmd_line -cmd_line: - .space 512 - - .globl intercept_table -intercept_table: - .long 0, 0, i0x200, i0x300, i0x400, 0, i0x600, i0x700 - .long i0x800, 0, 0, 0, 0, i0xd00, 0, 0 - .long 0, 0, 0, i0x1300, 0, 0, 0, 0 - .long 0, 0, 0, 0, 0, 0, 0, 0 - .long 0, 0, 0, 0, 0, 0, 0, 0 - .long 0, 0, 0, 0, 0, 0, 0, 0 - -/* Room for two PTE pointers, usually the kernel and current user pointers - * to their respective root page table. - */ -abatron_pteptrs: - .space 8 diff --git a/arch/ppc/kernel/head_44x.S b/arch/ppc/kernel/head_44x.S deleted file mode 100644 index ebb5a403829..00000000000 --- a/arch/ppc/kernel/head_44x.S +++ /dev/null @@ -1,769 +0,0 @@ -/* - * Kernel execution entry point code. - * - * Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org> - * Initial PowerPC version. - * Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu> - * Rewritten for PReP - * Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au> - * Low-level exception handers, MMU support, and rewrite. - * Copyright (c) 1997 Dan Malek <dmalek@jlc.net> - * PowerPC 8xx modifications. - * Copyright (c) 1998-1999 TiVo, Inc. - * PowerPC 403GCX modifications. - * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> - * PowerPC 403GCX/405GP modifications. - * Copyright 2000 MontaVista Software Inc. - * PPC405 modifications - * PowerPC 403GCX/405GP modifications. - * Author: MontaVista Software, Inc. - * frank_rowand@mvista.com or source@mvista.com - * debbie_chu@mvista.com - * Copyright 2002-2005 MontaVista Software, Inc. - * PowerPC 44x support, Matt Porter <mporter@kernel.crashing.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include <asm/processor.h> -#include <asm/page.h> -#include <asm/mmu.h> -#include <asm/pgtable.h> -#include <asm/ibm4xx.h> -#include <asm/ibm44x.h> -#include <asm/cputable.h> -#include <asm/thread_info.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> -#include "head_booke.h" - - -/* As with the other PowerPC ports, it is expected that when code - * execution begins here, the following registers contain valid, yet - * optional, information: - * - * r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.) - * r4 - Starting address of the init RAM disk - * r5 - Ending address of the init RAM disk - * r6 - Start of kernel command line string (e.g. "mem=128") - * r7 - End of kernel command line string - * - */ - .text -_GLOBAL(_stext) -_GLOBAL(_start) - /* - * Reserve a word at a fixed location to store the address - * of abatron_pteptrs - */ - nop -/* - * Save parameters we are passed - */ - mr r31,r3 - mr r30,r4 - mr r29,r5 - mr r28,r6 - mr r27,r7 - li r24,0 /* CPU number */ - -/* - * Set up the initial MMU state - * - * We are still executing code at the virtual address - * mappings set by the firmware for the base of RAM. - * - * We first invalidate all TLB entries but the one - * we are running from. We then load the KERNELBASE - * mappings so we can begin to use kernel addresses - * natively and so the interrupt vector locations are - * permanently pinned (necessary since Book E - * implementations always have translation enabled). - * - * TODO: Use the known TLB entry we are running from to - * determine which physical region we are located - * in. This can be used to determine where in RAM - * (on a shared CPU system) or PCI memory space - * (on a DRAMless system) we are located. - * For now, we assume a perfect world which means - * we are located at the base of DRAM (physical 0). - */ - -/* - * Search TLB for entry that we are currently using. - * Invalidate all entries but the one we are using. - */ - /* Load our current PID->MMUCR TID and MSR IS->MMUCR STS */ - mfspr r3,SPRN_PID /* Get PID */ - mfmsr r4 /* Get MSR */ - andi. r4,r4,MSR_IS@l /* TS=1? */ - beq wmmucr /* If not, leave STS=0 */ - oris r3,r3,PPC44x_MMUCR_STS@h /* Set STS=1 */ -wmmucr: mtspr SPRN_MMUCR,r3 /* Put MMUCR */ - sync - - bl invstr /* Find our address */ -invstr: mflr r5 /* Make it accessible */ - tlbsx r23,0,r5 /* Find entry we are in */ - li r4,0 /* Start at TLB entry 0 */ - li r3,0 /* Set PAGEID inval value */ -1: cmpw r23,r4 /* Is this our entry? */ - beq skpinv /* If so, skip the inval */ - tlbwe r3,r4,PPC44x_TLB_PAGEID /* If not, inval the entry */ -skpinv: addi r4,r4,1 /* Increment */ - cmpwi r4,64 /* Are we done? */ - bne 1b /* If not, repeat */ - isync /* If so, context change */ - -/* - * Configure and load pinned entry into TLB slot 63. - */ - - lis r3,KERNELBASE@h /* Load the kernel virtual address */ - ori r3,r3,KERNELBASE@l - - /* Kernel is at the base of RAM */ - li r4, 0 /* Load the kernel physical address */ - - /* Load the kernel PID = 0 */ - li r0,0 - mtspr SPRN_PID,r0 - sync - - /* Initialize MMUCR */ - li r5,0 - mtspr SPRN_MMUCR,r5 - sync - - /* pageid fields */ - clrrwi r3,r3,10 /* Mask off the effective page number */ - ori r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_256M - - /* xlat fields */ - clrrwi r4,r4,10 /* Mask off the real page number */ - /* ERPN is 0 for first 4GB page */ - - /* attrib fields */ - /* Added guarded bit to protect against speculative loads/stores */ - li r5,0 - ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G) - - li r0,63 /* TLB slot 63 */ - - tlbwe r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */ - tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */ - tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */ - - /* Force context change */ - mfmsr r0 - mtspr SPRN_SRR1, r0 - lis r0,3f@h - ori r0,r0,3f@l - mtspr SPRN_SRR0,r0 - sync - rfi - - /* If necessary, invalidate original entry we used */ -3: cmpwi r23,63 - beq 4f - li r6,0 - tlbwe r6,r23,PPC44x_TLB_PAGEID - isync - -4: -#ifdef CONFIG_SERIAL_TEXT_DEBUG - /* - * Add temporary UART mapping for early debug. - * We can map UART registers wherever we want as long as they don't - * interfere with other system mappings (e.g. with pinned entries). - * For an example of how we handle this - see ocotea.h. --ebs - */ - /* pageid fields */ - lis r3,UART0_IO_BASE@h - ori r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_4K - - /* xlat fields */ - lis r4,UART0_PHYS_IO_BASE@h /* RPN depends on SoC */ -#ifdef UART0_PHYS_ERPN - ori r4,r4,UART0_PHYS_ERPN /* Add ERPN if above 4GB */ -#endif - - /* attrib fields */ - li r5,0 - ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_I | PPC44x_TLB_G) - - li r0,62 /* TLB slot 62 */ - - tlbwe r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */ - tlbwe r4,r0,PPC44x_TLB_XLAT /* Load the translation fields */ - tlbwe r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */ - - /* Force context change */ - isync -#endif /* CONFIG_SERIAL_TEXT_DEBUG */ - - /* Establish the interrupt vector offsets */ - SET_IVOR(0, CriticalInput); - SET_IVOR(1, MachineCheck); - SET_IVOR(2, DataStorage); - SET_IVOR(3, InstructionStorage); - SET_IVOR(4, ExternalInput); - SET_IVOR(5, Alignment); - SET_IVOR(6, Program); - SET_IVOR(7, FloatingPointUnavailable); - SET_IVOR(8, SystemCall); - SET_IVOR(9, AuxillaryProcessorUnavailable); - SET_IVOR(10, Decrementer); - SET_IVOR(11, FixedIntervalTimer); - SET_IVOR(12, WatchdogTimer); - SET_IVOR(13, DataTLBError); - SET_IVOR(14, InstructionTLBError); - SET_IVOR(15, Debug); - - /* Establish the interrupt vector base */ - lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ - mtspr SPRN_IVPR,r4 - - /* - * This is where the main kernel code starts. - */ - - /* ptr to current */ - lis r2,init_task@h - ori r2,r2,init_task@l - - /* ptr to current thread */ - addi r4,r2,THREAD /* init task's THREAD */ - mtspr SPRN_SPRG3,r4 - - /* stack */ - lis r1,init_thread_union@h - ori r1,r1,init_thread_union@l - li r0,0 - stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1) - - bl early_init - -/* - * Decide what sort of machine this is and initialize the MMU. - */ - mr r3,r31 - mr r4,r30 - mr r5,r29 - mr r6,r28 - mr r7,r27 - bl machine_init - bl MMU_init - - /* Setup PTE pointers for the Abatron bdiGDB */ - lis r6, swapper_pg_dir@h - ori r6, r6, swapper_pg_dir@l - lis r5, abatron_pteptrs@h - ori r5, r5, abatron_pteptrs@l - lis r4, KERNELBASE@h - ori r4, r4, KERNELBASE@l - stw r5, 0(r4) /* Save abatron_pteptrs at a fixed location */ - stw r6, 0(r5) - - /* Let's move on */ - lis r4,start_kernel@h - ori r4,r4,start_kernel@l - lis r3,MSR_KERNEL@h - ori r3,r3,MSR_KERNEL@l - mtspr SPRN_SRR0,r4 - mtspr SPRN_SRR1,r3 - rfi /* change context and jump to start_kernel */ - -/* - * Interrupt vector entry code - * - * The Book E MMUs are always on so we don't need to handle - * interrupts in real mode as with previous PPC processors. In - * this case we handle interrupts in the kernel virtual address - * space. - * - * Interrupt vectors are dynamically placed relative to the - * interrupt prefix as determined by the address of interrupt_base. - * The interrupt vectors offsets are programmed using the labels - * for each interrupt vector entry. - * - * Interrupt vectors must be aligned on a 16 byte boundary. - * We align on a 32 byte cache line boundary for good measure. - */ - -interrupt_base: - /* Critical Input Interrupt */ - CRITICAL_EXCEPTION(0x0100, CriticalInput, unknown_exception) - - /* Machine Check Interrupt */ -#ifdef CONFIG_440A - MCHECK_EXCEPTION(0x0200, MachineCheck, machine_check_exception) -#else - CRITICAL_EXCEPTION(0x0200, MachineCheck, machine_check_exception) -#endif - - /* Data Storage Interrupt */ - START_EXCEPTION(DataStorage) - mtspr SPRN_SPRG0, r10 /* Save some working registers */ - mtspr SPRN_SPRG1, r11 - mtspr SPRN_SPRG4W, r12 - mtspr SPRN_SPRG5W, r13 - mfcr r11 - mtspr SPRN_SPRG7W, r11 - - /* - * Check if it was a store fault, if not then bail - * because a user tried to access a kernel or - * read-protected page. Otherwise, get the - * offending address and handle it. - */ - mfspr r10, SPRN_ESR - andis. r10, r10, ESR_ST@h - beq 2f - - mfspr r10, SPRN_DEAR /* Get faulting address */ - - /* If we are faulting a kernel address, we have to use the - * kernel page tables. - */ - lis r11, TASK_SIZE@h - cmplw r10, r11 - blt+ 3f - lis r11, swapper_pg_dir@h - ori r11, r11, swapper_pg_dir@l - - mfspr r12,SPRN_MMUCR - rlwinm r12,r12,0,0,23 /* Clear TID */ - - b 4f - - /* Get the PGD for the current thread */ -3: - mfspr r11,SPRN_SPRG3 - lwz r11,PGDIR(r11) - - /* Load PID into MMUCR TID */ - mfspr r12,SPRN_MMUCR /* Get MMUCR */ - mfspr r13,SPRN_PID /* Get PID */ - rlwimi r12,r13,0,24,31 /* Set TID */ - -4: - mtspr SPRN_MMUCR,r12 - - rlwinm r12, r10, 13, 19, 29 /* Compute pgdir/pmd offset */ - lwzx r11, r12, r11 /* Get pgd/pmd entry */ - rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */ - beq 2f /* Bail if no table */ - - rlwimi r12, r10, 23, 20, 28 /* Compute pte address */ - lwz r11, 4(r12) /* Get pte entry */ - - andi. r13, r11, _PAGE_RW /* Is it writeable? */ - beq 2f /* Bail if not */ - - /* Update 'changed'. - */ - ori r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE - stw r11, 4(r12) /* Update Linux page table */ - - li r13, PPC44x_TLB_SR@l /* Set SR */ - rlwimi r13, r11, 29, 29, 29 /* SX = _PAGE_HWEXEC */ - rlwimi r13, r11, 0, 30, 30 /* SW = _PAGE_RW */ - rlwimi r13, r11, 29, 28, 28 /* UR = _PAGE_USER */ - rlwimi r12, r11, 31, 26, 26 /* (_PAGE_USER>>1)->r12 */ - rlwimi r12, r11, 29, 30, 30 /* (_PAGE_USER>>3)->r12 */ - and r12, r12, r11 /* HWEXEC/RW & USER */ - rlwimi r13, r12, 0, 26, 26 /* UX = HWEXEC & USER */ - rlwimi r13, r12, 3, 27, 27 /* UW = RW & USER */ - - rlwimi r11,r13,0,26,31 /* Insert static perms */ - - rlwinm r11,r11,0,20,15 /* Clear U0-U3 */ - - /* find the TLB index that caused the fault. It has to be here. */ - tlbsx r10, 0, r10 - - tlbwe r11, r10, PPC44x_TLB_ATTRIB /* Write ATTRIB */ - - /* Done...restore registers and get out of here. - */ - mfspr r11, SPRN_SPRG7R - mtcr r11 - mfspr r13, SPRN_SPRG5R - mfspr r12, SPRN_SPRG4R - - mfspr r11, SPRN_SPRG1 - mfspr r10, SPRN_SPRG0 - rfi /* Force context change */ - -2: - /* - * The bailout. Restore registers to pre-exception conditions - * and call the heavyweights to help us out. - */ - mfspr r11, SPRN_SPRG7R - mtcr r11 - mfspr r13, SPRN_SPRG5R - mfspr r12, SPRN_SPRG4R - - mfspr r11, SPRN_SPRG1 - mfspr r10, SPRN_SPRG0 - b data_access - - /* Instruction Storage Interrupt */ - INSTRUCTION_STORAGE_EXCEPTION - - /* External Input Interrupt */ - EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE) - - /* Alignment Interrupt */ - ALIGNMENT_EXCEPTION - - /* Program Interrupt */ - PROGRAM_EXCEPTION - - /* Floating Point Unavailable Interrupt */ -#ifdef CONFIG_PPC_FPU - FP_UNAVAILABLE_EXCEPTION -#else - EXCEPTION(0x2010, FloatingPointUnavailable, unknown_exception, EXC_XFER_EE) -#endif - - /* System Call Interrupt */ - START_EXCEPTION(SystemCall) - NORMAL_EXCEPTION_PROLOG - EXC_XFER_EE_LITE(0x0c00, DoSyscall) - - /* Auxillary Processor Unavailable Interrupt */ - EXCEPTION(0x2020, AuxillaryProcessorUnavailable, unknown_exception, EXC_XFER_EE) - - /* Decrementer Interrupt */ - DECREMENTER_EXCEPTION - - /* Fixed Internal Timer Interrupt */ - /* TODO: Add FIT support */ - EXCEPTION(0x1010, FixedIntervalTimer, unknown_exception, EXC_XFER_EE) - - /* Watchdog Timer Interrupt */ - /* TODO: Add watchdog support */ -#ifdef CONFIG_BOOKE_WDT - CRITICAL_EXCEPTION(0x1020, WatchdogTimer, WatchdogException) -#else - CRITICAL_EXCEPTION(0x1020, WatchdogTimer, unknown_exception) -#endif - - /* Data TLB Error Interrupt */ - START_EXCEPTION(DataTLBError) - mtspr SPRN_SPRG0, r10 /* Save some working registers */ - mtspr SPRN_SPRG1, r11 - mtspr SPRN_SPRG4W, r12 - mtspr SPRN_SPRG5W, r13 - mfcr r11 - mtspr SPRN_SPRG7W, r11 - mfspr r10, SPRN_DEAR /* Get faulting address */ - - /* If we are faulting a kernel address, we have to use the - * kernel page tables. - */ - lis r11, TASK_SIZE@h - cmplw r10, r11 - blt+ 3f - lis r11, swapper_pg_dir@h - ori r11, r11, swapper_pg_dir@l - - mfspr r12,SPRN_MMUCR - rlwinm r12,r12,0,0,23 /* Clear TID */ - - b 4f - - /* Get the PGD for the current thread */ -3: - mfspr r11,SPRN_SPRG3 - lwz r11,PGDIR(r11) - - /* Load PID into MMUCR TID */ - mfspr r12,SPRN_MMUCR - mfspr r13,SPRN_PID /* Get PID */ - rlwimi r12,r13,0,24,31 /* Set TID */ - -4: - mtspr SPRN_MMUCR,r12 - - rlwinm r12, r10, 13, 19, 29 /* Compute pgdir/pmd offset */ - lwzx r11, r12, r11 /* Get pgd/pmd entry */ - rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */ - beq 2f /* Bail if no table */ - - rlwimi r12, r10, 23, 20, 28 /* Compute pte address */ - lwz r11, 4(r12) /* Get pte entry */ - andi. r13, r11, _PAGE_PRESENT /* Is the page present? */ - beq 2f /* Bail if not present */ - - ori r11, r11, _PAGE_ACCESSED - stw r11, 4(r12) - - /* Jump to common tlb load */ - b finish_tlb_load - -2: - /* The bailout. Restore registers to pre-exception conditions - * and call the heavyweights to help us out. - */ - mfspr r11, SPRN_SPRG7R - mtcr r11 - mfspr r13, SPRN_SPRG5R - mfspr r12, SPRN_SPRG4R - mfspr r11, SPRN_SPRG1 - mfspr r10, SPRN_SPRG0 - b data_access - - /* Instruction TLB Error Interrupt */ - /* - * Nearly the same as above, except we get our - * information from different registers and bailout - * to a different point. - */ - START_EXCEPTION(InstructionTLBError) - mtspr SPRN_SPRG0, r10 /* Save some working registers */ - mtspr SPRN_SPRG1, r11 - mtspr SPRN_SPRG4W, r12 - mtspr SPRN_SPRG5W, r13 - mfcr r11 - mtspr SPRN_SPRG7W, r11 - mfspr r10, SPRN_SRR0 /* Get faulting address */ - - /* If we are faulting a kernel address, we have to use the - * kernel page tables. - */ - lis r11, TASK_SIZE@h - cmplw r10, r11 - blt+ 3f - lis r11, swapper_pg_dir@h - ori r11, r11, swapper_pg_dir@l - - mfspr r12,SPRN_MMUCR - rlwinm r12,r12,0,0,23 /* Clear TID */ - - b 4f - - /* Get the PGD for the current thread */ -3: - mfspr r11,SPRN_SPRG3 - lwz r11,PGDIR(r11) - - /* Load PID into MMUCR TID */ - mfspr r12,SPRN_MMUCR - mfspr r13,SPRN_PID /* Get PID */ - rlwimi r12,r13,0,24,31 /* Set TID */ - -4: - mtspr SPRN_MMUCR,r12 - - rlwinm r12, r10, 13, 19, 29 /* Compute pgdir/pmd offset */ - lwzx r11, r12, r11 /* Get pgd/pmd entry */ - rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */ - beq 2f /* Bail if no table */ - - rlwimi r12, r10, 23, 20, 28 /* Compute pte address */ - lwz r11, 4(r12) /* Get pte entry */ - andi. r13, r11, _PAGE_PRESENT /* Is the page present? */ - beq 2f /* Bail if not present */ - - ori r11, r11, _PAGE_ACCESSED - stw r11, 4(r12) - - /* Jump to common TLB load point */ - b finish_tlb_load - -2: - /* The bailout. Restore registers to pre-exception conditions - * and call the heavyweights to help us out. - */ - mfspr r11, SPRN_SPRG7R - mtcr r11 - mfspr r13, SPRN_SPRG5R - mfspr r12, SPRN_SPRG4R - mfspr r11, SPRN_SPRG1 - mfspr r10, SPRN_SPRG0 - b InstructionStorage - - /* Debug Interrupt */ - DEBUG_EXCEPTION - -/* - * Local functions - */ - /* - * Data TLB exceptions will bail out to this point - * if they can't resolve the lightweight TLB fault. - */ -data_access: - NORMAL_EXCEPTION_PROLOG - mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ - stw r5,_ESR(r11) - mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ - EXC_XFER_EE_LITE(0x0300, handle_page_fault) - -/* - - * Both the instruction and data TLB miss get to this - * point to load the TLB. - * r10 - EA of fault - * r11 - available to use - * r12 - Pointer to the 64-bit PTE - * r13 - available to use - * MMUCR - loaded with proper value when we get here - * Upon exit, we reload everything and RFI. - */ -finish_tlb_load: - /* - * We set execute, because we don't have the granularity to - * properly set this at the page level (Linux problem). - * If shared is set, we cause a zero PID->TID load. - * Many of these bits are software only. Bits we don't set - * here we (properly should) assume have the appropriate value. - */ - - /* Load the next available TLB index */ - lis r13, tlb_44x_index@ha - lwz r13, tlb_44x_index@l(r13) - /* Load the TLB high watermark */ - lis r11, tlb_44x_hwater@ha - lwz r11, tlb_44x_hwater@l(r11) - - /* Increment, rollover, and store TLB index */ - addi r13, r13, 1 - cmpw 0, r13, r11 /* reserve entries */ - ble 7f - li r13, 0 -7: - /* Store the next available TLB index */ - lis r11, tlb_44x_index@ha - stw r13, tlb_44x_index@l(r11) - - lwz r11, 0(r12) /* Get MS word of PTE */ - lwz r12, 4(r12) /* Get LS word of PTE */ - rlwimi r11, r12, 0, 0 , 19 /* Insert RPN */ - tlbwe r11, r13, PPC44x_TLB_XLAT /* Write XLAT */ - - /* - * Create PAGEID. This is the faulting address, - * page size, and valid flag. - */ - li r11, PPC44x_TLB_VALID | PPC44x_TLB_4K - rlwimi r10, r11, 0, 20, 31 /* Insert valid and page size */ - tlbwe r10, r13, PPC44x_TLB_PAGEID /* Write PAGEID */ - - li r10, PPC44x_TLB_SR@l /* Set SR */ - rlwimi r10, r12, 0, 30, 30 /* Set SW = _PAGE_RW */ - rlwimi r10, r12, 29, 29, 29 /* SX = _PAGE_HWEXEC */ - rlwimi r10, r12, 29, 28, 28 /* UR = _PAGE_USER */ - rlwimi r11, r12, 31, 26, 26 /* (_PAGE_USER>>1)->r12 */ - and r11, r12, r11 /* HWEXEC & USER */ - rlwimi r10, r11, 0, 26, 26 /* UX = HWEXEC & USER */ - - rlwimi r12, r10, 0, 26, 31 /* Insert static perms */ - rlwinm r12, r12, 0, 20, 15 /* Clear U0-U3 */ - tlbwe r12, r13, PPC44x_TLB_ATTRIB /* Write ATTRIB */ - - /* Done...restore registers and get out of here. - */ - mfspr r11, SPRN_SPRG7R - mtcr r11 - mfspr r13, SPRN_SPRG5R - mfspr r12, SPRN_SPRG4R - mfspr r11, SPRN_SPRG1 - mfspr r10, SPRN_SPRG0 - rfi /* Force context change */ - -/* - * Global functions - */ - -/* - * extern void giveup_altivec(struct task_struct *prev) - * - * The 44x core does not have an AltiVec unit. - */ -_GLOBAL(giveup_altivec) - blr - -/* - * extern void giveup_fpu(struct task_struct *prev) - * - * The 44x core does not have an FPU. - */ -#ifndef CONFIG_PPC_FPU -_GLOBAL(giveup_fpu) - blr -#endif - -/* - * extern void abort(void) - * - * At present, this routine just applies a system reset. - */ -_GLOBAL(abort) - mfspr r13,SPRN_DBCR0 - oris r13,r13,DBCR0_RST_SYSTEM@h - mtspr SPRN_DBCR0,r13 - -_GLOBAL(set_context) - -#ifdef CONFIG_BDI_SWITCH - /* Context switch the PTE pointer for the Abatron BDI2000. - * The PGDIR is the second parameter. - */ - lis r5, abatron_pteptrs@h - ori r5, r5, abatron_pteptrs@l - stw r4, 0x4(r5) -#endif - mtspr SPRN_PID,r3 - isync /* Force context change */ - blr - -/* - * We put a few things here that have to be page-aligned. This stuff - * goes at the beginning of the data segment, which is page-aligned. - */ - .data - .align 12 - .globl sdata -sdata: - .globl empty_zero_page -empty_zero_page: - .space 4096 - -/* - * To support >32-bit physical addresses, we use an 8KB pgdir. - */ - .globl swapper_pg_dir -swapper_pg_dir: - .space 8192 - -/* Reserved 4k for the critical exception stack & 4k for the machine - * check stack per CPU for kernel mode exceptions */ - .section .bss - .align 12 -exception_stack_bottom: - .space BOOKE_EXCEPTION_STACK_SIZE - .globl exception_stack_top -exception_stack_top: - -/* - * This space gets a copy of optional info passed to us by the bootstrap - * which is used to pass parameters into the kernel like root=/dev/sda1, etc. - */ - .globl cmd_line -cmd_line: - .space 512 - -/* - * Room for two PTE pointers, usually the kernel and current user pointers - * to their respective root page table. - */ -abatron_pteptrs: - .space 8 diff --git a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S deleted file mode 100644 index 51da157a629..00000000000 --- a/arch/ppc/kernel/head_4xx.S +++ /dev/null @@ -1,1021 +0,0 @@ -/* - * Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org> - * Initial PowerPC version. - * Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu> - * Rewritten for PReP - * Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au> - * Low-level exception handers, MMU support, and rewrite. - * Copyright (c) 1997 Dan Malek <dmalek@jlc.net> - * PowerPC 8xx modifications. - * Copyright (c) 1998-1999 TiVo, Inc. - * PowerPC 403GCX modifications. - * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu> - * PowerPC 403GCX/405GP modifications. - * Copyright 2000 MontaVista Software Inc. - * PPC405 modifications - * PowerPC 403GCX/405GP modifications. - * Author: MontaVista Software, Inc. - * frank_rowand@mvista.com or source@mvista.com - * debbie_chu@mvista.com - * - * - * Module name: head_4xx.S - * - * Description: - * Kernel execution entry point code. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include <asm/processor.h> -#include <asm/page.h> -#include <asm/mmu.h> -#include <asm/pgtable.h> -#include <asm/ibm4xx.h> -#include <asm/cputable.h> -#include <asm/thread_info.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> - -/* As with the other PowerPC ports, it is expected that when code - * execution begins here, the following registers contain valid, yet - * optional, information: - * - * r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.) - * r4 - Starting address of the init RAM disk - * r5 - Ending address of the init RAM disk - * r6 - Start of kernel command line string (e.g. "mem=96m") - * r7 - End of kernel command line string - * - * This is all going to change RSN when we add bi_recs....... -- Dan - */ - .text -_GLOBAL(_stext) -_GLOBAL(_start) - - /* Save parameters we are passed. - */ - mr r31,r3 - mr r30,r4 - mr r29,r5 - mr r28,r6 - mr r27,r7 - - /* We have to turn on the MMU right away so we get cache modes - * set correctly. - */ - bl initial_mmu - -/* We now have the lower 16 Meg mapped into TLB entries, and the caches - * ready to work. - */ -turn_on_mmu: - lis r0,MSR_KERNEL@h - ori r0,r0,MSR_KERNEL@l - mtspr SPRN_SRR1,r0 - lis r0,start_here@h - ori r0,r0,start_here@l - mtspr SPRN_SRR0,r0 - SYNC - rfi /* enables MMU */ - b . /* prevent prefetch past rfi */ - -/* - * This area is used for temporarily saving registers during the - * critical exception prolog. - */ - . = 0xc0 -crit_save: -_GLOBAL(crit_r10) - .space 4 -_GLOBAL(crit_r11) - .space 4 - -/* - * Exception vector entry code. This code runs with address translation - * turned off (i.e. using physical addresses). We assume SPRG3 has the - * physical address of the current task thread_struct. - * Note that we have to have decremented r1 before we write to any fields - * of the exception frame, since a critical interrupt could occur at any - * time, and it will write to the area immediately below the current r1. - */ -#define NORMAL_EXCEPTION_PROLOG \ - mtspr SPRN_SPRG0,r10; /* save two registers to work with */\ - mtspr SPRN_SPRG1,r11; \ - mtspr SPRN_SPRG2,r1; \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_SRR1; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - beq 1f; \ - mfspr r1,SPRN_SPRG3; /* if from user, start at top of */\ - lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\ - addi r1,r1,THREAD_SIZE; \ -1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\ - tophys(r11,r1); \ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mfspr r10,SPRN_SPRG0; \ - stw r10,GPR10(r11); \ - mfspr r12,SPRN_SPRG1; \ - stw r12,GPR11(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r10,SPRN_SPRG2; \ - mfspr r12,SPRN_SRR0; \ - stw r10,GPR1(r11); \ - mfspr r9,SPRN_SRR1; \ - stw r10,0(r11); \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -/* - * Exception prolog for critical exceptions. This is a little different - * from the normal exception prolog above since a critical exception - * can potentially occur at any point during normal exception processing. - * Thus we cannot use the same SPRG registers as the normal prolog above. - * Instead we use a couple of words of memory at low physical addresses. - * This is OK since we don't support SMP on these processors. - */ -#define CRITICAL_EXCEPTION_PROLOG \ - stw r10,crit_r10@l(0); /* save two registers to work with */\ - stw r11,crit_r11@l(0); \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_SRR3; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - lis r11,critical_stack_top@h; \ - ori r11,r11,critical_stack_top@l; \ - beq 1f; \ - /* COMING FROM USER MODE */ \ - mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\ - lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ - addi r11,r11,THREAD_SIZE; \ -1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ - tophys(r11,r11); \ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ - stw r12,_DEAR(r11); /* since they may have had stuff */\ - mfspr r9,SPRN_ESR; /* in them at the point where the */\ - stw r9,_ESR(r11); /* exception was taken */\ - mfspr r12,SPRN_SRR2; \ - stw r1,GPR1(r11); \ - mfspr r9,SPRN_SRR3; \ - stw r1,0(r11); \ - tovirt(r1,r11); \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - - /* - * State at this point: - * r9 saved in stack frame, now saved SRR3 & ~MSR_WE - * r10 saved in crit_r10 and in stack frame, trashed - * r11 saved in crit_r11 and in stack frame, - * now phys stack/exception frame pointer - * r12 saved in stack frame, now saved SRR2 - * CR saved in stack frame, CR0.EQ = !SRR3.PR - * LR, DEAR, ESR in stack frame - * r1 saved in stack frame, now virt stack/excframe pointer - * r0, r3-r8 saved in stack frame - */ - -/* - * Exception vectors. - */ -#define START_EXCEPTION(n, label) \ - . = n; \ -label: - -#define EXCEPTION(n, label, hdlr, xfer) \ - START_EXCEPTION(n, label); \ - NORMAL_EXCEPTION_PROLOG; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - xfer(n, hdlr) - -#define CRITICAL_EXCEPTION(n, label, hdlr) \ - START_EXCEPTION(n, label); \ - CRITICAL_EXCEPTION_PROLOG; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ - NOCOPY, crit_transfer_to_handler, \ - ret_from_crit_exc) - -#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret) \ - li r10,trap; \ - stw r10,TRAP(r11); \ - lis r10,msr@h; \ - ori r10,r10,msr@l; \ - copyee(r10, r9); \ - bl tfer; \ - .long hdlr; \ - .long ret - -#define COPY_EE(d, s) rlwimi d,s,0,16,16 -#define NOCOPY(d, s) - -#define EXC_XFER_STD(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \ - ret_from_except_full) - -#define EXC_XFER_LITE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \ - ret_from_except) - -#define EXC_XFER_EE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \ - ret_from_except_full) - -#define EXC_XFER_EE_LITE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \ - ret_from_except) - - -/* - * 0x0100 - Critical Interrupt Exception - */ - CRITICAL_EXCEPTION(0x0100, CriticalInterrupt, unknown_exception) - -/* - * 0x0200 - Machine Check Exception - */ - CRITICAL_EXCEPTION(0x0200, MachineCheck, machine_check_exception) - -/* - * 0x0300 - Data Storage Exception - * This happens for just a few reasons. U0 set (but we don't do that), - * or zone protection fault (user violation, write to protected page). - * If this is just an update of modified status, we do that quickly - * and exit. Otherwise, we call heavywight functions to do the work. - */ - START_EXCEPTION(0x0300, DataStorage) - mtspr SPRN_SPRG0, r10 /* Save some working registers */ - mtspr SPRN_SPRG1, r11 -#ifdef CONFIG_403GCX - stw r12, 0(r0) - stw r9, 4(r0) - mfcr r11 - mfspr r12, SPRN_PID - stw r11, 8(r0) - stw r12, 12(r0) -#else - mtspr SPRN_SPRG4, r12 - mtspr SPRN_SPRG5, r9 - mfcr r11 - mfspr r12, SPRN_PID - mtspr SPRN_SPRG7, r11 - mtspr SPRN_SPRG6, r12 -#endif - - /* First, check if it was a zone fault (which means a user - * tried to access a kernel or read-protected page - always - * a SEGV). All other faults here must be stores, so no - * need to check ESR_DST as well. */ - mfspr r10, SPRN_ESR - andis. r10, r10, ESR_DIZ@h - bne 2f - - mfspr r10, SPRN_DEAR /* Get faulting address */ - - /* If we are faulting a kernel address, we have to use the - * kernel page tables. - */ - lis r11, TASK_SIZE@h - cmplw r10, r11 - blt+ 3f - lis r11, swapper_pg_dir@h - ori r11, r11, swapper_pg_dir@l - li r9, 0 - mtspr SPRN_PID, r9 /* TLB will have 0 TID */ - b 4f - - /* Get the PGD for the current thread. - */ -3: - mfspr r11,SPRN_SPRG3 - lwz r11,PGDIR(r11) -4: - tophys(r11, r11) - rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ - lwz r11, 0(r11) /* Get L1 entry */ - rlwinm. r12, r11, 0, 0, 19 /* Extract L2 (pte) base address */ - beq 2f /* Bail if no table */ - - rlwimi r12, r10, 22, 20, 29 /* Compute PTE address */ - lwz r11, 0(r12) /* Get Linux PTE */ - - andi. r9, r11, _PAGE_RW /* Is it writeable? */ - beq 2f /* Bail if not */ - - /* Update 'changed'. - */ - ori r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE - stw r11, 0(r12) /* Update Linux page table */ - - /* Most of the Linux PTE is ready to load into the TLB LO. - * We set ZSEL, where only the LS-bit determines user access. - * We set execute, because we don't have the granularity to - * properly set this at the page level (Linux problem). - * If shared is set, we cause a zero PID->TID load. - * Many of these bits are software only. Bits we don't set - * here we (properly should) assume have the appropriate value. - */ - li r12, 0x0ce2 - andc r11, r11, r12 /* Make sure 20, 21 are zero */ - - /* find the TLB index that caused the fault. It has to be here. - */ - tlbsx r9, 0, r10 - - tlbwe r11, r9, TLB_DATA /* Load TLB LO */ - - /* Done...restore registers and get out of here. - */ -#ifdef CONFIG_403GCX - lwz r12, 12(r0) - lwz r11, 8(r0) - mtspr SPRN_PID, r12 - mtcr r11 - lwz r9, 4(r0) - lwz r12, 0(r0) -#else - mfspr r12, SPRN_SPRG6 - mfspr r11, SPRN_SPRG7 - mtspr SPRN_PID, r12 - mtcr r11 - mfspr r9, SPRN_SPRG5 - mfspr r12, SPRN_SPRG4 -#endif - mfspr r11, SPRN_SPRG1 - mfspr r10, SPRN_SPRG0 - PPC405_ERR77_SYNC - rfi /* Should sync shadow TLBs */ - b . /* prevent prefetch past rfi */ - -2: - /* The bailout. Restore registers to pre-exception conditions - * and call the heavyweights to help us out. - */ -#ifdef CONFIG_403GCX - lwz r12, 12(r0) - lwz r11, 8(r0) - mtspr SPRN_PID, r12 - mtcr r11 - lwz r9, 4(r0) - lwz r12, 0(r0) -#else - mfspr r12, SPRN_SPRG6 - mfspr r11, SPRN_SPRG7 - mtspr SPRN_PID, r12 - mtcr r11 - mfspr r9, SPRN_SPRG5 - mfspr r12, SPRN_SPRG4 -#endif - mfspr r11, SPRN_SPRG1 - mfspr r10, SPRN_SPRG0 - b DataAccess - -/* - * 0x0400 - Instruction Storage Exception - * This is caused by a fetch from non-execute or guarded pages. - */ - START_EXCEPTION(0x0400, InstructionAccess) - NORMAL_EXCEPTION_PROLOG - mr r4,r12 /* Pass SRR0 as arg2 */ - li r5,0 /* Pass zero as arg3 */ - EXC_XFER_EE_LITE(0x400, handle_page_fault) - -/* 0x0500 - External Interrupt Exception */ - EXCEPTION(0x0500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) - -/* 0x0600 - Alignment Exception */ - START_EXCEPTION(0x0600, Alignment) - NORMAL_EXCEPTION_PROLOG - mfspr r4,SPRN_DEAR /* Grab the DEAR and save it */ - stw r4,_DEAR(r11) - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE(0x600, alignment_exception) - -/* 0x0700 - Program Exception */ - START_EXCEPTION(0x0700, ProgramCheck) - NORMAL_EXCEPTION_PROLOG - mfspr r4,SPRN_ESR /* Grab the ESR and save it */ - stw r4,_ESR(r11) - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_STD(0x700, program_check_exception) - - EXCEPTION(0x0800, Trap_08, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x0900, Trap_09, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x0A00, Trap_0A, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x0B00, Trap_0B, unknown_exception, EXC_XFER_EE) - -/* 0x0C00 - System Call Exception */ - START_EXCEPTION(0x0C00, SystemCall) - NORMAL_EXCEPTION_PROLOG - EXC_XFER_EE_LITE(0xc00, DoSyscall) - - EXCEPTION(0x0D00, Trap_0D, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x0E00, Trap_0E, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x0F00, Trap_0F, unknown_exception, EXC_XFER_EE) - -/* 0x1000 - Programmable Interval Timer (PIT) Exception */ - START_EXCEPTION(0x1000, Decrementer) - NORMAL_EXCEPTION_PROLOG - lis r0,TSR_PIS@h - mtspr SPRN_TSR,r0 /* Clear the PIT exception */ - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_LITE(0x1000, timer_interrupt) - -#if 0 -/* NOTE: - * FIT and WDT handlers are not implemented yet. - */ - -/* 0x1010 - Fixed Interval Timer (FIT) Exception -*/ - STND_EXCEPTION(0x1010, FITException, unknown_exception) - -/* 0x1020 - Watchdog Timer (WDT) Exception -*/ -#ifdef CONFIG_BOOKE_WDT - CRITICAL_EXCEPTION(0x1020, WDTException, WatchdogException) -#else - CRITICAL_EXCEPTION(0x1020, WDTException, unknown_exception) -#endif -#endif - -/* 0x1100 - Data TLB Miss Exception - * As the name implies, translation is not in the MMU, so search the - * page tables and fix it. The only purpose of this function is to - * load TLB entries from the page table if they exist. - */ - START_EXCEPTION(0x1100, DTLBMiss) - mtspr SPRN_SPRG0, r10 /* Save some working registers */ - mtspr SPRN_SPRG1, r11 -#ifdef CONFIG_403GCX - stw r12, 0(r0) - stw r9, 4(r0) - mfcr r11 - mfspr r12, SPRN_PID - stw r11, 8(r0) - stw r12, 12(r0) -#else - mtspr SPRN_SPRG4, r12 - mtspr SPRN_SPRG5, r9 - mfcr r11 - mfspr r12, SPRN_PID - mtspr SPRN_SPRG7, r11 - mtspr SPRN_SPRG6, r12 -#endif - mfspr r10, SPRN_DEAR /* Get faulting address */ - - /* If we are faulting a kernel address, we have to use the - * kernel page tables. - */ - lis r11, TASK_SIZE@h - cmplw r10, r11 - blt+ 3f - lis r11, swapper_pg_dir@h - ori r11, r11, swapper_pg_dir@l - li r9, 0 - mtspr SPRN_PID, r9 /* TLB will have 0 TID */ - b 4f - - /* Get the PGD for the current thread. - */ -3: - mfspr r11,SPRN_SPRG3 - lwz r11,PGDIR(r11) -4: - tophys(r11, r11) - rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ - lwz r12, 0(r11) /* Get L1 entry */ - andi. r9, r12, _PMD_PRESENT /* Check if it points to a PTE page */ - beq 2f /* Bail if no table */ - - rlwimi r12, r10, 22, 20, 29 /* Compute PTE address */ - lwz r11, 0(r12) /* Get Linux PTE */ - andi. r9, r11, _PAGE_PRESENT - beq 5f - - ori r11, r11, _PAGE_ACCESSED - stw r11, 0(r12) - - /* Create TLB tag. This is the faulting address plus a static - * set of bits. These are size, valid, E, U0. - */ - li r12, 0x00c0 - rlwimi r10, r12, 0, 20, 31 - - b finish_tlb_load - -2: /* Check for possible large-page pmd entry */ - rlwinm. r9, r12, 2, 22, 24 - beq 5f - - /* Create TLB tag. This is the faulting address, plus a static - * set of bits (valid, E, U0) plus the size from the PMD. - */ - ori r9, r9, 0x40 - rlwimi r10, r9, 0, 20, 31 - mr r11, r12 - - b finish_tlb_load - -5: - /* The bailout. Restore registers to pre-exception conditions - * and call the heavyweights to help us out. - */ -#ifdef CONFIG_403GCX - lwz r12, 12(r0) - lwz r11, 8(r0) - mtspr SPRN_PID, r12 - mtcr r11 - lwz r9, 4(r0) - lwz r12, 0(r0) -#else - mfspr r12, SPRN_SPRG6 - mfspr r11, SPRN_SPRG7 - mtspr SPRN_PID, r12 - mtcr r11 - mfspr r9, SPRN_SPRG5 - mfspr r12, SPRN_SPRG4 -#endif - mfspr r11, SPRN_SPRG1 - mfspr r10, SPRN_SPRG0 - b DataAccess - -/* 0x1200 - Instruction TLB Miss Exception - * Nearly the same as above, except we get our information from different - * registers and bailout to a different point. - */ - START_EXCEPTION(0x1200, ITLBMiss) - mtspr SPRN_SPRG0, r10 /* Save some working registers */ - mtspr SPRN_SPRG1, r11 -#ifdef CONFIG_403GCX - stw r12, 0(r0) - stw r9, 4(r0) - mfcr r11 - mfspr r12, SPRN_PID - stw r11, 8(r0) - stw r12, 12(r0) -#else - mtspr SPRN_SPRG4, r12 - mtspr SPRN_SPRG5, r9 - mfcr r11 - mfspr r12, SPRN_PID - mtspr SPRN_SPRG7, r11 - mtspr SPRN_SPRG6, r12 -#endif - mfspr r10, SPRN_SRR0 /* Get faulting address */ - - /* If we are faulting a kernel address, we have to use the - * kernel page tables. - */ - lis r11, TASK_SIZE@h - cmplw r10, r11 - blt+ 3f - lis r11, swapper_pg_dir@h - ori r11, r11, swapper_pg_dir@l - li r9, 0 - mtspr SPRN_PID, r9 /* TLB will have 0 TID */ - b 4f - - /* Get the PGD for the current thread. - */ -3: - mfspr r11,SPRN_SPRG3 - lwz r11,PGDIR(r11) -4: - tophys(r11, r11) - rlwimi r11, r10, 12, 20, 29 /* Create L1 (pgdir/pmd) address */ - lwz r12, 0(r11) /* Get L1 entry */ - andi. r9, r12, _PMD_PRESENT /* Check if it points to a PTE page */ - beq 2f /* Bail if no table */ - - rlwimi r12, r10, 22, 20, 29 /* Compute PTE address */ - lwz r11, 0(r12) /* Get Linux PTE */ - andi. r9, r11, _PAGE_PRESENT - beq 5f - - ori r11, r11, _PAGE_ACCESSED - stw r11, 0(r12) - - /* Create TLB tag. This is the faulting address plus a static - * set of bits. These are size, valid, E, U0. - */ - li r12, 0x00c0 - rlwimi r10, r12, 0, 20, 31 - - b finish_tlb_load - -2: /* Check for possible large-page pmd entry */ - rlwinm. r9, r12, 2, 22, 24 - beq 5f - - /* Create TLB tag. This is the faulting address, plus a static - * set of bits (valid, E, U0) plus the size from the PMD. - */ - ori r9, r9, 0x40 - rlwimi r10, r9, 0, 20, 31 - mr r11, r12 - - b finish_tlb_load - -5: - /* The bailout. Restore registers to pre-exception conditions - * and call the heavyweights to help us out. - */ -#ifdef CONFIG_403GCX - lwz r12, 12(r0) - lwz r11, 8(r0) - mtspr SPRN_PID, r12 - mtcr r11 - lwz r9, 4(r0) - lwz r12, 0(r0) -#else - mfspr r12, SPRN_SPRG6 - mfspr r11, SPRN_SPRG7 - mtspr SPRN_PID, r12 - mtcr r11 - mfspr r9, SPRN_SPRG5 - mfspr r12, SPRN_SPRG4 -#endif - mfspr r11, SPRN_SPRG1 - mfspr r10, SPRN_SPRG0 - b InstructionAccess - - EXCEPTION(0x1300, Trap_13, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1400, Trap_14, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1600, Trap_16, unknown_exception, EXC_XFER_EE) -#ifdef CONFIG_IBM405_ERR51 - /* 405GP errata 51 */ - START_EXCEPTION(0x1700, Trap_17) - b DTLBMiss -#else - EXCEPTION(0x1700, Trap_17, unknown_exception, EXC_XFER_EE) -#endif - EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1A00, Trap_1A, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1B00, Trap_1B, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1C00, Trap_1C, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1D00, Trap_1D, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1E00, Trap_1E, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1F00, Trap_1F, unknown_exception, EXC_XFER_EE) - -/* Check for a single step debug exception while in an exception - * handler before state has been saved. This is to catch the case - * where an instruction that we are trying to single step causes - * an exception (eg ITLB/DTLB miss) and thus the first instruction of - * the exception handler generates a single step debug exception. - * - * If we get a debug trap on the first instruction of an exception handler, - * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is - * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR). - * The exception handler was handling a non-critical interrupt, so it will - * save (and later restore) the MSR via SPRN_SRR1, which will still have - * the MSR_DE bit set. - */ - /* 0x2000 - Debug Exception */ - START_EXCEPTION(0x2000, DebugTrap) - CRITICAL_EXCEPTION_PROLOG - - /* - * If this is a single step or branch-taken exception in an - * exception entry sequence, it was probably meant to apply to - * the code where the exception occurred (since exception entry - * doesn't turn off DE automatically). We simulate the effect - * of turning off DE on entry to an exception handler by turning - * off DE in the SRR3 value and clearing the debug status. - */ - mfspr r10,SPRN_DBSR /* check single-step/branch taken */ - andis. r10,r10,DBSR_IC@h - beq+ 2f - - andi. r10,r9,MSR_IR|MSR_PR /* check supervisor + MMU off */ - beq 1f /* branch and fix it up */ - - mfspr r10,SPRN_SRR2 /* Faulting instruction address */ - cmplwi r10,0x2100 - bgt+ 2f /* address above exception vectors */ - - /* here it looks like we got an inappropriate debug exception. */ -1: rlwinm r9,r9,0,~MSR_DE /* clear DE in the SRR3 value */ - lis r10,DBSR_IC@h /* clear the IC event */ - mtspr SPRN_DBSR,r10 - /* restore state and get out */ - lwz r10,_CCR(r11) - lwz r0,GPR0(r11) - lwz r1,GPR1(r11) - mtcrf 0x80,r10 - mtspr SPRN_SRR2,r12 - mtspr SPRN_SRR3,r9 - lwz r9,GPR9(r11) - lwz r12,GPR12(r11) - lwz r10,crit_r10@l(0) - lwz r11,crit_r11@l(0) - PPC405_ERR77_SYNC - rfci - b . - - /* continue normal handling for a critical exception... */ -2: mfspr r4,SPRN_DBSR - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_TEMPLATE(DebugException, 0x2002, \ - (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ - NOCOPY, crit_transfer_to_handler, ret_from_crit_exc) - -/* - * The other Data TLB exceptions bail out to this point - * if they can't resolve the lightweight TLB fault. - */ -DataAccess: - NORMAL_EXCEPTION_PROLOG - mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ - stw r5,_ESR(r11) - mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ - EXC_XFER_EE_LITE(0x300, handle_page_fault) - -/* Other PowerPC processors, namely those derived from the 6xx-series - * have vectors from 0x2100 through 0x2F00 defined, but marked as reserved. - * However, for the 4xx-series processors these are neither defined nor - * reserved. - */ - - /* Damn, I came up one instruction too many to fit into the - * exception space :-). Both the instruction and data TLB - * miss get to this point to load the TLB. - * r10 - TLB_TAG value - * r11 - Linux PTE - * r12, r9 - avilable to use - * PID - loaded with proper value when we get here - * Upon exit, we reload everything and RFI. - * Actually, it will fit now, but oh well.....a common place - * to load the TLB. - */ -tlb_4xx_index: - .long 0 -finish_tlb_load: - /* load the next available TLB index. - */ - lwz r9, tlb_4xx_index@l(0) - addi r9, r9, 1 - andi. r9, r9, (PPC4XX_TLB_SIZE-1) - stw r9, tlb_4xx_index@l(0) - -6: - /* - * Clear out the software-only bits in the PTE to generate the - * TLB_DATA value. These are the bottom 2 bits of the RPM, the - * top 3 bits of the zone field, and M. - */ - li r12, 0x0ce2 - andc r11, r11, r12 - - tlbwe r11, r9, TLB_DATA /* Load TLB LO */ - tlbwe r10, r9, TLB_TAG /* Load TLB HI */ - - /* Done...restore registers and get out of here. - */ -#ifdef CONFIG_403GCX - lwz r12, 12(r0) - lwz r11, 8(r0) - mtspr SPRN_PID, r12 - mtcr r11 - lwz r9, 4(r0) - lwz r12, 0(r0) -#else - mfspr r12, SPRN_SPRG6 - mfspr r11, SPRN_SPRG7 - mtspr SPRN_PID, r12 - mtcr r11 - mfspr r9, SPRN_SPRG5 - mfspr r12, SPRN_SPRG4 -#endif - mfspr r11, SPRN_SPRG1 - mfspr r10, SPRN_SPRG0 - PPC405_ERR77_SYNC - rfi /* Should sync shadow TLBs */ - b . /* prevent prefetch past rfi */ - -/* extern void giveup_fpu(struct task_struct *prev) - * - * The PowerPC 4xx family of processors do not have an FPU, so this just - * returns. - */ -_GLOBAL(giveup_fpu) - blr - -/* This is where the main kernel code starts. - */ -start_here: - - /* ptr to current */ - lis r2,init_task@h - ori r2,r2,init_task@l - - /* ptr to phys current thread */ - tophys(r4,r2) - addi r4,r4,THREAD /* init task's THREAD */ - mtspr SPRN_SPRG3,r4 - - /* stack */ - lis r1,init_thread_union@ha - addi r1,r1,init_thread_union@l - li r0,0 - stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1) - - bl early_init /* We have to do this with MMU on */ - -/* - * Decide what sort of machine this is and initialize the MMU. - */ - mr r3,r31 - mr r4,r30 - mr r5,r29 - mr r6,r28 - mr r7,r27 - bl machine_init - bl MMU_init - -/* Go back to running unmapped so we can load up new values - * and change to using our exception vectors. - * On the 4xx, all we have to do is invalidate the TLB to clear - * the old 16M byte TLB mappings. - */ - lis r4,2f@h - ori r4,r4,2f@l - tophys(r4,r4) - lis r3,(MSR_KERNEL & ~(MSR_IR|MSR_DR))@h - ori r3,r3,(MSR_KERNEL & ~(MSR_IR|MSR_DR))@l - mtspr SPRN_SRR0,r4 - mtspr SPRN_SRR1,r3 - rfi - b . /* prevent prefetch past rfi */ - -/* Load up the kernel context */ -2: - sync /* Flush to memory before changing TLB */ - tlbia - isync /* Flush shadow TLBs */ - - /* set up the PTE pointers for the Abatron bdiGDB. - */ - lis r6, swapper_pg_dir@h - ori r6, r6, swapper_pg_dir@l - lis r5, abatron_pteptrs@h - ori r5, r5, abatron_pteptrs@l - stw r5, 0xf0(r0) /* Must match your Abatron config file */ - tophys(r5,r5) - stw r6, 0(r5) - -/* Now turn on the MMU for real! */ - lis r4,MSR_KERNEL@h - ori r4,r4,MSR_KERNEL@l - lis r3,start_kernel@h - ori r3,r3,start_kernel@l - mtspr SPRN_SRR0,r3 - mtspr SPRN_SRR1,r4 - rfi /* enable MMU and jump to start_kernel */ - b . /* prevent prefetch past rfi */ - -/* Set up the initial MMU state so we can do the first level of - * kernel initialization. This maps the first 16 MBytes of memory 1:1 - * virtual to physical and more importantly sets the cache mode. - */ -initial_mmu: - tlbia /* Invalidate all TLB entries */ - isync - - /* We should still be executing code at physical address 0x0000xxxx - * at this point. However, start_here is at virtual address - * 0xC000xxxx. So, set up a TLB mapping to cover this once - * translation is enabled. - */ - - lis r3,KERNELBASE@h /* Load the kernel virtual address */ - ori r3,r3,KERNELBASE@l - tophys(r4,r3) /* Load the kernel physical address */ - - iccci r0,r3 /* Invalidate the i-cache before use */ - - /* Load the kernel PID. - */ - li r0,0 - mtspr SPRN_PID,r0 - sync - - /* Configure and load two entries into TLB slots 62 and 63. - * In case we are pinning TLBs, these are reserved in by the - * other TLB functions. If not reserving, then it doesn't - * matter where they are loaded. - */ - clrrwi r4,r4,10 /* Mask off the real page number */ - ori r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */ - - clrrwi r3,r3,10 /* Mask off the effective page number */ - ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_16M)) - - li r0,63 /* TLB slot 63 */ - - tlbwe r4,r0,TLB_DATA /* Load the data portion of the entry */ - tlbwe r3,r0,TLB_TAG /* Load the tag portion of the entry */ - -#if defined(CONFIG_SERIAL_TEXT_DEBUG) && defined(SERIAL_DEBUG_IO_BASE) - - /* Load a TLB entry for the UART, so that ppc4xx_progress() can use - * the UARTs nice and early. We use a 4k real==virtual mapping. */ - - lis r3,SERIAL_DEBUG_IO_BASE@h - ori r3,r3,SERIAL_DEBUG_IO_BASE@l - mr r4,r3 - clrrwi r4,r4,12 - ori r4,r4,(TLB_WR|TLB_I|TLB_M|TLB_G) - - clrrwi r3,r3,12 - ori r3,r3,(TLB_VALID | TLB_PAGESZ(PAGESZ_4K)) - - li r0,0 /* TLB slot 0 */ - tlbwe r4,r0,TLB_DATA - tlbwe r3,r0,TLB_TAG -#endif /* CONFIG_SERIAL_DEBUG_TEXT && SERIAL_DEBUG_IO_BASE */ - - isync - - /* Establish the exception vector base - */ - lis r4,KERNELBASE@h /* EVPR only uses the high 16-bits */ - tophys(r0,r4) /* Use the physical address */ - mtspr SPRN_EVPR,r0 - - blr - -_GLOBAL(abort) - mfspr r13,SPRN_DBCR0 - oris r13,r13,DBCR0_RST_SYSTEM@h - mtspr SPRN_DBCR0,r13 - -_GLOBAL(set_context) - -#ifdef CONFIG_BDI_SWITCH - /* Context switch the PTE pointer for the Abatron BDI2000. - * The PGDIR is the second parameter. - */ - lis r5, KERNELBASE@h - lwz r5, 0xf0(r5) - stw r4, 0x4(r5) -#endif - sync - mtspr SPRN_PID,r3 - isync /* Need an isync to flush shadow */ - /* TLBs after changing PID */ - blr - -/* We put a few things here that have to be page-aligned. This stuff - * goes at the beginning of the data segment, which is page-aligned. - */ - .data - .align 12 - .globl sdata -sdata: - .globl empty_zero_page -empty_zero_page: - .space 4096 - .globl swapper_pg_dir -swapper_pg_dir: - .space 4096 - - -/* Stack for handling critical exceptions from kernel mode */ - .section .bss - .align 12 -exception_stack_bottom: - .space 4096 -critical_stack_top: - .globl exception_stack_top -exception_stack_top: - -/* This space gets a copy of optional info passed to us by the bootstrap - * which is used to pass parameters into the kernel like root=/dev/sda1, etc. - */ - .globl cmd_line -cmd_line: - .space 512 - -/* Room for two PTE pointers, usually the kernel and current user pointers - * to their respective root page table. - */ -abatron_pteptrs: - .space 8 diff --git a/arch/ppc/kernel/head_8xx.S b/arch/ppc/kernel/head_8xx.S deleted file mode 100644 index 321bda2de2c..00000000000 --- a/arch/ppc/kernel/head_8xx.S +++ /dev/null @@ -1,959 +0,0 @@ -/* - * PowerPC version - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP - * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> - * Low-level exception handlers and MMU support - * rewritten by Paul Mackerras. - * Copyright (C) 1996 Paul Mackerras. - * MPC8xx modifications by Dan Malek - * Copyright (C) 1997 Dan Malek (dmalek@jlc.net). - * - * This file contains low-level support and setup for PowerPC 8xx - * embedded processors, including trap and interrupt dispatch. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include <asm/processor.h> -#include <asm/page.h> -#include <asm/mmu.h> -#include <asm/cache.h> -#include <asm/pgtable.h> -#include <asm/cputable.h> -#include <asm/thread_info.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> - -/* Macro to make the code more readable. */ -#ifdef CONFIG_8xx_CPU6 -#define DO_8xx_CPU6(val, reg) \ - li reg, val; \ - stw reg, 12(r0); \ - lwz reg, 12(r0); -#else -#define DO_8xx_CPU6(val, reg) -#endif - .text - .globl _stext -_stext: - .text - .globl _start -_start: - -/* MPC8xx - * This port was done on an MBX board with an 860. Right now I only - * support an ELF compressed (zImage) boot from EPPC-Bug because the - * code there loads up some registers before calling us: - * r3: ptr to board info data - * r4: initrd_start or if no initrd then 0 - * r5: initrd_end - unused if r4 is 0 - * r6: Start of command line string - * r7: End of command line string - * - * I decided to use conditional compilation instead of checking PVR and - * adding more processor specific branches around code I don't need. - * Since this is an embedded processor, I also appreciate any memory - * savings I can get. - * - * The MPC8xx does not have any BATs, but it supports large page sizes. - * We first initialize the MMU to support 8M byte pages, then load one - * entry into each of the instruction and data TLBs to map the first - * 8M 1:1. I also mapped an additional I/O space 1:1 so we can get to - * the "internal" processor registers before MMU_init is called. - * - * The TLB code currently contains a major hack. Since I use the condition - * code register, I have to save and restore it. I am out of registers, so - * I just store it in memory location 0 (the TLB handlers are not reentrant). - * To avoid making any decisions, I need to use the "segment" valid bit - * in the first level table, but that would require many changes to the - * Linux page directory/table functions that I don't want to do right now. - * - * I used to use SPRG2 for a temporary register in the TLB handler, but it - * has since been put to other uses. I now use a hack to save a register - * and the CCR at memory location 0.....Someday I'll fix this..... - * -- Dan - */ - .globl __start -__start: - mr r31,r3 /* save parameters */ - mr r30,r4 - mr r29,r5 - mr r28,r6 - mr r27,r7 - - /* We have to turn on the MMU right away so we get cache modes - * set correctly. - */ - bl initial_mmu - -/* We now have the lower 8 Meg mapped into TLB entries, and the caches - * ready to work. - */ - -turn_on_mmu: - mfmsr r0 - ori r0,r0,MSR_DR|MSR_IR - mtspr SPRN_SRR1,r0 - lis r0,start_here@h - ori r0,r0,start_here@l - mtspr SPRN_SRR0,r0 - SYNC - rfi /* enables MMU */ - -/* - * Exception entry code. This code runs with address translation - * turned off, i.e. using physical addresses. - * We assume sprg3 has the physical address of the current - * task's thread_struct. - */ -#define EXCEPTION_PROLOG \ - mtspr SPRN_SPRG0,r10; \ - mtspr SPRN_SPRG1,r11; \ - mfcr r10; \ - EXCEPTION_PROLOG_1; \ - EXCEPTION_PROLOG_2 - -#define EXCEPTION_PROLOG_1 \ - mfspr r11,SPRN_SRR1; /* check whether user or kernel */ \ - andi. r11,r11,MSR_PR; \ - tophys(r11,r1); /* use tophys(r1) if kernel */ \ - beq 1f; \ - mfspr r11,SPRN_SPRG3; \ - lwz r11,THREAD_INFO-THREAD(r11); \ - addi r11,r11,THREAD_SIZE; \ - tophys(r11,r11); \ -1: subi r11,r11,INT_FRAME_SIZE /* alloc exc. frame */ - - -#define EXCEPTION_PROLOG_2 \ - CLR_TOP32(r11); \ - stw r10,_CCR(r11); /* save registers */ \ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mfspr r10,SPRN_SPRG0; \ - stw r10,GPR10(r11); \ - mfspr r12,SPRN_SPRG1; \ - stw r12,GPR11(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r12,SPRN_SRR0; \ - mfspr r9,SPRN_SRR1; \ - stw r1,GPR1(r11); \ - stw r1,0(r11); \ - tovirt(r1,r11); /* set new kernel sp */ \ - li r10,MSR_KERNEL & ~(MSR_IR|MSR_DR); /* can take exceptions */ \ - MTMSRD(r10); /* (except for mach check in rtas) */ \ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -/* - * Note: code which follows this uses cr0.eq (set if from kernel), - * r11, r12 (SRR0), and r9 (SRR1). - * - * Note2: once we have set r1 we are in a position to take exceptions - * again, and we could thus set MSR:RI at that point. - */ - -/* - * Exception vectors. - */ -#define EXCEPTION(n, label, hdlr, xfer) \ - . = n; \ -label: \ - EXCEPTION_PROLOG; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - xfer(n, hdlr) - -#define EXC_XFER_TEMPLATE(n, hdlr, trap, copyee, tfer, ret) \ - li r10,trap; \ - stw r10,TRAP(r11); \ - li r10,MSR_KERNEL; \ - copyee(r10, r9); \ - bl tfer; \ -i##n: \ - .long hdlr; \ - .long ret - -#define COPY_EE(d, s) rlwimi d,s,0,16,16 -#define NOCOPY(d, s) - -#define EXC_XFER_STD(n, hdlr) \ - EXC_XFER_TEMPLATE(n, hdlr, n, NOCOPY, transfer_to_handler_full, \ - ret_from_except_full) - -#define EXC_XFER_LITE(n, hdlr) \ - EXC_XFER_TEMPLATE(n, hdlr, n+1, NOCOPY, transfer_to_handler, \ - ret_from_except) - -#define EXC_XFER_EE(n, hdlr) \ - EXC_XFER_TEMPLATE(n, hdlr, n, COPY_EE, transfer_to_handler_full, \ - ret_from_except_full) - -#define EXC_XFER_EE_LITE(n, hdlr) \ - EXC_XFER_TEMPLATE(n, hdlr, n+1, COPY_EE, transfer_to_handler, \ - ret_from_except) - -/* System reset */ - EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD) - -/* Machine check */ - . = 0x200 -MachineCheck: - EXCEPTION_PROLOG - mfspr r4,SPRN_DAR - stw r4,_DAR(r11) - mfspr r5,SPRN_DSISR - stw r5,_DSISR(r11) - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_STD(0x200, machine_check_exception) - -/* Data access exception. - * This is "never generated" by the MPC8xx. We jump to it for other - * translation errors. - */ - . = 0x300 -DataAccess: - EXCEPTION_PROLOG - mfspr r10,SPRN_DSISR - stw r10,_DSISR(r11) - mr r5,r10 - mfspr r4,SPRN_DAR - EXC_XFER_EE_LITE(0x300, handle_page_fault) - -/* Instruction access exception. - * This is "never generated" by the MPC8xx. We jump to it for other - * translation errors. - */ - . = 0x400 -InstructionAccess: - EXCEPTION_PROLOG - mr r4,r12 - mr r5,r9 - EXC_XFER_EE_LITE(0x400, handle_page_fault) - -/* External interrupt */ - EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) - -/* Alignment exception */ - . = 0x600 -Alignment: - EXCEPTION_PROLOG - mfspr r4,SPRN_DAR - stw r4,_DAR(r11) - mfspr r5,SPRN_DSISR - stw r5,_DSISR(r11) - addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE(0x600, alignment_exception) - -/* Program check exception */ - EXCEPTION(0x700, ProgramCheck, program_check_exception, EXC_XFER_STD) - -/* No FPU on MPC8xx. This exception is not supposed to happen. -*/ - EXCEPTION(0x800, FPUnavailable, unknown_exception, EXC_XFER_STD) - -/* Decrementer */ - EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE) - - EXCEPTION(0xa00, Trap_0a, unknown_exception, EXC_XFER_EE) - EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_EE) - -/* System call */ - . = 0xc00 -SystemCall: - EXCEPTION_PROLOG - EXC_XFER_EE_LITE(0xc00, DoSyscall) - -/* Single step - not used on 601 */ - EXCEPTION(0xd00, SingleStep, single_step_exception, EXC_XFER_STD) - EXCEPTION(0xe00, Trap_0e, unknown_exception, EXC_XFER_EE) - EXCEPTION(0xf00, Trap_0f, unknown_exception, EXC_XFER_EE) - -/* On the MPC8xx, this is a software emulation interrupt. It occurs - * for all unimplemented and illegal instructions. - */ - EXCEPTION(0x1000, SoftEmu, SoftwareEmulation, EXC_XFER_STD) - - . = 0x1100 -/* - * For the MPC8xx, this is a software tablewalk to load the instruction - * TLB. It is modelled after the example in the Motorola manual. The task - * switch loads the M_TWB register with the pointer to the first level table. - * If we discover there is no second level table (value is zero) or if there - * is an invalid pte, we load that into the TLB, which causes another fault - * into the TLB Error interrupt where we can handle such problems. - * We have to use the MD_xxx registers for the tablewalk because the - * equivalent MI_xxx registers only perform the attribute functions. - */ -InstructionTLBMiss: -#ifdef CONFIG_8xx_CPU6 - stw r3, 8(r0) -#endif - DO_8xx_CPU6(0x3f80, r3) - mtspr SPRN_M_TW, r10 /* Save a couple of working registers */ - mfcr r10 - stw r10, 0(r0) - stw r11, 4(r0) - mfspr r10, SPRN_SRR0 /* Get effective address of fault */ - DO_8xx_CPU6(0x3780, r3) - mtspr SPRN_MD_EPN, r10 /* Have to use MD_EPN for walk, MI_EPN can't */ - mfspr r10, SPRN_M_TWB /* Get level 1 table entry address */ - - /* If we are faulting a kernel address, we have to use the - * kernel page tables. - */ - andi. r11, r10, 0x0800 /* Address >= 0x80000000 */ - beq 3f - lis r11, swapper_pg_dir@h - ori r11, r11, swapper_pg_dir@l - rlwimi r10, r11, 0, 2, 19 -3: - lwz r11, 0(r10) /* Get the level 1 entry */ - rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */ - beq 2f /* If zero, don't try to find a pte */ - - /* We have a pte table, so load the MI_TWC with the attributes - * for this "segment." - */ - ori r11,r11,1 /* Set valid bit */ - DO_8xx_CPU6(0x2b80, r3) - mtspr SPRN_MI_TWC, r11 /* Set segment attributes */ - DO_8xx_CPU6(0x3b80, r3) - mtspr SPRN_MD_TWC, r11 /* Load pte table base address */ - mfspr r11, SPRN_MD_TWC /* ....and get the pte address */ - lwz r10, 0(r11) /* Get the pte */ - -#ifdef CONFIG_SWAP - /* do not set the _PAGE_ACCESSED bit of a non-present page */ - andi. r11, r10, _PAGE_PRESENT - beq 4f - ori r10, r10, _PAGE_ACCESSED - mfspr r11, SPRN_MD_TWC /* get the pte address again */ - stw r10, 0(r11) -4: -#else - ori r10, r10, _PAGE_ACCESSED - stw r10, 0(r11) -#endif - - /* The Linux PTE won't go exactly into the MMU TLB. - * Software indicator bits 21, 22 and 28 must be clear. - * Software indicator bits 24, 25, 26, and 27 must be - * set. All other Linux PTE bits control the behavior - * of the MMU. - */ -2: li r11, 0x00f0 - rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ - DO_8xx_CPU6(0x2d80, r3) - mtspr SPRN_MI_RPN, r10 /* Update TLB entry */ - - mfspr r10, SPRN_M_TW /* Restore registers */ - lwz r11, 0(r0) - mtcr r11 - lwz r11, 4(r0) -#ifdef CONFIG_8xx_CPU6 - lwz r3, 8(r0) -#endif - rfi - - . = 0x1200 -DataStoreTLBMiss: - stw r3, 8(r0) - DO_8xx_CPU6(0x3f80, r3) - mtspr SPRN_M_TW, r10 /* Save a couple of working registers */ - mfcr r10 - stw r10, 0(r0) - stw r11, 4(r0) - mfspr r10, SPRN_M_TWB /* Get level 1 table entry address */ - - /* If we are faulting a kernel address, we have to use the - * kernel page tables. - */ - andi. r11, r10, 0x0800 - beq 3f - lis r11, swapper_pg_dir@h - ori r11, r11, swapper_pg_dir@l - rlwimi r10, r11, 0, 2, 19 - stw r12, 16(r0) - b LoadLargeDTLB -3: - lwz r11, 0(r10) /* Get the level 1 entry */ - rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */ - beq 2f /* If zero, don't try to find a pte */ - - /* We have a pte table, so load fetch the pte from the table. - */ - ori r11, r11, 1 /* Set valid bit in physical L2 page */ - DO_8xx_CPU6(0x3b80, r3) - mtspr SPRN_MD_TWC, r11 /* Load pte table base address */ - mfspr r10, SPRN_MD_TWC /* ....and get the pte address */ - lwz r10, 0(r10) /* Get the pte */ - - /* Insert the Guarded flag into the TWC from the Linux PTE. - * It is bit 27 of both the Linux PTE and the TWC (at least - * I got that right :-). It will be better when we can put - * this into the Linux pgd/pmd and load it in the operation - * above. - */ - rlwimi r11, r10, 0, 27, 27 - DO_8xx_CPU6(0x3b80, r3) - mtspr SPRN_MD_TWC, r11 - -#ifdef CONFIG_SWAP - /* do not set the _PAGE_ACCESSED bit of a non-present page */ - andi. r11, r10, _PAGE_PRESENT - beq 4f - ori r10, r10, _PAGE_ACCESSED -4: - /* and update pte in table */ -#else - ori r10, r10, _PAGE_ACCESSED -#endif - mfspr r11, SPRN_MD_TWC /* get the pte address again */ - stw r10, 0(r11) - - /* The Linux PTE won't go exactly into the MMU TLB. - * Software indicator bits 21, 22 and 28 must be clear. - * Software indicator bits 24, 25, 26, and 27 must be - * set. All other Linux PTE bits control the behavior - * of the MMU. - */ -2: li r11, 0x00f0 - rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ - DO_8xx_CPU6(0x3d80, r3) - mtspr SPRN_MD_RPN, r10 /* Update TLB entry */ - - mfspr r10, SPRN_M_TW /* Restore registers */ - lwz r11, 0(r0) - mtcr r11 - lwz r11, 4(r0) - lwz r3, 8(r0) - rfi - -/* This is an instruction TLB error on the MPC8xx. This could be due - * to many reasons, such as executing guarded memory or illegal instruction - * addresses. There is nothing to do but handle a big time error fault. - */ - . = 0x1300 -InstructionTLBError: - b InstructionAccess - -LoadLargeDTLB: - li r12, 0 - lwz r11, 0(r10) /* Get the level 1 entry */ - rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */ - beq 3f /* If zero, don't try to find a pte */ - - /* We have a pte table, so load fetch the pte from the table. - */ - ori r11, r11, 1 /* Set valid bit in physical L2 page */ - DO_8xx_CPU6(0x3b80, r3) - mtspr SPRN_MD_TWC, r11 /* Load pte table base address */ - mfspr r10, SPRN_MD_TWC /* ....and get the pte address */ - lwz r10, 0(r10) /* Get the pte */ - - /* Insert the Guarded flag into the TWC from the Linux PTE. - * It is bit 27 of both the Linux PTE and the TWC (at least - * I got that right :-). It will be better when we can put - * this into the Linux pgd/pmd and load it in the operation - * above. - */ - rlwimi r11, r10, 0, 27, 27 - - rlwimi r12, r10, 0, 0, 9 /* extract phys. addr */ - mfspr r3, SPRN_MD_EPN - rlwinm r3, r3, 0, 0, 9 /* extract virtual address */ - tophys(r3, r3) - cmpw r3, r12 /* only use 8M page if it is a direct - kernel mapping */ - bne 1f - ori r11, r11, MD_PS8MEG - li r12, 1 - b 2f -1: - li r12, 0 /* can't use 8MB TLB, so zero r12. */ -2: - DO_8xx_CPU6(0x3b80, r3) - mtspr SPRN_MD_TWC, r11 - - /* The Linux PTE won't go exactly into the MMU TLB. - * Software indicator bits 21, 22 and 28 must be clear. - * Software indicator bits 24, 25, 26, and 27 must be - * set. All other Linux PTE bits control the behavior - * of the MMU. - */ -3: li r11, 0x00f0 - rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ - cmpwi r12, 1 - bne 4f - ori r10, r10, 0x8 - - mfspr r12, SPRN_MD_EPN - lis r3, 0xff80 /* 10-19 must be clear for 8MB TLB */ - ori r3, r3, 0x0fff - and r12, r3, r12 - DO_8xx_CPU6(0x3780, r3) - mtspr SPRN_MD_EPN, r12 - - lis r3, 0xff80 /* 10-19 must be clear for 8MB TLB */ - ori r3, r3, 0x0fff - and r10, r3, r10 -4: - DO_8xx_CPU6(0x3d80, r3) - mtspr SPRN_MD_RPN, r10 /* Update TLB entry */ - - mfspr r10, SPRN_M_TW /* Restore registers */ - lwz r11, 0(r0) - mtcr r11 - lwz r11, 4(r0) - - lwz r12, 16(r0) - lwz r3, 8(r0) - rfi - -/* This is the data TLB error on the MPC8xx. This could be due to - * many reasons, including a dirty update to a pte. We can catch that - * one here, but anything else is an error. First, we track down the - * Linux pte. If it is valid, write access is allowed, but the - * page dirty bit is not set, we will set it and reload the TLB. For - * any other case, we bail out to a higher level function that can - * handle it. - */ - . = 0x1400 -DataTLBError: -#ifdef CONFIG_8xx_CPU6 - stw r3, 8(r0) -#endif - DO_8xx_CPU6(0x3f80, r3) - mtspr SPRN_M_TW, r10 /* Save a couple of working registers */ - mfcr r10 - stw r10, 0(r0) - stw r11, 4(r0) - - /* First, make sure this was a store operation. - */ - mfspr r10, SPRN_DSISR - andis. r11, r10, 0x0200 /* If set, indicates store op */ - beq 2f - - /* The EA of a data TLB miss is automatically stored in the MD_EPN - * register. The EA of a data TLB error is automatically stored in - * the DAR, but not the MD_EPN register. We must copy the 20 most - * significant bits of the EA from the DAR to MD_EPN before we - * start walking the page tables. We also need to copy the CASID - * value from the M_CASID register. - * Addendum: The EA of a data TLB error is _supposed_ to be stored - * in DAR, but it seems that this doesn't happen in some cases, such - * as when the error is due to a dcbi instruction to a page with a - * TLB that doesn't have the changed bit set. In such cases, there - * does not appear to be any way to recover the EA of the error - * since it is neither in DAR nor MD_EPN. As a workaround, the - * _PAGE_HWWRITE bit is set for all kernel data pages when the PTEs - * are initialized in mapin_ram(). This will avoid the problem, - * assuming we only use the dcbi instruction on kernel addresses. - */ - mfspr r10, SPRN_DAR - rlwinm r11, r10, 0, 0, 19 - ori r11, r11, MD_EVALID - mfspr r10, SPRN_M_CASID - rlwimi r11, r10, 0, 28, 31 - DO_8xx_CPU6(0x3780, r3) - mtspr SPRN_MD_EPN, r11 - - mfspr r10, SPRN_M_TWB /* Get level 1 table entry address */ - - /* If we are faulting a kernel address, we have to use the - * kernel page tables. - */ - andi. r11, r10, 0x0800 - beq 3f - lis r11, swapper_pg_dir@h - ori r11, r11, swapper_pg_dir@l - rlwimi r10, r11, 0, 2, 19 -3: - lwz r11, 0(r10) /* Get the level 1 entry */ - rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */ - beq 2f /* If zero, bail */ - - /* We have a pte table, so fetch the pte from the table. - */ - ori r11, r11, 1 /* Set valid bit in physical L2 page */ - DO_8xx_CPU6(0x3b80, r3) - mtspr SPRN_MD_TWC, r11 /* Load pte table base address */ - mfspr r11, SPRN_MD_TWC /* ....and get the pte address */ - lwz r10, 0(r11) /* Get the pte */ - - andi. r11, r10, _PAGE_RW /* Is it writeable? */ - beq 2f /* Bail out if not */ - - /* Update 'changed', among others. - */ -#ifdef CONFIG_SWAP - ori r10, r10, _PAGE_DIRTY|_PAGE_HWWRITE - /* do not set the _PAGE_ACCESSED bit of a non-present page */ - andi. r11, r10, _PAGE_PRESENT - beq 4f - ori r10, r10, _PAGE_ACCESSED -4: -#else - ori r10, r10, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE -#endif - mfspr r11, SPRN_MD_TWC /* Get pte address again */ - stw r10, 0(r11) /* and update pte in table */ - - /* The Linux PTE won't go exactly into the MMU TLB. - * Software indicator bits 21, 22 and 28 must be clear. - * Software indicator bits 24, 25, 26, and 27 must be - * set. All other Linux PTE bits control the behavior - * of the MMU. - */ - li r11, 0x00f0 - rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ - DO_8xx_CPU6(0x3d80, r3) - mtspr SPRN_MD_RPN, r10 /* Update TLB entry */ - - mfspr r10, SPRN_M_TW /* Restore registers */ - lwz r11, 0(r0) - mtcr r11 - lwz r11, 4(r0) -#ifdef CONFIG_8xx_CPU6 - lwz r3, 8(r0) -#endif - rfi -2: - mfspr r10, SPRN_M_TW /* Restore registers */ - lwz r11, 0(r0) - mtcr r11 - lwz r11, 4(r0) -#ifdef CONFIG_8xx_CPU6 - lwz r3, 8(r0) -#endif - b DataAccess - - EXCEPTION(0x1500, Trap_15, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1600, Trap_16, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1700, Trap_17, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1800, Trap_18, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1900, Trap_19, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1a00, Trap_1a, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1b00, Trap_1b, unknown_exception, EXC_XFER_EE) - -/* On the MPC8xx, these next four traps are used for development - * support of breakpoints and such. Someday I will get around to - * using them. - */ - EXCEPTION(0x1c00, Trap_1c, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1d00, Trap_1d, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1e00, Trap_1e, unknown_exception, EXC_XFER_EE) - EXCEPTION(0x1f00, Trap_1f, unknown_exception, EXC_XFER_EE) - - . = 0x2000 - - .globl giveup_fpu -giveup_fpu: - blr - -/* - * This is where the main kernel code starts. - */ -start_here: - /* ptr to current */ - lis r2,init_task@h - ori r2,r2,init_task@l - - /* ptr to phys current thread */ - tophys(r4,r2) - addi r4,r4,THREAD /* init task's THREAD */ - mtspr SPRN_SPRG3,r4 - li r3,0 - mtspr SPRN_SPRG2,r3 /* 0 => r1 has kernel sp */ - - /* stack */ - lis r1,init_thread_union@ha - addi r1,r1,init_thread_union@l - li r0,0 - stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1) - - bl early_init /* We have to do this with MMU on */ - -/* - * Decide what sort of machine this is and initialize the MMU. - */ - mr r3,r31 - mr r4,r30 - mr r5,r29 - mr r6,r28 - mr r7,r27 - bl machine_init - bl MMU_init - -/* - * Go back to running unmapped so we can load up new values - * and change to using our exception vectors. - * On the 8xx, all we have to do is invalidate the TLB to clear - * the old 8M byte TLB mappings and load the page table base register. - */ - /* The right way to do this would be to track it down through - * init's THREAD like the context switch code does, but this is - * easier......until someone changes init's static structures. - */ - lis r6, swapper_pg_dir@h - ori r6, r6, swapper_pg_dir@l - tophys(r6,r6) -#ifdef CONFIG_8xx_CPU6 - lis r4, cpu6_errata_word@h - ori r4, r4, cpu6_errata_word@l - li r3, 0x3980 - stw r3, 12(r4) - lwz r3, 12(r4) -#endif - mtspr SPRN_M_TWB, r6 - lis r4,2f@h - ori r4,r4,2f@l - tophys(r4,r4) - li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR) - mtspr SPRN_SRR0,r4 - mtspr SPRN_SRR1,r3 - rfi -/* Load up the kernel context */ -2: - SYNC /* Force all PTE updates to finish */ - tlbia /* Clear all TLB entries */ - sync /* wait for tlbia/tlbie to finish */ - TLBSYNC /* ... on all CPUs */ - - /* set up the PTE pointers for the Abatron bdiGDB. - */ - tovirt(r6,r6) - lis r5, abatron_pteptrs@h - ori r5, r5, abatron_pteptrs@l - stw r5, 0xf0(r0) /* Must match your Abatron config file */ - tophys(r5,r5) - stw r6, 0(r5) - -/* Now turn on the MMU for real! */ - li r4,MSR_KERNEL - lis r3,start_kernel@h - ori r3,r3,start_kernel@l - mtspr SPRN_SRR0,r3 - mtspr SPRN_SRR1,r4 - rfi /* enable MMU and jump to start_kernel */ - -/* Set up the initial MMU state so we can do the first level of - * kernel initialization. This maps the first 8 MBytes of memory 1:1 - * virtual to physical. Also, set the cache mode since that is defined - * by TLB entries and perform any additional mapping (like of the IMMR). - * If configured to pin some TLBs, we pin the first 8 Mbytes of kernel, - * 24 Mbytes of data, and the 8M IMMR space. Anything not covered by - * these mappings is mapped by page tables. - */ -initial_mmu: - tlbia /* Invalidate all TLB entries */ -#ifdef CONFIG_PIN_TLB - lis r8, MI_RSV4I@h - ori r8, r8, 0x1c00 -#else - li r8, 0 -#endif - mtspr SPRN_MI_CTR, r8 /* Set instruction MMU control */ - -#ifdef CONFIG_PIN_TLB - lis r10, (MD_RSV4I | MD_RESETVAL)@h - ori r10, r10, 0x1c00 - mr r8, r10 -#else - lis r10, MD_RESETVAL@h -#endif -#ifndef CONFIG_8xx_COPYBACK - oris r10, r10, MD_WTDEF@h -#endif - mtspr SPRN_MD_CTR, r10 /* Set data TLB control */ - - /* Now map the lower 8 Meg into the TLBs. For this quick hack, - * we can load the instruction and data TLB registers with the - * same values. - */ - lis r8, KERNELBASE@h /* Create vaddr for TLB */ - ori r8, r8, MI_EVALID /* Mark it valid */ - mtspr SPRN_MI_EPN, r8 - mtspr SPRN_MD_EPN, r8 - li r8, MI_PS8MEG /* Set 8M byte page */ - ori r8, r8, MI_SVALID /* Make it valid */ - mtspr SPRN_MI_TWC, r8 - mtspr SPRN_MD_TWC, r8 - li r8, MI_BOOTINIT /* Create RPN for address 0 */ - mtspr SPRN_MI_RPN, r8 /* Store TLB entry */ - mtspr SPRN_MD_RPN, r8 - lis r8, MI_Kp@h /* Set the protection mode */ - mtspr SPRN_MI_AP, r8 - mtspr SPRN_MD_AP, r8 - - /* Map another 8 MByte at the IMMR to get the processor - * internal registers (among other things). - */ -#ifdef CONFIG_PIN_TLB - addi r10, r10, 0x0100 - mtspr SPRN_MD_CTR, r10 -#endif - mfspr r9, 638 /* Get current IMMR */ - andis. r9, r9, 0xff80 /* Get 8Mbyte boundary */ - - mr r8, r9 /* Create vaddr for TLB */ - ori r8, r8, MD_EVALID /* Mark it valid */ - mtspr SPRN_MD_EPN, r8 - li r8, MD_PS8MEG /* Set 8M byte page */ - ori r8, r8, MD_SVALID /* Make it valid */ - mtspr SPRN_MD_TWC, r8 - mr r8, r9 /* Create paddr for TLB */ - ori r8, r8, MI_BOOTINIT|0x2 /* Inhibit cache -- Cort */ - mtspr SPRN_MD_RPN, r8 - -#ifdef CONFIG_PIN_TLB - /* Map two more 8M kernel data pages. - */ - addi r10, r10, 0x0100 - mtspr SPRN_MD_CTR, r10 - - lis r8, KERNELBASE@h /* Create vaddr for TLB */ - addis r8, r8, 0x0080 /* Add 8M */ - ori r8, r8, MI_EVALID /* Mark it valid */ - mtspr SPRN_MD_EPN, r8 - li r9, MI_PS8MEG /* Set 8M byte page */ - ori r9, r9, MI_SVALID /* Make it valid */ - mtspr SPRN_MD_TWC, r9 - li r11, MI_BOOTINIT /* Create RPN for address 0 */ - addis r11, r11, 0x0080 /* Add 8M */ - mtspr SPRN_MD_RPN, r11 - - addi r10, r10, 0x0100 - mtspr SPRN_MD_CTR, r10 - - addis r8, r8, 0x0080 /* Add 8M */ - mtspr SPRN_MD_EPN, r8 - mtspr SPRN_MD_TWC, r9 - addis r11, r11, 0x0080 /* Add 8M */ - mtspr SPRN_MD_RPN, r11 -#endif - - /* Since the cache is enabled according to the information we - * just loaded into the TLB, invalidate and enable the caches here. - * We should probably check/set other modes....later. - */ - lis r8, IDC_INVALL@h - mtspr SPRN_IC_CST, r8 - mtspr SPRN_DC_CST, r8 - lis r8, IDC_ENABLE@h - mtspr SPRN_IC_CST, r8 -#ifdef CONFIG_8xx_COPYBACK - mtspr SPRN_DC_CST, r8 -#else - /* For a debug option, I left this here to easily enable - * the write through cache mode - */ - lis r8, DC_SFWT@h - mtspr SPRN_DC_CST, r8 - lis r8, IDC_ENABLE@h - mtspr SPRN_DC_CST, r8 -#endif - blr - - -/* - * Set up to use a given MMU context. - * r3 is context number, r4 is PGD pointer. - * - * We place the physical address of the new task page directory loaded - * into the MMU base register, and set the ASID compare register with - * the new "context." - */ -_GLOBAL(set_context) - -#ifdef CONFIG_BDI_SWITCH - /* Context switch the PTE pointer for the Abatron BDI2000. - * The PGDIR is passed as second argument. - */ - lis r5, KERNELBASE@h - lwz r5, 0xf0(r5) - stw r4, 0x4(r5) -#endif - -#ifdef CONFIG_8xx_CPU6 - lis r6, cpu6_errata_word@h - ori r6, r6, cpu6_errata_word@l - tophys (r4, r4) - li r7, 0x3980 - stw r7, 12(r6) - lwz r7, 12(r6) - mtspr SPRN_M_TWB, r4 /* Update MMU base address */ - li r7, 0x3380 - stw r7, 12(r6) - lwz r7, 12(r6) - mtspr SPRN_M_CASID, r3 /* Update context */ -#else - mtspr SPRN_M_CASID,r3 /* Update context */ - tophys (r4, r4) - mtspr SPRN_M_TWB, r4 /* and pgd */ -#endif - SYNC - blr - -#ifdef CONFIG_8xx_CPU6 -/* It's here because it is unique to the 8xx. - * It is important we get called with interrupts disabled. I used to - * do that, but it appears that all code that calls this already had - * interrupt disabled. - */ - .globl set_dec_cpu6 -set_dec_cpu6: - lis r7, cpu6_errata_word@h - ori r7, r7, cpu6_errata_word@l - li r4, 0x2c00 - stw r4, 8(r7) - lwz r4, 8(r7) - mtspr 22, r3 /* Update Decrementer */ - SYNC - blr -#endif - -/* - * We put a few things here that have to be page-aligned. - * This stuff goes at the beginning of the data segment, - * which is page-aligned. - */ - .data - .globl sdata -sdata: - .globl empty_zero_page -empty_zero_page: - .space 4096 - - .globl swapper_pg_dir -swapper_pg_dir: - .space 4096 - -/* - * This space gets a copy of optional info passed to us by the bootstrap - * Used to pass parameters into the kernel like root=/dev/sda1, etc. - */ - .globl cmd_line -cmd_line: - .space 512 - -/* Room for two PTE table poiners, usually the kernel and current user - * pointer to their respective root page table (pgdir). - */ -abatron_pteptrs: - .space 8 - -#ifdef CONFIG_8xx_CPU6 - .globl cpu6_errata_word -cpu6_errata_word: - .space 16 -#endif - diff --git a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h deleted file mode 100644 index 166d597b6db..00000000000 --- a/arch/ppc/kernel/head_booke.h +++ /dev/null @@ -1,308 +0,0 @@ -#ifndef __HEAD_BOOKE_H__ -#define __HEAD_BOOKE_H__ - -/* - * Macros used for common Book-e exception handling - */ - -#define SET_IVOR(vector_number, vector_label) \ - li r26,vector_label@l; \ - mtspr SPRN_IVOR##vector_number,r26; \ - sync - -#define NORMAL_EXCEPTION_PROLOG \ - mtspr SPRN_SPRG0,r10; /* save two registers to work with */\ - mtspr SPRN_SPRG1,r11; \ - mtspr SPRN_SPRG4W,r1; \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,SPRN_SRR1; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - beq 1f; \ - mfspr r1,SPRN_SPRG3; /* if from user, start at top of */\ - lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\ - addi r1,r1,THREAD_SIZE; \ -1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\ - mr r11,r1; \ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mfspr r10,SPRN_SPRG0; \ - stw r10,GPR10(r11); \ - mfspr r12,SPRN_SPRG1; \ - stw r12,GPR11(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r10,SPRN_SPRG4R; \ - mfspr r12,SPRN_SRR0; \ - stw r10,GPR1(r11); \ - mfspr r9,SPRN_SRR1; \ - stw r10,0(r11); \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -/* To handle the additional exception priority levels on 40x and Book-E - * processors we allocate a 4k stack per additional priority level. The various - * head_xxx.S files allocate space (exception_stack_top) for each priority's - * stack times the number of CPUs - * - * On 40x critical is the only additional level - * On 44x/e500 we have critical and machine check - * On e200 we have critical and debug (machine check occurs via critical) - * - * Additionally we reserve a SPRG for each priority level so we can free up a - * GPR to use as the base for indirect access to the exception stacks. This - * is necessary since the MMU is always on, for Book-E parts, and the stacks - * are offset from KERNELBASE. - * - */ -#define BOOKE_EXCEPTION_STACK_SIZE (8192) - -/* CRIT_SPRG only used in critical exception handling */ -#define CRIT_SPRG SPRN_SPRG2 -/* MCHECK_SPRG only used in machine check exception handling */ -#define MCHECK_SPRG SPRN_SPRG6W - -#define MCHECK_STACK_TOP (exception_stack_top - 4096) -#define CRIT_STACK_TOP (exception_stack_top) - -/* only on e200 for now */ -#define DEBUG_STACK_TOP (exception_stack_top - 4096) -#define DEBUG_SPRG SPRN_SPRG6W - -#ifdef CONFIG_SMP -#define BOOKE_LOAD_EXC_LEVEL_STACK(level) \ - mfspr r8,SPRN_PIR; \ - mulli r8,r8,BOOKE_EXCEPTION_STACK_SIZE; \ - neg r8,r8; \ - addis r8,r8,level##_STACK_TOP@ha; \ - addi r8,r8,level##_STACK_TOP@l -#else -#define BOOKE_LOAD_EXC_LEVEL_STACK(level) \ - lis r8,level##_STACK_TOP@h; \ - ori r8,r8,level##_STACK_TOP@l -#endif - -/* - * Exception prolog for critical/machine check exceptions. This is a - * little different from the normal exception prolog above since a - * critical/machine check exception can potentially occur at any point - * during normal exception processing. Thus we cannot use the same SPRG - * registers as the normal prolog above. Instead we use a portion of the - * critical/machine check exception stack at low physical addresses. - */ -#define EXC_LEVEL_EXCEPTION_PROLOG(exc_level, exc_level_srr0, exc_level_srr1) \ - mtspr exc_level##_SPRG,r8; \ - BOOKE_LOAD_EXC_LEVEL_STACK(exc_level);/* r8 points to the exc_level stack*/ \ - stw r10,GPR10-INT_FRAME_SIZE(r8); \ - stw r11,GPR11-INT_FRAME_SIZE(r8); \ - mfcr r10; /* save CR in r10 for now */\ - mfspr r11,exc_level_srr1; /* check whether user or kernel */\ - andi. r11,r11,MSR_PR; \ - mr r11,r8; \ - mfspr r8,exc_level##_SPRG; \ - beq 1f; \ - /* COMING FROM USER MODE */ \ - mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\ - lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ - addi r11,r11,THREAD_SIZE; \ -1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ - stw r10,_CCR(r11); /* save various registers */\ - stw r12,GPR12(r11); \ - stw r9,GPR9(r11); \ - mflr r10; \ - stw r10,_LINK(r11); \ - mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ - stw r12,_DEAR(r11); /* since they may have had stuff */\ - mfspr r9,SPRN_ESR; /* in them at the point where the */\ - stw r9,_ESR(r11); /* exception was taken */\ - mfspr r12,exc_level_srr0; \ - stw r1,GPR1(r11); \ - mfspr r9,exc_level_srr1; \ - stw r1,0(r11); \ - mr r1,r11; \ - rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ - stw r0,GPR0(r11); \ - SAVE_4GPRS(3, r11); \ - SAVE_2GPRS(7, r11) - -#define CRITICAL_EXCEPTION_PROLOG \ - EXC_LEVEL_EXCEPTION_PROLOG(CRIT, SPRN_CSRR0, SPRN_CSRR1) -#define DEBUG_EXCEPTION_PROLOG \ - EXC_LEVEL_EXCEPTION_PROLOG(DEBUG, SPRN_DSRR0, SPRN_DSRR1) -#define MCHECK_EXCEPTION_PROLOG \ - EXC_LEVEL_EXCEPTION_PROLOG(MCHECK, SPRN_MCSRR0, SPRN_MCSRR1) - -/* - * Exception vectors. - */ -#define START_EXCEPTION(label) \ - .align 5; \ -label: - -#define FINISH_EXCEPTION(func) \ - bl transfer_to_handler_full; \ - .long func; \ - .long ret_from_except_full - -#define EXCEPTION(n, label, hdlr, xfer) \ - START_EXCEPTION(label); \ - NORMAL_EXCEPTION_PROLOG; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - xfer(n, hdlr) - -#define CRITICAL_EXCEPTION(n, label, hdlr) \ - START_EXCEPTION(label); \ - CRITICAL_EXCEPTION_PROLOG; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ - NOCOPY, crit_transfer_to_handler, \ - ret_from_crit_exc) - -#define MCHECK_EXCEPTION(n, label, hdlr) \ - START_EXCEPTION(label); \ - MCHECK_EXCEPTION_PROLOG; \ - mfspr r5,SPRN_ESR; \ - stw r5,_ESR(r11); \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ - NOCOPY, mcheck_transfer_to_handler, \ - ret_from_mcheck_exc) - -#define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret) \ - li r10,trap; \ - stw r10,TRAP(r11); \ - lis r10,msr@h; \ - ori r10,r10,msr@l; \ - copyee(r10, r9); \ - bl tfer; \ - .long hdlr; \ - .long ret - -#define COPY_EE(d, s) rlwimi d,s,0,16,16 -#define NOCOPY(d, s) - -#define EXC_XFER_STD(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \ - ret_from_except_full) - -#define EXC_XFER_LITE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \ - ret_from_except) - -#define EXC_XFER_EE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \ - ret_from_except_full) - -#define EXC_XFER_EE_LITE(n, hdlr) \ - EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \ - ret_from_except) - -/* Check for a single step debug exception while in an exception - * handler before state has been saved. This is to catch the case - * where an instruction that we are trying to single step causes - * an exception (eg ITLB/DTLB miss) and thus the first instruction of - * the exception handler generates a single step debug exception. - * - * If we get a debug trap on the first instruction of an exception handler, - * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is - * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR). - * The exception handler was handling a non-critical interrupt, so it will - * save (and later restore) the MSR via SPRN_CSRR1, which will still have - * the MSR_DE bit set. - */ -#define DEBUG_EXCEPTION \ - START_EXCEPTION(Debug); \ - CRITICAL_EXCEPTION_PROLOG; \ - \ - /* \ - * If there is a single step or branch-taken exception in an \ - * exception entry sequence, it was probably meant to apply to \ - * the code where the exception occurred (since exception entry \ - * doesn't turn off DE automatically). We simulate the effect \ - * of turning off DE on entry to an exception handler by turning \ - * off DE in the CSRR1 value and clearing the debug status. \ - */ \ - mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \ - andis. r10,r10,DBSR_IC@h; \ - beq+ 2f; \ - \ - lis r10,KERNELBASE@h; /* check if exception in vectors */ \ - ori r10,r10,KERNELBASE@l; \ - cmplw r12,r10; \ - blt+ 2f; /* addr below exception vectors */ \ - \ - lis r10,Debug@h; \ - ori r10,r10,Debug@l; \ - cmplw r12,r10; \ - bgt+ 2f; /* addr above exception vectors */ \ - \ - /* here it looks like we got an inappropriate debug exception. */ \ -1: rlwinm r9,r9,0,~MSR_DE; /* clear DE in the CSRR1 value */ \ - lis r10,DBSR_IC@h; /* clear the IC event */ \ - mtspr SPRN_DBSR,r10; \ - /* restore state and get out */ \ - lwz r10,_CCR(r11); \ - lwz r0,GPR0(r11); \ - lwz r1,GPR1(r11); \ - mtcrf 0x80,r10; \ - mtspr SPRN_CSRR0,r12; \ - mtspr SPRN_CSRR1,r9; \ - lwz r9,GPR9(r11); \ - lwz r12,GPR12(r11); \ - mtspr CRIT_SPRG,r8; \ - BOOKE_LOAD_EXC_LEVEL_STACK(CRIT); /* r8 points to the debug stack */ \ - lwz r10,GPR10-INT_FRAME_SIZE(r8); \ - lwz r11,GPR11-INT_FRAME_SIZE(r8); \ - mfspr r8,CRIT_SPRG; \ - \ - rfci; \ - b .; \ - \ - /* continue normal handling for a critical exception... */ \ -2: mfspr r4,SPRN_DBSR; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc) - -#define INSTRUCTION_STORAGE_EXCEPTION \ - START_EXCEPTION(InstructionStorage) \ - NORMAL_EXCEPTION_PROLOG; \ - mfspr r5,SPRN_ESR; /* Grab the ESR and save it */ \ - stw r5,_ESR(r11); \ - mr r4,r12; /* Pass SRR0 as arg2 */ \ - li r5,0; /* Pass zero as arg3 */ \ - EXC_XFER_EE_LITE(0x0400, handle_page_fault) - -#define ALIGNMENT_EXCEPTION \ - START_EXCEPTION(Alignment) \ - NORMAL_EXCEPTION_PROLOG; \ - mfspr r4,SPRN_DEAR; /* Grab the DEAR and save it */ \ - stw r4,_DEAR(r11); \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_EE(0x0600, alignment_exception) - -#define PROGRAM_EXCEPTION \ - START_EXCEPTION(Program) \ - NORMAL_EXCEPTION_PROLOG; \ - mfspr r4,SPRN_ESR; /* Grab the ESR and save it */ \ - stw r4,_ESR(r11); \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_STD(0x0700, program_check_exception) - -#define DECREMENTER_EXCEPTION \ - START_EXCEPTION(Decrementer) \ - NORMAL_EXCEPTION_PROLOG; \ - lis r0,TSR_DIS@h; /* Setup the DEC interrupt mask */ \ - mtspr SPRN_TSR,r0; /* Clear the DEC interrupt */ \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_LITE(0x0900, timer_interrupt) - -#define FP_UNAVAILABLE_EXCEPTION \ - START_EXCEPTION(FloatingPointUnavailable) \ - NORMAL_EXCEPTION_PROLOG; \ - bne load_up_fpu; /* if from user, just load it up */ \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception) - -#endif /* __HEAD_BOOKE_H__ */ diff --git a/arch/ppc/kernel/machine_kexec.c b/arch/ppc/kernel/machine_kexec.c deleted file mode 100644 index a469ba438cb..00000000000 --- a/arch/ppc/kernel/machine_kexec.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * machine_kexec.c - handle transition of Linux booting another kernel - * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com> - * - * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. - */ - -#include <linux/mm.h> -#include <linux/kexec.h> -#include <linux/delay.h> -#include <linux/reboot.h> -#include <asm/pgtable.h> -#include <asm/pgalloc.h> -#include <asm/mmu_context.h> -#include <asm/io.h> -#include <asm/hw_irq.h> -#include <asm/cacheflush.h> -#include <asm/machdep.h> - -typedef NORET_TYPE void (*relocate_new_kernel_t)( - unsigned long indirection_page, - unsigned long reboot_code_buffer, - unsigned long start_address) ATTRIB_NORET; - -extern const unsigned char relocate_new_kernel[]; -extern const unsigned int relocate_new_kernel_size; - -void machine_shutdown(void) -{ - if (ppc_md.machine_shutdown) - ppc_md.machine_shutdown(); -} - -void machine_crash_shutdown(struct pt_regs *regs) -{ - if (ppc_md.machine_crash_shutdown) - ppc_md.machine_crash_shutdown(); -} - -/* - * Do what every setup is needed on image and the - * reboot code buffer to allow us to avoid allocations - * later. - */ -int machine_kexec_prepare(struct kimage *image) -{ - if (ppc_md.machine_kexec_prepare) - return ppc_md.machine_kexec_prepare(image); - /* - * Fail if platform doesn't provide its own machine_kexec_prepare - * implementation. - */ - return -ENOSYS; -} - -void machine_kexec_cleanup(struct kimage *image) -{ - if (ppc_md.machine_kexec_cleanup) - ppc_md.machine_kexec_cleanup(image); -} - -/* - * Do not allocate memory (or fail in any way) in machine_kexec(). - * We are past the point of no return, committed to rebooting now. - */ -NORET_TYPE void machine_kexec(struct kimage *image) -{ - if (ppc_md.machine_kexec) - ppc_md.machine_kexec(image); - else { - /* - * Fall back to normal restart if platform doesn't provide - * its own kexec function, and user insist to kexec... - */ - machine_restart(NULL); - } - for(;;); -} - -/* - * This is a generic machine_kexec function suitable at least for - * non-OpenFirmware embedded platforms. - * It merely copies the image relocation code to the control page and - * jumps to it. - * A platform specific function may just call this one. - */ -void machine_kexec_simple(struct kimage *image) -{ - unsigned long page_list; - unsigned long reboot_code_buffer, reboot_code_buffer_phys; - relocate_new_kernel_t rnk; - - /* Interrupts aren't acceptable while we reboot */ - local_irq_disable(); - - page_list = image->head; - - /* we need both effective and real address here */ - reboot_code_buffer = - (unsigned long)page_address(image->control_code_page); - reboot_code_buffer_phys = virt_to_phys((void *)reboot_code_buffer); - - /* copy our kernel relocation code to the control code page */ - memcpy((void *)reboot_code_buffer, relocate_new_kernel, - relocate_new_kernel_size); - - flush_icache_range(reboot_code_buffer, - reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE); - printk(KERN_INFO "Bye!\n"); - - /* now call it */ - rnk = (relocate_new_kernel_t) reboot_code_buffer; - (*rnk)(page_list, reboot_code_buffer_phys, image->start); -} - diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S deleted file mode 100644 index d5e0dfc9ffe..00000000000 --- a/arch/ppc/kernel/misc.S +++ /dev/null @@ -1,868 +0,0 @@ -/* - * This file contains miscellaneous low-level functions. - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) - * and Paul Mackerras. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include <linux/sys.h> -#include <asm/unistd.h> -#include <asm/errno.h> -#include <asm/processor.h> -#include <asm/page.h> -#include <asm/cache.h> -#include <asm/cputable.h> -#include <asm/mmu.h> -#include <asm/ppc_asm.h> -#include <asm/thread_info.h> -#include <asm/asm-offsets.h> - -#ifdef CONFIG_8xx -#define ISYNC_8xx isync -#else -#define ISYNC_8xx -#endif - .text - - .align 5 -_GLOBAL(__delay) - cmpwi 0,r3,0 - mtctr r3 - beqlr -1: bdnz 1b - blr - -/* - * Returns (address we're running at) - (address we were linked at) - * for use before the text and data are mapped to KERNELBASE. - */ -_GLOBAL(reloc_offset) - mflr r0 - bl 1f -1: mflr r3 - lis r4,1b@ha - addi r4,r4,1b@l - subf r3,r4,r3 - mtlr r0 - blr - -/* - * add_reloc_offset(x) returns x + reloc_offset(). - */ -_GLOBAL(add_reloc_offset) - mflr r0 - bl 1f -1: mflr r5 - lis r4,1b@ha - addi r4,r4,1b@l - subf r5,r4,r5 - add r3,r3,r5 - mtlr r0 - blr - -/* - * sub_reloc_offset(x) returns x - reloc_offset(). - */ -_GLOBAL(sub_reloc_offset) - mflr r0 - bl 1f -1: mflr r5 - lis r4,1b@ha - addi r4,r4,1b@l - subf r5,r4,r5 - subf r3,r5,r3 - mtlr r0 - blr - -/* - * reloc_got2 runs through the .got2 section adding an offset - * to each entry. - */ -_GLOBAL(reloc_got2) - mflr r11 - lis r7,__got2_start@ha - addi r7,r7,__got2_start@l - lis r8,__got2_end@ha - addi r8,r8,__got2_end@l - subf r8,r7,r8 - srwi. r8,r8,2 - beqlr - mtctr r8 - bl 1f -1: mflr r0 - lis r4,1b@ha - addi r4,r4,1b@l - subf r0,r4,r0 - add r7,r0,r7 -2: lwz r0,0(r7) - add r0,r0,r3 - stw r0,0(r7) - addi r7,r7,4 - bdnz 2b - mtlr r11 - blr - -/* - * call_setup_cpu - call the setup_cpu function for this cpu - * r3 = data offset, r24 = cpu number - * - * Setup function is called with: - * r3 = data offset - * r4 = ptr to CPU spec (relocated) - */ -_GLOBAL(call_setup_cpu) - addis r4,r3,cur_cpu_spec@ha - addi r4,r4,cur_cpu_spec@l - lwz r4,0(r4) - add r4,r4,r3 - lwz r5,CPU_SPEC_SETUP(r4) - cmpi 0,r5,0 - add r5,r5,r3 - beqlr - mtctr r5 - bctr - -/* - * complement mask on the msr then "or" some values on. - * _nmask_and_or_msr(nmask, value_to_or) - */ -_GLOBAL(_nmask_and_or_msr) - mfmsr r0 /* Get current msr */ - andc r0,r0,r3 /* And off the bits set in r3 (first parm) */ - or r0,r0,r4 /* Or on the bits in r4 (second parm) */ - SYNC /* Some chip revs have problems here... */ - mtmsr r0 /* Update machine state */ - isync - blr /* Done */ - - -/* - * Flush MMU TLB - */ -_GLOBAL(_tlbia) -#if defined(CONFIG_40x) - sync /* Flush to memory before changing mapping */ - tlbia - isync /* Flush shadow TLB */ -#elif defined(CONFIG_44x) - li r3,0 - sync - - /* Load high watermark */ - lis r4,tlb_44x_hwater@ha - lwz r5,tlb_44x_hwater@l(r4) - -1: tlbwe r3,r3,PPC44x_TLB_PAGEID - addi r3,r3,1 - cmpw 0,r3,r5 - ble 1b - - isync -#else /* !(CONFIG_40x || CONFIG_44x) */ -#if defined(CONFIG_SMP) - rlwinm r8,r1,0,0,18 - lwz r8,TI_CPU(r8) - oris r8,r8,10 - mfmsr r10 - SYNC - rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ - rlwinm r0,r0,0,28,26 /* clear DR */ - mtmsr r0 - SYNC_601 - isync - lis r9,mmu_hash_lock@h - ori r9,r9,mmu_hash_lock@l - tophys(r9,r9) -10: lwarx r7,0,r9 - cmpwi 0,r7,0 - bne- 10b - stwcx. r8,0,r9 - bne- 10b - sync - tlbia - sync - TLBSYNC - li r0,0 - stw r0,0(r9) /* clear mmu_hash_lock */ - mtmsr r10 - SYNC_601 - isync -#else /* CONFIG_SMP */ - sync - tlbia - sync -#endif /* CONFIG_SMP */ -#endif /* ! defined(CONFIG_40x) */ - blr - -/* - * Flush MMU TLB for a particular address - */ -_GLOBAL(_tlbie) -#if defined(CONFIG_40x) - /* We run the search with interrupts disabled because we have to change - * the PID and I don't want to preempt when that happens. - */ - mfmsr r5 - mfspr r6,SPRN_PID - wrteei 0 - mtspr SPRN_PID,r4 - tlbsx. r3, 0, r3 - mtspr SPRN_PID,r6 - wrtee r5 - bne 10f - sync - /* There are only 64 TLB entries, so r3 < 64, which means bit 25 is clear. - * Since 25 is the V bit in the TLB_TAG, loading this value will invalidate - * the TLB entry. */ - tlbwe r3, r3, TLB_TAG - isync -10: -#elif defined(CONFIG_44x) - mfspr r5,SPRN_MMUCR - rlwimi r5,r4,0,24,31 /* Set TID */ - - /* We have to run the search with interrupts disabled, even critical - * and debug interrupts (in fact the only critical exceptions we have - * are debug and machine check). Otherwise an interrupt which causes - * a TLB miss can clobber the MMUCR between the mtspr and the tlbsx. */ - mfmsr r4 - lis r6,(MSR_EE|MSR_CE|MSR_ME|MSR_DE)@ha - addi r6,r6,(MSR_EE|MSR_CE|MSR_ME|MSR_DE)@l - andc r6,r4,r6 - mtmsr r6 - mtspr SPRN_MMUCR,r5 - tlbsx. r3, 0, r3 - mtmsr r4 - bne 10f - sync - /* There are only 64 TLB entries, so r3 < 64, - * which means bit 22, is clear. Since 22 is - * the V bit in the TLB_PAGEID, loading this - * value will invalidate the TLB entry. - */ - tlbwe r3, r3, PPC44x_TLB_PAGEID - isync -10: -#else /* !(CONFIG_40x || CONFIG_44x) */ -#if defined(CONFIG_SMP) - rlwinm r8,r1,0,0,18 - lwz r8,TI_CPU(r8) - oris r8,r8,11 - mfmsr r10 - SYNC - rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */ - rlwinm r0,r0,0,28,26 /* clear DR */ - mtmsr r0 - SYNC_601 - isync - lis r9,mmu_hash_lock@h - ori r9,r9,mmu_hash_lock@l - tophys(r9,r9) -10: lwarx r7,0,r9 - cmpwi 0,r7,0 - bne- 10b - stwcx. r8,0,r9 - bne- 10b - eieio - tlbie r3 - sync - TLBSYNC - li r0,0 - stw r0,0(r9) /* clear mmu_hash_lock */ - mtmsr r10 - SYNC_601 - isync -#else /* CONFIG_SMP */ - tlbie r3 - sync -#endif /* CONFIG_SMP */ -#endif /* ! CONFIG_40x */ - blr - -/* - * Flush instruction cache. - * This is a no-op on the 601. - */ -_GLOBAL(flush_instruction_cache) -#if defined(CONFIG_8xx) - isync - lis r5, IDC_INVALL@h - mtspr SPRN_IC_CST, r5 -#elif defined(CONFIG_4xx) -#ifdef CONFIG_403GCX - li r3, 512 - mtctr r3 - lis r4, KERNELBASE@h -1: iccci 0, r4 - addi r4, r4, 16 - bdnz 1b -#else - lis r3, KERNELBASE@h - iccci 0,r3 -#endif -#else - mfspr r3,SPRN_PVR - rlwinm r3,r3,16,16,31 - cmpwi 0,r3,1 - beqlr /* for 601, do nothing */ - /* 603/604 processor - use invalidate-all bit in HID0 */ - mfspr r3,SPRN_HID0 - ori r3,r3,HID0_ICFI - mtspr SPRN_HID0,r3 -#endif /* CONFIG_8xx/4xx */ - isync - blr - -/* - * Write any modified data cache blocks out to memory - * and invalidate the corresponding instruction cache blocks. - * This is a no-op on the 601. - * - * __flush_icache_range(unsigned long start, unsigned long stop) - */ -_GLOBAL(__flush_icache_range) -BEGIN_FTR_SECTION - blr /* for 601, do nothing */ -END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) - li r5,L1_CACHE_BYTES-1 - andc r3,r3,r5 - subf r4,r3,r4 - add r4,r4,r5 - srwi. r4,r4,L1_CACHE_SHIFT - beqlr - mtctr r4 - mr r6,r3 -1: dcbst 0,r3 - addi r3,r3,L1_CACHE_BYTES - bdnz 1b - sync /* wait for dcbst's to get to ram */ - mtctr r4 -2: icbi 0,r6 - addi r6,r6,L1_CACHE_BYTES - bdnz 2b - sync /* additional sync needed on g4 */ - isync - blr -/* - * Write any modified data cache blocks out to memory. - * Does not invalidate the corresponding cache lines (especially for - * any corresponding instruction cache). - * - * clean_dcache_range(unsigned long start, unsigned long stop) - */ -_GLOBAL(clean_dcache_range) - li r5,L1_CACHE_BYTES-1 - andc r3,r3,r5 - subf r4,r3,r4 - add r4,r4,r5 - srwi. r4,r4,L1_CACHE_SHIFT - beqlr - mtctr r4 - -1: dcbst 0,r3 - addi r3,r3,L1_CACHE_BYTES - bdnz 1b - sync /* wait for dcbst's to get to ram */ - blr - -/* - * Write any modified data cache blocks out to memory and invalidate them. - * Does not invalidate the corresponding instruction cache blocks. - * - * flush_dcache_range(unsigned long start, unsigned long stop) - */ -_GLOBAL(flush_dcache_range) - li r5,L1_CACHE_BYTES-1 - andc r3,r3,r5 - subf r4,r3,r4 - add r4,r4,r5 - srwi. r4,r4,L1_CACHE_SHIFT - beqlr - mtctr r4 - -1: dcbf 0,r3 - addi r3,r3,L1_CACHE_BYTES - bdnz 1b - sync /* wait for dcbst's to get to ram */ - blr - -/* - * Like above, but invalidate the D-cache. This is used by the 8xx - * to invalidate the cache so the PPC core doesn't get stale data - * from the CPM (no cache snooping here :-). - * - * invalidate_dcache_range(unsigned long start, unsigned long stop) - */ -_GLOBAL(invalidate_dcache_range) - li r5,L1_CACHE_BYTES-1 - andc r3,r3,r5 - subf r4,r3,r4 - add r4,r4,r5 - srwi. r4,r4,L1_CACHE_SHIFT - beqlr - mtctr r4 - -1: dcbi 0,r3 - addi r3,r3,L1_CACHE_BYTES - bdnz 1b - sync /* wait for dcbi's to get to ram */ - blr - -#ifdef CONFIG_NOT_COHERENT_CACHE -/* - * 40x cores have 8K or 16K dcache and 32 byte line size. - * 44x has a 32K dcache and 32 byte line size. - * 8xx has 1, 2, 4, 8K variants. - * For now, cover the worst case of the 44x. - * Must be called with external interrupts disabled. - */ -#define CACHE_NWAYS 64 -#define CACHE_NLINES 16 - -_GLOBAL(flush_dcache_all) - li r4, (2 * CACHE_NWAYS * CACHE_NLINES) - mtctr r4 - lis r5, KERNELBASE@h -1: lwz r3, 0(r5) /* Load one word from every line */ - addi r5, r5, L1_CACHE_BYTES - bdnz 1b - blr -#endif /* CONFIG_NOT_COHERENT_CACHE */ - -/* - * Flush a particular page from the data cache to RAM. - * Note: this is necessary because the instruction cache does *not* - * snoop from the data cache. - * This is a no-op on the 601 which has a unified cache. - * - * void __flush_dcache_icache(void *page) - */ -_GLOBAL(__flush_dcache_icache) -BEGIN_FTR_SECTION - blr /* for 601, do nothing */ -END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) - rlwinm r3,r3,0,0,19 /* Get page base address */ - li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */ - mtctr r4 - mr r6,r3 -0: dcbst 0,r3 /* Write line to ram */ - addi r3,r3,L1_CACHE_BYTES - bdnz 0b - sync -#ifndef CONFIG_44x - /* We don't flush the icache on 44x. Those have a virtual icache - * and we don't have access to the virtual address here (it's - * not the page vaddr but where it's mapped in user space). The - * flushing of the icache on these is handled elsewhere, when - * a change in the address space occurs, before returning to - * user space - */ - mtctr r4 -1: icbi 0,r6 - addi r6,r6,L1_CACHE_BYTES - bdnz 1b - sync - isync -#endif /* CONFIG_44x */ - blr - -/* - * Flush a particular page from the data cache to RAM, identified - * by its physical address. We turn off the MMU so we can just use - * the physical address (this may be a highmem page without a kernel - * mapping). - * - * void __flush_dcache_icache_phys(unsigned long physaddr) - */ -_GLOBAL(__flush_dcache_icache_phys) -BEGIN_FTR_SECTION - blr /* for 601, do nothing */ -END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) - mfmsr r10 - rlwinm r0,r10,0,28,26 /* clear DR */ - mtmsr r0 - isync - rlwinm r3,r3,0,0,19 /* Get page base address */ - li r4,4096/L1_CACHE_BYTES /* Number of lines in a page */ - mtctr r4 - mr r6,r3 -0: dcbst 0,r3 /* Write line to ram */ - addi r3,r3,L1_CACHE_BYTES - bdnz 0b - sync - mtctr r4 -1: icbi 0,r6 - addi r6,r6,L1_CACHE_BYTES - bdnz 1b - sync - mtmsr r10 /* restore DR */ - isync - blr - -/* - * Clear pages using the dcbz instruction, which doesn't cause any - * memory traffic (except to write out any cache lines which get - * displaced). This only works on cacheable memory. - * - * void clear_pages(void *page, int order) ; - */ -_GLOBAL(clear_pages) - li r0,4096/L1_CACHE_BYTES - slw r0,r0,r4 - mtctr r0 -#ifdef CONFIG_8xx - li r4, 0 -1: stw r4, 0(r3) - stw r4, 4(r3) - stw r4, 8(r3) - stw r4, 12(r3) -#else -1: dcbz 0,r3 -#endif - addi r3,r3,L1_CACHE_BYTES - bdnz 1b - blr - -/* - * Copy a whole page. We use the dcbz instruction on the destination - * to reduce memory traffic (it eliminates the unnecessary reads of - * the destination into cache). This requires that the destination - * is cacheable. - */ -#define COPY_16_BYTES \ - lwz r6,4(r4); \ - lwz r7,8(r4); \ - lwz r8,12(r4); \ - lwzu r9,16(r4); \ - stw r6,4(r3); \ - stw r7,8(r3); \ - stw r8,12(r3); \ - stwu r9,16(r3) - -_GLOBAL(copy_page) - addi r3,r3,-4 - addi r4,r4,-4 - -#ifdef CONFIG_8xx - /* don't use prefetch on 8xx */ - li r0,4096/L1_CACHE_BYTES - mtctr r0 -1: COPY_16_BYTES - bdnz 1b - blr - -#else /* not 8xx, we can prefetch */ - li r5,4 - -#if MAX_COPY_PREFETCH > 1 - li r0,MAX_COPY_PREFETCH - li r11,4 - mtctr r0 -11: dcbt r11,r4 - addi r11,r11,L1_CACHE_BYTES - bdnz 11b -#else /* MAX_COPY_PREFETCH == 1 */ - dcbt r5,r4 - li r11,L1_CACHE_BYTES+4 -#endif /* MAX_COPY_PREFETCH */ - li r0,4096/L1_CACHE_BYTES - MAX_COPY_PREFETCH - crclr 4*cr0+eq -2: - mtctr r0 -1: - dcbt r11,r4 - dcbz r5,r3 - COPY_16_BYTES -#if L1_CACHE_BYTES >= 32 - COPY_16_BYTES -#if L1_CACHE_BYTES >= 64 - COPY_16_BYTES - COPY_16_BYTES -#if L1_CACHE_BYTES >= 128 - COPY_16_BYTES - COPY_16_BYTES - COPY_16_BYTES - COPY_16_BYTES -#endif -#endif -#endif - bdnz 1b - beqlr - crnot 4*cr0+eq,4*cr0+eq - li r0,MAX_COPY_PREFETCH - li r11,4 - b 2b -#endif /* CONFIG_8xx */ - -/* - * void atomic_clear_mask(atomic_t mask, atomic_t *addr) - * void atomic_set_mask(atomic_t mask, atomic_t *addr); - */ -_GLOBAL(atomic_clear_mask) -10: lwarx r5,0,r4 - andc r5,r5,r3 - PPC405_ERR77(0,r4) - stwcx. r5,0,r4 - bne- 10b - blr -_GLOBAL(atomic_set_mask) -10: lwarx r5,0,r4 - or r5,r5,r3 - PPC405_ERR77(0,r4) - stwcx. r5,0,r4 - bne- 10b - blr - -/* - * I/O string operations - * - * insb(port, buf, len) - * outsb(port, buf, len) - * insw(port, buf, len) - * outsw(port, buf, len) - * insl(port, buf, len) - * outsl(port, buf, len) - * insw_ns(port, buf, len) - * outsw_ns(port, buf, len) - * insl_ns(port, buf, len) - * outsl_ns(port, buf, len) - * - * The *_ns versions don't do byte-swapping. - */ -_GLOBAL(_insb) - cmpwi 0,r5,0 - mtctr r5 - subi r4,r4,1 - blelr- -00: lbz r5,0(r3) -01: eieio -02: stbu r5,1(r4) - ISYNC_8xx - .section .fixup,"ax" -03: blr - .text - .section __ex_table, "a" - .align 2 - .long 00b, 03b - .long 01b, 03b - .long 02b, 03b - .text - bdnz 00b - blr - -_GLOBAL(_outsb) - cmpwi 0,r5,0 - mtctr r5 - subi r4,r4,1 - blelr- -00: lbzu r5,1(r4) -01: stb r5,0(r3) -02: eieio - ISYNC_8xx - .section .fixup,"ax" -03: blr - .text - .section __ex_table, "a" - .align 2 - .long 00b, 03b - .long 01b, 03b - .long 02b, 03b - .text - bdnz 00b - blr - -_GLOBAL(_insw_ns) - cmpwi 0,r5,0 - mtctr r5 - subi r4,r4,2 - blelr- -00: lhz r5,0(r3) -01: eieio -02: sthu r5,2(r4) - ISYNC_8xx - .section .fixup,"ax" -03: blr - .text - .section __ex_table, "a" - .align 2 - .long 00b, 03b - .long 01b, 03b - .long 02b, 03b - .text - bdnz 00b - blr - -_GLOBAL(_outsw_ns) - cmpwi 0,r5,0 - mtctr r5 - subi r4,r4,2 - blelr- -00: lhzu r5,2(r4) -01: sth r5,0(r3) -02: eieio - ISYNC_8xx - .section .fixup,"ax" -03: blr - .text - .section __ex_table, "a" - .align 2 - .long 00b, 03b - .long 01b, 03b - .long 02b, 03b - .text - bdnz 00b - blr - -_GLOBAL(_insl_ns) - cmpwi 0,r5,0 - mtctr r5 - subi r4,r4,4 - blelr- -00: lwz r5,0(r3) -01: eieio -02: stwu r5,4(r4) - ISYNC_8xx - .section .fixup,"ax" -03: blr - .text - .section __ex_table, "a" - .align 2 - .long 00b, 03b - .long 01b, 03b - .long 02b, 03b - .text - bdnz 00b - blr - -_GLOBAL(_outsl_ns) - cmpwi 0,r5,0 - mtctr r5 - subi r4,r4,4 - blelr- -00: lwzu r5,4(r4) -01: stw r5,0(r3) -02: eieio - ISYNC_8xx - .section .fixup,"ax" -03: blr - .text - .section __ex_table, "a" - .align 2 - .long 00b, 03b - .long 01b, 03b - .long 02b, 03b - .text - bdnz 00b - blr - -/* - * Extended precision shifts. - * - * Updated to be valid for shift counts from 0 to 63 inclusive. - * -- Gabriel - * - * R3/R4 has 64 bit value - * R5 has shift count - * result in R3/R4 - * - * ashrdi3: arithmetic right shift (sign propagation) - * lshrdi3: logical right shift - * ashldi3: left shift - */ -_GLOBAL(__ashrdi3) - subfic r6,r5,32 - srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count - addi r7,r5,32 # could be xori, or addi with -32 - slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count) - rlwinm r8,r7,0,32 # t3 = (count < 32) ? 32 : 0 - sraw r7,r3,r7 # t2 = MSW >> (count-32) - or r4,r4,r6 # LSW |= t1 - slw r7,r7,r8 # t2 = (count < 32) ? 0 : t2 - sraw r3,r3,r5 # MSW = MSW >> count - or r4,r4,r7 # LSW |= t2 - blr - -_GLOBAL(__ashldi3) - subfic r6,r5,32 - slw r3,r3,r5 # MSW = count > 31 ? 0 : MSW << count - addi r7,r5,32 # could be xori, or addi with -32 - srw r6,r4,r6 # t1 = count > 31 ? 0 : LSW >> (32-count) - slw r7,r4,r7 # t2 = count < 32 ? 0 : LSW << (count-32) - or r3,r3,r6 # MSW |= t1 - slw r4,r4,r5 # LSW = LSW << count - or r3,r3,r7 # MSW |= t2 - blr - -_GLOBAL(__lshrdi3) - subfic r6,r5,32 - srw r4,r4,r5 # LSW = count > 31 ? 0 : LSW >> count - addi r7,r5,32 # could be xori, or addi with -32 - slw r6,r3,r6 # t1 = count > 31 ? 0 : MSW << (32-count) - srw r7,r3,r7 # t2 = count < 32 ? 0 : MSW >> (count-32) - or r4,r4,r6 # LSW |= t1 - srw r3,r3,r5 # MSW = MSW >> count - or r4,r4,r7 # LSW |= t2 - blr - -_GLOBAL(abs) - srawi r4,r3,31 - xor r3,r3,r4 - sub r3,r3,r4 - blr - -_GLOBAL(_get_SP) - mr r3,r1 /* Close enough */ - blr - -/* - * Create a kernel thread - * kernel_thread(fn, arg, flags) - */ -_GLOBAL(kernel_thread) - stwu r1,-16(r1) - stw r30,8(r1) - stw r31,12(r1) - mr r30,r3 /* function */ - mr r31,r4 /* argument */ - ori r3,r5,CLONE_VM /* flags */ - oris r3,r3,CLONE_UNTRACED>>16 - li r4,0 /* new sp (unused) */ - li r0,__NR_clone - sc - cmpwi 0,r3,0 /* parent or child? */ - bne 1f /* return if parent */ - li r0,0 /* make top-level stack frame */ - stwu r0,-16(r1) - mtlr r30 /* fn addr in lr */ - mr r3,r31 /* load arg and call fn */ - PPC440EP_ERR42 - blrl - li r0,__NR_exit /* exit if function returns */ - li r3,0 - sc -1: lwz r30,8(r1) - lwz r31,12(r1) - addi r1,r1,16 - blr - -_GLOBAL(kernel_execve) - li r0,__NR_execve - sc - bnslr - neg r3,r3 - blr - -/* - * This routine is just here to keep GCC happy - sigh... - */ -_GLOBAL(__main) - blr - diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c deleted file mode 100644 index df3ef6db072..00000000000 --- a/arch/ppc/kernel/pci.c +++ /dev/null @@ -1,1233 +0,0 @@ -/* - * Common prep/chrp pci routines. -- Cort - */ - -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/capability.h> -#include <linux/sched.h> -#include <linux/errno.h> -#include <linux/bootmem.h> - -#include <asm/processor.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/sections.h> -#include <asm/pci-bridge.h> -#include <asm/byteorder.h> -#include <asm/irq.h> -#include <asm/uaccess.h> -#include <asm/machdep.h> - -#undef DEBUG - -#ifdef DEBUG -#define DBG(x...) printk(x) -#else -#define DBG(x...) -#endif - -unsigned long isa_io_base = 0; -unsigned long isa_mem_base = 0; -unsigned long pci_dram_offset = 0; -int pcibios_assign_bus_offset = 1; - -void pcibios_make_OF_bus_map(void); - -static int pci_relocate_bridge_resource(struct pci_bus *bus, int i); -static int probe_resource(struct pci_bus *parent, struct resource *pr, - struct resource *res, struct resource **conflict); -static void update_bridge_base(struct pci_bus *bus, int i); -static void pcibios_fixup_resources(struct pci_dev* dev); -static void fixup_broken_pcnet32(struct pci_dev* dev); -static int reparent_resources(struct resource *parent, struct resource *res); -static void fixup_cpc710_pci64(struct pci_dev* dev); - -/* By default, we don't re-assign bus numbers. - */ -int pci_assign_all_buses; - -struct pci_controller* hose_head; -struct pci_controller** hose_tail = &hose_head; - -static int pci_bus_count; - -static void -fixup_broken_pcnet32(struct pci_dev* dev) -{ - if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) { - dev->vendor = PCI_VENDOR_ID_AMD; - pci_write_config_word(dev, PCI_VENDOR_ID, PCI_VENDOR_ID_AMD); - } -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32); - -static void -fixup_cpc710_pci64(struct pci_dev* dev) -{ - /* Hide the PCI64 BARs from the kernel as their content doesn't - * fit well in the resource management - */ - dev->resource[0].start = dev->resource[0].end = 0; - dev->resource[0].flags = 0; - dev->resource[1].start = dev->resource[1].end = 0; - dev->resource[1].flags = 0; -} -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64); - -static void -pcibios_fixup_resources(struct pci_dev *dev) -{ - struct pci_controller* hose = (struct pci_controller *)dev->sysdata; - int i; - unsigned long offset; - - if (!hose) { - printk(KERN_ERR "No hose for PCI dev %s!\n", pci_name(dev)); - return; - } - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - struct resource *res = dev->resource + i; - if (!res->flags) - continue; - if (res->end == 0xffffffff) { - DBG("PCI:%s Resource %d [%016llx-%016llx] is unassigned\n", - pci_name(dev), i, - (unsigned long long)res->start, - (unsigned long long)res->end); - res->end -= res->start; - res->start = 0; - res->flags |= IORESOURCE_UNSET; - continue; - } - offset = 0; - if (res->flags & IORESOURCE_MEM) { - offset = hose->pci_mem_offset; - } else if (res->flags & IORESOURCE_IO) { - offset = (unsigned long) hose->io_base_virt - - isa_io_base; - } - if (offset != 0) { - res->start += offset; - res->end += offset; -#ifdef DEBUG - printk("Fixup res %d (%lx) of dev %s: %lx -> %lx\n", - i, res->flags, pci_name(dev), - res->start - offset, res->start); -#endif - } - } - - /* Call machine specific resource fixup */ - if (ppc_md.pcibios_fixup_resources) - ppc_md.pcibios_fixup_resources(dev); -} -DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources); - -void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, - struct resource *res) -{ - unsigned long offset = 0; - struct pci_controller *hose = dev->sysdata; - - if (hose && res->flags & IORESOURCE_IO) - offset = (unsigned long)hose->io_base_virt - isa_io_base; - else if (hose && res->flags & IORESOURCE_MEM) - offset = hose->pci_mem_offset; - region->start = res->start - offset; - region->end = res->end - offset; -} -EXPORT_SYMBOL(pcibios_resource_to_bus); - -void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, - struct pci_bus_region *region) -{ - unsigned long offset = 0; - struct pci_controller *hose = dev->sysdata; - - if (hose && res->flags & IORESOURCE_IO) - offset = (unsigned long)hose->io_base_virt - isa_io_base; - else if (hose && res->flags & IORESOURCE_MEM) - offset = hose->pci_mem_offset; - res->start = region->start + offset; - res->end = region->end + offset; -} -EXPORT_SYMBOL(pcibios_bus_to_resource); - -/* - * We need to avoid collisions with `mirrored' VGA ports - * and other strange ISA hardware, so we always want the - * addresses to be allocated in the 0x000-0x0ff region - * modulo 0x400. - * - * Why? Because some silly external IO cards only decode - * the low 10 bits of the IO address. The 0x00-0xff region - * is reserved for motherboard devices that decode all 16 - * bits, so it's ok to allocate at, say, 0x2800-0x28ff, - * but we want to try to avoid allocating at 0x2900-0x2bff - * which might have be mirrored at 0x0100-0x03ff.. - */ -void pcibios_align_resource(void *data, struct resource *res, - resource_size_t size, resource_size_t align) -{ - struct pci_dev *dev = data; - - if (res->flags & IORESOURCE_IO) { - resource_size_t start = res->start; - - if (size > 0x100) { - printk(KERN_ERR "PCI: I/O Region %s/%d too large" - " (%lld bytes)\n", pci_name(dev), - dev->resource - res, (unsigned long long)size); - } - - if (start & 0x300) { - start = (start + 0x3ff) & ~0x3ff; - res->start = start; - } - } -} -EXPORT_SYMBOL(pcibios_align_resource); - -/* - * Handle resources of PCI devices. If the world were perfect, we could - * just allocate all the resource regions and do nothing more. It isn't. - * On the other hand, we cannot just re-allocate all devices, as it would - * require us to know lots of host bridge internals. So we attempt to - * keep as much of the original configuration as possible, but tweak it - * when it's found to be wrong. - * - * Known BIOS problems we have to work around: - * - I/O or memory regions not configured - * - regions configured, but not enabled in the command register - * - bogus I/O addresses above 64K used - * - expansion ROMs left enabled (this may sound harmless, but given - * the fact the PCI specs explicitly allow address decoders to be - * shared between expansion ROMs and other resource regions, it's - * at least dangerous) - * - * Our solution: - * (1) Allocate resources for all buses behind PCI-to-PCI bridges. - * This gives us fixed barriers on where we can allocate. - * (2) Allocate resources for all enabled devices. If there is - * a collision, just mark the resource as unallocated. Also - * disable expansion ROMs during this step. - * (3) Try to allocate resources for disabled devices. If the - * resources were assigned correctly, everything goes well, - * if they weren't, they won't disturb allocation of other - * resources. - * (4) Assign new addresses to resources which were either - * not configured at all or misconfigured. If explicitly - * requested by the user, configure expansion ROM address - * as well. - */ - -static void __init -pcibios_allocate_bus_resources(struct list_head *bus_list) -{ - struct pci_bus *bus; - int i; - struct resource *res, *pr; - - /* Depth-First Search on bus tree */ - list_for_each_entry(bus, bus_list, node) { - for (i = 0; i < 4; ++i) { - if ((res = bus->resource[i]) == NULL || !res->flags - || res->start > res->end) - continue; - if (bus->parent == NULL) - pr = (res->flags & IORESOURCE_IO)? - &ioport_resource: &iomem_resource; - else { - pr = pci_find_parent_resource(bus->self, res); - if (pr == res) { - /* this happens when the generic PCI - * code (wrongly) decides that this - * bridge is transparent -- paulus - */ - continue; - } - } - - DBG("PCI: bridge rsrc %llx..%llx (%lx), parent %p\n", - (unsigned long long)res->start, - (unsigned long long)res->end, res->flags, pr); - if (pr) { - if (request_resource(pr, res) == 0) - continue; - /* - * Must be a conflict with an existing entry. - * Move that entry (or entries) under the - * bridge resource and try again. - */ - if (reparent_resources(pr, res) == 0) - continue; - } - printk(KERN_ERR "PCI: Cannot allocate resource region " - "%d of PCI bridge %d\n", i, bus->number); - if (pci_relocate_bridge_resource(bus, i)) - bus->resource[i] = NULL; - } - pcibios_allocate_bus_resources(&bus->children); - } -} - -/* - * Reparent resource children of pr that conflict with res - * under res, and make res replace those children. - */ -static int __init -reparent_resources(struct resource *parent, struct resource *res) -{ - struct resource *p, **pp; - struct resource **firstpp = NULL; - - for (pp = &parent->child; (p = *pp) != NULL; pp = &p->sibling) { - if (p->end < res->start) - continue; - if (res->end < p->start) - break; - if (p->start < res->start || p->end > res->end) - return -1; /* not completely contained */ - if (firstpp == NULL) - firstpp = pp; - } - if (firstpp == NULL) - return -1; /* didn't find any conflicting entries? */ - res->parent = parent; - res->child = *firstpp; - res->sibling = *pp; - *firstpp = res; - *pp = NULL; - for (p = res->child; p != NULL; p = p->sibling) { - p->parent = res; - DBG(KERN_INFO "PCI: reparented %s [%llx..%llx] under %s\n", - p->name, (unsigned long long)p->start, - (unsigned long long)p->end, res->name); - } - return 0; -} - -/* - * A bridge has been allocated a range which is outside the range - * of its parent bridge, so it needs to be moved. - */ -static int __init -pci_relocate_bridge_resource(struct pci_bus *bus, int i) -{ - struct resource *res, *pr, *conflict; - unsigned long try, size; - int j; - struct pci_bus *parent = bus->parent; - - if (parent == NULL) { - /* shouldn't ever happen */ - printk(KERN_ERR "PCI: can't move host bridge resource\n"); - return -1; - } - res = bus->resource[i]; - if (res == NULL) - return -1; - pr = NULL; - for (j = 0; j < 4; j++) { - struct resource *r = parent->resource[j]; - if (!r) - continue; - if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM)) - continue; - if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH)) { - pr = r; - break; - } - if (res->flags & IORESOURCE_PREFETCH) - pr = r; - } - if (pr == NULL) - return -1; - size = res->end - res->start; - if (pr->start > pr->end || size > pr->end - pr->start) - return -1; - try = pr->end; - for (;;) { - res->start = try - size; - res->end = try; - if (probe_resource(bus->parent, pr, res, &conflict) == 0) - break; - if (conflict->start <= pr->start + size) - return -1; - try = conflict->start - 1; - } - if (request_resource(pr, res)) { - DBG(KERN_ERR "PCI: huh? couldn't move to %llx..%llx\n", - (unsigned long long)res->start, - (unsigned long long)res->end); - return -1; /* "can't happen" */ - } - update_bridge_base(bus, i); - printk(KERN_INFO "PCI: bridge %d resource %d moved to %llx..%llx\n", - bus->number, i, (unsigned long long)res->start, - (unsigned long long)res->end); - return 0; -} - -static int __init -probe_resource(struct pci_bus *parent, struct resource *pr, - struct resource *res, struct resource **conflict) -{ - struct pci_bus *bus; - struct pci_dev *dev; - struct resource *r; - int i; - - for (r = pr->child; r != NULL; r = r->sibling) { - if (r->end >= res->start && res->end >= r->start) { - *conflict = r; - return 1; - } - } - list_for_each_entry(bus, &parent->children, node) { - for (i = 0; i < 4; ++i) { - if ((r = bus->resource[i]) == NULL) - continue; - if (!r->flags || r->start > r->end || r == res) - continue; - if (pci_find_parent_resource(bus->self, r) != pr) - continue; - if (r->end >= res->start && res->end >= r->start) { - *conflict = r; - return 1; - } - } - } - list_for_each_entry(dev, &parent->devices, bus_list) { - for (i = 0; i < 6; ++i) { - r = &dev->resource[i]; - if (!r->flags || (r->flags & IORESOURCE_UNSET)) - continue; - if (pci_find_parent_resource(dev, r) != pr) - continue; - if (r->end >= res->start && res->end >= r->start) { - *conflict = r; - return 1; - } - } - } - return 0; -} - -static void __init -update_bridge_base(struct pci_bus *bus, int i) -{ - struct resource *res = bus->resource[i]; - u8 io_base_lo, io_limit_lo; - u16 mem_base, mem_limit; - u16 cmd; - unsigned long start, end, off; - struct pci_dev *dev = bus->self; - struct pci_controller *hose = dev->sysdata; - - if (!hose) { - printk("update_bridge_base: no hose?\n"); - return; - } - pci_read_config_word(dev, PCI_COMMAND, &cmd); - pci_write_config_word(dev, PCI_COMMAND, - cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)); - if (res->flags & IORESOURCE_IO) { - off = (unsigned long) hose->io_base_virt - isa_io_base; - start = res->start - off; - end = res->end - off; - io_base_lo = (start >> 8) & PCI_IO_RANGE_MASK; - io_limit_lo = (end >> 8) & PCI_IO_RANGE_MASK; - if (end > 0xffff) { - pci_write_config_word(dev, PCI_IO_BASE_UPPER16, - start >> 16); - pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16, - end >> 16); - io_base_lo |= PCI_IO_RANGE_TYPE_32; - } else - io_base_lo |= PCI_IO_RANGE_TYPE_16; - pci_write_config_byte(dev, PCI_IO_BASE, io_base_lo); - pci_write_config_byte(dev, PCI_IO_LIMIT, io_limit_lo); - - } else if ((res->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH)) - == IORESOURCE_MEM) { - off = hose->pci_mem_offset; - mem_base = ((res->start - off) >> 16) & PCI_MEMORY_RANGE_MASK; - mem_limit = ((res->end - off) >> 16) & PCI_MEMORY_RANGE_MASK; - pci_write_config_word(dev, PCI_MEMORY_BASE, mem_base); - pci_write_config_word(dev, PCI_MEMORY_LIMIT, mem_limit); - - } else if ((res->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH)) - == (IORESOURCE_MEM | IORESOURCE_PREFETCH)) { - off = hose->pci_mem_offset; - mem_base = ((res->start - off) >> 16) & PCI_PREF_RANGE_MASK; - mem_limit = ((res->end - off) >> 16) & PCI_PREF_RANGE_MASK; - pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, mem_base); - pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, mem_limit); - - } else { - DBG(KERN_ERR "PCI: ugh, bridge %s res %d has flags=%lx\n", - pci_name(dev), i, res->flags); - } - pci_write_config_word(dev, PCI_COMMAND, cmd); -} - -static inline void alloc_resource(struct pci_dev *dev, int idx) -{ - struct resource *pr, *r = &dev->resource[idx]; - - DBG("PCI:%s: Resource %d: %016llx-%016llx (f=%lx)\n", - pci_name(dev), idx, (unsigned long long)r->start, - (unsigned long long)r->end, r->flags); - pr = pci_find_parent_resource(dev, r); - if (!pr || request_resource(pr, r) < 0) { - printk(KERN_ERR "PCI: Cannot allocate resource region %d" - " of device %s\n", idx, pci_name(dev)); - if (pr) - DBG("PCI: parent is %p: %016llx-%016llx (f=%lx)\n", - pr, (unsigned long long)pr->start, - (unsigned long long)pr->end, pr->flags); - /* We'll assign a new address later */ - r->flags |= IORESOURCE_UNSET; - r->end -= r->start; - r->start = 0; - } -} - -static void __init -pcibios_allocate_resources(int pass) -{ - struct pci_dev *dev = NULL; - int idx, disabled; - u16 command; - struct resource *r; - - for_each_pci_dev(dev) { - pci_read_config_word(dev, PCI_COMMAND, &command); - for (idx = 0; idx < 6; idx++) { - r = &dev->resource[idx]; - if (r->parent) /* Already allocated */ - continue; - if (!r->flags || (r->flags & IORESOURCE_UNSET)) - continue; /* Not assigned at all */ - if (r->flags & IORESOURCE_IO) - disabled = !(command & PCI_COMMAND_IO); - else - disabled = !(command & PCI_COMMAND_MEMORY); - if (pass == disabled) - alloc_resource(dev, idx); - } - if (pass) - continue; - r = &dev->resource[PCI_ROM_RESOURCE]; - if (r->flags & IORESOURCE_ROM_ENABLE) { - /* Turn the ROM off, leave the resource region, but keep it unregistered. */ - u32 reg; - DBG("PCI: Switching off ROM of %s\n", pci_name(dev)); - r->flags &= ~IORESOURCE_ROM_ENABLE; - pci_read_config_dword(dev, dev->rom_base_reg, ®); - pci_write_config_dword(dev, dev->rom_base_reg, - reg & ~PCI_ROM_ADDRESS_ENABLE); - } - } -} - -static void __init -pcibios_assign_resources(void) -{ - struct pci_dev *dev = NULL; - int idx; - struct resource *r; - - for_each_pci_dev(dev) { - int class = dev->class >> 8; - - /* Don't touch classless devices and host bridges */ - if (!class || class == PCI_CLASS_BRIDGE_HOST) - continue; - - for (idx = 0; idx < 6; idx++) { - r = &dev->resource[idx]; - - /* - * We shall assign a new address to this resource, - * either because the BIOS (sic) forgot to do so - * or because we have decided the old address was - * unusable for some reason. - */ - if ((r->flags & IORESOURCE_UNSET) && r->end && - (!ppc_md.pcibios_enable_device_hook || - !ppc_md.pcibios_enable_device_hook(dev, 1))) { - r->flags &= ~IORESOURCE_UNSET; - pci_assign_resource(dev, idx); - } - } - -#if 0 /* don't assign ROMs */ - r = &dev->resource[PCI_ROM_RESOURCE]; - r->end -= r->start; - r->start = 0; - if (r->end) - pci_assign_resource(dev, PCI_ROM_RESOURCE); -#endif - } -} - - -static int next_controller_index; - -struct pci_controller * __init -pcibios_alloc_controller(void) -{ - struct pci_controller *hose; - - hose = (struct pci_controller *)alloc_bootmem(sizeof(*hose)); - memset(hose, 0, sizeof(struct pci_controller)); - - *hose_tail = hose; - hose_tail = &hose->next; - - hose->index = next_controller_index++; - - return hose; -} - -void pcibios_make_OF_bus_map(void) -{ -} - -static int __init -pcibios_init(void) -{ - struct pci_controller *hose; - struct pci_bus *bus; - int next_busno; - - printk(KERN_INFO "PCI: Probing PCI hardware\n"); - - /* Scan all of the recorded PCI controllers. */ - for (next_busno = 0, hose = hose_head; hose; hose = hose->next) { - if (pci_assign_all_buses) - hose->first_busno = next_busno; - hose->last_busno = 0xff; - bus = pci_scan_bus(hose->first_busno, hose->ops, hose); - hose->last_busno = bus->subordinate; - if (pci_assign_all_buses || next_busno <= hose->last_busno) - next_busno = hose->last_busno + pcibios_assign_bus_offset; - } - pci_bus_count = next_busno; - - /* OpenFirmware based machines need a map of OF bus - * numbers vs. kernel bus numbers since we may have to - * remap them. - */ - if (pci_assign_all_buses && have_of) - pcibios_make_OF_bus_map(); - - /* Do machine dependent PCI interrupt routing */ - if (ppc_md.pci_swizzle && ppc_md.pci_map_irq) - pci_fixup_irqs(ppc_md.pci_swizzle, ppc_md.pci_map_irq); - - /* Call machine dependent fixup */ - if (ppc_md.pcibios_fixup) - ppc_md.pcibios_fixup(); - - /* Allocate and assign resources */ - pcibios_allocate_bus_resources(&pci_root_buses); - pcibios_allocate_resources(0); - pcibios_allocate_resources(1); - pcibios_assign_resources(); - - /* Call machine dependent post-init code */ - if (ppc_md.pcibios_after_init) - ppc_md.pcibios_after_init(); - - return 0; -} - -subsys_initcall(pcibios_init); - -unsigned char __init -common_swizzle(struct pci_dev *dev, unsigned char *pinp) -{ - struct pci_controller *hose = dev->sysdata; - - if (dev->bus->number != hose->first_busno) { - u8 pin = *pinp; - do { - pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); - /* Move up the chain of bridges. */ - dev = dev->bus->self; - } while (dev->bus->self); - *pinp = pin; - - /* The slot is the idsel of the last bridge. */ - } - return PCI_SLOT(dev->devfn); -} - -unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, - unsigned long start, unsigned long size) -{ - return start; -} - -void __init pcibios_fixup_bus(struct pci_bus *bus) -{ - struct pci_controller *hose = (struct pci_controller *) bus->sysdata; - unsigned long io_offset; - struct resource *res; - int i; - - io_offset = (unsigned long)hose->io_base_virt - isa_io_base; - if (bus->parent == NULL) { - /* This is a host bridge - fill in its resources */ - hose->bus = bus; - - bus->resource[0] = res = &hose->io_resource; - if (!res->flags) { - if (io_offset) - printk(KERN_ERR "I/O resource not set for host" - " bridge %d\n", hose->index); - res->start = 0; - res->end = IO_SPACE_LIMIT; - res->flags = IORESOURCE_IO; - } - res->start += io_offset; - res->end += io_offset; - - for (i = 0; i < 3; ++i) { - res = &hose->mem_resources[i]; - if (!res->flags) { - if (i > 0) - continue; - printk(KERN_ERR "Memory resource not set for " - "host bridge %d\n", hose->index); - res->start = hose->pci_mem_offset; - res->end = ~0U; - res->flags = IORESOURCE_MEM; - } - bus->resource[i+1] = res; - } - } else { - /* This is a subordinate bridge */ - pci_read_bridge_bases(bus); - - for (i = 0; i < 4; ++i) { - if ((res = bus->resource[i]) == NULL) - continue; - if (!res->flags) - continue; - if (io_offset && (res->flags & IORESOURCE_IO)) { - res->start += io_offset; - res->end += io_offset; - } else if (hose->pci_mem_offset - && (res->flags & IORESOURCE_MEM)) { - res->start += hose->pci_mem_offset; - res->end += hose->pci_mem_offset; - } - } - } - - if (ppc_md.pcibios_fixup_bus) - ppc_md.pcibios_fixup_bus(bus); -} - -char __init *pcibios_setup(char *str) -{ - return str; -} - -/* the next one is stolen from the alpha port... */ -void __init -pcibios_update_irq(struct pci_dev *dev, int irq) -{ - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); - /* XXX FIXME - update OF device tree node interrupt property */ -} - -int pcibios_enable_device(struct pci_dev *dev, int mask) -{ - if (ppc_md.pcibios_enable_device_hook) - if (ppc_md.pcibios_enable_device_hook(dev, 0)) - return -EINVAL; - - return pci_enable_resources(dev, mask); -} - -struct pci_controller* -pci_bus_to_hose(int bus) -{ - struct pci_controller* hose = hose_head; - - for (; hose; hose = hose->next) - if (bus >= hose->first_busno && bus <= hose->last_busno) - return hose; - return NULL; -} - -void __iomem * -pci_bus_io_base(unsigned int bus) -{ - struct pci_controller *hose; - - hose = pci_bus_to_hose(bus); - if (!hose) - return NULL; - return hose->io_base_virt; -} - -unsigned long -pci_bus_io_base_phys(unsigned int bus) -{ - struct pci_controller *hose; - - hose = pci_bus_to_hose(bus); - if (!hose) - return 0; - return hose->io_base_phys; -} - -unsigned long -pci_bus_mem_base_phys(unsigned int bus) -{ - struct pci_controller *hose; - - hose = pci_bus_to_hose(bus); - if (!hose) - return 0; - return hose->pci_mem_offset; -} - -unsigned long -pci_resource_to_bus(struct pci_dev *pdev, struct resource *res) -{ - /* Hack alert again ! See comments in chrp_pci.c - */ - struct pci_controller* hose = - (struct pci_controller *)pdev->sysdata; - if (hose && res->flags & IORESOURCE_MEM) - return res->start - hose->pci_mem_offset; - /* We may want to do something with IOs here... */ - return res->start; -} - - -static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, - resource_size_t *offset, - enum pci_mmap_state mmap_state) -{ - struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); - unsigned long io_offset = 0; - int i, res_bit; - - if (hose == 0) - return NULL; /* should never happen */ - - /* If memory, add on the PCI bridge address offset */ - if (mmap_state == pci_mmap_mem) { -#if 0 /* See comment in pci_resource_to_user() for why this is disabled */ - *offset += hose->pci_mem_offset; -#endif - res_bit = IORESOURCE_MEM; - } else { - io_offset = hose->io_base_virt - ___IO_BASE; - *offset += io_offset; - res_bit = IORESOURCE_IO; - } - - /* - * Check that the offset requested corresponds to one of the - * resources of the device. - */ - for (i = 0; i <= PCI_ROM_RESOURCE; i++) { - struct resource *rp = &dev->resource[i]; - int flags = rp->flags; - - /* treat ROM as memory (should be already) */ - if (i == PCI_ROM_RESOURCE) - flags |= IORESOURCE_MEM; - - /* Active and same type? */ - if ((flags & res_bit) == 0) - continue; - - /* In the range of this resource? */ - if (*offset < (rp->start & PAGE_MASK) || *offset > rp->end) - continue; - - /* found it! construct the final physical address */ - if (mmap_state == pci_mmap_io) - *offset += hose->io_base_phys - io_offset; - return rp; - } - - return NULL; -} - -/* - * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci - * device mapping. - */ -static pgprot_t __pci_mmap_set_pgprot(struct pci_dev *dev, struct resource *rp, - pgprot_t protection, - enum pci_mmap_state mmap_state, - int write_combine) -{ - unsigned long prot = pgprot_val(protection); - - /* Write combine is always 0 on non-memory space mappings. On - * memory space, if the user didn't pass 1, we check for a - * "prefetchable" resource. This is a bit hackish, but we use - * this to workaround the inability of /sysfs to provide a write - * combine bit - */ - if (mmap_state != pci_mmap_mem) - write_combine = 0; - else if (write_combine == 0) { - if (rp->flags & IORESOURCE_PREFETCH) - write_combine = 1; - } - - /* XXX would be nice to have a way to ask for write-through */ - prot |= _PAGE_NO_CACHE; - if (write_combine) - prot &= ~_PAGE_GUARDED; - else - prot |= _PAGE_GUARDED; - - printk("PCI map for %s:%llx, prot: %lx\n", pci_name(dev), - (unsigned long long)rp->start, prot); - - return __pgprot(prot); -} - -/* - * This one is used by /dev/mem and fbdev who have no clue about the - * PCI device, it tries to find the PCI device first and calls the - * above routine - */ -pgprot_t pci_phys_mem_access_prot(struct file *file, - unsigned long pfn, - unsigned long size, - pgprot_t protection) -{ - struct pci_dev *pdev = NULL; - struct resource *found = NULL; - unsigned long prot = pgprot_val(protection); - unsigned long offset = pfn << PAGE_SHIFT; - int i; - - if (page_is_ram(pfn)) - return prot; - - prot |= _PAGE_NO_CACHE | _PAGE_GUARDED; - - for_each_pci_dev(pdev) { - for (i = 0; i <= PCI_ROM_RESOURCE; i++) { - struct resource *rp = &pdev->resource[i]; - int flags = rp->flags; - - /* Active and same type? */ - if ((flags & IORESOURCE_MEM) == 0) - continue; - /* In the range of this resource? */ - if (offset < (rp->start & PAGE_MASK) || - offset > rp->end) - continue; - found = rp; - break; - } - if (found) - break; - } - if (found) { - if (found->flags & IORESOURCE_PREFETCH) - prot &= ~_PAGE_GUARDED; - pci_dev_put(pdev); - } - - DBG("non-PCI map for %lx, prot: %lx\n", offset, prot); - - return __pgprot(prot); -} - - -/* - * Perform the actual remap of the pages for a PCI device mapping, as - * appropriate for this architecture. The region in the process to map - * is described by vm_start and vm_end members of VMA, the base physical - * address is found in vm_pgoff. - * The pci device structure is provided so that architectures may make mapping - * decisions on a per-device or per-bus basis. - * - * Returns a negative error code on failure, zero on success. - */ -int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, - enum pci_mmap_state mmap_state, - int write_combine) -{ - resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT; - struct resource *rp; - int ret; - - rp = __pci_mmap_make_offset(dev, &offset, mmap_state); - if (rp == NULL) - return -EINVAL; - - vma->vm_pgoff = offset >> PAGE_SHIFT; - vma->vm_page_prot = __pci_mmap_set_pgprot(dev, rp, - vma->vm_page_prot, - mmap_state, write_combine); - - ret = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, - vma->vm_end - vma->vm_start, vma->vm_page_prot); - - return ret; -} - -/* Obsolete functions. Should be removed once the symbios driver - * is fixed - */ -unsigned long -phys_to_bus(unsigned long pa) -{ - struct pci_controller *hose; - int i; - - for (hose = hose_head; hose; hose = hose->next) { - for (i = 0; i < 3; ++i) { - if (pa >= hose->mem_resources[i].start - && pa <= hose->mem_resources[i].end) { - /* - * XXX the hose->pci_mem_offset really - * only applies to mem_resources[0]. - * We need a way to store an offset for - * the others. -- paulus - */ - if (i == 0) - pa -= hose->pci_mem_offset; - return pa; - } - } - } - /* hmmm, didn't find it */ - return 0; -} - -unsigned long -pci_phys_to_bus(unsigned long pa, int busnr) -{ - struct pci_controller* hose = pci_bus_to_hose(busnr); - if (!hose) - return pa; - return pa - hose->pci_mem_offset; -} - -unsigned long -pci_bus_to_phys(unsigned int ba, int busnr) -{ - struct pci_controller* hose = pci_bus_to_hose(busnr); - if (!hose) - return ba; - return ba + hose->pci_mem_offset; -} - -/* Provide information on locations of various I/O regions in physical - * memory. Do this on a per-card basis so that we choose the right - * root bridge. - * Note that the returned IO or memory base is a physical address - */ - -long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) -{ - struct pci_controller* hose; - long result = -EOPNOTSUPP; - - hose = pci_bus_to_hose(bus); - if (!hose) - return -ENODEV; - - switch (which) { - case IOBASE_BRIDGE_NUMBER: - return (long)hose->first_busno; - case IOBASE_MEMORY: - return (long)hose->pci_mem_offset; - case IOBASE_IO: - return (long)hose->io_base_phys; - case IOBASE_ISA_IO: - return (long)isa_io_base; - case IOBASE_ISA_MEM: - return (long)isa_mem_base; - } - - return result; -} - -void pci_resource_to_user(const struct pci_dev *dev, int bar, - const struct resource *rsrc, - resource_size_t *start, resource_size_t *end) -{ - struct pci_controller *hose = pci_bus_to_hose(dev->bus->number); - resource_size_t offset = 0; - - if (hose == NULL) - return; - - if (rsrc->flags & IORESOURCE_IO) - offset = (unsigned long)hose->io_base_virt - _IO_BASE; - - /* We pass a fully fixed up address to userland for MMIO instead of - * a BAR value because X is lame and expects to be able to use that - * to pass to /dev/mem ! - * - * That means that we'll have potentially 64 bits values where some - * userland apps only expect 32 (like X itself since it thinks only - * Sparc has 64 bits MMIO) but if we don't do that, we break it on - * 32 bits CHRPs :-( - * - * Hopefully, the sysfs insterface is immune to that gunk. Once X - * has been fixed (and the fix spread enough), we can re-enable the - * 2 lines below and pass down a BAR value to userland. In that case - * we'll also have to re-enable the matching code in - * __pci_mmap_make_offset(). - * - * BenH. - */ -#if 0 - else if (rsrc->flags & IORESOURCE_MEM) - offset = hose->pci_mem_offset; -#endif - - *start = rsrc->start - offset; - *end = rsrc->end - offset; -} - -void __init pci_init_resource(struct resource *res, resource_size_t start, - resource_size_t end, int flags, char *name) -{ - res->start = start; - res->end = end; - res->flags = flags; - res->name = name; - res->parent = NULL; - res->sibling = NULL; - res->child = NULL; -} - -void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) -{ - resource_size_t start = pci_resource_start(dev, bar); - resource_size_t len = pci_resource_len(dev, bar); - unsigned long flags = pci_resource_flags(dev, bar); - - if (!len) - return NULL; - if (max && len > max) - len = max; - if (flags & IORESOURCE_IO) - return ioport_map(start, len); - if (flags & IORESOURCE_MEM) - /* Not checking IORESOURCE_CACHEABLE because PPC does - * not currently distinguish between ioremap and - * ioremap_nocache. - */ - return ioremap(start, len); - /* What? */ - return NULL; -} - -void pci_iounmap(struct pci_dev *dev, void __iomem *addr) -{ - /* Nothing to do */ -} -EXPORT_SYMBOL(pci_iomap); -EXPORT_SYMBOL(pci_iounmap); - -unsigned long pci_address_to_pio(phys_addr_t address) -{ - struct pci_controller* hose = hose_head; - - for (; hose; hose = hose->next) { - unsigned int size = hose->io_resource.end - - hose->io_resource.start + 1; - if (address >= hose->io_base_phys && - address < (hose->io_base_phys + size)) { - unsigned long base = - (unsigned long)hose->io_base_virt - _IO_BASE; - return base + (address - hose->io_base_phys); - } - } - return (unsigned int)-1; -} -EXPORT_SYMBOL(pci_address_to_pio); - -/* - * Null PCI config access functions, for the case when we can't - * find a hose. - */ -#define NULL_PCI_OP(rw, size, type) \ -static int \ -null_##rw##_config_##size(struct pci_dev *dev, int offset, type val) \ -{ \ - return PCIBIOS_DEVICE_NOT_FOUND; \ -} - -static int -null_read_config(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 *val) -{ - return PCIBIOS_DEVICE_NOT_FOUND; -} - -static int -null_write_config(struct pci_bus *bus, unsigned int devfn, int offset, - int len, u32 val) -{ - return PCIBIOS_DEVICE_NOT_FOUND; -} - -static struct pci_ops null_pci_ops = -{ - null_read_config, - null_write_config -}; - -/* - * These functions are used early on before PCI scanning is done - * and all of the pci_dev and pci_bus structures have been created. - */ -static struct pci_bus * -fake_pci_bus(struct pci_controller *hose, int busnr) -{ - static struct pci_bus bus; - - if (hose == 0) { - hose = pci_bus_to_hose(busnr); - if (hose == 0) - printk(KERN_ERR "Can't find hose for PCI bus %d!\n", busnr); - } - bus.number = busnr; - bus.sysdata = hose; - bus.ops = hose? hose->ops: &null_pci_ops; - return &bus; -} - -#define EARLY_PCI_OP(rw, size, type) \ -int early_##rw##_config_##size(struct pci_controller *hose, int bus, \ - int devfn, int offset, type value) \ -{ \ - return pci_bus_##rw##_config_##size(fake_pci_bus(hose, bus), \ - devfn, offset, value); \ -} - -EARLY_PCI_OP(read, byte, u8 *) -EARLY_PCI_OP(read, word, u16 *) -EARLY_PCI_OP(read, dword, u32 *) -EARLY_PCI_OP(write, byte, u8) -EARLY_PCI_OP(write, word, u16) -EARLY_PCI_OP(write, dword, u32) diff --git a/arch/ppc/kernel/ppc-stub.c b/arch/ppc/kernel/ppc-stub.c deleted file mode 100644 index 5f9ee7bb67e..00000000000 --- a/arch/ppc/kernel/ppc-stub.c +++ /dev/null @@ -1,866 +0,0 @@ -/* - * ppc-stub.c: KGDB support for the Linux kernel. - * - * adapted from arch/sparc/kernel/sparc-stub.c for the PowerPC - * some stuff borrowed from Paul Mackerras' xmon - * Copyright (C) 1998 Michael AK Tesch (tesch@cs.wisc.edu) - * - * Modifications to run under Linux - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - * - * This file originally came from the gdb sources, and the - * copyright notices have been retained below. - */ - -/**************************************************************************** - - THIS SOFTWARE IS NOT COPYRIGHTED - - HP offers the following for use in the public domain. HP makes no - warranty with regard to the software or its performance and the - user accepts the software "AS IS" with all faults. - - HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD - TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - -****************************************************************************/ - -/**************************************************************************** - * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $ - * - * Module name: remcom.c $ - * Revision: 1.34 $ - * Date: 91/03/09 12:29:49 $ - * Contributor: Lake Stevens Instrument Division$ - * - * Description: low level support for gdb debugger. $ - * - * Considerations: only works on target hardware $ - * - * Written by: Glenn Engel $ - * ModuleState: Experimental $ - * - * NOTES: See Below $ - * - * Modified for SPARC by Stu Grossman, Cygnus Support. - * - * This code has been extensively tested on the Fujitsu SPARClite demo board. - * - * To enable debugger support, two things need to happen. One, a - * call to set_debug_traps() is necessary in order to allow any breakpoints - * or error conditions to be properly intercepted and reported to gdb. - * Two, a breakpoint needs to be generated to begin communication. This - * is most easily accomplished by a call to breakpoint(). Breakpoint() - * simulates a breakpoint by executing a trap #1. - * - ************* - * - * The following gdb commands are supported: - * - * command function Return value - * - * g return the value of the CPU registers hex data or ENN - * G set the value of the CPU registers OK or ENN - * qOffsets Get section offsets. Reply is Text=xxx;Data=yyy;Bss=zzz - * - * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN - * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN - * - * c Resume at current address SNN ( signal NN) - * cAA..AA Continue at address AA..AA SNN - * - * s Step one instruction SNN - * sAA..AA Step one instruction from AA..AA SNN - * - * k kill - * - * ? What was the last sigval ? SNN (signal NN) - * - * bBB..BB Set baud rate to BB..BB OK or BNN, then sets - * baud rate - * - * All commands and responses are sent with a packet which includes a - * checksum. A packet consists of - * - * $<packet info>#<checksum>. - * - * where - * <packet info> :: <characters representing the command or response> - * <checksum> :: <two hex digits computed as modulo 256 sum of <packetinfo>> - * - * When a packet is received, it is first acknowledged with either '+' or '-'. - * '+' indicates a successful transfer. '-' indicates a failed transfer. - * - * Example: - * - * Host: Reply: - * $m0,10#2a +$00010203040506070809101112131415#42 - * - ****************************************************************************/ - -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/init.h> -#include <linux/sysrq.h> - -#include <asm/cacheflush.h> -#include <asm/system.h> -#include <asm/signal.h> -#include <asm/kgdb.h> -#include <asm/pgtable.h> -#include <asm/ptrace.h> - -void breakinst(void); - -/* - * BUFMAX defines the maximum number of characters in inbound/outbound buffers - * at least NUMREGBYTES*2 are needed for register packets - */ -#define BUFMAX 2048 -static char remcomInBuffer[BUFMAX]; -static char remcomOutBuffer[BUFMAX]; - -static int initialized; -static int kgdb_active; -static int kgdb_started; -static u_int fault_jmp_buf[100]; -static int kdebug; - - -static const char hexchars[]="0123456789abcdef"; - -/* Place where we save old trap entries for restoration - sparc*/ -/* struct tt_entry kgdb_savettable[256]; */ -/* typedef void (*trapfunc_t)(void); */ - -static void kgdb_fault_handler(struct pt_regs *regs); -static int handle_exception (struct pt_regs *regs); - -#if 0 -/* Install an exception handler for kgdb */ -static void exceptionHandler(int tnum, unsigned int *tfunc) -{ - /* We are dorking with a live trap table, all irqs off */ -} -#endif - -int -kgdb_setjmp(long *buf) -{ - asm ("mflr 0; stw 0,0(%0);" - "stw 1,4(%0); stw 2,8(%0);" - "mfcr 0; stw 0,12(%0);" - "stmw 13,16(%0)" - : : "r" (buf)); - /* XXX should save fp regs as well */ - return 0; -} -void -kgdb_longjmp(long *buf, int val) -{ - if (val == 0) - val = 1; - asm ("lmw 13,16(%0);" - "lwz 0,12(%0); mtcrf 0x38,0;" - "lwz 0,0(%0); lwz 1,4(%0); lwz 2,8(%0);" - "mtlr 0; mr 3,%1" - : : "r" (buf), "r" (val)); -} -/* Convert ch from a hex digit to an int */ -static int -hex(unsigned char ch) -{ - if (ch >= 'a' && ch <= 'f') - return ch-'a'+10; - if (ch >= '0' && ch <= '9') - return ch-'0'; - if (ch >= 'A' && ch <= 'F') - return ch-'A'+10; - return -1; -} - -/* Convert the memory pointed to by mem into hex, placing result in buf. - * Return a pointer to the last char put in buf (null), in case of mem fault, - * return 0. - */ -static unsigned char * -mem2hex(const char *mem, char *buf, int count) -{ - unsigned char ch; - unsigned short tmp_s; - unsigned long tmp_l; - - if (kgdb_setjmp((long*)fault_jmp_buf) == 0) { - debugger_fault_handler = kgdb_fault_handler; - - /* Accessing 16 bit and 32 bit objects in a single - ** load instruction is required to avoid bad side - ** effects for some IO registers. - */ - - if ((count == 2) && (((long)mem & 1) == 0)) { - tmp_s = *(unsigned short *)mem; - mem += 2; - *buf++ = hexchars[(tmp_s >> 12) & 0xf]; - *buf++ = hexchars[(tmp_s >> 8) & 0xf]; - *buf++ = hexchars[(tmp_s >> 4) & 0xf]; - *buf++ = hexchars[tmp_s & 0xf]; - - } else if ((count == 4) && (((long)mem & 3) == 0)) { - tmp_l = *(unsigned int *)mem; - mem += 4; - *buf++ = hexchars[(tmp_l >> 28) & 0xf]; - *buf++ = hexchars[(tmp_l >> 24) & 0xf]; - *buf++ = hexchars[(tmp_l >> 20) & 0xf]; - *buf++ = hexchars[(tmp_l >> 16) & 0xf]; - *buf++ = hexchars[(tmp_l >> 12) & 0xf]; - *buf++ = hexchars[(tmp_l >> 8) & 0xf]; - *buf++ = hexchars[(tmp_l >> 4) & 0xf]; - *buf++ = hexchars[tmp_l & 0xf]; - - } else { - while (count-- > 0) { - ch = *mem++; - *buf++ = hexchars[ch >> 4]; - *buf++ = hexchars[ch & 0xf]; - } - } - - } else { - /* error condition */ - } - debugger_fault_handler = NULL; - *buf = 0; - return buf; -} - -/* convert the hex array pointed to by buf into binary to be placed in mem - * return a pointer to the character AFTER the last byte written. -*/ -static char * -hex2mem(char *buf, char *mem, int count) -{ - unsigned char ch; - int i; - char *orig_mem; - unsigned short tmp_s; - unsigned long tmp_l; - - orig_mem = mem; - - if (kgdb_setjmp((long*)fault_jmp_buf) == 0) { - debugger_fault_handler = kgdb_fault_handler; - - /* Accessing 16 bit and 32 bit objects in a single - ** store instruction is required to avoid bad side - ** effects for some IO registers. - */ - - if ((count == 2) && (((long)mem & 1) == 0)) { - tmp_s = hex(*buf++) << 12; - tmp_s |= hex(*buf++) << 8; - tmp_s |= hex(*buf++) << 4; - tmp_s |= hex(*buf++); - - *(unsigned short *)mem = tmp_s; - mem += 2; - - } else if ((count == 4) && (((long)mem & 3) == 0)) { - tmp_l = hex(*buf++) << 28; - tmp_l |= hex(*buf++) << 24; - tmp_l |= hex(*buf++) << 20; - tmp_l |= hex(*buf++) << 16; - tmp_l |= hex(*buf++) << 12; - tmp_l |= hex(*buf++) << 8; - tmp_l |= hex(*buf++) << 4; - tmp_l |= hex(*buf++); - - *(unsigned long *)mem = tmp_l; - mem += 4; - - } else { - for (i=0; i<count; i++) { - ch = hex(*buf++) << 4; - ch |= hex(*buf++); - *mem++ = ch; - } - } - - - /* - ** Flush the data cache, invalidate the instruction cache. - */ - flush_icache_range((int)orig_mem, (int)orig_mem + count - 1); - - } else { - /* error condition */ - } - debugger_fault_handler = NULL; - return mem; -} - -/* - * While we find nice hex chars, build an int. - * Return number of chars processed. - */ -static int -hexToInt(char **ptr, int *intValue) -{ - int numChars = 0; - int hexValue; - - *intValue = 0; - - if (kgdb_setjmp((long*)fault_jmp_buf) == 0) { - debugger_fault_handler = kgdb_fault_handler; - while (**ptr) { - hexValue = hex(**ptr); - if (hexValue < 0) - break; - - *intValue = (*intValue << 4) | hexValue; - numChars ++; - - (*ptr)++; - } - } else { - /* error condition */ - } - debugger_fault_handler = NULL; - - return (numChars); -} - -/* scan for the sequence $<data>#<checksum> */ -static void -getpacket(char *buffer) -{ - unsigned char checksum; - unsigned char xmitcsum; - int i; - int count; - unsigned char ch; - - do { - /* wait around for the start character, ignore all other - * characters */ - while ((ch = (getDebugChar() & 0x7f)) != '$') ; - - checksum = 0; - xmitcsum = -1; - - count = 0; - - /* now, read until a # or end of buffer is found */ - while (count < BUFMAX) { - ch = getDebugChar() & 0x7f; - if (ch == '#') - break; - checksum = checksum + ch; - buffer[count] = ch; - count = count + 1; - } - - if (count >= BUFMAX) - continue; - - buffer[count] = 0; - - if (ch == '#') { - xmitcsum = hex(getDebugChar() & 0x7f) << 4; - xmitcsum |= hex(getDebugChar() & 0x7f); - if (checksum != xmitcsum) - putDebugChar('-'); /* failed checksum */ - else { - putDebugChar('+'); /* successful transfer */ - /* if a sequence char is present, reply the ID */ - if (buffer[2] == ':') { - putDebugChar(buffer[0]); - putDebugChar(buffer[1]); - /* remove sequence chars from buffer */ - count = strlen(buffer); - for (i=3; i <= count; i++) - buffer[i-3] = buffer[i]; - } - } - } - } while (checksum != xmitcsum); -} - -/* send the packet in buffer. */ -static void putpacket(unsigned char *buffer) -{ - unsigned char checksum; - int count; - unsigned char ch, recv; - - /* $<packet info>#<checksum>. */ - do { - putDebugChar('$'); - checksum = 0; - count = 0; - - while ((ch = buffer[count])) { - putDebugChar(ch); - checksum += ch; - count += 1; - } - - putDebugChar('#'); - putDebugChar(hexchars[checksum >> 4]); - putDebugChar(hexchars[checksum & 0xf]); - recv = getDebugChar(); - } while ((recv & 0x7f) != '+'); -} - -static void kgdb_flush_cache_all(void) -{ - flush_instruction_cache(); -} - -/* Set up exception handlers for tracing and breakpoints - * [could be called kgdb_init()] - */ -void set_debug_traps(void) -{ -#if 0 - unsigned char c; - - save_and_cli(flags); - - /* In case GDB is started before us, ack any packets (presumably - * "$?#xx") sitting there. - * - * I've found this code causes more problems than it solves, - * so that's why it's commented out. GDB seems to work fine - * now starting either before or after the kernel -bwb - */ - - while((c = getDebugChar()) != '$'); - while((c = getDebugChar()) != '#'); - c = getDebugChar(); /* eat first csum byte */ - c = getDebugChar(); /* eat second csum byte */ - putDebugChar('+'); /* ack it */ -#endif - debugger = kgdb; - debugger_bpt = kgdb_bpt; - debugger_sstep = kgdb_sstep; - debugger_iabr_match = kgdb_iabr_match; - debugger_dabr_match = kgdb_dabr_match; - - initialized = 1; -} - -static void kgdb_fault_handler(struct pt_regs *regs) -{ - kgdb_longjmp((long*)fault_jmp_buf, 1); -} - -int kgdb_bpt(struct pt_regs *regs) -{ - return handle_exception(regs); -} - -int kgdb_sstep(struct pt_regs *regs) -{ - return handle_exception(regs); -} - -void kgdb(struct pt_regs *regs) -{ - handle_exception(regs); -} - -int kgdb_iabr_match(struct pt_regs *regs) -{ - printk(KERN_ERR "kgdb doesn't support iabr, what?!?\n"); - return handle_exception(regs); -} - -int kgdb_dabr_match(struct pt_regs *regs) -{ - printk(KERN_ERR "kgdb doesn't support dabr, what?!?\n"); - return handle_exception(regs); -} - -/* Convert the hardware trap type code to a unix signal number. */ -/* - * This table contains the mapping between PowerPC hardware trap types, and - * signals, which are primarily what GDB understands. - */ -static struct hard_trap_info -{ - unsigned int tt; /* Trap type code for powerpc */ - unsigned char signo; /* Signal that we map this trap into */ -} hard_trap_info[] = { -#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) - { 0x100, SIGINT }, /* critical input interrupt */ - { 0x200, SIGSEGV }, /* machine check */ - { 0x300, SIGSEGV }, /* data storage */ - { 0x400, SIGBUS }, /* instruction storage */ - { 0x500, SIGINT }, /* interrupt */ - { 0x600, SIGBUS }, /* alignment */ - { 0x700, SIGILL }, /* program */ - { 0x800, SIGILL }, /* reserved */ - { 0x900, SIGILL }, /* reserved */ - { 0xa00, SIGILL }, /* reserved */ - { 0xb00, SIGILL }, /* reserved */ - { 0xc00, SIGCHLD }, /* syscall */ - { 0xd00, SIGILL }, /* reserved */ - { 0xe00, SIGILL }, /* reserved */ - { 0xf00, SIGILL }, /* reserved */ - /* - ** 0x1000 PIT - ** 0x1010 FIT - ** 0x1020 watchdog - ** 0x1100 data TLB miss - ** 0x1200 instruction TLB miss - */ - { 0x2002, SIGTRAP}, /* debug */ -#else - { 0x200, SIGSEGV }, /* machine check */ - { 0x300, SIGSEGV }, /* address error (store) */ - { 0x400, SIGBUS }, /* instruction bus error */ - { 0x500, SIGINT }, /* interrupt */ - { 0x600, SIGBUS }, /* alingment */ - { 0x700, SIGTRAP }, /* breakpoint trap */ - { 0x800, SIGFPE }, /* fpu unavail */ - { 0x900, SIGALRM }, /* decrementer */ - { 0xa00, SIGILL }, /* reserved */ - { 0xb00, SIGILL }, /* reserved */ - { 0xc00, SIGCHLD }, /* syscall */ - { 0xd00, SIGTRAP }, /* single-step/watch */ - { 0xe00, SIGFPE }, /* fp assist */ -#endif - { 0, 0} /* Must be last */ - -}; - -static int computeSignal(unsigned int tt) -{ - struct hard_trap_info *ht; - - for (ht = hard_trap_info; ht->tt && ht->signo; ht++) - if (ht->tt == tt) - return ht->signo; - - return SIGHUP; /* default for things we don't know about */ -} - -#define PC_REGNUM 64 -#define SP_REGNUM 1 - -/* - * This function does all command processing for interfacing to gdb. - */ -static int -handle_exception (struct pt_regs *regs) -{ - int sigval; - int addr; - int length; - char *ptr; - unsigned int msr; - - /* We don't handle user-mode breakpoints. */ - if (user_mode(regs)) - return 0; - - if (debugger_fault_handler) { - debugger_fault_handler(regs); - panic("kgdb longjump failed!\n"); - } - if (kgdb_active) { - printk(KERN_ERR "interrupt while in kgdb, returning\n"); - return 0; - } - - kgdb_active = 1; - kgdb_started = 1; - -#ifdef KGDB_DEBUG - printk("kgdb: entering handle_exception; trap [0x%x]\n", - (unsigned int)regs->trap); -#endif - - kgdb_interruptible(0); - lock_kernel(); - msr = mfmsr(); - mtmsr(msr & ~MSR_EE); /* disable interrupts */ - - if (regs->nip == (unsigned long)breakinst) { - /* Skip over breakpoint trap insn */ - regs->nip += 4; - } - - /* reply to host that an exception has occurred */ - sigval = computeSignal(regs->trap); - ptr = remcomOutBuffer; - - *ptr++ = 'T'; - *ptr++ = hexchars[sigval >> 4]; - *ptr++ = hexchars[sigval & 0xf]; - *ptr++ = hexchars[PC_REGNUM >> 4]; - *ptr++ = hexchars[PC_REGNUM & 0xf]; - *ptr++ = ':'; - ptr = mem2hex((char *)®s->nip, ptr, 4); - *ptr++ = ';'; - *ptr++ = hexchars[SP_REGNUM >> 4]; - *ptr++ = hexchars[SP_REGNUM & 0xf]; - *ptr++ = ':'; - ptr = mem2hex(((char *)regs) + SP_REGNUM*4, ptr, 4); - *ptr++ = ';'; - *ptr++ = 0; - - putpacket(remcomOutBuffer); - if (kdebug) - printk("remcomOutBuffer: %s\n", remcomOutBuffer); - - /* XXX We may want to add some features dealing with poking the - * XXX page tables, ... (look at sparc-stub.c for more info) - * XXX also required hacking to the gdb sources directly... - */ - - while (1) { - remcomOutBuffer[0] = 0; - - getpacket(remcomInBuffer); - switch (remcomInBuffer[0]) { - case '?': /* report most recent signal */ - remcomOutBuffer[0] = 'S'; - remcomOutBuffer[1] = hexchars[sigval >> 4]; - remcomOutBuffer[2] = hexchars[sigval & 0xf]; - remcomOutBuffer[3] = 0; - break; -#if 0 - case 'q': /* this screws up gdb for some reason...*/ - { - extern long _start, sdata, __bss_start; - - ptr = &remcomInBuffer[1]; - if (strncmp(ptr, "Offsets", 7) != 0) - break; - - ptr = remcomOutBuffer; - sprintf(ptr, "Text=%8.8x;Data=%8.8x;Bss=%8.8x", - &_start, &sdata, &__bss_start); - break; - } -#endif - case 'd': - /* toggle debug flag */ - kdebug ^= 1; - break; - - case 'g': /* return the value of the CPU registers. - * some of them are non-PowerPC names :( - * they are stored in gdb like: - * struct { - * u32 gpr[32]; - * f64 fpr[32]; - * u32 pc, ps, cnd, lr; (ps=msr) - * u32 cnt, xer, mq; - * } - */ - { - int i; - ptr = remcomOutBuffer; - /* General Purpose Regs */ - ptr = mem2hex((char *)regs, ptr, 32 * 4); - /* Floating Point Regs - FIXME */ - /*ptr = mem2hex((char *), ptr, 32 * 8);*/ - for(i=0; i<(32*8*2); i++) { /* 2chars/byte */ - ptr[i] = '0'; - } - ptr += 32*8*2; - /* pc, msr, cr, lr, ctr, xer, (mq is unused) */ - ptr = mem2hex((char *)®s->nip, ptr, 4); - ptr = mem2hex((char *)®s->msr, ptr, 4); - ptr = mem2hex((char *)®s->ccr, ptr, 4); - ptr = mem2hex((char *)®s->link, ptr, 4); - ptr = mem2hex((char *)®s->ctr, ptr, 4); - ptr = mem2hex((char *)®s->xer, ptr, 4); - } - break; - - case 'G': /* set the value of the CPU registers */ - { - ptr = &remcomInBuffer[1]; - - /* - * If the stack pointer has moved, you should pray. - * (cause only god can help you). - */ - - /* General Purpose Regs */ - hex2mem(ptr, (char *)regs, 32 * 4); - - /* Floating Point Regs - FIXME?? */ - /*ptr = hex2mem(ptr, ??, 32 * 8);*/ - ptr += 32*8*2; - - /* pc, msr, cr, lr, ctr, xer, (mq is unused) */ - ptr = hex2mem(ptr, (char *)®s->nip, 4); - ptr = hex2mem(ptr, (char *)®s->msr, 4); - ptr = hex2mem(ptr, (char *)®s->ccr, 4); - ptr = hex2mem(ptr, (char *)®s->link, 4); - ptr = hex2mem(ptr, (char *)®s->ctr, 4); - ptr = hex2mem(ptr, (char *)®s->xer, 4); - - strcpy(remcomOutBuffer,"OK"); - } - break; - case 'H': - /* don't do anything, yet, just acknowledge */ - hexToInt(&ptr, &addr); - strcpy(remcomOutBuffer,"OK"); - break; - - case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */ - /* Try to read %x,%x. */ - - ptr = &remcomInBuffer[1]; - - if (hexToInt(&ptr, &addr) && *ptr++ == ',' - && hexToInt(&ptr, &length)) { - if (mem2hex((char *)addr, remcomOutBuffer, - length)) - break; - strcpy(remcomOutBuffer, "E03"); - } else - strcpy(remcomOutBuffer, "E01"); - break; - - case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */ - /* Try to read '%x,%x:'. */ - - ptr = &remcomInBuffer[1]; - - if (hexToInt(&ptr, &addr) && *ptr++ == ',' - && hexToInt(&ptr, &length) - && *ptr++ == ':') { - if (hex2mem(ptr, (char *)addr, length)) - strcpy(remcomOutBuffer, "OK"); - else - strcpy(remcomOutBuffer, "E03"); - flush_icache_range(addr, addr+length); - } else - strcpy(remcomOutBuffer, "E02"); - break; - - - case 'k': /* kill the program, actually just continue */ - case 'c': /* cAA..AA Continue; address AA..AA optional */ - /* try to read optional parameter, pc unchanged if no parm */ - - ptr = &remcomInBuffer[1]; - if (hexToInt(&ptr, &addr)) - regs->nip = addr; - -/* Need to flush the instruction cache here, as we may have deposited a - * breakpoint, and the icache probably has no way of knowing that a data ref to - * some location may have changed something that is in the instruction cache. - */ - kgdb_flush_cache_all(); - mtmsr(msr); - - kgdb_interruptible(1); - unlock_kernel(); - kgdb_active = 0; - if (kdebug) { - printk("remcomInBuffer: %s\n", remcomInBuffer); - printk("remcomOutBuffer: %s\n", remcomOutBuffer); - } - return 1; - - case 's': - kgdb_flush_cache_all(); -#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) - mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC); - regs->msr |= MSR_DE; -#else - regs->msr |= MSR_SE; -#endif - unlock_kernel(); - kgdb_active = 0; - if (kdebug) { - printk("remcomInBuffer: %s\n", remcomInBuffer); - printk("remcomOutBuffer: %s\n", remcomOutBuffer); - } - return 1; - - case 'r': /* Reset (if user process..exit ???)*/ - panic("kgdb reset."); - break; - } /* switch */ - if (remcomOutBuffer[0] && kdebug) { - printk("remcomInBuffer: %s\n", remcomInBuffer); - printk("remcomOutBuffer: %s\n", remcomOutBuffer); - } - /* reply to the request */ - putpacket(remcomOutBuffer); - } /* while(1) */ -} - -/* This function will generate a breakpoint exception. It is used at the - beginning of a program to sync up with a debugger and can be used - otherwise as a quick means to stop program execution and "break" into - the debugger. */ - -void -breakpoint(void) -{ - if (!initialized) { - printk("breakpoint() called b4 kgdb init\n"); - return; - } - - asm(" .globl breakinst \n\ - breakinst: .long 0x7d821008"); -} - -#ifdef CONFIG_KGDB_CONSOLE -/* Output string in GDB O-packet format if GDB has connected. If nothing - output, returns 0 (caller must then handle output). */ -int -kgdb_output_string (const char* s, unsigned int count) -{ - char buffer[512]; - - if (!kgdb_started) - return 0; - - count = (count <= (sizeof(buffer) / 2 - 2)) - ? count : (sizeof(buffer) / 2 - 2); - - buffer[0] = 'O'; - mem2hex (s, &buffer[1], count); - putpacket(buffer); - - return 1; -} -#endif - -static void sysrq_handle_gdb(int key, struct pt_regs *pt_regs, - struct tty_struct *tty) -{ - printk("Entering GDB stub\n"); - breakpoint(); -} -static struct sysrq_key_op sysrq_gdb_op = { - .handler = sysrq_handle_gdb, - .help_msg = "Gdb", - .action_msg = "GDB", -}; - -static int gdb_register_sysrq(void) -{ - printk("Registering GDB sysrq handler\n"); - register_sysrq_key('g', &sysrq_gdb_op); - return 0; -} -module_init(gdb_register_sysrq); diff --git a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c deleted file mode 100644 index 9ed36dd9cbf..00000000000 --- a/arch/ppc/kernel/ppc_htab.c +++ /dev/null @@ -1,464 +0,0 @@ -/* - * PowerPC hash table management proc entry. Will show information - * about the current hash table and will allow changes to it. - * - * Written by Cort Dougan (cort@cs.nmt.edu) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/proc_fs.h> -#include <linux/stat.h> -#include <linux/sysctl.h> -#include <linux/capability.h> -#include <linux/ctype.h> -#include <linux/threads.h> -#include <linux/seq_file.h> -#include <linux/init.h> -#include <linux/bitops.h> - -#include <asm/uaccess.h> -#include <asm/mmu.h> -#include <asm/residual.h> -#include <asm/io.h> -#include <asm/pgtable.h> -#include <asm/cputable.h> -#include <asm/system.h> -#include <asm/reg.h> - -static int ppc_htab_show(struct seq_file *m, void *v); -static ssize_t ppc_htab_write(struct file * file, const char __user * buffer, - size_t count, loff_t *ppos); -extern PTE *Hash, *Hash_end; -extern unsigned long Hash_size, Hash_mask; -extern unsigned long _SDR1; -extern unsigned long htab_reloads; -extern unsigned long htab_preloads; -extern unsigned long htab_evicts; -extern unsigned long pte_misses; -extern unsigned long pte_errors; -extern unsigned int primary_pteg_full; -extern unsigned int htab_hash_searches; - -static int ppc_htab_open(struct inode *inode, struct file *file) -{ - return single_open(file, ppc_htab_show, NULL); -} - -const struct file_operations ppc_htab_operations = { - .open = ppc_htab_open, - .read = seq_read, - .llseek = seq_lseek, - .write = ppc_htab_write, - .release = single_release, -}; - -static char *pmc1_lookup(unsigned long mmcr0) -{ - switch ( mmcr0 & (0x7f<<7) ) - { - case 0x0: - return "none"; - case MMCR0_PMC1_CYCLES: - return "cycles"; - case MMCR0_PMC1_ICACHEMISS: - return "ic miss"; - case MMCR0_PMC1_DTLB: - return "dtlb miss"; - default: - return "unknown"; - } -} - -static char *pmc2_lookup(unsigned long mmcr0) -{ - switch ( mmcr0 & 0x3f ) - { - case 0x0: - return "none"; - case MMCR0_PMC2_CYCLES: - return "cycles"; - case MMCR0_PMC2_DCACHEMISS: - return "dc miss"; - case MMCR0_PMC2_ITLB: - return "itlb miss"; - case MMCR0_PMC2_LOADMISSTIME: - return "load miss time"; - default: - return "unknown"; - } -} - -/* - * print some useful info about the hash table. This function - * is _REALLY_ slow (see the nested for loops below) but nothing - * in here should be really timing critical. -- Cort - */ -static int ppc_htab_show(struct seq_file *m, void *v) -{ - unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0; -#if defined(CONFIG_PPC_STD_MMU) - unsigned int kptes = 0, uptes = 0; - PTE *ptr; -#endif /* CONFIG_PPC_STD_MMU */ - - if (cpu_has_feature(CPU_FTR_604_PERF_MON)) { - mmcr0 = mfspr(SPRN_MMCR0); - pmc1 = mfspr(SPRN_PMC1); - pmc2 = mfspr(SPRN_PMC2); - seq_printf(m, - "604 Performance Monitoring\n" - "MMCR0\t\t: %08lx %s%s ", - mmcr0, - ( mmcr0>>28 & 0x2 ) ? "(user mode counted)" : "", - ( mmcr0>>28 & 0x4 ) ? "(kernel mode counted)" : ""); - seq_printf(m, - "\nPMC1\t\t: %08lx (%s)\n" - "PMC2\t\t: %08lx (%s)\n", - pmc1, pmc1_lookup(mmcr0), - pmc2, pmc2_lookup(mmcr0)); - } - -#ifdef CONFIG_PPC_STD_MMU - /* if we don't have a htab */ - if ( Hash_size == 0 ) { - seq_printf(m, "No Hash Table used\n"); - return 0; - } - - for (ptr = Hash; ptr < Hash_end; ptr++) { - unsigned int mctx, vsid; - - if (!ptr->v) - continue; - /* undo the esid skew */ - vsid = ptr->vsid; - mctx = ((vsid - (vsid & 0xf) * 0x111) >> 4) & 0xfffff; - if (mctx == 0) - kptes++; - else - uptes++; - } - - seq_printf(m, - "PTE Hash Table Information\n" - "Size\t\t: %luKb\n" - "Buckets\t\t: %lu\n" - "Address\t\t: %08lx\n" - "Entries\t\t: %lu\n" - "User ptes\t: %u\n" - "Kernel ptes\t: %u\n" - "Percent full\t: %lu%%\n" - , (unsigned long)(Hash_size>>10), - (Hash_size/(sizeof(PTE)*8)), - (unsigned long)Hash, - Hash_size/sizeof(PTE) - , uptes, - kptes, - ((kptes+uptes)*100) / (Hash_size/sizeof(PTE)) - ); - - seq_printf(m, - "Reloads\t\t: %lu\n" - "Preloads\t: %lu\n" - "Searches\t: %u\n" - "Overflows\t: %u\n" - "Evicts\t\t: %lu\n", - htab_reloads, htab_preloads, htab_hash_searches, - primary_pteg_full, htab_evicts); -#endif /* CONFIG_PPC_STD_MMU */ - - seq_printf(m, - "Non-error misses: %lu\n" - "Error misses\t: %lu\n", - pte_misses, pte_errors); - return 0; -} - -/* - * Allow user to define performance counters and resize the hash table - */ -static ssize_t ppc_htab_write(struct file * file, const char __user * ubuffer, - size_t count, loff_t *ppos) -{ -#ifdef CONFIG_PPC_STD_MMU - unsigned long tmp; - char buffer[16]; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (strncpy_from_user(buffer, ubuffer, 15)) - return -EFAULT; - buffer[15] = 0; - - /* don't set the htab size for now */ - if ( !strncmp( buffer, "size ", 5) ) - return -EBUSY; - - if ( !strncmp( buffer, "reset", 5) ) - { - if (cpu_has_feature(CPU_FTR_604_PERF_MON)) { - /* reset PMC1 and PMC2 */ - mtspr(SPRN_PMC1, 0); - mtspr(SPRN_PMC2, 0); - } - htab_reloads = 0; - htab_evicts = 0; - pte_misses = 0; - pte_errors = 0; - } - - /* Everything below here requires the performance monitor feature. */ - if (!cpu_has_feature(CPU_FTR_604_PERF_MON)) - return count; - - /* turn off performance monitoring */ - if ( !strncmp( buffer, "off", 3) ) - { - mtspr(SPRN_MMCR0, 0); - mtspr(SPRN_PMC1, 0); - mtspr(SPRN_PMC2, 0); - } - - if ( !strncmp( buffer, "user", 4) ) - { - /* setup mmcr0 and clear the correct pmc */ - tmp = (mfspr(SPRN_MMCR0) & ~(0x60000000)) | 0x20000000; - mtspr(SPRN_MMCR0, tmp); - mtspr(SPRN_PMC1, 0); - mtspr(SPRN_PMC2, 0); - } - - if ( !strncmp( buffer, "kernel", 6) ) - { - /* setup mmcr0 and clear the correct pmc */ - tmp = (mfspr(SPRN_MMCR0) & ~(0x60000000)) | 0x40000000; - mtspr(SPRN_MMCR0, tmp); - mtspr(SPRN_PMC1, 0); - mtspr(SPRN_PMC2, 0); - } - - /* PMC1 values */ - if ( !strncmp( buffer, "dtlb", 4) ) - { - /* setup mmcr0 and clear the correct pmc */ - tmp = (mfspr(SPRN_MMCR0) & ~(0x7F << 7)) | MMCR0_PMC1_DTLB; - mtspr(SPRN_MMCR0, tmp); - mtspr(SPRN_PMC1, 0); - } - - if ( !strncmp( buffer, "ic miss", 7) ) - { - /* setup mmcr0 and clear the correct pmc */ - tmp = (mfspr(SPRN_MMCR0) & ~(0x7F<<7)) | MMCR0_PMC1_ICACHEMISS; - mtspr(SPRN_MMCR0, tmp); - mtspr(SPRN_PMC1, 0); - } - - /* PMC2 values */ - if ( !strncmp( buffer, "load miss time", 14) ) - { - /* setup mmcr0 and clear the correct pmc */ - asm volatile( - "mfspr %0,%1\n\t" /* get current mccr0 */ - "rlwinm %0,%0,0,0,31-6\n\t" /* clear bits [26-31] */ - "ori %0,%0,%2 \n\t" /* or in mmcr0 settings */ - "mtspr %1,%0 \n\t" /* set new mccr0 */ - "mtspr %3,%4 \n\t" /* reset the pmc */ - : "=r" (tmp) - : "i" (SPRN_MMCR0), - "i" (MMCR0_PMC2_LOADMISSTIME), - "i" (SPRN_PMC2), "r" (0) ); - } - - if ( !strncmp( buffer, "itlb", 4) ) - { - /* setup mmcr0 and clear the correct pmc */ - asm volatile( - "mfspr %0,%1\n\t" /* get current mccr0 */ - "rlwinm %0,%0,0,0,31-6\n\t" /* clear bits [26-31] */ - "ori %0,%0,%2 \n\t" /* or in mmcr0 settings */ - "mtspr %1,%0 \n\t" /* set new mccr0 */ - "mtspr %3,%4 \n\t" /* reset the pmc */ - : "=r" (tmp) - : "i" (SPRN_MMCR0), "i" (MMCR0_PMC2_ITLB), - "i" (SPRN_PMC2), "r" (0) ); - } - - if ( !strncmp( buffer, "dc miss", 7) ) - { - /* setup mmcr0 and clear the correct pmc */ - asm volatile( - "mfspr %0,%1\n\t" /* get current mccr0 */ - "rlwinm %0,%0,0,0,31-6\n\t" /* clear bits [26-31] */ - "ori %0,%0,%2 \n\t" /* or in mmcr0 settings */ - "mtspr %1,%0 \n\t" /* set new mccr0 */ - "mtspr %3,%4 \n\t" /* reset the pmc */ - : "=r" (tmp) - : "i" (SPRN_MMCR0), "i" (MMCR0_PMC2_DCACHEMISS), - "i" (SPRN_PMC2), "r" (0) ); - } - - return count; -#else /* CONFIG_PPC_STD_MMU */ - return 0; -#endif /* CONFIG_PPC_STD_MMU */ -} - -int proc_dol2crvec(ctl_table *table, int write, struct file *filp, - void __user *buffer_arg, size_t *lenp, loff_t *ppos) -{ - int vleft, first=1, len, left, val; - char __user *buffer = (char __user *) buffer_arg; - #define TMPBUFLEN 256 - char buf[TMPBUFLEN], *p; - static const char *sizestrings[4] = { - "2MB", "256KB", "512KB", "1MB" - }; - static const char *clockstrings[8] = { - "clock disabled", "+1 clock", "+1.5 clock", "reserved(3)", - "+2 clock", "+2.5 clock", "+3 clock", "reserved(7)" - }; - static const char *typestrings[4] = { - "flow-through burst SRAM", "reserved SRAM", - "pipelined burst SRAM", "pipelined late-write SRAM" - }; - static const char *holdstrings[4] = { - "0.5", "1.0", "(reserved2)", "(reserved3)" - }; - - if (!cpu_has_feature(CPU_FTR_L2CR)) - return -EFAULT; - - if ( /*!table->maxlen ||*/ (*ppos && !write)) { - *lenp = 0; - return 0; - } - - vleft = table->maxlen / sizeof(int); - left = *lenp; - - for (; left /*&& vleft--*/; first=0) { - if (write) { - while (left) { - char c; - if(get_user(c, buffer)) - return -EFAULT; - if (!isspace(c)) - break; - left--; - buffer++; - } - if (!left) - break; - len = left; - if (len > TMPBUFLEN-1) - len = TMPBUFLEN-1; - if(copy_from_user(buf, buffer, len)) - return -EFAULT; - buf[len] = 0; - p = buf; - if (*p < '0' || *p > '9') - break; - val = simple_strtoul(p, &p, 0); - len = p-buf; - if ((len < left) && *p && !isspace(*p)) - break; - buffer += len; - left -= len; - _set_L2CR(val); - } else { - p = buf; - if (!first) - *p++ = '\t'; - val = _get_L2CR(); - p += sprintf(p, "0x%08x: ", val); - p += sprintf(p, " %s", (val >> 31) & 1 ? "enabled" : - "disabled"); - p += sprintf(p, ", %sparity", (val>>30)&1 ? "" : "no "); - p += sprintf(p, ", %s", sizestrings[(val >> 28) & 3]); - p += sprintf(p, ", %s", clockstrings[(val >> 25) & 7]); - p += sprintf(p, ", %s", typestrings[(val >> 23) & 2]); - p += sprintf(p, "%s", (val>>22)&1 ? ", data only" : ""); - p += sprintf(p, "%s", (val>>20)&1 ? ", ZZ enabled": ""); - p += sprintf(p, ", %s", (val>>19)&1 ? "write-through" : - "copy-back"); - p += sprintf(p, "%s", (val>>18)&1 ? ", testing" : ""); - p += sprintf(p, ", %sns hold",holdstrings[(val>>16)&3]); - p += sprintf(p, "%s", (val>>15)&1 ? ", DLL slow" : ""); - p += sprintf(p, "%s", (val>>14)&1 ? ", diff clock" :""); - p += sprintf(p, "%s", (val>>13)&1 ? ", DLL bypass" :""); - - p += sprintf(p,"\n"); - - len = strlen(buf); - if (len > left) - len = left; - if (copy_to_user(buffer, buf, len)) - return -EFAULT; - left -= len; - buffer += len; - break; - } - } - - if (!write && !first && left) { - if(put_user('\n', (char __user *) buffer)) - return -EFAULT; - left--, buffer++; - } - if (write) { - char __user *s = (char __user *) buffer; - while (left) { - char c; - if(get_user(c, s++)) - return -EFAULT; - if (!isspace(c)) - break; - left--; - } - } - if (write && first) - return -EINVAL; - *lenp -= left; - *ppos += *lenp; - return 0; -} - -#ifdef CONFIG_SYSCTL -/* - * Register our sysctl. - */ -static ctl_table htab_ctl_table[]={ - { - .procname = "l2cr", - .mode = 0644, - .proc_handler = &proc_dol2crvec, - }, - {} -}; -static ctl_table htab_sysctl_root[] = { - { - .ctl_name = CTL_KERN, - .procname = "kernel", - .mode = 0555, - .child = htab_ctl_table, - }, - {} -}; - -static int __init -register_ppc_htab_sysctl(void) -{ - register_sysctl_table(htab_sysctl_root); - - return 0; -} - -__initcall(register_ppc_htab_sysctl); -#endif diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c deleted file mode 100644 index 5d529bcbeee..00000000000 --- a/arch/ppc/kernel/ppc_ksyms.c +++ /dev/null @@ -1,258 +0,0 @@ -#include <linux/module.h> -#include <linux/threads.h> -#include <linux/smp.h> -#include <linux/sched.h> -#include <linux/elfcore.h> -#include <linux/string.h> -#include <linux/interrupt.h> -#include <linux/screen_info.h> -#include <linux/vt_kern.h> -#include <linux/nvram.h> -#include <linux/console.h> -#include <linux/irq.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/pm.h> -#include <linux/bitops.h> - -#include <asm/page.h> -#include <asm/processor.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/ide.h> -#include <asm/atomic.h> -#include <asm/checksum.h> -#include <asm/pgtable.h> -#include <asm/tlbflush.h> -#include <asm/cacheflush.h> -#include <linux/adb.h> -#include <linux/cuda.h> -#include <linux/pmu.h> -#include <asm/system.h> -#include <asm/pci-bridge.h> -#include <asm/irq.h> -#include <asm/dma.h> -#include <asm/machdep.h> -#include <asm/hw_irq.h> -#include <asm/nvram.h> -#include <asm/mmu_context.h> -#include <asm/backlight.h> -#include <asm/time.h> -#include <asm/cputable.h> -#include <asm/btext.h> -#include <asm/xmon.h> -#include <asm/signal.h> -#include <asm/dcr.h> - -#ifdef CONFIG_8xx -#include <asm/cpm1.h> -#endif - -extern void transfer_to_handler(void); -extern void do_IRQ(struct pt_regs *regs); -extern void machine_check_exception(struct pt_regs *regs); -extern void alignment_exception(struct pt_regs *regs); -extern void program_check_exception(struct pt_regs *regs); -extern void single_step_exception(struct pt_regs *regs); -extern int sys_sigreturn(struct pt_regs *regs); - -long long __ashrdi3(long long, int); -long long __ashldi3(long long, int); -long long __lshrdi3(long long, int); - -EXPORT_SYMBOL(empty_zero_page); -EXPORT_SYMBOL(clear_pages); -EXPORT_SYMBOL(clear_user_page); -EXPORT_SYMBOL(copy_page); -EXPORT_SYMBOL(transfer_to_handler); -EXPORT_SYMBOL(do_IRQ); -EXPORT_SYMBOL(machine_check_exception); -EXPORT_SYMBOL(alignment_exception); -EXPORT_SYMBOL(program_check_exception); -EXPORT_SYMBOL(single_step_exception); -EXPORT_SYMBOL(sys_sigreturn); -EXPORT_SYMBOL(ppc_n_lost_interrupts); - -EXPORT_SYMBOL(ISA_DMA_THRESHOLD); -EXPORT_SYMBOL(DMA_MODE_READ); -EXPORT_SYMBOL(DMA_MODE_WRITE); - -#if !defined(__INLINE_BITOPS) -EXPORT_SYMBOL(set_bit); -EXPORT_SYMBOL(clear_bit); -EXPORT_SYMBOL(change_bit); -EXPORT_SYMBOL(test_and_set_bit); -EXPORT_SYMBOL(test_and_clear_bit); -EXPORT_SYMBOL(test_and_change_bit); -#endif /* __INLINE_BITOPS */ - -EXPORT_SYMBOL(strcpy); -EXPORT_SYMBOL(strncpy); -EXPORT_SYMBOL(strcat); -EXPORT_SYMBOL(strlen); -EXPORT_SYMBOL(strcmp); -EXPORT_SYMBOL(strncmp); - -EXPORT_SYMBOL(csum_partial); -EXPORT_SYMBOL(csum_partial_copy_generic); -EXPORT_SYMBOL(ip_fast_csum); -EXPORT_SYMBOL(csum_tcpudp_magic); - -EXPORT_SYMBOL(__copy_tofrom_user); -EXPORT_SYMBOL(__clear_user); -EXPORT_SYMBOL(__strncpy_from_user); -EXPORT_SYMBOL(__strnlen_user); - -/* -EXPORT_SYMBOL(inb); -EXPORT_SYMBOL(inw); -EXPORT_SYMBOL(inl); -EXPORT_SYMBOL(outb); -EXPORT_SYMBOL(outw); -EXPORT_SYMBOL(outl); -EXPORT_SYMBOL(outsl);*/ - -EXPORT_SYMBOL(_insb); -EXPORT_SYMBOL(_outsb); -EXPORT_SYMBOL(_insw_ns); -EXPORT_SYMBOL(_outsw_ns); -EXPORT_SYMBOL(_insl_ns); -EXPORT_SYMBOL(_outsl_ns); -EXPORT_SYMBOL(iopa); -EXPORT_SYMBOL(ioremap); -#ifdef CONFIG_44x -EXPORT_SYMBOL(ioremap64); -#endif -EXPORT_SYMBOL(__ioremap); -EXPORT_SYMBOL(iounmap); -EXPORT_SYMBOL(ioremap_bot); /* aka VMALLOC_END */ - -#ifdef CONFIG_PCI -EXPORT_SYMBOL(isa_io_base); -EXPORT_SYMBOL(isa_mem_base); -EXPORT_SYMBOL(pci_dram_offset); -EXPORT_SYMBOL(pci_alloc_consistent); -EXPORT_SYMBOL(pci_free_consistent); -EXPORT_SYMBOL(pci_bus_io_base); -EXPORT_SYMBOL(pci_bus_io_base_phys); -EXPORT_SYMBOL(pci_bus_mem_base_phys); -EXPORT_SYMBOL(pci_bus_to_hose); -EXPORT_SYMBOL(pci_resource_to_bus); -EXPORT_SYMBOL(pci_phys_to_bus); -EXPORT_SYMBOL(pci_bus_to_phys); -#endif /* CONFIG_PCI */ - -#ifdef CONFIG_NOT_COHERENT_CACHE -extern void flush_dcache_all(void); -EXPORT_SYMBOL(flush_dcache_all); -#endif - -EXPORT_SYMBOL(start_thread); -EXPORT_SYMBOL(kernel_thread); - -EXPORT_SYMBOL(flush_instruction_cache); -EXPORT_SYMBOL(giveup_fpu); -EXPORT_SYMBOL(__flush_icache_range); -EXPORT_SYMBOL(flush_dcache_range); -EXPORT_SYMBOL(flush_icache_user_range); -EXPORT_SYMBOL(flush_dcache_page); -EXPORT_SYMBOL(flush_tlb_kernel_range); -EXPORT_SYMBOL(flush_tlb_page); -EXPORT_SYMBOL(_tlbie); -#ifdef CONFIG_ALTIVEC -#ifndef CONFIG_SMP -EXPORT_SYMBOL(last_task_used_altivec); -#endif -EXPORT_SYMBOL(giveup_altivec); -#endif /* CONFIG_ALTIVEC */ -#ifdef CONFIG_SMP -EXPORT_SYMBOL(smp_call_function); -EXPORT_SYMBOL(smp_hw_index); -#endif - -EXPORT_SYMBOL(ppc_md); - -#ifdef CONFIG_ADB -EXPORT_SYMBOL(adb_request); -EXPORT_SYMBOL(adb_register); -EXPORT_SYMBOL(adb_unregister); -EXPORT_SYMBOL(adb_poll); -EXPORT_SYMBOL(adb_try_handler_change); -#endif /* CONFIG_ADB */ -#ifdef CONFIG_ADB_CUDA -EXPORT_SYMBOL(cuda_request); -EXPORT_SYMBOL(cuda_poll); -#endif /* CONFIG_ADB_CUDA */ -#if defined(CONFIG_BOOTX_TEXT) -EXPORT_SYMBOL(btext_update_display); -#endif -EXPORT_SYMBOL(to_tm); - -EXPORT_SYMBOL(pm_power_off); - -EXPORT_SYMBOL(__ashrdi3); -EXPORT_SYMBOL(__ashldi3); -EXPORT_SYMBOL(__lshrdi3); -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(cacheable_memcpy); -EXPORT_SYMBOL(memset); -EXPORT_SYMBOL(memmove); -EXPORT_SYMBOL(memcmp); -EXPORT_SYMBOL(memchr); - -#if defined(CONFIG_FB_VGA16_MODULE) -EXPORT_SYMBOL(screen_info); -#endif - -EXPORT_SYMBOL(__delay); -EXPORT_SYMBOL(timer_interrupt); -EXPORT_SYMBOL(irq_desc); -EXPORT_SYMBOL(tb_ticks_per_jiffy); -EXPORT_SYMBOL(console_drivers); -#ifdef CONFIG_XMON -EXPORT_SYMBOL(xmon); -EXPORT_SYMBOL(xmon_printf); -#endif - -#if defined(CONFIG_KGDB) || defined(CONFIG_XMON) -extern void (*debugger)(struct pt_regs *regs); -extern int (*debugger_bpt)(struct pt_regs *regs); -extern int (*debugger_sstep)(struct pt_regs *regs); -extern int (*debugger_iabr_match)(struct pt_regs *regs); -extern int (*debugger_dabr_match)(struct pt_regs *regs); -extern void (*debugger_fault_handler)(struct pt_regs *regs); - -EXPORT_SYMBOL(debugger); -EXPORT_SYMBOL(debugger_bpt); -EXPORT_SYMBOL(debugger_sstep); -EXPORT_SYMBOL(debugger_iabr_match); -EXPORT_SYMBOL(debugger_dabr_match); -EXPORT_SYMBOL(debugger_fault_handler); -#endif - -#ifdef CONFIG_8xx -EXPORT_SYMBOL(cpm_install_handler); -EXPORT_SYMBOL(cpm_free_handler); -#endif /* CONFIG_8xx */ -#if defined(CONFIG_8xx) || defined(CONFIG_40x) -EXPORT_SYMBOL(__res); -#endif - -EXPORT_SYMBOL(next_mmu_context); -EXPORT_SYMBOL(set_context); -EXPORT_SYMBOL(disarm_decr); -#ifdef CONFIG_PPC_STD_MMU -extern long mol_trampoline; -EXPORT_SYMBOL(mol_trampoline); /* For MOL */ -EXPORT_SYMBOL(flush_hash_pages); /* For MOL */ -#ifdef CONFIG_SMP -extern int mmu_hash_lock; -EXPORT_SYMBOL(mmu_hash_lock); /* For MOL */ -#endif /* CONFIG_SMP */ -extern long *intercept_table; -EXPORT_SYMBOL(intercept_table); -#endif /* CONFIG_PPC_STD_MMU */ -#ifdef CONFIG_PPC_DCR_NATIVE -EXPORT_SYMBOL(__mtdcr); -EXPORT_SYMBOL(__mfdcr); -#endif diff --git a/arch/ppc/kernel/relocate_kernel.S b/arch/ppc/kernel/relocate_kernel.S deleted file mode 100644 index 9b2ad48e988..00000000000 --- a/arch/ppc/kernel/relocate_kernel.S +++ /dev/null @@ -1,123 +0,0 @@ -/* - * relocate_kernel.S - put the kernel image in place to boot - * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com> - * - * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. - */ - -#include <asm/reg.h> -#include <asm/ppc_asm.h> -#include <asm/processor.h> - -#include <asm/kexec.h> - -#define PAGE_SIZE 4096 /* must be same value as in <asm/page.h> */ - - /* - * Must be relocatable PIC code callable as a C function. - */ - .globl relocate_new_kernel -relocate_new_kernel: - /* r3 = page_list */ - /* r4 = reboot_code_buffer */ - /* r5 = start_address */ - - li r0, 0 - - /* - * Set Machine Status Register to a known status, - * switch the MMU off and jump to 1: in a single step. - */ - - mr r8, r0 - ori r8, r8, MSR_RI|MSR_ME - mtspr SPRN_SRR1, r8 - addi r8, r4, 1f - relocate_new_kernel - mtspr SPRN_SRR0, r8 - sync - rfi - -1: - /* from this point address translation is turned off */ - /* and interrupts are disabled */ - - /* set a new stack at the bottom of our page... */ - /* (not really needed now) */ - addi r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */ - stw r0, 0(r1) - - /* Do the copies */ - li r6, 0 /* checksum */ - mr r0, r3 - b 1f - -0: /* top, read another word for the indirection page */ - lwzu r0, 4(r3) - -1: - /* is it a destination page? (r8) */ - rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */ - beq 2f - - rlwinm r8, r0, 0, 0, 19 /* clear kexec flags, page align */ - b 0b - -2: /* is it an indirection page? (r3) */ - rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */ - beq 2f - - rlwinm r3, r0, 0, 0, 19 /* clear kexec flags, page align */ - subi r3, r3, 4 - b 0b - -2: /* are we done? */ - rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */ - beq 2f - b 3f - -2: /* is it a source page? (r9) */ - rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */ - beq 0b - - rlwinm r9, r0, 0, 0, 19 /* clear kexec flags, page align */ - - li r7, PAGE_SIZE / 4 - mtctr r7 - subi r9, r9, 4 - subi r8, r8, 4 -9: - lwzu r0, 4(r9) /* do the copy */ - xor r6, r6, r0 - stwu r0, 4(r8) - dcbst 0, r8 - sync - icbi 0, r8 - bdnz 9b - - addi r9, r9, 4 - addi r8, r8, 4 - b 0b - -3: - - /* To be certain of avoiding problems with self-modifying code - * execute a serializing instruction here. - */ - isync - sync - - /* jump to the entry point, usually the setup routine */ - mtlr r5 - blrl - -1: b 1b - -relocate_new_kernel_end: - - .globl relocate_new_kernel_size -relocate_new_kernel_size: - .long relocate_new_kernel_end - relocate_new_kernel - diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c deleted file mode 100644 index 51e8094f52d..00000000000 --- a/arch/ppc/kernel/setup.c +++ /dev/null @@ -1,572 +0,0 @@ -/* - * Common prep boot and setup code. - */ - -#include <linux/module.h> -#include <linux/string.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/reboot.h> -#include <linux/delay.h> -#include <linux/initrd.h> -#include <linux/screen_info.h> -#include <linux/bootmem.h> -#include <linux/seq_file.h> -#include <linux/root_dev.h> -#include <linux/cpu.h> -#include <linux/console.h> - -#include <asm/residual.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/processor.h> -#include <asm/pgtable.h> -#include <asm/bootinfo.h> -#include <asm/setup.h> -#include <asm/smp.h> -#include <asm/elf.h> -#include <asm/cputable.h> -#include <asm/bootx.h> -#include <asm/btext.h> -#include <asm/machdep.h> -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/sections.h> -#include <asm/nvram.h> -#include <asm/xmon.h> -#include <asm/ocp.h> -#include <asm/irq.h> - -#define USES_PPC_SYS (defined(CONFIG_MPC10X_BRIDGE) || defined(CONFIG_8260) || \ - defined(CONFIG_PPC_MPC52xx)) - -#if USES_PPC_SYS -#include <asm/ppc_sys.h> -#endif - -#if defined CONFIG_KGDB -#include <asm/kgdb.h> -#endif - -extern void platform_init(unsigned long r3, unsigned long r4, - unsigned long r5, unsigned long r6, unsigned long r7); -extern void reloc_got2(unsigned long offset); - -extern void ppc6xx_idle(void); -extern void power4_idle(void); - -extern boot_infos_t *boot_infos; - -/* Used with the BI_MEMSIZE bootinfo parameter to store the memory - size value reported by the boot loader. */ -unsigned long boot_mem_size; - -unsigned long ISA_DMA_THRESHOLD; -unsigned int DMA_MODE_READ; -unsigned int DMA_MODE_WRITE; - -#ifdef CONFIG_PPC_PREP -extern void prep_init(unsigned long r3, unsigned long r4, - unsigned long r5, unsigned long r6, unsigned long r7); - -dev_t boot_dev; -#endif /* CONFIG_PPC_PREP */ - -int have_of; -EXPORT_SYMBOL(have_of); - -#ifdef __DO_IRQ_CANON -int ppc_do_canonicalize_irqs; -EXPORT_SYMBOL(ppc_do_canonicalize_irqs); -#endif - -#ifdef CONFIG_VGA_CONSOLE -unsigned long vgacon_remap_base; -#endif - -struct machdep_calls ppc_md; - -/* - * These are used in binfmt_elf.c to put aux entries on the stack - * for each elf executable being started. - */ -int dcache_bsize; -int icache_bsize; -int ucache_bsize; - -#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_FB_VGA16) || \ - defined(CONFIG_FB_VGA16_MODULE) || defined(CONFIG_FB_VESA) -struct screen_info screen_info = { - 0, 25, /* orig-x, orig-y */ - 0, /* unused */ - 0, /* orig-video-page */ - 0, /* orig-video-mode */ - 80, /* orig-video-cols */ - 0,0,0, /* ega_ax, ega_bx, ega_cx */ - 25, /* orig-video-lines */ - 1, /* orig-video-isVGA */ - 16 /* orig-video-points */ -}; -#endif /* CONFIG_VGA_CONSOLE || CONFIG_FB_VGA16 || CONFIG_FB_VESA */ - -void machine_restart(char *cmd) -{ -#ifdef CONFIG_NVRAM - nvram_sync(); -#endif - ppc_md.restart(cmd); -} - -static void ppc_generic_power_off(void) -{ - ppc_md.power_off(); -} - -void machine_halt(void) -{ -#ifdef CONFIG_NVRAM - nvram_sync(); -#endif - ppc_md.halt(); -} - -void (*pm_power_off)(void) = ppc_generic_power_off; - -void machine_power_off(void) -{ -#ifdef CONFIG_NVRAM - nvram_sync(); -#endif - if (pm_power_off) - pm_power_off(); - ppc_generic_power_off(); -} - -#ifdef CONFIG_TAU -extern u32 cpu_temp(unsigned long cpu); -extern u32 cpu_temp_both(unsigned long cpu); -#endif /* CONFIG_TAU */ - -int show_cpuinfo(struct seq_file *m, void *v) -{ - int i = (int) v - 1; - int err = 0; - unsigned int pvr; - unsigned short maj, min; - unsigned long lpj; - - if (i >= NR_CPUS) { - /* Show summary information */ -#ifdef CONFIG_SMP - unsigned long bogosum = 0; - for_each_online_cpu(i) - bogosum += cpu_data[i].loops_per_jiffy; - seq_printf(m, "total bogomips\t: %lu.%02lu\n", - bogosum/(500000/HZ), bogosum/(5000/HZ) % 100); -#endif /* CONFIG_SMP */ - - if (ppc_md.show_cpuinfo != NULL) - err = ppc_md.show_cpuinfo(m); - return err; - } - -#ifdef CONFIG_SMP - if (!cpu_online(i)) - return 0; - pvr = cpu_data[i].pvr; - lpj = cpu_data[i].loops_per_jiffy; -#else - pvr = mfspr(SPRN_PVR); - lpj = loops_per_jiffy; -#endif - - seq_printf(m, "processor\t: %d\n", i); - seq_printf(m, "cpu\t\t: "); - - if (cur_cpu_spec->pvr_mask) - seq_printf(m, "%s", cur_cpu_spec->cpu_name); - else - seq_printf(m, "unknown (%08x)", pvr); -#ifdef CONFIG_ALTIVEC - if (cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC) - seq_printf(m, ", altivec supported"); -#endif - seq_printf(m, "\n"); - -#ifdef CONFIG_TAU - if (cur_cpu_spec->cpu_features & CPU_FTR_TAU) { -#ifdef CONFIG_TAU_AVERAGE - /* more straightforward, but potentially misleading */ - seq_printf(m, "temperature \t: %u C (uncalibrated)\n", - cpu_temp(i)); -#else - /* show the actual temp sensor range */ - u32 temp; - temp = cpu_temp_both(i); - seq_printf(m, "temperature \t: %u-%u C (uncalibrated)\n", - temp & 0xff, temp >> 16); -#endif - } -#endif /* CONFIG_TAU */ - - if (ppc_md.show_percpuinfo != NULL) { - err = ppc_md.show_percpuinfo(m, i); - if (err) - return err; - } - - /* If we are a Freescale core do a simple check so - * we dont have to keep adding cases in the future */ - if ((PVR_VER(pvr) & 0x8000) == 0x8000) { - maj = PVR_MAJ(pvr); - min = PVR_MIN(pvr); - } else { - switch (PVR_VER(pvr)) { - case 0x0020: /* 403 family */ - maj = PVR_MAJ(pvr) + 1; - min = PVR_MIN(pvr); - break; - case 0x1008: /* 740P/750P ?? */ - maj = ((pvr >> 8) & 0xFF) - 1; - min = pvr & 0xFF; - break; - default: - maj = (pvr >> 8) & 0xFF; - min = pvr & 0xFF; - break; - } - } - - seq_printf(m, "revision\t: %hd.%hd (pvr %04x %04x)\n", - maj, min, PVR_VER(pvr), PVR_REV(pvr)); - - seq_printf(m, "bogomips\t: %lu.%02lu\n", - lpj / (500000/HZ), (lpj / (5000/HZ)) % 100); - -#if USES_PPC_SYS - if (cur_ppc_sys_spec->ppc_sys_name) - seq_printf(m, "chipset\t\t: %s\n", - cur_ppc_sys_spec->ppc_sys_name); -#endif - -#ifdef CONFIG_SMP - seq_printf(m, "\n"); -#endif - - return 0; -} - -static void *c_start(struct seq_file *m, loff_t *pos) -{ - int i = *pos; - - return i <= NR_CPUS? (void *) (i + 1): NULL; -} - -static void *c_next(struct seq_file *m, void *v, loff_t *pos) -{ - ++*pos; - return c_start(m, pos); -} - -static void c_stop(struct seq_file *m, void *v) -{ -} - -const struct seq_operations cpuinfo_op = { - .start =c_start, - .next = c_next, - .stop = c_stop, - .show = show_cpuinfo, -}; - -/* - * We're called here very early in the boot. We determine the machine - * type and call the appropriate low-level setup functions. - * -- Cort <cort@fsmlabs.com> - * - * Note that the kernel may be running at an address which is different - * from the address that it was linked at, so we must use RELOC/PTRRELOC - * to access static data (including strings). -- paulus - */ -__init -unsigned long -early_init(int r3, int r4, int r5) -{ - unsigned long phys; - unsigned long offset = reloc_offset(); - struct cpu_spec *spec; - - /* Default */ - phys = offset + KERNELBASE; - - /* First zero the BSS -- use memset, some arches don't have - * caches on yet */ - memset_io(PTRRELOC(&__bss_start), 0, _end - __bss_start); - - /* - * Identify the CPU type and fix up code sections - * that depend on which cpu we have. - */ -#if defined(CONFIG_440EP) && defined(CONFIG_PPC_FPU) - /* We pass the virtual PVR here for 440EP as 440EP and 440GR have - * identical PVRs and there is no reliable way to check for the FPU - */ - spec = identify_cpu(offset, (mfspr(SPRN_PVR) | 0x8)); -#else - spec = identify_cpu(offset, mfspr(SPRN_PVR)); -#endif - do_feature_fixups(spec->cpu_features, - PTRRELOC(&__start___ftr_fixup), - PTRRELOC(&__stop___ftr_fixup)); - - return phys; -} - -#ifdef CONFIG_PPC_PREP -/* - * The PPC_PREP version of platform_init... - */ -void __init -platform_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ -#ifdef CONFIG_BOOTX_TEXT - if (boot_text_mapped) { - btext_clearscreen(); - btext_welcome(); - } -#endif - - parse_bootinfo(find_bootinfo()); - - prep_init(r3, r4, r5, r6, r7); -} -#endif /* CONFIG_PPC_PREP */ - -struct bi_record *find_bootinfo(void) -{ - struct bi_record *rec; - - rec = (struct bi_record *)_ALIGN((ulong)__bss_start+(1<<20)-1,(1<<20)); - if ( rec->tag != BI_FIRST ) { - /* - * This 0x10000 offset is a terrible hack but it will go away when - * we have the bootloader handle all the relocation and - * prom calls -- Cort - */ - rec = (struct bi_record *)_ALIGN((ulong)__bss_start+0x10000+(1<<20)-1,(1<<20)); - if ( rec->tag != BI_FIRST ) - return NULL; - } - return rec; -} - -void parse_bootinfo(struct bi_record *rec) -{ - if (rec == NULL || rec->tag != BI_FIRST) - return; - while (rec->tag != BI_LAST) { - ulong *data = rec->data; - switch (rec->tag) { - case BI_CMD_LINE: - strlcpy(cmd_line, (void *)data, sizeof(cmd_line)); - break; -#ifdef CONFIG_BLK_DEV_INITRD - case BI_INITRD: - initrd_start = data[0] + KERNELBASE; - initrd_end = data[0] + data[1] + KERNELBASE; - break; -#endif /* CONFIG_BLK_DEV_INITRD */ - case BI_MEMSIZE: - boot_mem_size = data[0]; - break; - } - rec = (struct bi_record *)((ulong)rec + rec->size); - } -} - -/* - * Find out what kind of machine we're on and save any data we need - * from the early boot process (devtree is copied on pmac by prom_init()). - * This is called very early on the boot process, after a minimal - * MMU environment has been set up but before MMU_init is called. - */ -void __init -machine_init(unsigned long r3, unsigned long r4, unsigned long r5, - unsigned long r6, unsigned long r7) -{ -#ifdef CONFIG_CMDLINE - strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line)); -#endif /* CONFIG_CMDLINE */ - -#ifdef CONFIG_6xx - ppc_md.power_save = ppc6xx_idle; -#endif - - platform_init(r3, r4, r5, r6, r7); - - if (ppc_md.progress) - ppc_md.progress("id mach(): done", 0x200); -} -#ifdef CONFIG_BOOKE_WDT -/* Checks wdt=x and wdt_period=xx command-line option */ -int __init early_parse_wdt(char *p) -{ - if (p && strncmp(p, "0", 1) != 0) - booke_wdt_enabled = 1; - - return 0; -} -early_param("wdt", early_parse_wdt); - -int __init early_parse_wdt_period (char *p) -{ - if (p) - booke_wdt_period = simple_strtoul(p, NULL, 0); - - return 0; -} -early_param("wdt_period", early_parse_wdt_period); -#endif /* CONFIG_BOOKE_WDT */ - -/* Checks "l2cr=xxxx" command-line option */ -int __init ppc_setup_l2cr(char *str) -{ - if (cpu_has_feature(CPU_FTR_L2CR)) { - unsigned long val = simple_strtoul(str, NULL, 0); - printk(KERN_INFO "l2cr set to %lx\n", val); - _set_L2CR(0); /* force invalidate by disable cache */ - _set_L2CR(val); /* and enable it */ - } - return 1; -} -__setup("l2cr=", ppc_setup_l2cr); - -#ifdef CONFIG_GENERIC_NVRAM - -/* Generic nvram hooks used by drivers/char/gen_nvram.c */ -unsigned char nvram_read_byte(int addr) -{ - if (ppc_md.nvram_read_val) - return ppc_md.nvram_read_val(addr); - return 0xff; -} -EXPORT_SYMBOL(nvram_read_byte); - -void nvram_write_byte(unsigned char val, int addr) -{ - if (ppc_md.nvram_write_val) - ppc_md.nvram_write_val(addr, val); -} -EXPORT_SYMBOL(nvram_write_byte); - -void nvram_sync(void) -{ - if (ppc_md.nvram_sync) - ppc_md.nvram_sync(); -} -EXPORT_SYMBOL(nvram_sync); - -#endif /* CONFIG_NVRAM */ - -static struct cpu cpu_devices[NR_CPUS]; - -int __init ppc_init(void) -{ - int i; - - /* clear the progress line */ - if ( ppc_md.progress ) ppc_md.progress(" ", 0xffff); - - /* register CPU devices */ - for_each_possible_cpu(i) - register_cpu(&cpu_devices[i], i); - - /* call platform init */ - if (ppc_md.init != NULL) { - ppc_md.init(); - } - return 0; -} - -arch_initcall(ppc_init); - -/* Warning, IO base is not yet inited */ -void __init setup_arch(char **cmdline_p) -{ - extern char *klimit; - extern void do_init_bootmem(void); - - /* so udelay does something sensible, assume <= 1000 bogomips */ - loops_per_jiffy = 500000000 / HZ; - - if (ppc_md.init_early) - ppc_md.init_early(); - -#ifdef CONFIG_XMON - xmon_init(1); - if (strstr(cmd_line, "xmon")) - xmon(NULL); -#endif /* CONFIG_XMON */ - if ( ppc_md.progress ) ppc_md.progress("setup_arch: enter", 0x3eab); - -#if defined(CONFIG_KGDB) - if (ppc_md.kgdb_map_scc) - ppc_md.kgdb_map_scc(); - set_debug_traps(); - if (strstr(cmd_line, "gdb")) { - if (ppc_md.progress) - ppc_md.progress("setup_arch: kgdb breakpoint", 0x4000); - printk("kgdb breakpoint activated\n"); - breakpoint(); - } -#endif - - /* - * Set cache line size based on type of cpu as a default. - * Systems with OF can look in the properties on the cpu node(s) - * for a possibly more accurate value. - */ - if (! cpu_has_feature(CPU_FTR_UNIFIED_ID_CACHE)) { - dcache_bsize = cur_cpu_spec->dcache_bsize; - icache_bsize = cur_cpu_spec->icache_bsize; - ucache_bsize = 0; - } else - ucache_bsize = dcache_bsize = icache_bsize - = cur_cpu_spec->dcache_bsize; - - /* reboot on panic */ - panic_timeout = 180; - - init_mm.start_code = PAGE_OFFSET; - init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; - init_mm.brk = (unsigned long) klimit; - - /* Save unparsed command line copy for /proc/cmdline */ - strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE); - *cmdline_p = cmd_line; - - parse_early_param(); - - /* set up the bootmem stuff with available memory */ - do_init_bootmem(); - if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab); - -#ifdef CONFIG_PPC_OCP - /* Initialize OCP device list */ - ocp_early_init(); - if ( ppc_md.progress ) ppc_md.progress("ocp: exit", 0x3eab); -#endif - -#ifdef CONFIG_DUMMY_CONSOLE - conswitchp = &dummy_con; -#endif - - ppc_md.setup_arch(); - if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); - - paging_init(); -} diff --git a/arch/ppc/kernel/smp-tbsync.c b/arch/ppc/kernel/smp-tbsync.c deleted file mode 100644 index d0cf3f86931..00000000000 --- a/arch/ppc/kernel/smp-tbsync.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Smp timebase synchronization for ppc. - * - * Copyright (C) 2003 Samuel Rydh (samuel@ibrium.se) - * - */ - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/unistd.h> -#include <linux/init.h> -#include <asm/atomic.h> -#include <asm/smp.h> -#include <asm/time.h> - -#define NUM_ITER 300 - -enum { - kExit=0, kSetAndTest, kTest -}; - -static struct { - volatile int tbu; - volatile int tbl; - volatile int mark; - volatile int cmd; - volatile int handshake; - int filler[3]; - - volatile int ack; - int filler2[7]; - - volatile int race_result; -} *tbsync; - -static volatile int running; - -static void __devinit -enter_contest( int mark, int add ) -{ - while( (int)(get_tbl() - mark) < 0 ) - tbsync->race_result = add; -} - -void __devinit -smp_generic_take_timebase( void ) -{ - int cmd, tbl, tbu; - unsigned long flags; - - local_irq_save(flags); - while( !running ) - ; - rmb(); - - for( ;; ) { - tbsync->ack = 1; - while( !tbsync->handshake ) - ; - rmb(); - - cmd = tbsync->cmd; - tbl = tbsync->tbl; - tbu = tbsync->tbu; - tbsync->ack = 0; - if( cmd == kExit ) - break; - - if( cmd == kSetAndTest ) { - while( tbsync->handshake ) - ; - asm volatile ("mttbl %0" :: "r" (tbl) ); - asm volatile ("mttbu %0" :: "r" (tbu) ); - } else { - while( tbsync->handshake ) - ; - } - enter_contest( tbsync->mark, -1 ); - } - local_irq_restore(flags); -} - -static int __devinit -start_contest( int cmd, int offset, int num ) -{ - int i, tbu, tbl, mark, score=0; - - tbsync->cmd = cmd; - - local_irq_disable(); - for( i=-3; i<num; ) { - tbl = get_tbl() + 400; - tbsync->tbu = tbu = get_tbu(); - tbsync->tbl = tbl + offset; - tbsync->mark = mark = tbl + 400; - - wmb(); - - tbsync->handshake = 1; - while( tbsync->ack ) - ; - - while( (int)(get_tbl() - tbl) <= 0 ) - ; - tbsync->handshake = 0; - enter_contest( mark, 1 ); - - while( !tbsync->ack ) - ; - - if( tbsync->tbu != get_tbu() || ((tbsync->tbl ^ get_tbl()) & 0x80000000) ) - continue; - if( i++ > 0 ) - score += tbsync->race_result; - } - local_irq_enable(); - return score; -} - -void __devinit -smp_generic_give_timebase( void ) -{ - int i, score, score2, old, min=0, max=5000, offset=1000; - - printk("Synchronizing timebase\n"); - - /* if this fails then this kernel won't work anyway... */ - tbsync = kzalloc( sizeof(*tbsync), GFP_KERNEL ); - mb(); - running = 1; - - while( !tbsync->ack ) - ; - - /* binary search */ - for( old=-1 ; old != offset ; offset=(min+max)/2 ) { - score = start_contest( kSetAndTest, offset, NUM_ITER ); - - printk("score %d, offset %d\n", score, offset ); - - if( score > 0 ) - max = offset; - else - min = offset; - old = offset; - } - score = start_contest( kSetAndTest, min, NUM_ITER ); - score2 = start_contest( kSetAndTest, max, NUM_ITER ); - - printk( "Min %d (score %d), Max %d (score %d)\n", min, score, max, score2 ); - score = abs( score ); - score2 = abs( score2 ); - offset = (score < score2) ? min : max; - - /* guard against inaccurate mttb */ - for( i=0; i<10; i++ ) { - start_contest( kSetAndTest, offset, NUM_ITER/10 ); - - if( (score2=start_contest(kTest, offset, NUM_ITER)) < 0 ) - score2 = -score2; - if( score2 <= score || score2 < 20 ) - break; - } - printk("Final offset: %d (%d/%d)\n", offset, score2, NUM_ITER ); - - /* exiting */ - tbsync->cmd = kExit; - wmb(); - tbsync->handshake = 1; - while( tbsync->ack ) - ; - tbsync->handshake = 0; - kfree( tbsync ); - tbsync = NULL; - running = 0; - - /* all done */ - smp_tb_synchronized = 1; -} diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c deleted file mode 100644 index 055998575cb..00000000000 --- a/arch/ppc/kernel/smp.c +++ /dev/null @@ -1,414 +0,0 @@ -/* - * Smp support for ppc. - * - * Written by Cort Dougan (cort@cs.nmt.edu) borrowing a great - * deal of code from the sparc and intel versions. - * - * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu> - * - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/interrupt.h> -#include <linux/kernel_stat.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/cache.h> - -#include <asm/ptrace.h> -#include <asm/atomic.h> -#include <asm/irq.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/smp.h> -#include <asm/residual.h> -#include <asm/time.h> -#include <asm/thread_info.h> -#include <asm/tlbflush.h> -#include <asm/xmon.h> -#include <asm/machdep.h> - -volatile int smp_commenced; -int smp_tb_synchronized; -struct cpuinfo_PPC cpu_data[NR_CPUS]; -atomic_t ipi_recv; -atomic_t ipi_sent; -cpumask_t cpu_online_map; -cpumask_t cpu_possible_map; -int smp_hw_index[NR_CPUS]; -struct thread_info *secondary_ti; -static struct task_struct *idle_tasks[NR_CPUS]; - -EXPORT_SYMBOL(cpu_online_map); -EXPORT_SYMBOL(cpu_possible_map); - -/* SMP operations for this machine */ -struct smp_ops_t *smp_ops; - -/* all cpu mappings are 1-1 -- Cort */ -volatile unsigned long cpu_callin_map[NR_CPUS]; - -int start_secondary(void *); -void smp_call_function_interrupt(void); -static int __smp_call_function(void (*func) (void *info), void *info, - int wait, int target); - -/* Low level assembly function used to backup CPU 0 state */ -extern void __save_cpu_setup(void); - -/* Since OpenPIC has only 4 IPIs, we use slightly different message numbers. - * - * Make sure this matches openpic_request_IPIs in open_pic.c, or what shows up - * in /proc/interrupts will be wrong!!! --Troy */ -#define PPC_MSG_CALL_FUNCTION 0 -#define PPC_MSG_RESCHEDULE 1 -#define PPC_MSG_INVALIDATE_TLB 2 -#define PPC_MSG_XMON_BREAK 3 - -static inline void -smp_message_pass(int target, int msg) -{ - if (smp_ops) { - atomic_inc(&ipi_sent); - smp_ops->message_pass(target, msg); - } -} - -/* - * Common functions - */ -void smp_message_recv(int msg) -{ - atomic_inc(&ipi_recv); - - switch( msg ) { - case PPC_MSG_CALL_FUNCTION: - smp_call_function_interrupt(); - break; - case PPC_MSG_RESCHEDULE: - set_need_resched(); - break; - case PPC_MSG_INVALIDATE_TLB: - _tlbia(); - break; -#ifdef CONFIG_XMON - case PPC_MSG_XMON_BREAK: - xmon(get_irq_regs()); - break; -#endif /* CONFIG_XMON */ - default: - printk("SMP %d: smp_message_recv(): unknown msg %d\n", - smp_processor_id(), msg); - break; - } -} - -/* - * 750's don't broadcast tlb invalidates so - * we have to emulate that behavior. - * -- Cort - */ -void smp_send_tlb_invalidate(int cpu) -{ - if ( PVR_VER(mfspr(SPRN_PVR)) == 8 ) - smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_INVALIDATE_TLB); -} - -void smp_send_reschedule(int cpu) -{ - /* - * This is only used if `cpu' is running an idle task, - * so it will reschedule itself anyway... - * - * This isn't the case anymore since the other CPU could be - * sleeping and won't reschedule until the next interrupt (such - * as the timer). - * -- Cort - */ - /* This is only used if `cpu' is running an idle task, - so it will reschedule itself anyway... */ - smp_message_pass(cpu, PPC_MSG_RESCHEDULE); -} - -#ifdef CONFIG_XMON -void smp_send_xmon_break(int cpu) -{ - smp_message_pass(cpu, PPC_MSG_XMON_BREAK); -} -#endif /* CONFIG_XMON */ - -static void stop_this_cpu(void *dummy) -{ - local_irq_disable(); - while (1) - ; -} - -void smp_send_stop(void) -{ - smp_call_function(stop_this_cpu, NULL, 1, 0); -} - -/* - * Structure and data for smp_call_function(). This is designed to minimise - * static memory requirements. It also looks cleaner. - * Stolen from the i386 version. - */ -static DEFINE_SPINLOCK(call_lock); - -static struct call_data_struct { - void (*func) (void *info); - void *info; - atomic_t started; - atomic_t finished; - int wait; -} *call_data; - -/* - * this function sends a 'generic call function' IPI to all other CPUs - * in the system. - */ - -int smp_call_function(void (*func) (void *info), void *info, int nonatomic, - int wait) -/* - * [SUMMARY] Run a function on all other CPUs. - * <func> The function to run. This must be fast and non-blocking. - * <info> An arbitrary pointer to pass to the function. - * <nonatomic> currently unused. - * <wait> If true, wait (atomically) until function has completed on other CPUs. - * [RETURNS] 0 on success, else a negative status code. Does not return until - * remote CPUs are nearly ready to execute <<func>> or are or have executed. - * - * You must not call this function with disabled interrupts or from a - * hardware interrupt handler or from a bottom half handler. - */ -{ - /* FIXME: get cpu lock with hotplug cpus, or change this to - bitmask. --RR */ - if (num_online_cpus() <= 1) - return 0; - /* Can deadlock when called with interrupts disabled */ - WARN_ON(irqs_disabled()); - return __smp_call_function(func, info, wait, MSG_ALL_BUT_SELF); -} - -static int __smp_call_function(void (*func) (void *info), void *info, - int wait, int target) -{ - struct call_data_struct data; - int ret = -1; - int timeout; - int ncpus = 1; - - if (target == MSG_ALL_BUT_SELF) - ncpus = num_online_cpus() - 1; - else if (target == MSG_ALL) - ncpus = num_online_cpus(); - - data.func = func; - data.info = info; - atomic_set(&data.started, 0); - data.wait = wait; - if (wait) - atomic_set(&data.finished, 0); - - spin_lock(&call_lock); - call_data = &data; - /* Send a message to all other CPUs and wait for them to respond */ - smp_message_pass(target, PPC_MSG_CALL_FUNCTION); - - /* Wait for response */ - timeout = 1000000; - while (atomic_read(&data.started) != ncpus) { - if (--timeout == 0) { - printk("smp_call_function on cpu %d: other cpus not responding (%d)\n", - smp_processor_id(), atomic_read(&data.started)); - goto out; - } - barrier(); - udelay(1); - } - - if (wait) { - timeout = 1000000; - while (atomic_read(&data.finished) != ncpus) { - if (--timeout == 0) { - printk("smp_call_function on cpu %d: other cpus not finishing (%d/%d)\n", - smp_processor_id(), atomic_read(&data.finished), atomic_read(&data.started)); - goto out; - } - barrier(); - udelay(1); - } - } - ret = 0; - - out: - spin_unlock(&call_lock); - return ret; -} - -void smp_call_function_interrupt(void) -{ - void (*func) (void *info) = call_data->func; - void *info = call_data->info; - int wait = call_data->wait; - - /* - * Notify initiating CPU that I've grabbed the data and am - * about to execute the function - */ - atomic_inc(&call_data->started); - /* - * At this point the info structure may be out of scope unless wait==1 - */ - (*func)(info); - if (wait) - atomic_inc(&call_data->finished); -} - -static void __devinit smp_store_cpu_info(int id) -{ - struct cpuinfo_PPC *c = &cpu_data[id]; - - /* assume bogomips are same for everything */ - c->loops_per_jiffy = loops_per_jiffy; - c->pvr = mfspr(SPRN_PVR); -} - -void __init smp_prepare_cpus(unsigned int max_cpus) -{ - int num_cpus, i, cpu; - struct task_struct *p; - - /* Fixup boot cpu */ - smp_store_cpu_info(smp_processor_id()); - cpu_callin_map[smp_processor_id()] = 1; - - if (smp_ops == NULL) { - printk("SMP not supported on this machine.\n"); - return; - } - - /* Probe platform for CPUs: always linear. */ - num_cpus = smp_ops->probe(); - - if (num_cpus < 2) - smp_tb_synchronized = 1; - - for (i = 0; i < num_cpus; ++i) - cpu_set(i, cpu_possible_map); - - /* Backup CPU 0 state */ - __save_cpu_setup(); - - for_each_possible_cpu(cpu) { - if (cpu == smp_processor_id()) - continue; - /* create a process for the processor */ - p = fork_idle(cpu); - if (IS_ERR(p)) - panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p)); - task_thread_info(p)->cpu = cpu; - idle_tasks[cpu] = p; - } -} - -void __devinit smp_prepare_boot_cpu(void) -{ - cpu_set(smp_processor_id(), cpu_online_map); - cpu_set(smp_processor_id(), cpu_possible_map); -} - -int __init setup_profiling_timer(unsigned int multiplier) -{ - return 0; -} - -/* Processor coming up starts here */ -int __devinit start_secondary(void *unused) -{ - int cpu; - - atomic_inc(&init_mm.mm_count); - current->active_mm = &init_mm; - - cpu = smp_processor_id(); - smp_store_cpu_info(cpu); - set_dec(tb_ticks_per_jiffy); - preempt_disable(); - cpu_callin_map[cpu] = 1; - - printk("CPU %d done callin...\n", cpu); - smp_ops->setup_cpu(cpu); - printk("CPU %d done setup...\n", cpu); - smp_ops->take_timebase(); - printk("CPU %d done timebase take...\n", cpu); - - spin_lock(&call_lock); - cpu_set(cpu, cpu_online_map); - spin_unlock(&call_lock); - - local_irq_enable(); - - cpu_idle(); - return 0; -} - -int __cpu_up(unsigned int cpu) -{ - char buf[32]; - int c; - - secondary_ti = task_thread_info(idle_tasks[cpu]); - mb(); - - /* - * There was a cache flush loop here to flush the cache - * to memory for the first 8MB of RAM. The cache flush - * has been pushed into the kick_cpu function for those - * platforms that need it. - */ - - /* wake up cpu */ - smp_ops->kick_cpu(cpu); - - /* - * wait to see if the cpu made a callin (is actually up). - * use this value that I found through experimentation. - * -- Cort - */ - for (c = 1000; c && !cpu_callin_map[cpu]; c--) - udelay(100); - - if (!cpu_callin_map[cpu]) { - sprintf(buf, "didn't find cpu %u", cpu); - if (ppc_md.progress) ppc_md.progress(buf, 0x360+cpu); - printk("Processor %u is stuck.\n", cpu); - return -ENOENT; - } - - sprintf(buf, "found cpu %u", cpu); - if (ppc_md.progress) ppc_md.progress(buf, 0x350+cpu); - printk("Processor %d found.\n", cpu); - - smp_ops->give_timebase(); - - /* Wait until cpu puts itself in the online map */ - while (!cpu_online(cpu)) - cpu_relax(); - - return 0; -} - -void smp_cpus_done(unsigned int max_cpus) -{ - smp_ops->setup_cpu(0); -} diff --git a/arch/ppc/kernel/softemu8xx.c b/arch/ppc/kernel/softemu8xx.c deleted file mode 100644 index 9bbb6bf7b64..00000000000 --- a/arch/ppc/kernel/softemu8xx.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Software emulation of some PPC instructions for the 8xx core. - * - * Copyright (C) 1998 Dan Malek (dmalek@jlc.net) - * - * Software floating emuation for the MPC8xx processor. I did this mostly - * because it was easier than trying to get the libraries compiled for - * software floating point. The goal is still to get the libraries done, - * but I lost patience and needed some hacks to at least get init and - * shells running. The first problem is the setjmp/longjmp that save - * and restore the floating point registers. - * - * For this emulation, our working registers are found on the register - * save area. - */ - -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/a.out.h> -#include <linux/interrupt.h> - -#include <asm/pgtable.h> -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/io.h> - -extern void -print_8xx_pte(struct mm_struct *mm, unsigned long addr); -extern int -get_8xx_pte(struct mm_struct *mm, unsigned long addr); - -/* Eventually we may need a look-up table, but this works for now. -*/ -#define LFS 48 -#define LFD 50 -#define LFDU 51 -#define STFD 54 -#define STFDU 55 -#define FMR 63 - -/* - * We return 0 on success, 1 on unimplemented instruction, and EFAULT - * if a load/store faulted. - */ -int -Soft_emulate_8xx(struct pt_regs *regs) -{ - uint inst, instword; - uint flreg, idxreg, disp; - uint retval; - signed short sdisp; - uint *ea, *ip; - - retval = 0; - - instword = *((uint *)regs->nip); - inst = instword >> 26; - - flreg = (instword >> 21) & 0x1f; - idxreg = (instword >> 16) & 0x1f; - disp = instword & 0xffff; - - ea = (uint *)(regs->gpr[idxreg] + disp); - ip = (uint *)¤t->thread.fpr[flreg]; - - switch ( inst ) - { - case LFD: - /* this is a 16 bit quantity that is sign extended - * so use a signed short here -- Cort - */ - sdisp = (instword & 0xffff); - ea = (uint *)(regs->gpr[idxreg] + sdisp); - if (copy_from_user(ip, ea, sizeof(double))) - retval = -EFAULT; - break; - - case LFDU: - if (copy_from_user(ip, ea, sizeof(double))) - retval = -EFAULT; - else - regs->gpr[idxreg] = (uint)ea; - break; - case LFS: - sdisp = (instword & 0xffff); - ea = (uint *)(regs->gpr[idxreg] + sdisp); - if (copy_from_user(ip, ea, sizeof(float))) - retval = -EFAULT; - break; - case STFD: - /* this is a 16 bit quantity that is sign extended - * so use a signed short here -- Cort - */ - sdisp = (instword & 0xffff); - ea = (uint *)(regs->gpr[idxreg] + sdisp); - if (copy_to_user(ea, ip, sizeof(double))) - retval = -EFAULT; - break; - - case STFDU: - if (copy_to_user(ea, ip, sizeof(double))) - retval = -EFAULT; - else - regs->gpr[idxreg] = (uint)ea; - break; - case FMR: - /* assume this is a fp move -- Cort */ - memcpy( ip, ¤t->thread.fpr[(instword>>11)&0x1f], - sizeof(double) ); - break; - default: - retval = 1; - printk("Bad emulation %s/%d\n" - " NIP: %08lx instruction: %08x opcode: %x " - "A: %x B: %x C: %x code: %x rc: %x\n", - current->comm,current->pid, - regs->nip, - instword,inst, - (instword>>16)&0x1f, - (instword>>11)&0x1f, - (instword>>6)&0x1f, - (instword>>1)&0x3ff, - instword&1); - { - int pa; - print_8xx_pte(current->mm,regs->nip); - pa = get_8xx_pte(current->mm,regs->nip) & PAGE_MASK; - pa |= (regs->nip & ~PAGE_MASK); - pa = (unsigned long)__va(pa); - printk("Kernel VA for NIP %x ", pa); - print_8xx_pte(current->mm,pa); - } - - } - - if (retval == 0) - regs->nip += 4; - return(retval); -} - diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c deleted file mode 100644 index 18ee851e33e..00000000000 --- a/arch/ppc/kernel/time.c +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Common time routines among all ppc machines. - * - * Written by Cort Dougan (cort@cs.nmt.edu) to merge - * Paul Mackerras' version and mine for PReP and Pmac. - * MPC8xx/MBX changes by Dan Malek (dmalek@jlc.net). - * - * First round of bugfixes by Gabriel Paubert (paubert@iram.es) - * to make clock more stable (2.4.0-test5). The only thing - * that this code assumes is that the timebases have been synchronized - * by firmware on SMP and are never stopped (never do sleep - * on SMP then, nap and doze are OK). - * - * TODO (not necessarily in this file): - * - improve precision and reproducibility of timebase frequency - * measurement at boot time. - * - get rid of xtime_lock for gettimeofday (generic kernel problem - * to be implemented on all architectures for SMP scalability and - * eventually implementing gettimeofday without entering the kernel). - * - put all time/clock related variables in a single structure - * to minimize number of cache lines touched by gettimeofday() - * - for astronomical applications: add a new function to get - * non ambiguous timestamps even around leap seconds. This needs - * a new timestamp format and a good name. - * - * - * The following comment is partially obsolete (at least the long wait - * is no more a valid reason): - * Since the MPC8xx has a programmable interrupt timer, I decided to - * use that rather than the decrementer. Two reasons: 1.) the clock - * frequency is low, causing 2.) a long wait in the timer interrupt - * while ((d = get_dec()) == dval) - * loop. The MPC8xx can be driven from a variety of input clocks, - * so a number of assumptions have been made here because the kernel - * parameter HZ is a constant. We assume (correctly, today :-) that - * the MPC8xx on the MBX board is driven from a 32.768 kHz crystal. - * This is then divided by 4, providing a 8192 Hz clock into the PIT. - * Since it is not possible to get a nice 100 Hz clock out of this, without - * creating a software PLL, I have set HZ to 128. -- Dan - * - * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 - * "A Kernel Model for Precision Timekeeping" by Dave Mills - */ - -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/timex.h> -#include <linux/kernel_stat.h> -#include <linux/mc146818rtc.h> -#include <linux/time.h> -#include <linux/init.h> -#include <linux/profile.h> - -#include <asm/io.h> -#include <asm/nvram.h> -#include <asm/cache.h> -#include <asm/8xx_immap.h> -#include <asm/machdep.h> -#include <asm/irq_regs.h> - -#include <asm/time.h> - -unsigned long disarm_decr[NR_CPUS]; - -extern struct timezone sys_tz; - -/* keep track of when we need to update the rtc */ -time_t last_rtc_update; - -/* The decrementer counts down by 128 every 128ns on a 601. */ -#define DECREMENTER_COUNT_601 (1000000000 / HZ) - -unsigned tb_ticks_per_jiffy; -unsigned tb_to_us; -unsigned tb_last_stamp; -unsigned long tb_to_ns_scale; - -/* used for timezone offset */ -static long timezone_offset; - -DEFINE_SPINLOCK(rtc_lock); - -EXPORT_SYMBOL(rtc_lock); - -/* Timer interrupt helper function */ -static inline int tb_delta(unsigned *jiffy_stamp) { - int delta; - if (__USE_RTC()) { - delta = get_rtcl(); - if (delta < *jiffy_stamp) *jiffy_stamp -= 1000000000; - delta -= *jiffy_stamp; - } else { - delta = get_tbl() - *jiffy_stamp; - } - return delta; -} - -#ifdef CONFIG_SMP -unsigned long profile_pc(struct pt_regs *regs) -{ - unsigned long pc = instruction_pointer(regs); - - if (in_lock_functions(pc)) - return regs->link; - - return pc; -} -EXPORT_SYMBOL(profile_pc); -#endif - -void wakeup_decrementer(void) -{ - set_dec(tb_ticks_per_jiffy); - /* No currently-supported powerbook has a 601, - * so use get_tbl, not native - */ - last_jiffy_stamp(0) = tb_last_stamp = get_tbl(); -} - -/* - * timer_interrupt - gets called when the decrementer overflows, - * with interrupts disabled. - * We set it up to overflow again in 1/HZ seconds. - */ -void timer_interrupt(struct pt_regs * regs) -{ - struct pt_regs *old_regs; - int next_dec; - unsigned long cpu = smp_processor_id(); - unsigned jiffy_stamp = last_jiffy_stamp(cpu); - extern void do_IRQ(struct pt_regs *); - - if (atomic_read(&ppc_n_lost_interrupts) != 0) - do_IRQ(regs); - - old_regs = set_irq_regs(regs); - irq_enter(); - - while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) <= 0) { - jiffy_stamp += tb_ticks_per_jiffy; - - profile_tick(CPU_PROFILING); - update_process_times(user_mode(regs)); - - if (smp_processor_id()) - continue; - - /* We are in an interrupt, no need to save/restore flags */ - write_seqlock(&xtime_lock); - tb_last_stamp = jiffy_stamp; - do_timer(1); - - /* - * update the rtc when needed, this should be performed on the - * right fraction of a second. Half or full second ? - * Full second works on mk48t59 clocks, others need testing. - * Note that this update is basically only used through - * the adjtimex system calls. Setting the HW clock in - * any other way is a /dev/rtc and userland business. - * This is still wrong by -0.5/+1.5 jiffies because of the - * timer interrupt resolution and possible delay, but here we - * hit a quantization limit which can only be solved by higher - * resolution timers and decoupling time management from timer - * interrupts. This is also wrong on the clocks - * which require being written at the half second boundary. - * We should have an rtc call that only sets the minutes and - * seconds like on Intel to avoid problems with non UTC clocks. - */ - if ( ppc_md.set_rtc_time && ntp_synced() && - xtime.tv_sec - last_rtc_update >= 659 && - abs((xtime.tv_nsec / 1000) - (1000000-1000000/HZ)) < 500000/HZ) { - if (ppc_md.set_rtc_time(xtime.tv_sec+1 + timezone_offset) == 0) - last_rtc_update = xtime.tv_sec+1; - else - /* Try again one minute later */ - last_rtc_update += 60; - } - write_sequnlock(&xtime_lock); - } - if ( !disarm_decr[smp_processor_id()] ) - set_dec(next_dec); - last_jiffy_stamp(cpu) = jiffy_stamp; - - if (ppc_md.heartbeat && !ppc_md.heartbeat_count--) - ppc_md.heartbeat(); - - irq_exit(); - set_irq_regs(old_regs); -} - -/* - * This version of gettimeofday has microsecond resolution. - */ -void do_gettimeofday(struct timeval *tv) -{ - unsigned long flags; - unsigned long seq; - unsigned delta, usec, sec; - - do { - seq = read_seqbegin_irqsave(&xtime_lock, flags); - sec = xtime.tv_sec; - usec = (xtime.tv_nsec / 1000); - delta = tb_ticks_since(tb_last_stamp); -#ifdef CONFIG_SMP - /* As long as timebases are not in sync, gettimeofday can only - * have jiffy resolution on SMP. - */ - if (!smp_tb_synchronized) - delta = 0; -#endif /* CONFIG_SMP */ - } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); - - usec += mulhwu(tb_to_us, delta); - while (usec >= 1000000) { - sec++; - usec -= 1000000; - } - tv->tv_sec = sec; - tv->tv_usec = usec; -} - -EXPORT_SYMBOL(do_gettimeofday); - -int do_settimeofday(struct timespec *tv) -{ - time_t wtm_sec, new_sec = tv->tv_sec; - long wtm_nsec, new_nsec = tv->tv_nsec; - unsigned long flags; - int tb_delta; - - if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) - return -EINVAL; - - write_seqlock_irqsave(&xtime_lock, flags); - /* Updating the RTC is not the job of this code. If the time is - * stepped under NTP, the RTC will be update after STA_UNSYNC - * is cleared. Tool like clock/hwclock either copy the RTC - * to the system time, in which case there is no point in writing - * to the RTC again, or write to the RTC but then they don't call - * settimeofday to perform this operation. Note also that - * we don't touch the decrementer since: - * a) it would lose timer interrupt synchronization on SMP - * (if it is working one day) - * b) it could make one jiffy spuriously shorter or longer - * which would introduce another source of uncertainty potentially - * harmful to relatively short timers. - */ - - /* This works perfectly on SMP only if the tb are in sync but - * guarantees an error < 1 jiffy even if they are off by eons, - * still reasonable when gettimeofday resolution is 1 jiffy. - */ - tb_delta = tb_ticks_since(last_jiffy_stamp(smp_processor_id())); - - new_nsec -= 1000 * mulhwu(tb_to_us, tb_delta); - - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - new_sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - new_nsec); - - set_normalized_timespec(&xtime, new_sec, new_nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - - /* In case of a large backwards jump in time with NTP, we want the - * clock to be updated as soon as the PLL is again in lock. - */ - last_rtc_update = new_sec - 658; - - ntp_clear(); - write_sequnlock_irqrestore(&xtime_lock, flags); - clock_was_set(); - return 0; -} - -EXPORT_SYMBOL(do_settimeofday); - -/* This function is only called on the boot processor */ -void __init time_init(void) -{ - time_t sec, old_sec; - unsigned old_stamp, stamp, elapsed; - - if (ppc_md.time_init != NULL) - timezone_offset = ppc_md.time_init(); - - if (__USE_RTC()) { - /* 601 processor: dec counts down by 128 every 128ns */ - tb_ticks_per_jiffy = DECREMENTER_COUNT_601; - /* mulhwu_scale_factor(1000000000, 1000000) is 0x418937 */ - tb_to_us = 0x418937; - } else { - ppc_md.calibrate_decr(); - tb_to_ns_scale = mulhwu(tb_to_us, 1000 << 10); - } - - /* Now that the decrementer is calibrated, it can be used in case the - * clock is stuck, but the fact that we have to handle the 601 - * makes things more complex. Repeatedly read the RTC until the - * next second boundary to try to achieve some precision. If there - * is no RTC, we still need to set tb_last_stamp and - * last_jiffy_stamp(cpu 0) to the current stamp. - */ - stamp = get_native_tbl(); - if (ppc_md.get_rtc_time) { - sec = ppc_md.get_rtc_time(); - elapsed = 0; - do { - old_stamp = stamp; - old_sec = sec; - stamp = get_native_tbl(); - if (__USE_RTC() && stamp < old_stamp) - old_stamp -= 1000000000; - elapsed += stamp - old_stamp; - sec = ppc_md.get_rtc_time(); - } while ( sec == old_sec && elapsed < 2*HZ*tb_ticks_per_jiffy); - if (sec==old_sec) - printk("Warning: real time clock seems stuck!\n"); - xtime.tv_sec = sec; - xtime.tv_nsec = 0; - /* No update now, we just read the time from the RTC ! */ - last_rtc_update = xtime.tv_sec; - } - last_jiffy_stamp(0) = tb_last_stamp = stamp; - - /* Not exact, but the timer interrupt takes care of this */ - set_dec(tb_ticks_per_jiffy); - - /* If platform provided a timezone (pmac), we correct the time */ - if (timezone_offset) { - sys_tz.tz_minuteswest = -timezone_offset / 60; - sys_tz.tz_dsttime = 0; - xtime.tv_sec -= timezone_offset; - } - set_normalized_timespec(&wall_to_monotonic, - -xtime.tv_sec, -xtime.tv_nsec); -} - -#define FEBRUARY 2 -#define STARTOFTIME 1970 -#define SECDAY 86400L -#define SECYR (SECDAY * 365) - -/* - * Note: this is wrong for 2100, but our signed 32-bit time_t will - * have overflowed long before that, so who cares. -- paulus - */ -#define leapyear(year) ((year) % 4 == 0) -#define days_in_year(a) (leapyear(a) ? 366 : 365) -#define days_in_month(a) (month_days[(a) - 1]) - -static int month_days[12] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 -}; - -void to_tm(int tim, struct rtc_time * tm) -{ - register int i; - register long hms, day, gday; - - gday = day = tim / SECDAY; - hms = tim % SECDAY; - - /* Hours, minutes, seconds are easy */ - tm->tm_hour = hms / 3600; - tm->tm_min = (hms % 3600) / 60; - tm->tm_sec = (hms % 3600) % 60; - - /* Number of years in days */ - for (i = STARTOFTIME; day >= days_in_year(i); i++) - day -= days_in_year(i); - tm->tm_year = i; - - /* Number of months in days left */ - if (leapyear(tm->tm_year)) - days_in_month(FEBRUARY) = 29; - for (i = 1; day >= days_in_month(i); i++) - day -= days_in_month(i); - days_in_month(FEBRUARY) = 28; - tm->tm_mon = i; - - /* Days are what is left over (+1) from all that. */ - tm->tm_mday = day + 1; - - /* - * Determine the day of week. Jan. 1, 1970 was a Thursday. - */ - tm->tm_wday = (gday + 4) % 7; -} - -/* Auxiliary function to compute scaling factors */ -/* Actually the choice of a timebase running at 1/4 the of the bus - * frequency giving resolution of a few tens of nanoseconds is quite nice. - * It makes this computation very precise (27-28 bits typically) which - * is optimistic considering the stability of most processor clock - * oscillators and the precision with which the timebase frequency - * is measured but does not harm. - */ -unsigned mulhwu_scale_factor(unsigned inscale, unsigned outscale) { - unsigned mlt=0, tmp, err; - /* No concern for performance, it's done once: use a stupid - * but safe and compact method to find the multiplier. - */ - for (tmp = 1U<<31; tmp != 0; tmp >>= 1) { - if (mulhwu(inscale, mlt|tmp) < outscale) mlt|=tmp; - } - /* We might still be off by 1 for the best approximation. - * A side effect of this is that if outscale is too large - * the returned value will be zero. - * Many corner cases have been checked and seem to work, - * some might have been forgotten in the test however. - */ - err = inscale*(mlt+1); - if (err <= inscale/2) mlt++; - return mlt; -} - -unsigned long long sched_clock(void) -{ - unsigned long lo, hi, hi2; - unsigned long long tb; - - if (!__USE_RTC()) { - do { - hi = get_tbu(); - lo = get_tbl(); - hi2 = get_tbu(); - } while (hi2 != hi); - tb = ((unsigned long long) hi << 32) | lo; - tb = (tb * tb_to_ns_scale) >> 10; - } else { - do { - hi = get_rtcu(); - lo = get_rtcl(); - hi2 = get_rtcu(); - } while (hi2 != hi); - tb = ((unsigned long long) hi) * 1000000000 + lo; - } - return tb; -} diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c deleted file mode 100644 index a467a429c2f..00000000000 --- a/arch/ppc/kernel/traps.c +++ /dev/null @@ -1,826 +0,0 @@ -/* - * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Modified by Cort Dougan (cort@cs.nmt.edu) - * and Paul Mackerras (paulus@cs.anu.edu.au) - */ - -/* - * This file handles the architecture-dependent parts of hardware exceptions - */ - -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/user.h> -#include <linux/a.out.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/prctl.h> -#include <linux/bug.h> - -#include <asm/pgtable.h> -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/reg.h> -#include <asm/xmon.h> -#include <asm/pmc.h> - -#ifdef CONFIG_XMON -extern int xmon_bpt(struct pt_regs *regs); -extern int xmon_sstep(struct pt_regs *regs); -extern int xmon_iabr_match(struct pt_regs *regs); -extern int xmon_dabr_match(struct pt_regs *regs); - -int (*debugger)(struct pt_regs *regs) = xmon; -int (*debugger_bpt)(struct pt_regs *regs) = xmon_bpt; -int (*debugger_sstep)(struct pt_regs *regs) = xmon_sstep; -int (*debugger_iabr_match)(struct pt_regs *regs) = xmon_iabr_match; -int (*debugger_dabr_match)(struct pt_regs *regs) = xmon_dabr_match; -void (*debugger_fault_handler)(struct pt_regs *regs); -#else -#ifdef CONFIG_KGDB -int (*debugger)(struct pt_regs *regs); -int (*debugger_bpt)(struct pt_regs *regs); -int (*debugger_sstep)(struct pt_regs *regs); -int (*debugger_iabr_match)(struct pt_regs *regs); -int (*debugger_dabr_match)(struct pt_regs *regs); -void (*debugger_fault_handler)(struct pt_regs *regs); -#else -#define debugger(regs) do { } while (0) -#define debugger_bpt(regs) 0 -#define debugger_sstep(regs) 0 -#define debugger_iabr_match(regs) 0 -#define debugger_dabr_match(regs) 0 -#define debugger_fault_handler ((void (*)(struct pt_regs *))0) -#endif -#endif - -/* - * Trap & Exception support - */ - -DEFINE_SPINLOCK(die_lock); - -int die(const char * str, struct pt_regs * fp, long err) -{ - static int die_counter; - int nl = 0; - console_verbose(); - spin_lock_irq(&die_lock); - printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); -#ifdef CONFIG_PREEMPT - printk("PREEMPT "); - nl = 1; -#endif -#ifdef CONFIG_SMP - printk("SMP NR_CPUS=%d ", NR_CPUS); - nl = 1; -#endif - if (nl) - printk("\n"); - show_regs(fp); - add_taint(TAINT_DIE); - spin_unlock_irq(&die_lock); - /* do_exit() should take care of panic'ing from an interrupt - * context so we don't handle it here - */ - do_exit(err); -} - -void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) -{ - siginfo_t info; - - if (!user_mode(regs)) { - debugger(regs); - die("Exception in kernel mode", regs, signr); - } - info.si_signo = signr; - info.si_errno = 0; - info.si_code = code; - info.si_addr = (void __user *) addr; - force_sig_info(signr, &info, current); - - /* - * Init gets no signals that it doesn't have a handler for. - * That's all very well, but if it has caused a synchronous - * exception and we ignore the resulting signal, it will just - * generate the same exception over and over again and we get - * nowhere. Better to kill it and let the kernel panic. - */ - if (is_global_init(current)) { - __sighandler_t handler; - - spin_lock_irq(¤t->sighand->siglock); - handler = current->sighand->action[signr-1].sa.sa_handler; - spin_unlock_irq(¤t->sighand->siglock); - if (handler == SIG_DFL) { - /* init has generated a synchronous exception - and it doesn't have a handler for the signal */ - printk(KERN_CRIT "init has generated signal %d " - "but has no handler for it\n", signr); - do_exit(signr); - } - } -} - -/* - * I/O accesses can cause machine checks on powermacs. - * Check if the NIP corresponds to the address of a sync - * instruction for which there is an entry in the exception - * table. - * Note that the 601 only takes a machine check on TEA - * (transfer error ack) signal assertion, and does not - * set any of the top 16 bits of SRR1. - * -- paulus. - */ -static inline int check_io_access(struct pt_regs *regs) -{ -#if defined CONFIG_8xx - unsigned long msr = regs->msr; - const struct exception_table_entry *entry; - unsigned int *nip = (unsigned int *)regs->nip; - - if (((msr & 0xffff0000) == 0 || (msr & (0x80000 | 0x40000))) - && (entry = search_exception_tables(regs->nip)) != NULL) { - /* - * Check that it's a sync instruction, or somewhere - * in the twi; isync; nop sequence that inb/inw/inl uses. - * As the address is in the exception table - * we should be able to read the instr there. - * For the debug message, we look at the preceding - * load or store. - */ - if (*nip == 0x60000000) /* nop */ - nip -= 2; - else if (*nip == 0x4c00012c) /* isync */ - --nip; - /* eieio from I/O string functions */ - else if ((*nip) == 0x7c0006ac || *(nip+1) == 0x7c0006ac) - nip += 2; - if (*nip == 0x7c0004ac || (*nip >> 26) == 3 || - (*(nip+1) >> 26) == 3) { - /* sync or twi */ - unsigned int rb; - - --nip; - rb = (*nip >> 11) & 0x1f; - printk(KERN_DEBUG "%s bad port %lx at %p\n", - (*nip & 0x100)? "OUT to": "IN from", - regs->gpr[rb] - _IO_BASE, nip); - regs->msr |= MSR_RI; - regs->nip = entry->fixup; - return 1; - } - } -#endif /* CONFIG_8xx */ - return 0; -} - -#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) -/* On 4xx, the reason for the machine check or program exception - is in the ESR. */ -#define get_reason(regs) ((regs)->dsisr) -#define get_mc_reason(regs) ((regs)->dsisr) -#define REASON_FP ESR_FP -#define REASON_ILLEGAL (ESR_PIL | ESR_PUO) -#define REASON_PRIVILEGED ESR_PPR -#define REASON_TRAP ESR_PTR - -/* single-step stuff */ -#define single_stepping(regs) (current->thread.dbcr0 & DBCR0_IC) -#define clear_single_step(regs) (current->thread.dbcr0 &= ~DBCR0_IC) - -#else -/* On non-4xx, the reason for the machine check or program - exception is in the MSR. */ -#define get_reason(regs) ((regs)->msr) -#define get_mc_reason(regs) ((regs)->msr) -#define REASON_FP 0x100000 -#define REASON_ILLEGAL 0x80000 -#define REASON_PRIVILEGED 0x40000 -#define REASON_TRAP 0x20000 - -#define single_stepping(regs) ((regs)->msr & MSR_SE) -#define clear_single_step(regs) ((regs)->msr &= ~MSR_SE) -#endif - -/* - * This is "fall-back" implementation for configurations - * which don't provide platform-specific machine check info - */ -void __attribute__ ((weak)) -platform_machine_check(struct pt_regs *regs) -{ -} - -#if defined(CONFIG_4xx) -int machine_check_4xx(struct pt_regs *regs) -{ - unsigned long reason = get_mc_reason(regs); - - if (reason & ESR_IMCP) { - printk("Instruction"); - mtspr(SPRN_ESR, reason & ~ESR_IMCP); - } else - printk("Data"); - printk(" machine check in kernel mode.\n"); - - return 0; -} - -int machine_check_440A(struct pt_regs *regs) -{ - unsigned long reason = get_mc_reason(regs); - - printk("Machine check in kernel mode.\n"); - if (reason & ESR_IMCP){ - printk("Instruction Synchronous Machine Check exception\n"); - mtspr(SPRN_ESR, reason & ~ESR_IMCP); - } - else { - u32 mcsr = mfspr(SPRN_MCSR); - if (mcsr & MCSR_IB) - printk("Instruction Read PLB Error\n"); - if (mcsr & MCSR_DRB) - printk("Data Read PLB Error\n"); - if (mcsr & MCSR_DWB) - printk("Data Write PLB Error\n"); - if (mcsr & MCSR_TLBP) - printk("TLB Parity Error\n"); - if (mcsr & MCSR_ICP){ - flush_instruction_cache(); - printk("I-Cache Parity Error\n"); - } - if (mcsr & MCSR_DCSP) - printk("D-Cache Search Parity Error\n"); - if (mcsr & MCSR_DCFP) - printk("D-Cache Flush Parity Error\n"); - if (mcsr & MCSR_IMPE) - printk("Machine Check exception is imprecise\n"); - - /* Clear MCSR */ - mtspr(SPRN_MCSR, mcsr); - } - return 0; -} -#else -int machine_check_generic(struct pt_regs *regs) -{ - unsigned long reason = get_mc_reason(regs); - - printk("Machine check in kernel mode.\n"); - printk("Caused by (from SRR1=%lx): ", reason); - switch (reason & 0x601F0000) { - case 0x80000: - printk("Machine check signal\n"); - break; - case 0: /* for 601 */ - case 0x40000: - case 0x140000: /* 7450 MSS error and TEA */ - printk("Transfer error ack signal\n"); - break; - case 0x20000: - printk("Data parity error signal\n"); - break; - case 0x10000: - printk("Address parity error signal\n"); - break; - case 0x20000000: - printk("L1 Data Cache error\n"); - break; - case 0x40000000: - printk("L1 Instruction Cache error\n"); - break; - case 0x00100000: - printk("L2 data cache parity error\n"); - break; - default: - printk("Unknown values in msr\n"); - } - return 0; -} -#endif /* everything else */ - -void machine_check_exception(struct pt_regs *regs) -{ - int recover = 0; - - if (cur_cpu_spec->machine_check) - recover = cur_cpu_spec->machine_check(regs); - if (recover > 0) - return; - - if (user_mode(regs)) { - regs->msr |= MSR_RI; - _exception(SIGBUS, regs, BUS_ADRERR, regs->nip); - return; - } - -#if defined(CONFIG_8xx) && defined(CONFIG_PCI) - /* the qspan pci read routines can cause machine checks -- Cort */ - bad_page_fault(regs, regs->dar, SIGBUS); - return; -#endif - - if (debugger_fault_handler) { - debugger_fault_handler(regs); - regs->msr |= MSR_RI; - return; - } - - if (check_io_access(regs)) - return; - - /* - * Optional platform-provided routine to print out - * additional info, e.g. bus error registers. - */ - platform_machine_check(regs); - - debugger(regs); - die("machine check", regs, SIGBUS); -} - -void SMIException(struct pt_regs *regs) -{ - debugger(regs); -#if !(defined(CONFIG_XMON) || defined(CONFIG_KGDB)) - show_regs(regs); - panic("System Management Interrupt"); -#endif -} - -void unknown_exception(struct pt_regs *regs) -{ - printk("Bad trap at PC: %lx, MSR: %lx, vector=%lx %s\n", - regs->nip, regs->msr, regs->trap, print_tainted()); - _exception(SIGTRAP, regs, 0, 0); -} - -void instruction_breakpoint_exception(struct pt_regs *regs) -{ - if (debugger_iabr_match(regs)) - return; - _exception(SIGTRAP, regs, TRAP_BRKPT, 0); -} - -void RunModeException(struct pt_regs *regs) -{ - _exception(SIGTRAP, regs, 0, 0); -} - -/* Illegal instruction emulation support. Originally written to - * provide the PVR to user applications using the mfspr rd, PVR. - * Return non-zero if we can't emulate, or -EFAULT if the associated - * memory access caused an access fault. Return zero on success. - * - * There are a couple of ways to do this, either "decode" the instruction - * or directly match lots of bits. In this case, matching lots of - * bits is faster and easier. - * - */ -#define INST_MFSPR_PVR 0x7c1f42a6 -#define INST_MFSPR_PVR_MASK 0xfc1fffff - -#define INST_DCBA 0x7c0005ec -#define INST_DCBA_MASK 0x7c0007fe - -#define INST_MCRXR 0x7c000400 -#define INST_MCRXR_MASK 0x7c0007fe - -#define INST_STRING 0x7c00042a -#define INST_STRING_MASK 0x7c0007fe -#define INST_STRING_GEN_MASK 0x7c00067e -#define INST_LSWI 0x7c0004aa -#define INST_LSWX 0x7c00042a -#define INST_STSWI 0x7c0005aa -#define INST_STSWX 0x7c00052a - -static int emulate_string_inst(struct pt_regs *regs, u32 instword) -{ - u8 rT = (instword >> 21) & 0x1f; - u8 rA = (instword >> 16) & 0x1f; - u8 NB_RB = (instword >> 11) & 0x1f; - u32 num_bytes; - unsigned long EA; - int pos = 0; - - /* Early out if we are an invalid form of lswx */ - if ((instword & INST_STRING_MASK) == INST_LSWX) - if ((rT == rA) || (rT == NB_RB)) - return -EINVAL; - - EA = (rA == 0) ? 0 : regs->gpr[rA]; - - switch (instword & INST_STRING_MASK) { - case INST_LSWX: - case INST_STSWX: - EA += NB_RB; - num_bytes = regs->xer & 0x7f; - break; - case INST_LSWI: - case INST_STSWI: - num_bytes = (NB_RB == 0) ? 32 : NB_RB; - break; - default: - return -EINVAL; - } - - while (num_bytes != 0) - { - u8 val; - u32 shift = 8 * (3 - (pos & 0x3)); - - switch ((instword & INST_STRING_MASK)) { - case INST_LSWX: - case INST_LSWI: - if (get_user(val, (u8 __user *)EA)) - return -EFAULT; - /* first time updating this reg, - * zero it out */ - if (pos == 0) - regs->gpr[rT] = 0; - regs->gpr[rT] |= val << shift; - break; - case INST_STSWI: - case INST_STSWX: - val = regs->gpr[rT] >> shift; - if (put_user(val, (u8 __user *)EA)) - return -EFAULT; - break; - } - /* move EA to next address */ - EA += 1; - num_bytes--; - - /* manage our position within the register */ - if (++pos == 4) { - pos = 0; - if (++rT == 32) - rT = 0; - } - } - - return 0; -} - -static int emulate_instruction(struct pt_regs *regs) -{ - u32 instword; - u32 rd; - - if (!user_mode(regs)) - return -EINVAL; - CHECK_FULL_REGS(regs); - - if (get_user(instword, (u32 __user *)(regs->nip))) - return -EFAULT; - - /* Emulate the mfspr rD, PVR. - */ - if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) { - rd = (instword >> 21) & 0x1f; - regs->gpr[rd] = mfspr(SPRN_PVR); - return 0; - } - - /* Emulating the dcba insn is just a no-op. */ - if ((instword & INST_DCBA_MASK) == INST_DCBA) - return 0; - - /* Emulate the mcrxr insn. */ - if ((instword & INST_MCRXR_MASK) == INST_MCRXR) { - int shift = (instword >> 21) & 0x1c; - unsigned long msk = 0xf0000000UL >> shift; - - regs->ccr = (regs->ccr & ~msk) | ((regs->xer >> shift) & msk); - regs->xer &= ~0xf0000000UL; - return 0; - } - - /* Emulate load/store string insn. */ - if ((instword & INST_STRING_GEN_MASK) == INST_STRING) - return emulate_string_inst(regs, instword); - - return -EINVAL; -} - -/* - * After we have successfully emulated an instruction, we have to - * check if the instruction was being single-stepped, and if so, - * pretend we got a single-step exception. This was pointed out - * by Kumar Gala. -- paulus - */ -static void emulate_single_step(struct pt_regs *regs) -{ - if (single_stepping(regs)) { - clear_single_step(regs); - _exception(SIGTRAP, regs, TRAP_TRACE, 0); - } -} - -int is_valid_bugaddr(unsigned long addr) -{ - return addr >= PAGE_OFFSET; -} - -void program_check_exception(struct pt_regs *regs) -{ - unsigned int reason = get_reason(regs); - extern int do_mathemu(struct pt_regs *regs); - -#ifdef CONFIG_MATH_EMULATION - /* (reason & REASON_ILLEGAL) would be the obvious thing here, - * but there seems to be a hardware bug on the 405GP (RevD) - * that means ESR is sometimes set incorrectly - either to - * ESR_DST (!?) or 0. In the process of chasing this with the - * hardware people - not sure if it can happen on any illegal - * instruction or only on FP instructions, whether there is a - * pattern to occurrences etc. -dgibson 31/Mar/2003 */ - if (!(reason & REASON_TRAP) && do_mathemu(regs) == 0) { - emulate_single_step(regs); - return; - } -#endif /* CONFIG_MATH_EMULATION */ - - if (reason & REASON_FP) { - /* IEEE FP exception */ - int code = 0; - u32 fpscr; - - /* We must make sure the FP state is consistent with - * our MSR_FP in regs - */ - preempt_disable(); - if (regs->msr & MSR_FP) - giveup_fpu(current); - preempt_enable(); - - fpscr = current->thread.fpscr.val; - fpscr &= fpscr << 22; /* mask summary bits with enables */ - if (fpscr & FPSCR_VX) - code = FPE_FLTINV; - else if (fpscr & FPSCR_OX) - code = FPE_FLTOVF; - else if (fpscr & FPSCR_UX) - code = FPE_FLTUND; - else if (fpscr & FPSCR_ZX) - code = FPE_FLTDIV; - else if (fpscr & FPSCR_XX) - code = FPE_FLTRES; - _exception(SIGFPE, regs, code, regs->nip); - return; - } - - if (reason & REASON_TRAP) { - /* trap exception */ - if (debugger_bpt(regs)) - return; - - if (!(regs->msr & MSR_PR) && /* not user-mode */ - report_bug(regs->nip, regs) == BUG_TRAP_TYPE_WARN) { - regs->nip += 4; - return; - } - _exception(SIGTRAP, regs, TRAP_BRKPT, 0); - return; - } - - /* Try to emulate it if we should. */ - if (reason & (REASON_ILLEGAL | REASON_PRIVILEGED)) { - switch (emulate_instruction(regs)) { - case 0: - regs->nip += 4; - emulate_single_step(regs); - return; - case -EFAULT: - _exception(SIGSEGV, regs, SEGV_MAPERR, regs->nip); - return; - } - } - - if (reason & REASON_PRIVILEGED) - _exception(SIGILL, regs, ILL_PRVOPC, regs->nip); - else - _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); -} - -void single_step_exception(struct pt_regs *regs) -{ - regs->msr &= ~(MSR_SE | MSR_BE); /* Turn off 'trace' bits */ - if (debugger_sstep(regs)) - return; - _exception(SIGTRAP, regs, TRAP_TRACE, 0); -} - -void alignment_exception(struct pt_regs *regs) -{ - int sig, code, fixed = 0; - - fixed = fix_alignment(regs); - if (fixed == 1) { - regs->nip += 4; /* skip over emulated instruction */ - emulate_single_step(regs); - return; - } - if (fixed == -EFAULT) { - sig = SIGSEGV; - code = SEGV_ACCERR; - } else { - sig = SIGBUS; - code = BUS_ADRALN; - } - if (user_mode(regs)) - _exception(sig, regs, code, regs->dar); - else - bad_page_fault(regs, regs->dar, sig); -} - -void StackOverflow(struct pt_regs *regs) -{ - printk(KERN_CRIT "Kernel stack overflow in process %p, r1=%lx\n", - current, regs->gpr[1]); - debugger(regs); - show_regs(regs); - panic("kernel stack overflow"); -} - -void nonrecoverable_exception(struct pt_regs *regs) -{ - printk(KERN_ERR "Non-recoverable exception at PC=%lx MSR=%lx\n", - regs->nip, regs->msr); - debugger(regs); - die("nonrecoverable exception", regs, SIGKILL); -} - -void trace_syscall(struct pt_regs *regs) -{ - printk("Task: %p(%d), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld %s\n", - current, current->pid, regs->nip, regs->link, regs->gpr[0], - regs->ccr&0x10000000?"Error=":"", regs->gpr[3], print_tainted()); -} - -#ifdef CONFIG_8xx -void SoftwareEmulation(struct pt_regs *regs) -{ - extern int do_mathemu(struct pt_regs *); - extern int Soft_emulate_8xx(struct pt_regs *); - int errcode; - - CHECK_FULL_REGS(regs); - - if (!user_mode(regs)) { - debugger(regs); - die("Kernel Mode Software FPU Emulation", regs, SIGFPE); - } - -#ifdef CONFIG_MATH_EMULATION - errcode = do_mathemu(regs); -#else - errcode = Soft_emulate_8xx(regs); -#endif - if (errcode) { - if (errcode > 0) - _exception(SIGFPE, regs, 0, 0); - else if (errcode == -EFAULT) - _exception(SIGSEGV, regs, 0, 0); - else - _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); - } else - emulate_single_step(regs); -} -#endif /* CONFIG_8xx */ - -#if defined(CONFIG_40x) || defined(CONFIG_BOOKE) - -void DebugException(struct pt_regs *regs, unsigned long debug_status) -{ - if (debug_status & DBSR_IC) { /* instruction completion */ - regs->msr &= ~MSR_DE; - if (user_mode(regs)) { - current->thread.dbcr0 &= ~DBCR0_IC; - } else { - /* Disable instruction completion */ - mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~DBCR0_IC); - /* Clear the instruction completion event */ - mtspr(SPRN_DBSR, DBSR_IC); - if (debugger_sstep(regs)) - return; - } - _exception(SIGTRAP, regs, TRAP_TRACE, 0); - } -} -#endif /* CONFIG_4xx || CONFIG_BOOKE */ - -#if !defined(CONFIG_TAU_INT) -void TAUException(struct pt_regs *regs) -{ - printk("TAU trap at PC: %lx, MSR: %lx, vector=%lx %s\n", - regs->nip, regs->msr, regs->trap, print_tainted()); -} -#endif /* CONFIG_INT_TAU */ - -/* - * FP unavailable trap from kernel - print a message, but let - * the task use FP in the kernel until it returns to user mode. - */ -void kernel_fp_unavailable_exception(struct pt_regs *regs) -{ - regs->msr |= MSR_FP; - printk(KERN_ERR "floating point used in kernel (task=%p, pc=%lx)\n", - current, regs->nip); -} - -void altivec_unavailable_exception(struct pt_regs *regs) -{ - static int kernel_altivec_count; - -#ifndef CONFIG_ALTIVEC - if (user_mode(regs)) { - /* A user program has executed an altivec instruction, - but this kernel doesn't support altivec. */ - _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); - return; - } -#endif - /* The kernel has executed an altivec instruction without - first enabling altivec. Whinge but let it do it. */ - if (++kernel_altivec_count < 10) - printk(KERN_ERR "AltiVec used in kernel (task=%p, pc=%lx)\n", - current, regs->nip); - regs->msr |= MSR_VEC; -} - -#ifdef CONFIG_ALTIVEC -void altivec_assist_exception(struct pt_regs *regs) -{ - int err; - - preempt_disable(); - if (regs->msr & MSR_VEC) - giveup_altivec(current); - preempt_enable(); - if (!user_mode(regs)) { - printk(KERN_ERR "altivec assist exception in kernel mode" - " at %lx\n", regs->nip); - debugger(regs); - die("altivec assist exception", regs, SIGFPE); - return; - } - - err = emulate_altivec(regs); - if (err == 0) { - regs->nip += 4; /* skip emulated instruction */ - emulate_single_step(regs); - return; - } - - if (err == -EFAULT) { - /* got an error reading the instruction */ - _exception(SIGSEGV, regs, SEGV_ACCERR, regs->nip); - } else { - /* didn't recognize the instruction */ - /* XXX quick hack for now: set the non-Java bit in the VSCR */ - printk(KERN_ERR "unrecognized altivec instruction " - "in %s at %lx\n", current->comm, regs->nip); - current->thread.vscr.u[3] |= 0x10000; - } -} -#endif /* CONFIG_ALTIVEC */ - -#ifdef CONFIG_BOOKE_WDT -/* - * Default handler for a Watchdog exception, - * spins until a reboot occurs - */ -void __attribute__ ((weak)) WatchdogHandler(struct pt_regs *regs) -{ - /* Generic WatchdogHandler, implement your own */ - mtspr(SPRN_TCR, mfspr(SPRN_TCR)&(~TCR_WIE)); - return; -} - -void WatchdogException(struct pt_regs *regs) -{ - printk (KERN_EMERG "PowerPC Book-E Watchdog Exception\n"); - WatchdogHandler(regs); -} -#endif - -void __init trap_init(void) -{ -} diff --git a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S deleted file mode 100644 index 8a24bc47eb6..00000000000 --- a/arch/ppc/kernel/vmlinux.lds.S +++ /dev/null @@ -1,164 +0,0 @@ -#include <asm-generic/vmlinux.lds.h> - -OUTPUT_ARCH(powerpc:common) -jiffies = jiffies_64 + 4; -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - . = + SIZEOF_HEADERS; - .interp : { *(.interp) } - .hash : { *(.hash) } - .gnu.hash : { *(.gnu.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .rel.text : { *(.rel.text) } - .rela.text : { *(.rela.text) } - .rel.data : { *(.rel.data) } - .rela.data : { *(.rela.data) } - .rel.rodata : { *(.rel.rodata) } - .rela.rodata : { *(.rela.rodata) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.bss : { *(.rel.bss) } - .rela.bss : { *(.rela.bss) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } -/* .init : { *(.init) } =0*/ - .plt : { *(.plt) } - .text : - { - _text = .; - TEXT_TEXT - SCHED_TEXT - LOCK_TEXT - *(.fixup) - *(.got1) - __got2_start = .; - *(.got2) - __got2_end = .; - } - _etext = .; - PROVIDE (etext = .); - - RODATA - .fini : { *(.fini) } =0 - .ctors : { *(.ctors) } - .dtors : { *(.dtors) } - - .fixup : { *(.fixup) } - - __ex_table : { - __start___ex_table = .; - *(__ex_table) - __stop___ex_table = .; - } - - __bug_table : { - __start___bug_table = .; - *(__bug_table) - __stop___bug_table = .; - } - - /* Read-write section, merged into data segment: */ - . = ALIGN(4096); - .data : - { - DATA_DATA - *(.data1) - *(.sdata) - *(.sdata2) - *(.got.plt) *(.got) - *(.dynamic) - CONSTRUCTORS - } - - . = ALIGN(4096); - __nosave_begin = .; - .data_nosave : { *(.data.nosave) } - . = ALIGN(4096); - __nosave_end = .; - - . = ALIGN(32); - .data.cacheline_aligned : { *(.data.cacheline_aligned) } - - _edata = .; - PROVIDE (edata = .); - - . = ALIGN(8192); - .data.init_task : { *(.data.init_task) } - - NOTES - - . = ALIGN(4096); - __init_begin = .; - .init.text : { - _sinittext = .; - INIT_TEXT - _einittext = .; - } - /* .exit.text is discarded at runtime, not link time, - to deal with references from __bug_table */ - .exit.text : { EXIT_TEXT } - .init.data : { - INIT_DATA - __vtop_table_begin = .; - *(.vtop_fixup); - __vtop_table_end = .; - __ptov_table_begin = .; - *(.ptov_fixup); - __ptov_table_end = .; - } - . = ALIGN(16); - __setup_start = .; - .init.setup : { *(.init.setup) } - __setup_end = .; - __initcall_start = .; - .initcall.init : { - INITCALLS - } - __initcall_end = .; - - __con_initcall_start = .; - .con_initcall.init : { *(.con_initcall.init) } - __con_initcall_end = .; - - SECURITY_INIT - - __start___ftr_fixup = .; - __ftr_fixup : { *(__ftr_fixup) } - __stop___ftr_fixup = .; - - PERCPU(4096) - -#ifdef CONFIG_BLK_DEV_INITRD - . = ALIGN(4096); - __initramfs_start = .; - .init.ramfs : { *(.init.ramfs) } - __initramfs_end = .; -#endif - - . = ALIGN(4096); - __init_end = .; - __bss_start = .; - .bss : - { - *(.sbss) *(.scommon) - *(.dynbss) - *(.bss) - *(COMMON) - } - __bss_stop = .; - - _end = . ; - PROVIDE (end = .); - - /* Sections to be discarded. */ - /DISCARD/ : { - *(.exitcall.exit) - EXIT_DATA - } -} |