summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel/head_4xx.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/kernel/head_4xx.S')
-rw-r--r--arch/ppc/kernel/head_4xx.S600
1 files changed, 600 insertions, 0 deletions
diff --git a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S
new file mode 100644
index 000000000..abc651218
--- /dev/null
+++ b/arch/ppc/kernel/head_4xx.S
@@ -0,0 +1,600 @@
+/*
+ * 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.
+ *
+ * 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 <linux/config.h>
+
+#include <asm/processor.h>
+#include <asm/4xx.h>
+#include <asm/403gcx.h>
+#include <asm/405gp.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+
+#include "ppc_asm.h"
+
+
+/* Preprocessor Defines */
+
+#define STND_EXC 0
+#define CRIT_EXC 1
+
+###
+### Check to make sure the right processor has been defined.
+###
+
+#if !defined(CONFIG_4xx)
+#error "This file is only appropriate for kernels supporting the PPC4xx."
+#endif
+
+###
+### Execution entry point.
+###
+
+###
+### As with the other PowerPC ports, it is expected that when code
+### execution begins here, the following registers contain valid, yet
+### optional, information:
+###
+### r3 - ???
+### 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
+###
+
+ .text
+_GLOBAL(_stext)
+_GLOBAL(_start)
+ ## Save residual data, init RAM disk, and command line parameters
+
+ mr r31,r3
+ mr r30,r4
+ mr r29,r5
+ mr r28,r6
+ mr r27,r7
+
+ ## Set the ID for this CPU
+
+ li r24,0
+
+ ## Establish exception vector base
+
+ lis r0,KERNELBASE@h
+ mtspr SPRN_EVPR,r0
+
+ ## Jump to the main PowerPC kernel start-up code
+
+1: lis r7,start_here@ha
+ addi r7,r7,start_here@l
+ mtlr r7
+ blr
+
+###
+### 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.
+###
+
+ ## Common exception code for all exception types.
+
+#define COMMON_PROLOG \
+0: mtspr SPRN_SPRG0,r20; /* We need r20, move it to SPRG0 */\
+ mtspr SPRN_SPRG1,r21; /* We need r21, move it to SPRG1 */\
+ mfcr r20; /* We need the CR, move it to r20 */\
+ mfspr r21,SPRN_SPRG2; /* Exception stack to use */\
+ cmpwi cr0,r21,0; /* From user mode or RTAS? */\
+ bne 1f; /* Not RTAS, branch */\
+ tophys(r21, r1); /* Convert vka in r1 to pka in r21 */\
+ subi r21,r21,INT_FRAME_SIZE; /* Allocate an exception frame */\
+1: stw r20,_CCR(r21); /* Save CR on the stack */\
+ stw r22,GPR22(r21); /* Save r22 on the stack */\
+ stw r23,GPR23(r21); /* r23 Save on the stack */\
+ mfspr r20,SPRN_SPRG0; /* Get r20 back out of SPRG0 */\
+ stw r20,GPR20(r21); /* Save r20 on the stack */\
+ mfspr r22,SPRN_SPRG1; /* Get r21 back out of SPRG0 */\
+ stw r22,GPR21(r21); /* Save r21 on the stack */\
+ mflr r20; \
+ stw r20,_LINK(r21); /* Save LR on the stack */\
+ mfctr r22; \
+ stw r22,_CTR(r21); /* Save CTR on the stack */\
+ mfspr r20,XER; \
+ stw r20,_XER(r21); /* Save XER on the stack */
+
+#define COMMON_EPILOG \
+ stw r0,GPR0(r21); /* Save r0 on the stack */\
+ stw r1,GPR1(r21); /* Save r1 on the stack */\
+ stw r2,GPR2(r21); /* Save r2 on the stack */\
+ stw r1,0(r21); \
+ tovirt(r1,r21); /* Set-up new kernel stack pointer */\
+ SAVE_4GPRS(3, r21); /* Save r3 through r6 on the stack */
+
+ ## Common exception code for standard (non-critical) exceptions.
+
+#define STND_EXCEPTION_PROLOG \
+ COMMON_PROLOG; \
+ mfspr r22,SPRN_SRR0; /* Faulting instruction address */\
+ mfspr r23,SPRN_SRR1; /* MSR at the time of fault */\
+ COMMON_EPILOG;
+
+ ## Common exception code for critical exceptions.
+
+#define CRIT_EXCEPTION_PROLOG \
+ COMMON_PROLOG; \
+ mfspr r22,SPRN_SRR2; /* Faulting instruction address */\
+ mfspr r23,SPRN_SRR3; /* MSR at the time of fault */\
+ COMMON_EPILOG;
+
+###
+### Macros for specific exception types
+###
+
+#define START_EXCEPTION(n, label) \
+ . = n; \
+label:
+
+
+#define FINISH_EXCEPTION(func) \
+ bl transfer_to_handler; \
+ .long func; \
+ .long ret_from_except
+
+
+#define STND_EXCEPTION(n, label, func) \
+ START_EXCEPTION(n, label); \
+ STND_EXCEPTION_PROLOG; \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ li r0,STND_EXC; \
+ li r20,MSR_KERNEL; \
+ FINISH_EXCEPTION(func)
+
+
+#define CRIT_EXCEPTION(n, label, func) \
+ START_EXCEPTION(n, label); \
+ CRIT_EXCEPTION_PROLOG; \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ li r0,CRIT_EXC; \
+ li r20,MSR_KERNEL; \
+ FINISH_EXCEPTION(func)
+
+
+#define INTR_EXCEPTION(n, label, func) \
+ START_EXCEPTION(n, label); \
+ STND_EXCEPTION_PROLOG; \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ li r0,STND_EXC; \
+ li r20,MSR_KERNEL; \
+ li r4,0; \
+ bl transfer_to_handler; \
+_GLOBAL(do_IRQ_intercept); \
+ .long func; \
+ .long ret_from_except
+
+
+###
+### Exception vectors.
+###
+
+### 0x0100 - Critical Interrupt Exception
+
+ CRIT_EXCEPTION(0x0100, CriticalInterrupt, UnknownException)
+
+### 0x0200 - Machine Check Exception
+
+ CRIT_EXCEPTION(0x0200, MachineCheck, MachineCheckException)
+
+### 0x0300 - Data Storage Exception
+
+ START_EXCEPTION(0x0300, DataAccess)
+ STND_EXCEPTION_PROLOG
+ mfspr r5,SPRN_ESR # Grab the ESR, save it, pass as arg3
+ stw r5,_ESR(r21)
+ mfspr r4,SPRN_DEAR # Grab the DEAR, save it, pass as arg2
+ stw r4,_DEAR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r0,STND_EXC # This is a standard exception
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR
+ FINISH_EXCEPTION(do_page_fault) # do_page_fault(regs, ESR, DEAR)
+
+### 0x0400 - Instruction Storage Exception
+
+ START_EXCEPTION(0x0400, InstructionAccess)
+ STND_EXCEPTION_PROLOG
+ mr r4,r22 # Pass SRR0 as arg2
+ mr r5,r23 # Pass SRR1 as arg3
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r0,STND_EXC # This is a standard exception
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR
+ FINISH_EXCEPTION(do_page_fault) # do_page_fault(regs, SRR0, SRR1)
+
+### 0x0500 - External Interrupt Exception
+
+ INTR_EXCEPTION(0x0500, HardwareInterrupt, do_IRQ)
+
+### 0x0600 - Alignment Exception
+
+ START_EXCEPTION(0x0600, Alignment)
+ STND_EXCEPTION_PROLOG
+ mfspr r4,SPRN_DEAR # Grab the DEAR and save it
+ stw r4,_DEAR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r0,STND_EXC # This is a standard exception
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR
+ FINISH_EXCEPTION(AlignmentException)
+
+### 0x0700 - Program Exception
+
+ START_EXCEPTION(0x0700, ProgramCheck)
+ STND_EXCEPTION_PROLOG
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r0,STND_EXC # This is a standard exception
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR
+ FINISH_EXCEPTION(ProgramCheckException)
+
+ STND_EXCEPTION(0x0800, Trap_08, UnknownException)
+ STND_EXCEPTION(0x0900, Trap_09, UnknownException)
+ STND_EXCEPTION(0x0A00, Trap_0A, UnknownException)
+ STND_EXCEPTION(0x0B00, Trap_0B, UnknownException)
+### 0x0C00 - System Call Exception
+
+ START_EXCEPTION(0x0C00, SystemCall)
+ STND_EXCEPTION_PROLOG
+ stw r3,ORIG_GPR3(r21)
+ li r0,STND_EXC # This is a standard exception
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 # Copy EE bit from the saved MSR
+ FINISH_EXCEPTION(DoSyscall)
+
+ STND_EXCEPTION(0x0D00, Trap_0D, UnknownException)
+ STND_EXCEPTION(0x0E00, Trap_0E, UnknownException)
+ STND_EXCEPTION(0x0F00, Trap_0F, UnknownException)
+
+#if 0
+### 0x1000 - Programmable Interval Timer (PIT) Exception
+
+ STND_EXCEPTION(0x1000, PITException, UnknownException)
+
+### 0x1010 - Fixed Interval Timer (FIT) Exception
+
+ STND_EXCEPTION(0x1010, FITException, UnknownException)
+
+### 0x1020 - Watchdog Timer (WDT) Exception
+
+ CRIT_EXCEPTION(0x1020, WDTException, UnknownException)
+#endif
+
+### 0x1100 - Data TLB Miss Exception
+
+ START_EXCEPTION(0x1100, DTLBMiss)
+ STND_EXCEPTION_PROLOG
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r0,STND_EXC
+ li r20,MSR_KERNEL
+ FINISH_EXCEPTION(UnknownException)
+
+### 0x1200 - Instruction TLB Miss Exception
+
+ START_EXCEPTION(0x1200, ITLBMiss)
+ STND_EXCEPTION_PROLOG
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r0,STND_EXC
+ li r20,MSR_KERNEL
+ FINISH_EXCEPTION(UnknownException)
+
+ STND_EXCEPTION(0x1300, Trap_13, UnknownException)
+ STND_EXCEPTION(0x1400, Trap_14, UnknownException)
+ STND_EXCEPTION(0x1500, Trap_15, UnknownException)
+ STND_EXCEPTION(0x1600, Trap_16, UnknownException)
+ STND_EXCEPTION(0x1700, Trap_17, UnknownException)
+ STND_EXCEPTION(0x1800, Trap_18, UnknownException)
+ STND_EXCEPTION(0x1900, Trap_19, UnknownException)
+ STND_EXCEPTION(0x1A00, Trap_1A, UnknownException)
+ STND_EXCEPTION(0x1B00, Trap_1B, UnknownException)
+ STND_EXCEPTION(0x1C00, Trap_1C, UnknownException)
+ STND_EXCEPTION(0x1D00, Trap_1D, UnknownException)
+ STND_EXCEPTION(0x1E00, Trap_1E, UnknownException)
+ STND_EXCEPTION(0x1F00, Trap_1F, UnknownException)
+
+### 0x2000 - Debug Exception
+
+ CRIT_EXCEPTION(0x2000, DebugTrap, UnknownException)
+
+###
+### 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.
+###
+
+###
+### This code finishes saving the registers to the exception frame
+### and jumps to the appropriate handler for the exception, turning
+### on address translation.
+###
+
+_GLOBAL(transfer_to_handler)
+ stw r22,_NIP(r21) # Save the faulting IP on the stack
+ stw r23,_MSR(r21) # Save the exception MSR on the stack
+ SAVE_GPR(7, r21) # Save r7 on the stack
+ SAVE_4GPRS(8, r21) # Save r8 through r11 on the stack
+ SAVE_8GPRS(12, r21) # Save r12 through r19 on the stack
+ SAVE_8GPRS(24, r21) # Save r24 through r31 on the stack
+ andi. r23,r23,MSR_PR # Is this from user space?
+ mfspr r23,SPRN_SPRG3 # If from user, fix up THREAD.regs
+ beq 2f # No, it is from the kernel; branch.
+ addi r24,r1,STACK_FRAME_OVERHEAD
+ stw r24,PT_REGS(r23) #
+2: addi r2,r23,-THREAD # Set r2 to current thread
+ tovirt(r2,r2)
+ mflr r23
+ andi. r24,r23,0x3f00 # Get vector offset
+ stw r24,TRAP(r21)
+ li r22,RESULT
+ stwcx. r22,r22,r21 # Clear the reservation
+ li r22,0
+ stw r22,RESULT(r21)
+ mtspr SPRN_SPRG2,r22 # r1 is now the kernel stack pointer
+ addi r24,r2,TASK_STRUCT_SIZE # Check for kernel stack overflow
+ cmplw cr0,r1,r2
+ cmplw cr1,r1,r24
+ crand cr1,cr1,cr4
+ bgt- stack_ovf # If r2 < r1 < r2 + TASK_STRUCT_SIZE
+ lwz r24,0(r23) # Virtual address of the handler
+ lwz r23,4(r23) # Handler return pointer
+ cmpwi cr0,r0,STND_EXC # What type of exception is this?
+ bne 3f # It is a critical exception...
+
+ ## Standard exception jump path
+
+ mtspr SPRN_SRR0,r24 # Set up the instruction pointer
+ mtspr SPRN_SRR1,r20 # Set up the machine state register
+ mtlr r23 # Set up the return pointer
+ SYNC
+ rfi # Enable the MMU, jump to the handler
+
+ ## Critical exception jump path
+
+3: mtspr SPRN_SRR2,r24 # Set up the instruction pointer
+ mtspr SPRN_SRR3,r20 # Set up the machine state register
+ mtlr r23 # Set up the return pointer
+ SYNC
+ rfci # Enable the MMU, jump to the handler
+
+###
+### On kernel stack overlow, load up an initial stack pointer and call
+### StackOverflow(regs), which should NOT return.
+###
+
+stack_ovf:
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ lis r1,init_task_union@ha
+ addi r1,r1,init_task_union@l
+ addi r1,r1,TASK_UNION_SIZE - STACK_FRAME_OVERHEAD
+ lis r24,StackOverflow@ha
+ addi r24,r24,StackOverflow@l
+ li r20,MSR_KERNEL
+ mtspr SPRN_SRR0,r24 # Set up the instruction pointer
+ mtspr SPRN_SRR1,r20 # Set up the machine state register
+ SYNC
+ rfi # Enable the MMU, jump to StackOverflow
+
+###
+### extern void giveup_altivec(struct task_struct *prev)
+###
+### The PowerPC 4xx family of processors do not have AltiVec capabilities, so
+### this just returns.
+###
+
+_GLOBAL(giveup_altivec)
+ blr
+
+###
+### 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
+
+###
+### extern void abort(void)
+###
+### At present, this routine just applies a system reset.
+###
+
+_GLOBAL(abort)
+ mfspr r13,SPRN_DBCR
+ ori r13,r13,DBCR_RST(SYSTEM)@h
+ mtspr SPRN_DBCR,r13
+
+
+###
+### This code is jumped-to from the startup code. It copies the kernel
+### image from wherever it happens to be currently running at in physical
+### address space to physical address 0.
+###
+### In general, for a running Linux/PPC system:
+### Kernel Physical Address (KPA) = 0x00000000
+### Kernel Virtual Address (KVA) = 0xC0000000
+###
+
+#if 0
+relocate_kernel:
+ lis r9,0x426f /* if booted from BootX, don't */
+ addi r9,r9,0x6f58 /* translate source addr */
+ cmpw r31,r9 /* (we have to on chrp) */
+ beq 7f
+ rlwinm r4,r4,0,8,31 /* translate source address */
+ add r4,r4,r3 /* to region mapped with BATs */
+7: addis r9,r26,klimit@ha /* fetch klimit */
+ lwz r25,klimit@l(r9)
+ addis r25,r25,-KERNELBASE@h
+ 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,8
+ 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
+ isync
+ addi r5,r5,4
+ addi r6,r6,4
+ blr
+#endif
+
+###
+### This is where the main kernel code starts.
+###
+
+start_here:
+ ## Establish a pointer to the current task
+
+ lis r2,init_task_union@h
+ ori r2,r2,init_task_union@l
+
+ ## Clear out the BSS as per ANSI C requirements
+
+ lis r7,_end@ha
+ addi r7,r7,_end@l
+ lis r8,__bss_start@ha
+ addi r8,r8,__bss_start@l
+ subf r7,r8,r7
+ addi r7,r7,3
+ srwi. r7,r7,2
+ beq 2f
+ addi r8,r8,-4
+ mtctr r7
+ li r0,0
+3: stwu r0,4(r8)
+ bdnz 3b
+
+ ## Stack
+
+2: addi r1,r2,TASK_UNION_SIZE
+ li r0,0
+ stwu r0,-STACK_FRAME_OVERHEAD(r1)
+
+ ## Determine what type of platform this is.
+
+ mr r3,r31
+ mr r4,r30
+ mr r5,r29
+ mr r6,r28
+ mr r7,r27
+ bl identify_machine
+
+ ## Initialize the memory management unit.
+
+ bl MMU_init
+
+ ## Go back to running unmapped so that we can change to our
+ ## exception vectors.
+
+ lis r4,2f@h
+ ori r4,r4,2f@l
+ tophys(r4,r4)
+ li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
+ mtspr SPRN_SRR0,r4 # Set up the instruction pointer
+ mtspr SPRN_SRR1,r3 # Set up the machine state register
+ rfi
+
+ ## Load up the kernel context
+
+2: SYNC # Force all PTE updates to finish
+# tlbia # Clear all TLB entries
+# sync # Wait for tlbia to finish...
+
+ ## Set up for using our exception vectors
+
+ tophys(r4,r2) # Pointer to physical current thread
+ addi r4,r4,THREAD # The init task thread
+ mtspr SPRN_SPRG3,r4 # Save it for exceptions later
+ li r3,0 #
+ mtspr SPRN_SPRG2,r3 # 0 implies r1 has kernel stack pointer
+
+ ## Really turn on the MMU and jump into the kernel
+
+ 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 # Set up the instruction pointer
+ mtspr SPRN_SRR1,r4 # Set up the machine state register
+ rfi # Enable the MMU, jump to the kernel
+
+_GLOBAL(set_context)
+ mtspr SPRN_PID,r3
+ tlbia
+ SYNC
+ 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
+_GLOBAL(sdata)
+_GLOBAL(empty_zero_page)
+ .space 4096
+_GLOBAL(swapper_pg_dir)
+ .space 4096
+
+###
+### 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.
+###
+
+_GLOBAL(cmd_line)
+ .space 512