summaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel/head.S
diff options
context:
space:
mode:
authorMiguel de Icaza <miguel@nuclecu.unam.mx>1997-08-06 19:14:48 +0000
committerMiguel de Icaza <miguel@nuclecu.unam.mx>1997-08-06 19:14:48 +0000
commite2819e52a162873ff5061de81bb749831bdb5de9 (patch)
tree6067ea700202750ba335a423696f2972700e5f76 /arch/ppc/kernel/head.S
parent17a005074429bbf143e40401f405ae4363e56828 (diff)
Merge to 2.1.38.
IMPORTANT NOTE: I could not figure out what information is the one that should be used for the following files (ie, those that were in our tree, or those that came from Linus' patch), please, check these: include/asm-mips/jazz.h include/asm-mips/jazzdma.h include/asm-mips/ioctls.h
Diffstat (limited to 'arch/ppc/kernel/head.S')
-rw-r--r--arch/ppc/kernel/head.S2866
1 files changed, 1559 insertions, 1307 deletions
diff --git a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
index 648c7bccf..25f2dd8a0 100644
--- a/arch/ppc/kernel/head.S
+++ b/arch/ppc/kernel/head.S
@@ -1,1077 +1,422 @@
-#include "ppc_asm.tmpl"
-#include "ppc_defs.h"
-#include <linux/errno.h>
-#include <linux/sys.h>
-#include <asm/ppc_machine.h>
-
-#define NEWMM 1
-#define SYNC() \
- isync; \
- sync
-
-#define STATS
/*
- * Increment a [64 bit] statistic counter
- * Uses R2, R3
+ * arch/ppc/kernel/head.S
+ *
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP
+ * Adapted for Power Macintosh by Paul Mackerras.
+ * Low-level exception handlers and MMU support
+ * rewritten by Paul Mackerras.
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * This file contains the low-level support and setup for the
+ * PowerPC platform, including trap and interrupt dispatch.
+ * Also included here is low-level thread/task switch support.
+ *
+ * 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.
+ *
*/
-#define BUMP(ctr) \
- lis r2,ctr@h; \
- ori r2,r2,ctr@l; \
- lwz r3,4(r2); \
- addic r3,r3,1; \
- stw r3,4(r2); \
- lwz r3,0(r2); \
- addze r3,r3; \
- stw r3,0(r2)
-
-/* The same as 'BUMP' but running unmapped (TLB code) */
-#define BUMP_UNMAPPED(ctr) \
- mfspr r0,XER; \
- lis r2,ctr@h; \
- ori r2,r2,ctr@l; \
- lis r3,0xF000; \
- andc r2,r2,r3; \
- lwz r3,4(r2); \
- addic r3,r3,1; \
- stw r3,4(r2); \
- lwz r3,0(r2); \
- addze r3,r3; \
- mtspr XER,r0; \
- stw r3,0(r2)
-
-#define DO_RFI_TRACE_UNMAPPED(mark)
-#define DO_RFI_TRACE_MAPPED(mark)
-
-#define DEFAULT_TRAP(offset) \
- li r13,0; \
- ori r13,r13,HID0_ICE; \
- mtspr HID0,r13; \
- lis r13,0xFFF00000>>16; \
- ori r13,r13,offset; \
- mtlr r13; \
- blr
-#define TRACE_TRAP(offset)
-#define DATA_CACHE_OFF() \
- mfspr r2,HID0; \
- li r3,0; \
- ori r3,r3,HID0_DCE; \
- andc r2,r2,r3; \
- mtspr HID0,r2;
+#include "ppc_asm.tmpl"
+#include "ppc_defs.h"
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <linux/sys.h>
+#include <linux/errno.h>
+#include <linux/config.h>
-#define DATA_CACHE_ON() \
- mfspr r2,HID0; \
- ori r2,r2,HID0_DCE; \
- mtspr HID0,r2;
+#define SYNC() \
+ sync; \
+ isync
-/* This instruction is not implemented on the PPC 603 */
+/* This instruction is not implemented on the PPC 603 or 601 */
#define tlbia \
- li r4,64; \
- mtspr CTR,r4; \
- lis r4,0x9000; \
+ li r4,128; \
+ mtctr r4; \
+ lis r4,0xC000; \
0: tlbie r4; \
addi r4,r4,0x1000; \
bdnz 0b
-/* Validate kernel stack - check for overflow */
-/* all regs are considered scratch since the C function will stomp them */
-#define CHECK_STACK() \
- /*lis r3,current_set@ha; \
- lwz r3,current_set@l(r3); \
- bl _EXTERN(check_stack)*/
-#if 0
-#define _CHECK_STACK() \
- mtspr SPR0,r3; \
- mtspr SPR1,r4; /* use r3,4 as scratch */ \
- lis r2,current_set@ha; \
- lwz r2,current_set@l(r2); \
- lwz r2,KERNEL_STACK_PAGE(r2); \
- /* if kernel stack is sys_stack skip check */ \
- /*lis r3,sys_stack@h; \
- ori r3,r3,sys_stack@l; \
- cmpl 0,r1,r3;*/ \
- /* check for STACK_MAGIC on kernel stack page */ \
- lis r3, 0xdead; /* STACK_MAGIC */ \
- ori r3,r3,0xbeef; \
- lwz r4,0(r2); /* get *kernel_stack_page */ \
- cmpl 0,r4,r3; \
- bne 01f; \
- /* check that ksp is > kernel page */ \
- /*li r3,0x0FFF; \
- andc r2,r2,r3; \
- andc r3,r1,r3; \
- cmp 0,r3,r2; \
- beq 02f;*/ \
- /* check that ksp and kernel stack page are on same page */ \
- cmp 0,r1,r2; \
- bge 02f; \
-01: mr r6,r1; /* setup info for call to bad_stack() */ \
- mr r5,r2; \
- bl _EXTERN(bad_stack); \
-02: mfspr r4,SPR1; \
- mfspr r3,SPR0
-#endif
-
-/* save fp regs if fp is used */
-/* assumes that r1 contains ptr to regs of task and r2 is scratch
- -- Cort */
-#define SAVE_FP_REGS() \
- /* check if fp has been used by checking msr_fp bit */ \
- lwz r2,_MSR(r1); \
- andi. r2,r2,MSR_FP; \
- bne 00f; \
- /* floating point has been used -- save fp regs */ \
- lis r2,current_set@h; \
- ori r2,r2,current_set@l; \
- addi r2,r2,TSS; \
- /*mr r2,r1;*/ \
- stfd fr0,TSS_FPR0(r2); \
- stfd fr1,TSS_FPR1(r2); \
- stfd fr2,TSS_FPR2(r2); \
- stfd fr3,TSS_FPR3(r2); \
- stfd fr4,TSS_FPR4(r2); \
- stfd fr5,TSS_FPR5(r2); \
- stfd fr6,TSS_FPR6(r2); \
- stfd fr7,TSS_FPR7(r2); \
- stfd fr8,TSS_FPR8(r2); \
- stfd fr9,TSS_FPR9(r2); \
- stfd fr10,TSS_FPR10(r2); \
- stfd fr11,TSS_FPR11(r2); \
- stfd fr12,TSS_FPR12(r2); \
- stfd fr13,TSS_FPR13(r2); \
- stfd fr14,TSS_FPR14(r2); \
- stfd fr15,TSS_FPR15(r2); \
- stfd fr16,TSS_FPR16(r2); \
- stfd fr17,TSS_FPR17(r2); \
- stfd fr18,TSS_FPR18(r2); \
- stfd fr19,TSS_FPR19(r2); \
- stfd fr20,TSS_FPR20(r2); \
- stfd fr21,TSS_FPR21(r2); \
- stfd fr22,TSS_FPR22(r2); \
- stfd fr23,TSS_FPR23(r2); \
- stfd fr24,TSS_FPR24(r2); \
- stfd fr25,TSS_FPR25(r2); \
- stfd fr26,TSS_FPR26(r2); \
- stfd fr27,TSS_FPR27(r2); \
- stfd fr28,TSS_FPR28(r2); \
- stfd fr29,TSS_FPR29(r2); \
- stfd fr30,TSS_FPR30(r2); \
- stfd fr31,TSS_FPR31(r2); \
-00:
-
-
-/* restores fp regs if fp has been used -- always restores fpscr */
-/* assumes that r1 contains ptr to regs, r2 is scratch and srr1 holds
- what will become the msr when this process executes -- Cort*/
-#define RESTORE_FP_REGS(mark) \
- /* check if restoring from _switch() */ \
- li r2, mark; \
- cmpi 0,r2,0x0f0f; \
- bne 00f; /* only need to save if called from _switch() with 0x0f0f */\
- /* check if fp has been used by checking msr_fp bit */ \
- /* srr1 contains msr */ \
- mfspr r2,SRR1; \
- andi. r2,r2,MSR_FP; \
- bne 00f; \
- /* floating point has been used -- restore fp regs */ \
- /* Hey, Rocky! Watch me pull fp regs from my stack! */ \
- lis r2,current_set@h; \
- ori r2,r2,current_set@l; \
- addi r2,r2,TSS; \
- /*mr r2,r1;*/\
- lfd fr0,TSS_FPR0(r2); \
- lfd fr1,TSS_FPR1(r2); \
- lfd fr2,TSS_FPR2(r2); \
- lfd fr3,TSS_FPR3(r2); \
- lfd fr4,TSS_FPR4(r2); \
- lfd fr5,TSS_FPR5(r2); \
- lfd fr6,TSS_FPR6(r2); \
- lfd fr7,TSS_FPR7(r2); \
- lfd fr8,TSS_FPR8(r2); \
- lfd fr9,TSS_FPR9(r2); \
- lfd fr10,TSS_FPR10(r2); \
- lfd fr11,TSS_FPR11(r2); \
- lfd fr12,TSS_FPR12(r2); \
- lfd fr13,TSS_FPR13(r2); \
- lfd fr14,TSS_FPR14(r2); \
- lfd fr15,TSS_FPR15(r2); \
- lfd fr16,TSS_FPR16(r2); \
- lfd fr17,TSS_FPR17(r2); \
- lfd fr18,TSS_FPR18(r2); \
- lfd fr19,TSS_FPR19(r2); \
- lfd fr20,TSS_FPR20(r2); \
- lfd fr21,TSS_FPR21(r2); \
- lfd fr22,TSS_FPR22(r2); \
- lfd fr23,TSS_FPR23(r2); \
- lfd fr24,TSS_FPR24(r2); \
- lfd fr25,TSS_FPR25(r2); \
- lfd fr26,TSS_FPR26(r2); \
- lfd fr27,TSS_FPR27(r2); \
- lfd fr28,TSS_FPR28(r2); \
- lfd fr29,TSS_FPR29(r2); \
- lfd fr30,TSS_FPR30(r2); \
- lfd fr31,TSS_FPR31(r2); \
-00:
-
-/* save all registers */
-#define SAVE_ALL_REGS(mark) \
- subi r1,r1,INT_FRAME_SIZE; /* Make room for frame */ \
- stmw r3,GPR3(r1); /* Save R3..R31 */ \
- stw r3,ORIG_GPR3(r1); \
- stw r0,GPR0(r1); \
- mfspr r2,SPR0; \
- stw r2,GPR1(r1); \
- mfspr r2,SPR1; \
- stw r2,GPR2(r1); \
- mfspr r2,SPR2; \
- stw r2,_NIP(r1); \
- mfspr r2,SPR3; \
- stw r2,_MSR(r1); \
- mfctr r2; \
- stw r2,_CTR(r1); \
- mflr r2; \
- stw r2,_LINK(r1); \
- mfcr r2; \
- stw r2,_CCR(r1); \
- mfspr r2,XER; \
- stw r2,_XER(r1); \
- mffs fr0; \
- stfd fr0,FPCSR(r1); \
- lis r2,_break_lwarx@h; \
- ori r2,r2,_break_lwarx@l; \
- stwcx. r2,0,r2; \
- li r2,mark; \
- stw r2,TRAP(r1); \
- lis r2,0xDEAD; \
- ori r2,r2,0xDEAD; \
- stw r2,MARKER(r1); \
- li r2,0; \
- stw r2,RESULT(r1)
-
-
-/* save registers clobbered by a page fault handler */
-#define SAVE_PAGE_FAULT_REGS(offset) \
- mfspr r2,DAR; \
- stw r2,_DAR(r1); \
- mfspr r2,DSISR; \
- stw r2,_DSISR(r1); \
- mfspr r2,PVR; /* Check for 603/603e */ \
- srwi r2,r2,16; \
- cmpi 0,r2,3; /* 603 */ \
- beq 22f; \
- cmpi 0,r2,6; /* 603e */ \
- bne 24f; \
-22: mfspr r2,HASH1; /* Note: these registers exist only on 603 */ \
- stw r2,_HASH1(r1); \
- mfspr r2,HASH2; \
- stw r2,_HASH2(r1); \
- mfspr r2,IMISS; \
- stw r2,_IMISS(r1); \
- mfspr r2,DMISS; \
- stw r2,_DMISS(r1); \
- mfspr r2,ICMP; \
- stw r2,_ICMP(r1); \
- mfspr r2,DCMP; \
- stw r2,_DCMP(r1); \
-24:
-
-#define SAVE_INT_REGS(mark) \
- mtspr SPR0,r1; /* Save current stack pointer */ \
- mtspr SPR1,r2; /* Scratch */ \
- mfcr r2; \
- mtspr SPR2,r2; \
- mfspr r2,SRR1; /* Interrupt from user/system mode */ \
- andi. r2,r2,MSR_PR; \
- beq+ 10f; /* Jump if system - already have stack */ \
- mfspr r2,SPR2; /* Restore CCR */ \
- mtcrf 0xFF,r2; \
- mfspr r2,SRR0; /* Preserve interrupt registers */ \
- mtspr SPR2,r2; \
- mfspr r2,SRR1; \
- mtspr SPR3,r2; \
- lis r2,05f@h; \
- ori r2,r2,05f@l; \
- mtspr SRR0,r2; \
- mfmsr r2; \
- ori r2,r2,MSR_|MSR_DR|MSR_IR; \
- mtspr SRR1,r2; \
- rfi; \
-05: lis r2,current_set@ha; \
- lwz r2,current_set@l(r2); \
- mfspr r1,SPR2; \
- stw r1,TSS+LAST_PC(r2); \
- mfspr r1,SPR0; \
- stw r1,TSS+USER_STACK(r2); \
- lwz r1,TSS+KSP(r2); \
- subi r1,r1,INT_FRAME_SIZE; /* Make room for frame */ \
- stw r1,TSS+PT_REGS(r2); /* Save regs pointer for 'ptrace' */ \
- lwz r1,TSS+KSP(r2); \
- b 20f; \
-10: mfspr r2,SPR2; /* Restore CCR */ \
- mtcrf 0xFF,r2; \
- mfspr r2,SRR0; /* Preserve interrupt registers */ \
- mtspr SPR2,r2; \
- mfspr r2,SRR1; \
- mtspr SPR3,r2; \
- lis r2,20f@h; \
- ori r2,r2,20f@l; \
- mtspr SRR0,r2; \
- mfmsr r2; \
- ori r2,r2,MSR_|MSR_DR|MSR_IR; \
- mtspr SRR1,r2; \
- SYNC(); \
- rfi; \
-20: SAVE_ALL_REGS(mark); \
- CHECK_STACK()
-
-#define RETURN_FROM_INT(mark) \
-90: mfmsr r0; /* Disable interrupts */ \
- li r4,0; \
- ori r4,r4,MSR_EE; \
- andc r0,r0,r4; \
- sync; /* Some chip revs need this... */ \
- mtmsr r0; \
- lis r2,intr_count@ha; /* Need to run 'bottom half' */ \
- lwz r3,intr_count@l(r2); \
- cmpi 0,r3,0; \
- bne 00f; \
- lis r4,bh_mask@ha; \
- lwz r4,bh_mask@l(r4); \
- lis r5,bh_active@ha; \
- lwz r5,bh_active@l(r5); \
- and. r4,r4,r5; \
- beq 00f; \
- addi r3,r3,1; \
- stw r3,intr_count@l(r2); \
- bl _EXTERN(_do_bottom_half); \
- lis r2,intr_count@ha; \
- lwz r3,intr_count@l(r2); \
- subi r3,r3,1; \
- stw r3,intr_count@l(r2); \
-00: lwz r2,_MSR(r1); /* Returning to user mode? */ \
- andi. r2,r2,MSR_PR; \
- beq+ 10f; /* no - no need to mess with stack */ \
-/* lis r2,kernel_pages_are_copyback@ha; \
- lwz r2,kernel_pages_are_copyback@l(r2); \
- cmpi 0,r2,0; \
- beq 05f; \
- bl _EXTERN(flush_instruction_cache); */ \
-05: lis r3,current_set@ha; /* need to save kernel stack pointer */ \
- lwz r3,current_set@l(r3); \
- /*addi r4,r1,INT_FRAME_SIZE*/; /* size of frame */ \
- lwz r4, KERNEL_STACK_PAGE(r3); \
- addi r4,r4,KERNEL_STACK_SIZE; /* reset stack pointer to top of stack page */ \
- /* stack isn't 0'd so show_task():sched.c shows highwater of stack */ \
- stw r4,TSS+KSP(r3); \
- lwz r4,STATE(r3); /* If state != 0, can't run */ \
- cmpi 0,r4,0; \
- beq 06f; \
- bl _EXTERN(schedule); \
- b 90b; \
-06: lwz r4,COUNTER(r3); /* Time quantum expired? */ \
- cmpi 0,r4,0; \
- bne 07f; \
- bl _EXTERN(schedule); \
- b 90b; \
-07: lwz r4,BLOCKED(r3); /* Check for pending unblocked signals */ \
- lwz r5,SIGNAL(r3); \
- andc. r0,r5,r4; /* Lets thru any unblocked */ \
- beq 10f; \
- mr r3,r4; \
- mr r4,r1; \
- bl _EXTERN(do_signal); \
-10: lwz r2,_NIP(r1); /* Restore environment */ \
- mtspr SRR0,r2; \
- lwz r2,_MSR(r1); \
- mtspr SRR1,r2; \
- lmw r3,GPR3(r1); \
- lwz r2,_CTR(r1); \
- mtctr r2; \
- lwz r2,_LINK(r1); \
- mtlr r2; \
- lwz r2,_XER(r1); \
- mtspr XER,r2; \
- lfd fr0,FPCSR(r1); \
- mtfsf 0xFF,fr0; \
- RESTORE_FP_REGS(mark) ; \
- lwz r2,_CCR(r1); \
- mtcrf 0xFF,r2; \
- lwz r0,GPR0(r1); \
- lwz r2,GPR2(r1); \
- lwz r1,GPR1(r1); \
- SYNC(); \
- rfi
-
-
-_TEXT()
-/*
- * This code may be executed by a bootstrap process. If so, the
- * purpose is to relocate the loaded image to it's final location
- * in memory.
- * R3: End of image
- * R4: Start of image - 0x400
- * R11: Start of command line string
- * R12: End of command line string
- * R30: 'BeBx' if this is a BeBox
- *
- */
- .globl _start
- .globl _stext
-_stext:
-_start:
- addi r4,r4,0x400 /* Point at start of image */
- li r5,0 /* Load address */
- subi r4,r4,4 /* Adjust for auto-increment */
- subi r5,r5,4
- subi r3,r3,4
-00: lwzu r0,4(r4) /* Fast move */
- stwu r0,4(r5)
- cmp 0,r3,r4
- bne 00b
- li r5,0x100 /* Actual code starts here */
- mtlr r5
- blr
+#define TOPHYS(x) (x - KERNELBASE)
-hang:
- ori r0,r0,0
- b hang
-/*
- * BeBox CPU #1 vector & code
+/* this is a very kludgey way of loading up the BATs on the
+ prep system. I'll kill this horrible macro and write
+ something clean when I have a chance -- Cort
*/
-_ORG(0x0080)
- .globl BeBox_CPU1_vector
-BeBox_CPU1_vector:
- .long 0
-BeBox_CPU1_reset:
- li r1,BeBox_CPU1_vector@l
- li r2,0
- stw r2,0(r1)
-00: lwz r2,0(r1)
- cmpi 0,r2,0
- bne 10f
- li r2,10000
- mtctr r2
-02: nop
- bdnz 02b
- b 00b
-10: mtlr r1
- blr
+#define LOAD_BATS(RA,RB) \
+ mfspr RA,PVR ; \
+ srwi r5,r5,16 ; \
+ cmpi 0,RA,1 ; \
+ beq 199f ; \
+ /* load bats for 60x */ ; \
+ lis RA,BAT0@h ; \
+ ori RA,RA,BAT0@l ; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT0U,RB ; \
+ mtspr DBAT0U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT0L,RB ; \
+ mtspr DBAT0L,RB ; \
+ lis RA,BAT1@h ; \
+ ori RA,RA,BAT1@l ; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT1U,RB ; \
+ mtspr DBAT1U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT1L,RB ; \
+ mtspr DBAT1L,RB ; \
+ lis RA,BAT2@h ; \
+ ori RA,RA,BAT2@l ; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT2U,RB ; \
+ mtspr DBAT2U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT2L,RB ; \
+ mtspr DBAT2L,RB ; \
+ lis RA,BAT3@h ; \
+ ori RA,RA,BAT3@l ; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT3U,RB ; \
+ mtspr DBAT3U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT3L,RB ; \
+ mtspr DBAT3L,RB ; \
+ b 200f ; \
+199: /*load bats for 601 */ ; \
+ lis RA,BAT0_601@h ; \
+ ori RA,RA,BAT0_601@l; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT0U,RB ; \
+ mtspr DBAT0U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT0L,RB ; \
+ mtspr DBAT0L,RB ; \
+ lis RA,BAT1_601@h ; \
+ ori RA,RA,BAT1_601@l; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT1U,RB ; \
+ mtspr DBAT1U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT1L,RB ; \
+ mtspr DBAT1L,RB ; \
+ lis RA,BAT2_601@h ; \
+ ori RA,RA,BAT2_601@l; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT2U,RB ; \
+ mtspr DBAT2U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT2L,RB ; \
+ mtspr DBAT2L,RB ; \
+ lis RA,BAT3_601@h ; \
+ ori RA,RA,BAT3_601@l; \
+ addis RA,RA,-KERNELBASE@h;\
+ lwz RB,0(RA) ; \
+ mtspr IBAT3U,RB ; \
+ mtspr DBAT3U,RB ; \
+ lwz RB,4(RA) ; \
+ mtspr IBAT3L,RB ; \
+ mtspr DBAT3L,RB ; \
+200:
-_ORG(0x0100)
-/* Hard Reset */
- .globl HardReset
-HardReset:
- b Reset
-_ORG(0x0200)
- b MachineCheck
-
-_ORG(0x0300)
- b DataAccess
-
-_ORG(0x0400)
- b InstructionAccess
-
-_ORG(0x0500)
- b HardwareInterrupt
-
-_ORG(0x0600)
- b Alignment
-
-_ORG(0x0700)
- b ProgramCheck
-
-_ORG(0x0800)
- b FloatingPointCheck
-
-/* Decrementer register - ignored for now... */
-_ORG(0x0900)
-/* TRACE_TRAP(0x900) */
- mtspr SPR0,r1
- lis r1,0x7FFF
- ori r1,r1,0xFFFF
- mtspr DEC,r1
- mfspr r1,SPR0
-#if 0
- SYNC
-#endif
- rfi
-_ORG(0x0A00)
-DEFAULT_TRAP(0x0A00)
-_ORG(0x0B00)
-DEFAULT_TRAP(0x0B00)
-
-/*
- * System call
- */
-_ORG(0x0C00)
- b SystemCall
+ .text
+ .globl _stext
+_stext:
-_ORG(0x0D00)
- b SingleStep
+#ifdef CONFIG_PREP
+ . = 0x100
+_GLOBAL(HardReset)
+ b _start
-_ORG(0x0E00)
-DEFAULT_TRAP(0x0E00)
-_ORG(0x0F00)
-DEFAULT_TRAP(0x0F00)
+#endif /* CONFIG_PREP */
+#ifdef CONFIG_PMAC
/*
- * Handle TLB Miss on an instruction load
+ * _start is defined this way because the XCOFF loader in the OpenFirmware
+ * on the powermac expects the entry point to be a procedure descriptor.
*/
-_ORG(0x1000)
-/* Note: It is *unsafe* to use the TRACE TRAP macro here since there */
-/* could be a 'trace' in progress when the TLB miss occurs. */
-/* TRACE_TRAP(0x1000) */
- b InstructionTLBMiss
+ .text
+ .globl _start
+_start:
+ .long TOPHYS(__start),0,0
/*
- * Handle TLB Miss on a data item load
+ * 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.
*/
-_ORG(0x1100)
-/* TRACE_TRAP(0x1100) */
- b DataLoadTLBMiss
+ .globl __start
+__start:
/*
- * Handle TLB Miss on a store operation
+ * Use the first pair of BAT registers to map the 1st 8MB
+ * of RAM to KERNELBASE.
*/
-_ORG(0x1200)
-/* TRACE_TRAP(0x1200) */
- b DataStoreTLBMiss
-
-_ORG(0x1300)
-InstructionAddressBreakpoint:
- DEFAULT_TRAP(0x1300)
-
-_ORG(0x1400)
-SystemManagementInterrupt:
- DEFAULT_TRAP(0x1400)
-
-_ORG(0x1500)
+ mfspr r9,PVR
+ rlwinm r9,r9,16,16,31 /* r9 = 1 for 601, 4 for 604 */
+ cmpi 0,r9,1
+ lis r7,KERNELBASE@h
+ bne 4f
+ ori r7,r7,4 /* set up BAT registers for 601 */
+ li r8,0x7f
+ b 5f
+4: ori r7,r7,0xff /* set up BAT registers for 604 */
+ li r8,2
+ mtspr DBAT0U,r7
+ mtspr DBAT0L,r8
+5: mtspr IBAT0U,r7
+ mtspr IBAT0L,r8
+ isync
/*
- * This space [buffer] is used to forceably flush the data cache when
- * running in copyback mode. This is necessary IFF the data cache could
- * contain instructions for which the instruction cache has stale data.
- * Since the instruction cache NEVER snoops the data cache, memory must
- * be made coherent with the data cache to insure that the instruction
- * cache gets a valid instruction stream. Note that this flushing is
- * only performed when switching from system to user mode since this is
- * the only juncture [as far as the OS goes] where the data cache may
- * contain instructions, e.g. after a disk read.
+ * Now we have the 1st 8M of RAM mapped at KERNELBASE, so we can
+ * refer to addresses of data items, procedures, etc. normally.
*/
-#define NUM_CACHE_LINES 128*4
-#define CACHE_LINE_SIZE 32
-cache_flush_buffer:
- .space NUM_CACHE_LINES*CACHE_LINE_SIZE /* CAUTION! these need to match hardware */
-
-#if NUM_CACHE_LINES < 512
-_ORG(0x4000)
-#endif
+ lis r7,start_here@ha /* jump up to our copy at KERNELBASE */
+ addi r7,r7,start_here@l
+ mtlr r7
+ blr
+#endif /* CONFIG_PMAC */
-/* changed to use r3 as residual pointer (as firmware does), that's all -- Cort */
-/*
- * Hardware reset [actually from bootstrap]
- * Initialize memory management & call secondary init
- * Registers initialized by bootstrap:
- * R11: Start of command line string
- * R12: End of command line string
- * R28: Residual data
- * R29: Total Memory Size
- * R30: 'BeBx' if this is a BeBox
- */
-Reset:
- lis r7,0xF000 /* To mask upper 4 bits */
-/* set pointer to residual data */
- lis r1,resptr@h
- ori r1,r1,resptr@l
- andc r1,r1,r7
-/* changed to use r3 as residual pointer (as firmware does) -- Cort */
-/* this is only a ptr, the actual data is copied in mmu_init */
- stw r3,0(r1)
-
-/* Copy argument string */
- li r0,0 /* Null terminate string */
- stb r0,0(r12)
- lis r1,cmd_line@h
- ori r1,r1,cmd_line@l
- andc r1,r1,r7 /* No MMU yet - need unmapped address */
- subi r1,r1,1
- subi r11,r11,1
-00: lbzu r0,1(r11)
- cmpi 0,r0,0
- stbu r0,1(r1)
- bne 00b
-#define IS_BE_BOX 0x42654278 /* 'BeBx' */
- lis r1,isBeBox@h
- ori r1,r1,isBeBox@l
- andc r1,r1,r7
-/* See if this is a CPU other than CPU#1 */
-/* This [currently] happens on the BeBox */
- lwz r2,0(r1)
- cmpi 0,r2,0
- bne Reset_BeBox_CPU1
-/* Save machine type indicator */
- li r2,0
- lis r3,IS_BE_BOX>>16
- ori r3,r3,IS_BE_BOX&0xFFFF
- cmp 0,r30,r3
- bne 00f
- li r2,1
- mr r11,r28
- mr r12,r29
- lis r5,BeBox_CPU1_vector@h
- ori r5,r5,BeBox_CPU1_vector@l
- andc r5,r5,r7 /* Tell CPU #1 where to go */
-00: stw r2,0(r1)
- stw r30,4(r1)
-
-#if 0
- lis r1,sys_stack@h
- ori r1,r1,sys_stack@l
-#else
- lis r1,init_kernel_stack@h
- ori r1,r1,init_kernel_stack@l
-#endif
- addi r1,r1,0x1000 /* top of stack */
-#if 0
- li r2,0x0FFF /* Mask stack address down to page boundary */
-#endif
- andc r1,r1,r2
- subi r1,r1,INT_FRAME_SIZE /* Padding for first frame */
- li r2,0 /* TOC pointer for nanokernel */
- li r0,MSR_ /* Make sure FPU enabled */
- mtmsr r0
- lis r3,_edata@h /* Clear BSS */
- ori r3,r3,_edata@l
- andc r3,r3,r7 /* make unmapped address */
- lis r4,_end@h
- ori r4,r4,_end@l
- andc r4,r4,r7 /* make unmapped address */
- subi r3,r3,4
- li r0,0
-00: stwu r0,4(r3)
- cmp 0,r3,r4
- blt 00b
-#if 0
-/* Save total memory size (passed from bootstrap) */
- lis r3,_TotalMemory@h
- ori r3,r3,_TotalMemory@l
- andc r3,r3,r7 /* make unmapped address */
- stw r29,0(r3)
-#endif
-/* Initialize BAT registers */
- lis r3,BAT0@h
- ori r3,r3,BAT0@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT0U,r0
- mtspr DBAT0U,r0
- lwz r0,4(r3)
- mtspr IBAT0L,r0
- mtspr DBAT0L,r0
- lis r3,BAT1@h
- ori r3,r3,BAT1@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT1U,r0
- mtspr DBAT1U,r0
- lwz r0,4(r3)
- mtspr IBAT1L,r0
- mtspr DBAT1L,r0
-/* this BAT mapping will cover all of kernel space */
-#ifdef NEWMM
- lis r3,BAT2@h
- ori r3,r3,BAT2@l
-#else
- lis r3,TMP_BAT2@h
- ori r3,r3,TMP_BAT2@l
-#endif
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT2U,r0
- mtspr DBAT2U,r0
- lwz r0,4(r3)
- mtspr IBAT2L,r0
- mtspr DBAT2L,r0
-#if 1
- lis r3,BAT3@h
- ori r3,r3,BAT3@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT3U,r0
- mtspr DBAT3U,r0
- lwz r0,4(r3)
- mtspr IBAT3L,r0
- mtspr DBAT3L,r0
-#endif
-/* Now we can turn on the MMU */
- mfmsr r3
- ori r3,r3,MSR_DR|MSR_IR
- mtspr SRR1,r3
- lis r3,10f@h
- ori r3,r3,10f@l
- mtspr SRR0,r3
-DO_RFI_TRACE_UNMAPPED(0xDEAD0000)
- SYNC
- rfi /* enables MMU */
-10: bl _EXTERN(MMU_init) /* initialize MMU environment */
-DO_RFI_TRACE_MAPPED(0xDEAD0100)
-/* Withdraw BAT2->RAM mapping */
- lis r7,0xF000 /* To mask upper 4 bits */
- lis r3,20f@h
- ori r3,r3,20f@l
- andc r3,r3,r7 /* make unmapped address */
- mtspr SRR0,r3
- mfmsr r3
- li r4,MSR_DR|MSR_IR
- andc r3,r3,r4
- mtspr SRR1,r3
- SYNC
-DO_RFI_TRACE_MAPPED(0xDEAD0200)
- SYNC
- rfi
-20:
-
-DO_RFI_TRACE_UNMAPPED(0xDEAD0400)
-20: lis r3,BAT2@h
- ori r3,r3,BAT2@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT2U,r0
- mtspr DBAT2U,r0
- lwz r0,4(r3)
- mtspr IBAT2L,r0
- mtspr DBAT2L,r0
-/* Load up the kernel context */
- lis r2,init_task@h
- ori r2,r2,init_task@l
- addi r2,r2,TSS
- andc r2,r2,r7 /* make unmapped address */
- SYNC /* Force all PTE updates to finish */
- tlbia /* Clear all TLB entries */
- lis r3,_SDR1@h
- ori r3,r3,_SDR1@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r3,0(r3)
- mtspr SDR1,r3
- lwz r0,MMU_SEG0(r2)
- mtsr SR0,r0
- lwz r0,MMU_SEG1(r2)
- mtsr SR1,r0
- lwz r0,MMU_SEG2(r2)
- mtsr SR2,r0
- lwz r0,MMU_SEG3(r2)
- mtsr SR3,r0
- lwz r0,MMU_SEG4(r2)
- mtsr SR4,r0
- lwz r0,MMU_SEG5(r2)
- mtsr SR5,r0
- lwz r0,MMU_SEG6(r2)
- mtsr SR6,r0
- lwz r0,MMU_SEG7(r2)
- mtsr SR7,r0
- lwz r0,MMU_SEG8(r2)
- mtsr SR8,r0
- lwz r0,MMU_SEG9(r2)
- mtsr SR9,r0
- lwz r0,MMU_SEG10(r2)
- mtsr SR10,r0
- lwz r0,MMU_SEG11(r2)
- mtsr SR11,r0
- lwz r0,MMU_SEG12(r2)
- mtsr SR12,r0
- lwz r0,MMU_SEG13(r2)
- mtsr SR13,r0
- lwz r0,MMU_SEG14(r2)
- mtsr SR14,r0
- lwz r0,MMU_SEG15(r2)
- mtsr SR15,r0
-/* Now turn on the MMU for real! */
- mfmsr r3
- ori r3,r3,MSR_DR|MSR_IR
- mtspr SRR1,r3
- lis r3,30f@h
- ori r3,r3,30f@l
- mtspr SRR0,r3
-DO_RFI_TRACE_UNMAPPED(0xDEAD0500)
- SYNC
- rfi /* enables MMU */
-30:
-/* Turn on L1 Data Cache */
- mfspr r3,HID0 /* Caches are controlled by this register */
- ori r4,r3,(HID0_ICE|HID0_ICFI)
- ori r3,r3,(HID0_ICE)
- ori r4,r4,(HID0_DCE|HID0_DCI)
- ori r3,r3,(HID0_DCE)
- sync
- mtspr HID0,r4
- mtspr HID0,r3
-/* L1 cache enable */
- mfspr r2,PVR /* Check for 603/603e */
- srwi r2,r2,16
- cmpi 0,r2,4 /* 604 */
- bne 40f
- mfspr r3,HID0 /* Turn on 604 specific features */
- ori r3,r3,(HID0_SIED|HID0_BHTE)
- mtspr HID0,r3
-40: b _EXTERN(start_kernel) /* call main code */
- .long 0 # Illegal!
-
/*
- * BeBox CPU #2 runs here
+ * Macros for storing registers into and loading registers from
+ * exception frames.
*/
-Reset_BeBox_CPU1:
- lis r1,CPU1_stack@h
- ori r1,r1,CPU1_stack@l
- li r2,0x0FFF /* Mask stack address down to page boundary */
- andc r1,r1,r2
- subi r1,r1,INT_FRAME_SIZE /* Padding for first frame */
- lis r30,CPU1_trace@h
- ori r30,r30,CPU1_trace@l
- andc r30,r30,r7
- li r5,1
- stw r5,0(r30)
- li r2,0 /* TOC pointer for nanokernel */
- li r0,MSR_ /* Make sure FPU enabled */
- mtmsr r0
-/* Initialize BAT registers */
- lis r3,BAT0@h
- ori r3,r3,BAT0@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT0U,r0
- mtspr DBAT0U,r0
- lwz r0,4(r3)
- mtspr IBAT0L,r0
- mtspr DBAT0L,r0
- lis r3,BAT1@h
- ori r3,r3,BAT1@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT1U,r0
- mtspr DBAT1U,r0
- lwz r0,4(r3)
- mtspr IBAT1L,r0
- mtspr DBAT1L,r0
- lis r3,TMP_BAT2@h
- ori r3,r3,TMP_BAT2@l
- andc r3,r3,r7 /* make unmapped address */
- lwz r0,0(r3)
- mtspr IBAT2U,r0
- mtspr DBAT2U,r0
- lwz r0,4(r3)
- mtspr IBAT2L,r0
- mtspr DBAT2L,r0
-/* Now we can turn on the MMU */
- mfmsr r3
- ori r3,r3,MSR_DR|MSR_IR
- mtspr SRR1,r3
- lis r3,10f@h
- ori r3,r3,10f@l
- mtspr SRR0,r3
- li r5,2
- stw r5,0(r30)
- SYNC
- rfi /* enables MMU */
-10:
- lis r30,CPU1_trace@h
- ori r30,r30,CPU1_trace@l
- li r5,3
- stw r5,0(r30)
- bl _EXTERN(BeBox_CPU1)
-
-/*
- * Machine Check (Bus Errors, etc)
- */
-MachineCheck:
- TRACE_TRAP(0x0200)
- SAVE_INT_REGS(0x0200)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(MachineCheckException)
- RETURN_FROM_INT(0x0200)
-
-/*
- * Data Access exception
- */
-DataAccess:
- SAVE_INT_REGS(0x0300)
-#if 1
- mfspr r3, DAR
- mfspr r4, DSISR
- li r5, 0 /* not a text fault */
- mr r6, r1
- bl _EXTERN(new_page_fault)
-#else
- SAVE_PAGE_FAULT_REGS(0x0D00)
- mr r3,r1
- bl _EXTERN(DataAccessException)
-#endif
- RETURN_FROM_INT(0x0300)
+#define SAVE_GPR(n, base) stw n,GPR0+4*(n)(base)
+#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base)
+#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
+#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
+#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
+#define REST_GPR(n, base) lwz n,GPR0+4*(n)(base)
+#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base)
+#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base)
+#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base)
+#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base)
+
+#define SAVE_FPR(n, base) stfd n,TSS_FPR0+8*(n)(base)
+#define SAVE_2FPRS(n, base) SAVE_FPR(n, base); SAVE_FPR(n+1, base)
+#define SAVE_4FPRS(n, base) SAVE_2FPRS(n, base); SAVE_2FPRS(n+2, base)
+#define SAVE_8FPRS(n, base) SAVE_4FPRS(n, base); SAVE_4FPRS(n+4, base)
+#define SAVE_16FPRS(n, base) SAVE_8FPRS(n, base); SAVE_8FPRS(n+8, base)
+#define SAVE_32FPRS(n, base) SAVE_16FPRS(n, base); SAVE_16FPRS(n+16, base)
+#define REST_FPR(n, base) lfd n,TSS_FPR0+8*(n)(base)
+#define REST_2FPRS(n, base) REST_FPR(n, base); REST_FPR(n+1, base)
+#define REST_4FPRS(n, base) REST_2FPRS(n, base); REST_2FPRS(n+2, base)
+#define REST_8FPRS(n, base) REST_4FPRS(n, base); REST_4FPRS(n+4, base)
+#define REST_16FPRS(n, base) REST_8FPRS(n, base); REST_8FPRS(n+8, base)
+#define REST_32FPRS(n, base) REST_16FPRS(n, base); REST_16FPRS(n+16, base)
/*
- * Instruction Access Exception
+ * 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.
*/
-InstructionAccess:
- SAVE_INT_REGS(0x0400)
-#if 1
- mfspr r3, SPR2 /* srr0 was saved here */
- mfspr r4, SPR3 /* srr1 was saved here */
- li r5, 1 /* a text fault */
- mr r6, r1
- bl _EXTERN(new_page_fault)
-#else
- SAVE_PAGE_FAULT_REGS(0x0D00)
- mr r3,r1
- bl _EXTERN(InstructionAccessException)
-#endif
- RETURN_FROM_INT(0x0400)
-
+#define EXCEPTION_PROLOG \
+0: mtspr SPRG0,r20; \
+ mtspr SPRG1,r21; \
+ mfcr r20; \
+ mfspr r21,SRR1; /* test whether from user or kernel */\
+ andi. r21,r21,MSR_PR; \
+ mr r21,r1; /* from kernel - use current sp */\
+ beq 1f; \
+ mfspr r21,SPRG3; /* from user - load kernel sp */\
+ lwz r21,KSP(r21); \
+1: addis r21,r21,-KERNELBASE@h; /* convert sp to physical */ \
+ subi r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD; /* alloc exc. frame */\
+ stw r1,GPR1(r21); \
+ stw r1,0(r21); \
+ addis r1,r21,KERNELBASE@h; /* set new kernel sp */ \
+ stw r20,_CCR(r21); /* save registers */ \
+ stw r22,GPR22(r21); \
+ stw r23,GPR23(r21); \
+ mfspr r20,SPRG0; \
+ stw r20,GPR20(r21); \
+ mfspr r22,SPRG1; \
+ stw r22,GPR21(r21); \
+ mflr r20; \
+ stw r20,_LINK(r21); \
+ mfctr r22; \
+ stw r22,_CTR(r21); \
+ mfspr r20,XER; \
+ stw r20,_XER(r21); \
+ mfspr r22,SRR0; \
+ mfspr r23,SRR1; /* we can now take exceptions */\
+ stw r0,GPR0(r21); \
+ stw r2,GPR2(r21); \
+ SAVE_4GPRS(3, r21);
/*
- * Hardware Interrupt
+ * Note: code which follows this uses cr0.eq (set if from kernel),
+ * r21, r22 (SRR0), and r23 (SRR1).
*/
-HardwareInterrupt:
- SAVE_INT_REGS(0x0500)
- BUMP(__Hardware_Interrupts)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(handle_IRQ)
- RETURN_FROM_INT(0x0500)
/*
- * Alignment
- */
-Alignment:
- TRACE_TRAP(0x0600)
- SAVE_INT_REGS(0x0600)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(AlignmentException)
- RETURN_FROM_INT(0x0600)
-
-/*
- * Illegal instruction
+ * Exception vectors.
*/
+#define STD_EXCEPTION(n, label, hdlr) \
+ . = n; \
+label: \
+ EXCEPTION_PROLOG; \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ li r20,MSR_KERNEL; \
+ bl transfer_to_handler; \
+ .long hdlr; \
+ .long int_return
+
+#ifndef CONFIG_PREP
+/* System reset */
+ STD_EXCEPTION(0x100, Reset, UnknownException)
+#endif /* ndef CONFIG_PREP */
+
+/* Machine check */
+ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)
+
+/* Data access exception */
+ . = 0x300
+DataAccess:
+ EXCEPTION_PROLOG
+ mfspr r20,DSISR
+ andis. r0,r20,0x8470 /* weird error? */
+ bne 1f /* if not, try to put a PTE */
+ mfspr r3,DAR /* into the hash table */
+ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */
+ rlwimi r4,r20,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */
+ mfspr r5,SPRG3 /* phys addr of TSS */
+ bl hash_page
+1: stw r20,_DSISR(r21)
+ mr r5,r20
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ bl transfer_to_handler
+ .long do_page_fault
+ .long int_return
+
+/* Instruction access exception */
+ . = 0x400
+InstructionAccess:
+ EXCEPTION_PROLOG
+ andis. r0,r23,0x4000 /* no pte found? */
+ beq 1f /* if so, try to put a PTE */
+ mr r3,r22 /* into the hash table */
+ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */
+ mr r20,r23 /* SRR1 has reason bits */
+ mfspr r5,SPRG3 /* phys addr of TSS */
+ bl hash_page
+1: addi r3,r1,STACK_FRAME_OVERHEAD
+ mr r4,r22
+ mr r5,r23
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ bl transfer_to_handler
+ .long do_page_fault
+ .long int_return
+
+/* External interrupt */
+ STD_EXCEPTION(0x500, HardwareInterrupt, handle_IRQ)
+
+/* Alignment exception */
+ . = 0x600
+Alignment:
+ EXCEPTION_PROLOG
+ mfspr r4,DAR
+ stw r4,_DAR(r21)
+ mfspr r5,DSISR
+ stw r5,_DSISR(r21)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ bl transfer_to_handler
+ .long AlignmentException
+ .long int_return
+
+/* Program check exception */
+ . = 0x700
ProgramCheck:
- TRACE_TRAP(0x0700)
- SAVE_INT_REGS(0x0700)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(ProgramCheckException)
- RETURN_FROM_INT(0x0700)
-
-/*
- * Single Step Exception
- */
-SingleStep:
- SAVE_INT_REGS(0x0D00)
- SAVE_PAGE_FAULT_REGS(0x0D00)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(SingleStepException)
-#if 0
- bl _EXTERN(flush_instruction_cache)
-#endif
- RETURN_FROM_INT(0x0D00)
+ EXCEPTION_PROLOG
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ bl transfer_to_handler
+ .long ProgramCheckException
+ .long int_return
+
+/* Floating-point unavailable */
+ . = 0x800
+FPUnavailable:
+ EXCEPTION_PROLOG
+ bne load_up_fpu /* if from user, just load it up */
+ li r20,MSR_KERNEL
+ bl transfer_to_handler /* if from kernel, take a trap */
+ .long KernelFP
+ .long int_return
+
+/* Decrementer */
+#ifdef CONFIG_PREP
+/* - ignored for now... */
+_ORG(0x0900)
+ mtspr SPRG0,r1
+ lis r1,0x7FFF
+ ori r1,r1,0xFFFF
+ mtspr DEC,r1
+ mfspr r1,SPRG0
+ rfi
+#endif /* CONFIG_PREP */
+#ifdef CONFIG_PMAC
+ STD_EXCEPTION(0x900, Decrementer, timer_interrupt)
+#endif /* CONFIG_PMAC */
-/*
- * Floating point [not available, etc]
- */
-FloatingPointCheck:
- SAVE_INT_REGS(0x0800)
- mr r3,r1 /* Set pointer to saved regs */
- bl _EXTERN(FloatingPointCheckException)
- cmpi 0,r3,MSR_FP /* check if fp was turned on by handler */
- bne 00f
- RETURN_FROM_INT(0x0f0f) /* 0xf0f tells to restore fp regs */
-00: RETURN_FROM_INT(0x0200)
+ STD_EXCEPTION(0xa00, Trap_0a, UnknownException)
+ STD_EXCEPTION(0xb00, Trap_0b, UnknownException)
-/*
- * System Call exception
- */
+/* System call */
+ . = 0xc00
SystemCall:
- SAVE_INT_REGS(0x0C00)
- lwz r2,_CCR(r1) /* Clear SO bit in CR */
- lis r9,0x1000
- andc r2,r2,r9
- stw r2,_CCR(r1)
- cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */
- bne+ 10f
- mr r3,r1
- bl _EXTERN(sys_sigreturn)
- cmpi 0,r3,0 /* Check for restarted system call */
- bge 99f
- b 20f
-10: lis r2,current_set@ha
- lwz r2,current_set@l(r2)
- lwz r2,TASK_FLAGS(r2)
- andi. r2,r2,PF_TRACESYS
- bne 50f
-
- lis r2,sys_call_table@h
- ori r2,r2,sys_call_table@l
- slwi r0,r0,2
- lwzx r2,r2,r0 /* Fetch system call handler [ptr] */
-#if 1
- cmpi 0,r2,0 /* make sure syscall handler not 0 */
- beq 99f
- cmpi 0,r0,NR_syscalls<<2 /* make sure syscallnum in bounds */
- bgt 99f
-#endif
- mtlr r2
- mr r9,r1
- blrl /* Call handler */
-
-20: stw r3,RESULT(r1) /* Save result */
- cmpi 0,r3,0
- bge 30f
- neg r3,r3
- cmpi 0,r3,ERESTARTNOHAND
- bne 22f
- li r3,EINTR
-22: lwz r2,_CCR(r1) /* Set SO bit in CR */
- oris r2,r2,0x1000
- stw r2,_CCR(r1)
-30: stw r3,GPR3(r1) /* Update return value */
- b 99f
-/* Traced system call support */
-50: bl _EXTERN(syscall_trace)
- 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)
- lwz r9,GPR9(r1)
- lis r2,sys_call_table@h
- ori r2,r2,sys_call_table@l
- slwi r0,r0,2
- lwzx r2,r2,r0 /* Fetch system call handler [ptr] */
- mtlr r2
- mr r9,r1
- blrl /* Call handler */
- stw r3,RESULT(r1) /* Save result */
- cmpi 0,r3,0
- bge 60f
- neg r3,r3
- cmpi 0,r3,ERESTARTNOHAND
- bne 52f
- li r3,EINTR
-52: lwz r2,_CCR(r1) /* Set SO bit in CR */
- oris r2,r2,0x1000
- stw r2,_CCR(r1)
-60: stw r3,GPR3(r1) /* Update return value */
- bl _EXTERN(syscall_trace)
-99:
- RETURN_FROM_INT(0x0C00)
+ EXCEPTION_PROLOG
+ stw r3,ORIG_GPR3(r21)
+ li r20,MSR_KERNEL
+ rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */
+ bl transfer_to_handler
+ .long DoSyscall
+ .long int_return
+
+/* Single step - not used on 601 */
+ STD_EXCEPTION(0xd00, SingleStep, SingleStepException)
+
+ STD_EXCEPTION(0xe00, Trap_0e, UnknownException)
+ STD_EXCEPTION(0xf00, Trap_0f, UnknownException)
/*
- * Handle TLB miss for instruction
+ * Handle TLB miss for instruction on 603/603e.
+ * Note: we get an alternate set of r0 - r3 to use automatically.
*/
+ . = 0x1000
InstructionTLBMiss:
- BUMP_UNMAPPED(__Instruction_TLB_Misses)
mfctr r0 /* Need to save this - CTR can't be touched! */
mfspr r2,HASH1 /* Get PTE pointer */
mfspr r3,ICMP /* Partial item compare value */
@@ -1080,37 +425,47 @@ InstructionTLBMiss:
subi r2,r2,8 /* Preset pointer */
10: lwzu r1,8(r2) /* Get next PTE */
cmp 0,r1,r3 /* Found entry yet? */
- bdne 10b /* Jump back if not, until CTR==0 */
+ bdnzf 2,10b /* Jump back if not, until CTR==0 */
bne 30f /* Try secondary hash if CTR==0 */
lwz r1,4(r2) /* Get second word of entry */
-#if 0
- andi. r3,r1,0x08 /* Check guard bit - invalid access if set */
- bne InstructionFetchError
-#endif
- andi. r3,r1,0x100 /* Check R bit (referenced) */
- bne 20f /* If set, all done */
- ori r1,r1,0x100 /* Set bit */
- stw r1,4(r2) /* Update memory image */
20: mtctr r0 /* Restore CTR */
mfspr r3,SRR1 /* Need to restore CR0 */
mtcrf 0x80,r3
mfspr r0,IMISS /* Set to update TLB */
mtspr RPA,r1
tlbli r0
-#if 0
- SYNC
-#endif
rfi /* All done */
/* Secondary hash */
30: andi. r1,r3,0x40 /* Already doing secondary hash? */
bne InstructionAddressInvalid /* Yes - item not in hash table */
mfspr r2,HASH2 /* Get hash table pointer */
ori r3,r3,0x40 /* Set secondary hash */
- b 00b /* Try lookup again */
+ b 00b /* Try lookup again */
+InstructionAddressInvalid:
+ mfspr r3,SRR1
+ rlwinm r1,r3,9,6,6 /* Get load/store bit */
+ addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
+ mtspr DSISR,r1
+ mtctr r0 /* Restore CTR */
+ andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */
+ or r2,r2,r1
+ mtspr SRR1,r2
+ mfspr r1,IMISS /* 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 DAR,r1 /* Set fault address */
+ mfmsr r0 /* Restore "normal" registers */
+ xoris r0,r0,MSR_TGPR>>16
+ mtcrf 0x80,r3 /* Restore CR0 */
+ sync /* Some chip revs have problems here... */
+ mtmsr r0
+ b InstructionAccess
/*
- * Handle TLB miss for DATA Load operation
- */
+ * Handle TLB miss for DATA Load operation on 603/603e
+ */
+ . = 0x1100
DataLoadTLBMiss:
mfctr r0 /* Need to save this - CTR can't be touched! */
mfspr r2,HASH1 /* Get PTE pointer */
@@ -1120,36 +475,47 @@ DataLoadTLBMiss:
subi r2,r2,8 /* Preset pointer */
10: lwzu r1,8(r2) /* Get next PTE */
cmp 0,r1,r3 /* Found entry yet? */
- bdne 10b /* Jump back if not, until CTR==0 */
+ bdnzf 2,10b /* Jump back if not, until CTR==0 */
bne 30f /* Try secondary hash if CTR==0 */
lwz r1,4(r2) /* Get second word of entry */
- andi. r3,r1,0x100 /* Check R bit (referenced) */
- ori r1,r1,0x100 /* Set bit */
- bne 20f /* If set, all done */
- stw r1,4(r2) /* Update memory image */
20: mtctr r0 /* Restore CTR */
mfspr r3,SRR1 /* Need to restore CR0 */
mtcrf 0x80,r3
mfspr r0,DMISS /* Set to update TLB */
mtspr RPA,r1
-/* SYNC() */
tlbld r0
-#if 0
- SYNC
-#endif
rfi /* All done */
/* Secondary hash */
30: andi. r1,r3,0x40 /* Already doing secondary hash? */
bne DataAddressInvalid /* Yes - item not in hash table */
mfspr r2,HASH2 /* Get hash table pointer */
ori r3,r3,0x40 /* Set secondary hash */
- b 00b /* Try lookup again */
+ b 00b /* Try lookup again */
+DataAddressInvalid:
+ mfspr r3,SRR1
+ rlwinm r1,r3,9,6,6 /* Get load/store bit */
+ addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
+ mtspr DSISR,r1
+ mtctr r0 /* Restore CTR */
+ andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */
+ mtspr SRR1,r2
+ mfspr r1,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 DAR,r1 /* Set fault address */
+ mfmsr r0 /* Restore "normal" registers */
+ xoris r0,r0,MSR_TGPR>>16
+ mtcrf 0x80,r3 /* Restore CR0 */
+ sync /* Some chip revs have problems here... */
+ mtmsr r0
+ b DataAccess
/*
- * Handle TLB miss for DATA STORE
+ * Handle TLB miss for DATA Store on 603/603e
*/
+ . = 0x1200
DataStoreTLBMiss:
- BUMP_UNMAPPED(__DataStore_TLB_Misses)
mfctr r0 /* Need to save this - CTR can't be touched! */
mfspr r2,HASH1 /* Get PTE pointer */
mfspr r3,DCMP /* Partial item compare value */
@@ -1158,26 +524,15 @@ DataStoreTLBMiss:
subi r2,r2,8 /* Preset pointer */
10: lwzu r1,8(r2) /* Get next PTE */
cmp 0,r1,r3 /* Found entry yet? */
- bdne 10b /* Jump back if not, until CTR==0 */
+ bdnzf 2,10b /* Jump back if not, until CTR==0 */
bne 30f /* Try secondary hash if CTR==0 */
lwz r1,4(r2) /* Get second word of entry */
- andi. r3,r1,0x80 /* Check C bit (changed) */
-#if 0 /* Note: no validation */
- beq 40f /* If not set (first time) validate access */
-#else
- ori r1,r1,0x180 /* Set changed, accessed */
- bne 20f
- stw r1,4(r2)
-#endif
20: mtctr r0 /* Restore CTR */
mfspr r3,SRR1 /* Need to restore CR0 */
mtcrf 0x80,r3
mfspr r0,DMISS /* Set to update TLB */
mtspr RPA,r1
tlbld r0
-#if 0
- SYNC
-#endif
rfi /* All done */
/* Secondary hash */
30: andi. r1,r3,0x40 /* Already doing secondary hash? */
@@ -1185,229 +540,980 @@ DataStoreTLBMiss:
mfspr r2,HASH2 /* Get hash table pointer */
ori r3,r3,0x40 /* Set secondary hash */
b 00b /* Try lookup again */
-/* PTE found - validate access */
-40: rlwinm. r3,r1,30,0,1 /* Extract PP bits */
- bge- 50f /* Jump if PP=0,1 */
- andi. r3,r1,1
- beq+ 70f /* Access OK */
- b WriteProtectError /* Not OK - fail! */
-50: mfspr r3,SRR1 /* Check privilege */
- andi. r3,r3,MSR_PR
- beq+ 60f /* Jump if supervisor mode */
- mfspr r3,DMISS /* Get address */
- mfsrin r3,r3 /* Get segment register */
- andis. r3,r3,0x2000 /* If Kp==0, OK */
- beq+ 70f
- b WriteProtectError /* Bad access */
-60: mfspr r3,DMISS /* Get address */
- mfsrin r3,r3 /* Get segment register */
- andis. r3,r3,0x4000 /* If Ks==0, OK */
- beq+ 70f
- b WriteProtectError /* Bad access */
-70: ori r1,r1,0x180 /* Set changed, accessed */
- stw r1,4(r2) /* Update PTE in memory */
- b 20b
-
+
+/* Instruction address breakpoint exception (on 603/604) */
+ STD_EXCEPTION(0x1300, Trap_13, InstructionBreakpoint)
+
+/* System management exception (603?) */
+ STD_EXCEPTION(0x1400, Trap_14, UnknownException)
+
+ STD_EXCEPTION(0x1500, Trap_15, UnknownException)
+ STD_EXCEPTION(0x1600, Trap_16, UnknownException)
+ STD_EXCEPTION(0x1700, Trap_17, UnknownException)
+ STD_EXCEPTION(0x1800, Trap_18, UnknownException)
+ STD_EXCEPTION(0x1900, Trap_19, UnknownException)
+ STD_EXCEPTION(0x1a00, Trap_1a, UnknownException)
+ STD_EXCEPTION(0x1b00, Trap_1b, UnknownException)
+ STD_EXCEPTION(0x1c00, Trap_1c, UnknownException)
+ STD_EXCEPTION(0x1d00, Trap_1d, UnknownException)
+ STD_EXCEPTION(0x1e00, Trap_1e, UnknownException)
+ STD_EXCEPTION(0x1f00, Trap_1f, UnknownException)
+
+/* Run mode exception */
+ STD_EXCEPTION(0x2000, RunMode, RunModeException)
+
+ STD_EXCEPTION(0x2100, Trap_21, UnknownException)
+ STD_EXCEPTION(0x2200, Trap_22, UnknownException)
+ STD_EXCEPTION(0x2300, Trap_23, UnknownException)
+ STD_EXCEPTION(0x2400, Trap_24, UnknownException)
+ STD_EXCEPTION(0x2500, Trap_25, UnknownException)
+ STD_EXCEPTION(0x2600, Trap_26, UnknownException)
+ STD_EXCEPTION(0x2700, Trap_27, UnknownException)
+ STD_EXCEPTION(0x2800, Trap_28, UnknownException)
+ STD_EXCEPTION(0x2900, Trap_29, UnknownException)
+ STD_EXCEPTION(0x2a00, Trap_2a, UnknownException)
+ STD_EXCEPTION(0x2b00, Trap_2b, UnknownException)
+ STD_EXCEPTION(0x2c00, Trap_2c, UnknownException)
+ STD_EXCEPTION(0x2d00, Trap_2d, UnknownException)
+ STD_EXCEPTION(0x2e00, Trap_2e, UnknownException)
+ STD_EXCEPTION(0x2f00, Trap_2f, UnknownException)
+
+ . = 0x3000
+
/*
- * These routines are error paths/continuations of the exception
- * handlers above. They are placed here to avoid the problems
- * of only 0x100 bytes per exception handler.
+ * This code finishes saving the registers to the exception frame
+ * and jumps to the appropriate handler for the exception, turning
+ * on address translation.
*/
-
-/* Invalid address */
-InstructionAddressInvalid:
- mfspr r3,SRR1
- rlwinm r1,r3,9,6,6 /* Get load/store bit */
- addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
- b 10f
+ .globl transfer_to_handler
+transfer_to_handler:
+ stw r22,_NIP(r21)
+ stw r23,_MSR(r21)
+ SAVE_GPR(7, r21)
+ SAVE_4GPRS(8, r21)
+ SAVE_8GPRS(12, r21)
+ SAVE_8GPRS(24, r21)
+ andi. r23,r23,MSR_PR
+ mfspr r23,SPRG3 /* if from user, fix up tss */
+ beq 2f
+#ifdef CONFIG_PMAC
+ lwz r24,GPR1(r21)
+ stw r22,LAST_PC(r23)
+ stw r24,USER_STACK(r23)
+#endif /* CONFIG_PMAC */
+ addi r24,r1,STACK_FRAME_OVERHEAD
+ stw r24,PT_REGS(r23)
+2: addi r2,r23,-TSS /* set r2 to current */
+ addis r2,r2,KERNELBASE@h
+ mflr r23
+ andi. r24,r23,0x3f00 /* get vector offset */
+ stw r24,TRAP(r21)
+ li r22,0
+ stw r22,RESULT(r21)
+ lwz r24,0(r23) /* virtual address of handler */
+ lwz r23,4(r23) /* where to go when done */
+ mtspr SRR0,r24
+ mtspr SRR1,r20
+ mtlr r23
+ SYNC
+ rfi /* jump to handler, enable MMU */
-/* Fetch from guarded or no-access page */
-InstructionFetchError:
- mfspr r3,SRR1
- rlwinm r1,r3,9,6,6 /* Get load/store bit */
- addis r1,r1,0x0800 /* Set bit 4 -> protection error */
-10: mtspr DSISR,r1
- mtctr r0 /* Restore CTR */
- andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */
- mtspr SRR1,r2
- mfspr r1,IMISS /* 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 DAR,r1 /* Set fault address */
- mfmsr r0 /* Restore "normal" registers */
- xoris r0,r0,MSR_TGPR>>16
- mtcrf 0x80,r3 /* Restore CR0 */
- ori r0,r0,MSR_FP /* Need to keep FP enabled */
- sync /* Some chip revs have problems here... */
- mtmsr r0
- b InstructionAccess
+/*
+ * Continuation of the floating-point unavailable handler.
+ */
+load_up_fpu:
+ bl giveup_fpu_unmapped
+ ori r23,r23,MSR_FP /* enable use of FP after return */
+ mfspr r5,SPRG3 /* current task's TSS (phys) */
+ lfd fr0,TSS_FPSCR-4(r5)
+ mtfsf 0xff,fr0
+ REST_32FPRS(0, r5)
+
+/* use last_task_used_math instead of fpu_tss */
+ lis r3,last_task_used_math@h/*a*/
+ addis r3,r3,-KERNELBASE@h
+ subi r4,r5,TSS
+ addis r4,r4,KERNELBASE@h
+ stw r4,last_task_used_math@l(r3)
+#if 0
+ lis r3,fpu_tss@ha
+ addis r4,r5,KERNELBASE@h
+ addis r3,r3,-KERNELBASE@h
+ stw r4,fpu_tss@l(r3)
+#endif
+ /* restore registers and return */
+ lwz r3,_CCR(r21)
+ lwz r4,_LINK(r21)
+ mtcrf 0xff,r3
+ mtlr r4
+ REST_GPR(1, r21)
+ REST_4GPRS(3, r21)
+ /* we haven't used ctr or xer */
+ mtspr SRR1,r23
+ mtspr SRR0,r22
+ REST_GPR(20, r21)
+ REST_2GPRS(22, r21)
+ lwz r21,GPR21(r21)
+ SYNC
+ rfi
-/* Invalid address */
-DataAddressInvalid:
- mfspr r3,SRR1
- rlwinm r1,r3,9,6,6 /* Get load/store bit */
- addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
- b 10f
+/*
+ * Load a PTE into the hash table, if possible.
+ * The address is in r3, and r4 contains access flags:
+ * _PAGE_USER (4) if a user-mode access, ored with
+ * _PAGE_RW (2) if a write. r20 contains DSISR or SRR1,
+ * so bit 1 (0x40000000) is set if the exception was due
+ * to no matching PTE being found in the hash table.
+ * r5 contains the physical address of the current task's tss.
+ *
+ * Returns to the caller if the access is illegal or there is no
+ * mapping for the address. Otherwise it places an appropriate PTE
+ * in the hash table and returns from the exception.
+ * Uses r0, r2 - r6, ctr, lr.
+ *
+ * For speed, 4 of the instructions get patched once the size and
+ * physical address of the hash table are known. These definitions
+ * of Hash_base and Hash_bits below are just an example.
+ */
+Hash_base = 0x180000
+Hash_bits = 12 /* e.g. 256kB hash table */
+Hash_msk = (((1 << Hash_bits) - 1) * 64)
+
+ .globl hash_page
+hash_page:
+ /* Get PTE (linux-style) and check access */
+ lwz r5,PG_TABLES(r5) /* task's page tables */
+ lis r2,-KERNELBASE@h
+ add r5,r5,r2 /* convert to phys addr */
+ rlwimi r5,r3,12,20,29 /* insert top 10 bits of address */
+ lwz r5,0(r5) /* get pmd entry */
+ rlwinm. r5,r5,0,0,19 /* extract address of pte page */
+ beqlr- /* return if no mapping */
+ add r2,r5,r2
+ rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */
+ lwz r6,0(r2) /* get linux-style pte */
+ ori r4,r4,1 /* set _PAGE_PRESENT bit in access */
+ andc. r0,r4,r6 /* check access & ~permission */
+ bnelr- /* return if access not permitted */
+ ori r6,r6,0x100 /* set _PAGE_ACCESSED in pte */
+ rlwinm r5,r4,5,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */
+ rlwimi r5,r4,7,22,22 /* _PAGE_RW -> _PAGE_HWWRITE */
+ or r6,r6,r5
+ stw r6,0(r2) /* update PTE (accessed/dirty bits) */
+
+ /* Convert linux-style PTE to low word of PPC-style PTE */
+ rlwinm r4,r6,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */
+ rlwimi r6,r6,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */
+ ori r4,r4,0xe04 /* clear out reserved bits */
+ andc r6,r6,r4 /* PP=2 or 0, when _PAGE_HWWRITE */
+
+ /* Construct the high word of the PPC-style PTE */
+ mfsrin r5,r3 /* get segment reg for segment */
+ rlwinm r5,r5,7,1,24 /* put VSID in 0x7fffff80 bits */
+ oris r5,r5,0x8000 /* set V (valid) bit */
+ rlwimi r5,r3,10,26,31 /* put in API (abbrev page index) */
+
+ /* Get the address of the primary PTE group in the hash table */
+ .globl hash_page_patch_A
+hash_page_patch_A:
+ lis r4,Hash_base@h /* base address of hash table */
+ rlwimi r4,r5,32-1,26-Hash_bits,25 /* (VSID & hash_mask) << 6 */
+ rlwinm r0,r3,32-6,26-Hash_bits,25 /* (PI & hash_mask) << 6 */
+ xor r4,r4,r0 /* make primary hash */
+
+ /* See whether it was a PTE not found exception or a
+ protection violation. */
+ andis. r0,r20,0x4000
+ li r2,8 /* PTEs/group */
+ bne 10f /* no PTE: go look for an empty slot */
+ tlbie r3 /* invalidate TLB entry */
+
+ /* Search the primary PTEG for a PTE whose 1st word matches r5 */
+ mtctr r2
+ addi r3,r4,-8
+1: lwzu r0,8(r3) /* get next PTE */
+ cmp 0,r0,r5
+ bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */
+ beq+ found_slot
+
+ /* Search the secondary PTEG for a matching PTE */
+ ori r5,r5,0x40 /* set H (secondary hash) bit */
+ .globl hash_page_patch_B
+hash_page_patch_B:
+ xoris r3,r4,Hash_msk>>16 /* compute secondary hash */
+ xori r3,r3,0xffc0
+ addi r3,r3,-8
+ mtctr r2
+2: lwzu r0,8(r3)
+ cmp 0,r0,r5
+ bdnzf 2,2b
+ beq+ found_slot
+ xori r5,r5,0x40 /* clear H bit again */
+
+ /* Search the primary PTEG for an empty slot */
+10: mtctr r2
+ addi r3,r4,-8 /* search primary PTEG */
+1: lwzu r0,8(r3) /* get next PTE */
+ cmpi 0,r0,0 /* empty? */
+ bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */
+ beq+ found_empty
+
+ /* Search the secondary PTEG for an empty slot */
+ ori r5,r5,0x40 /* set H (secondary hash) bit */
+ .globl hash_page_patch_C
+hash_page_patch_C:
+ xoris r3,r4,Hash_msk>>16 /* compute secondary hash */
+ xori r3,r3,0xffc0
+ addi r3,r3,-8
+ mtctr r2
+2: lwzu r0,8(r3)
+ cmpi 0,r0,0
+ bdnzf 2,2b
+ beq+ found_empty
+
+ /* Choose an arbitrary slot in the primary PTEG to overwrite */
+ xori r5,r5,0x40 /* clear H bit again */
+ lwz r2,next_slot@l(0)
+ addi r2,r2,8
+ andi. r2,r2,0x38
+ stw r2,next_slot@l(0)
+ add r3,r4,r2
+
+ /* Store PTE in PTEG */
+found_empty:
+ stw r5,0(r3)
+found_slot:
+ stw r6,4(r3)
+ SYNC
+ /* Return from the exception */
+ lwz r3,_CCR(r21)
+ lwz r4,_LINK(r21)
+ lwz r5,_CTR(r21)
+ mtcrf 0xff,r3
+ mtlr r4
+ mtctr r5
+ REST_GPR(0, r21)
+ REST_2GPRS(1, r21)
+ REST_4GPRS(3, r21)
+ /* we haven't used xer */
+ mtspr SRR1,r23
+ mtspr SRR0,r22
+ REST_GPR(20, r21)
+ REST_2GPRS(22, r21)
+ lwz r21,GPR21(r21)
+ SYNC
+ rfi
-/* Write to read-only space */
-WriteProtectError:
- mfspr r3,SRR1
- rlwinm r1,r3,9,6,6 /* Get load/store bit */
- addis r1,r1,0x0800 /* Set bit 4 -> protection error */
-10: mtspr DSISR,r1
- mtctr r0 /* Restore CTR */
- andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */
- mtspr SRR1,r2
- mfspr r1,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 DAR,r1 /* Set fault address */
- mfmsr r0 /* Restore "normal" registers */
- xoris r0,r0,MSR_TGPR>>16
- mtcrf 0x80,r3 /* Restore CR0 */
- ori r0,r0,MSR_FP /* Need to keep FP enabled */
- sync /* Some chip revs have problems here... */
- mtmsr r0
- b DataAccess
+next_slot:
+ .long 0
/*
- * Flush instruction cache
- * *** I'm really paranoid here!
+ * This is where the main kernel code starts.
*/
-_GLOBAL(flush_instruction_cache)
- mflr r5
- bl _EXTERN(flush_data_cache)
- mfspr r3,HID0 /* Caches are controlled by this register */
+
+start_here:
+ /*
+ * Enable caches and 604-specific features if necessary.
+ */
+ mfspr r9,PVR
+ rlwinm r9,r9,16,16,31
+ cmpi 0,r9,1
+ beq 4f /* not needed for 601 */
+ mfspr r7,HID0
+ andi. r0,r7,HID0_DCE
+ ori r7,r7,HID0_ICE|HID0_DCE
+ ori r8,r7,HID0_ICFI
+ bne 3f /* don't invalidate the D-cache */
+ ori r8,r8,HID0_DCI /* unless it wasn't enabled */
+3: sync
+ mtspr HID0,r8 /* enable and invalidate caches */
+ sync
+ mtspr HID0,r7 /* enable caches */
+ sync
+ isync
+ cmpi 0,r9,4 /* check for 604 */
+ cmpi 1,r9,9 /* or 604e */
+ cror 2,2,6
+ bne 4f
+ ori r7,r7,HID0_SIED|HID0_BHTE /* for 604[e], enable */
+ mtspr HID0,r7 /* superscalar exec & br history tbl */
+4:
+ /* ptr to current */
+ lis r2,init_task_union@h
+ ori r2,r2,init_task_union@l
+ /* ptr to phys current tss */
+ addis r3,r2,-KERNELBASE@h
+ addi r3,r3,TSS /* init task's TSS */
+ mtspr SPRG3,r3
+ /* stack */
+ addi r1,r2,TASK_UNION_SIZE
+ li r0,0
+ stwu r0,-STACK_FRAME_OVERHEAD(r1)
+
+ /* Clear out the BSS */
+ 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
+ rlwinm. r7,r7,30,2,31
+ beq 2f
+ addi r8,r8,-4
+ mtctr r7
+ li r0,0
+3: stwu r0,4(r8)
+ bdnz 3b
+2:
+/*
+ * Initialize the prom stuff (powermacs only) and the MMU.
+ */
+#ifdef CONFIG_PMAC
+ bl prom_init
+#endif /* CONFIG_PMAC */
+ 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 r6,_SDR1@ha
+ lwz r6,_SDR1@l(r6)
+ li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
+ lis r4,2f@h
+ addis r4,r4,-KERNELBASE@h
+ ori r4,r4,2f@l
+ mtspr SRR0,r4
+ mtspr SRR1,r3
+ rfi
+/* Load up the kernel context */
+2:
+#ifdef CONFIG_PREP
+ /* reload the bats now that MMU_init() has setup them up -- Cort */
+ LOAD_BATS(r3,r0)
+#endif
+
+ SYNC /* Force all PTE updates to finish */
+ tlbia /* Clear all TLB entries */
+ mtspr 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
- ori r4,r4,(HID0_ICE|HID0_ICFI)
- or r3,r3,r4 /* Need to enable+invalidate to clear */
- mtspr HID0,r3
- andc r3,r3,r4
- ori r3,r3,HID0_ICE /* Enable cache */
- mtspr HID0,r3
- mtlr r5
- blr
+3: mtsrin r3,r4
+ addi r3,r3,1 /* increment VSID */
+ addis r4,r4,0x1000 /* address of next segment */
+ bdnz 3b
+#ifdef CONFIG_PMAC
+ li r0,0 /* zot the BATs */
+#if 1
+ mtspr IBAT0U,r0
+ mtspr IBAT0L,r0
+ mtspr DBAT0U,r0
+ mtspr DBAT0L,r0
+#endif
+ mtspr IBAT1U,r0
+ mtspr IBAT1L,r0
+ mtspr DBAT1U,r0
+ mtspr DBAT1L,r0
+ mtspr IBAT2U,r0
+ mtspr IBAT2L,r0
+ mtspr DBAT2U,r0
+ mtspr DBAT2L,r0
+ mtspr IBAT3U,r0
+ mtspr IBAT3L,r0
+ mtspr DBAT3U,r0
+ mtspr DBAT3L,r0
+#endif
+/* Now turn on the MMU for real! */
+ li r4,MSR_KERNEL
+ lis r3,start_kernel@h
+ ori r3,r3,start_kernel@l
+ mtspr SRR0,r3
+ mtspr SRR1,r4
+ rfi /* enable MMU and jump to start_kernel */
+#ifdef CONFIG_PREP
/*
- * Flush data cache
- * *** I'm really paranoid here!
+ * 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: End of image
+ * R4: Start of image - 0x400
+ * R11: Start of command line string
+ * R12: 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
*/
-_GLOBAL(flush_data_cache)
- BUMP(__Cache_Flushes)
- lis r3,cache_is_copyback@ha
- lwz r3,cache_is_copyback@l(r3)
- cmpi 0,r3,0
- beq 10f
-/* When DATA CACHE is copy-back */
- lis r3,cache_flush_buffer@h
- ori r3,r3,cache_flush_buffer@l
- li r4,NUM_CACHE_LINES
- mtctr r4
-00: dcbz 0,r3 /* Flush cache line with minimal BUS traffic */
- addi r3,r3,CACHE_LINE_SIZE /* Next line, please */
- bdnz 00b
-10: blr
+ .globl __start
+__start:
+ .globl _start
+_start:
+ lis r7,0xF000 /* To mask upper 4 bits */
+/* save pointer to residual data */
+ lis r1,resptr@h
+ ori r1,r1,resptr@l
+ addis r1,r1,-KERNELBASE@h
+ stw r3,0(r1)
+/* save argument string */
+ li r0,0 /* Null terminate string */
+ stb r0,0(r12)
+ lis r1,cmd_line@h
+ ori r1,r1,cmd_line@l
+ addis r1,r1,-KERNELBASE@h
+ subi r1,r1,1
+ subi r11,r11,1
+00: lbzu r0,1(r11)
+ cmpi 0,r0,0
+ stbu r0,1(r1)
+ bne 00b
+/* setup the msr with sane values */
+ li r0,MSR_
+ mtmsr r0
+/* turn on the mmu with bats covering kernel enough to get started */
+ LOAD_BATS(r3,r0)
+ mfmsr r3
+ ori r3,r3,MSR_DR|MSR_IR
+ mtspr SRR1,r3
+ lis r3,10f@h
+ ori r3,r3,10f@l
+ mtspr SRR0,r3
+ SYNC
+ rfi /* enables MMU */
+10: lis r7,start_here@ha /* jump up to our copy at KERNELBASE */
+ addi r7,r7,start_here@l
+ mtlr r7
+ blr
+#endif /* CONFIG_PREP */
+
+/*
+ * FP unavailable trap from kernel - print a message, but let
+ * the task use FP in the kernel until it returns to user mode.
+ */
+KernelFP:
+ lwz r3,_MSR(r1)
+ ori r3,r3,MSR_FP
+ stw r3,_MSR(r1) /* enable use of FP after return */
+ lis r3,86f@h
+ ori r3,r3,86f@l
+ mr r4,r2 /* current */
+ lwz r5,_NIP(r1)
+ bl printk
+ b int_return
+86: .string "floating point used in kernel (task=%p, pc=%x)\n"
+ .align 4
/*
- * Flush a particular page from the DATA cache
- * Note: this is necessary because the instruction cache does *not*
- * snoop from the data cache.
- * void flush_page(void *page)
+ * Disable FP for the task which had the FPU previously,
+ * and save its floating-point registers in its thread_struct.
+ * Enables the FPU for use in the kernel on return.
+ * (If giveup_fpu_unmapped uses any integer registers other than
+ * r3 - r6, the return code at load_up_fpu above will have
+ * to be adjusted.)
*/
-_GLOBAL(flush_page)
- li r4,0x0FFF
- andc r3,r3,r4 /* Get page base address */
- li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
- mtctr r4
-00: dcbf 0,r3 /* Clear line */
- icbi 0,r3
- addi r3,r3,CACHE_LINE_SIZE
- bdnz 00b
+giveup_fpu_unmapped:
+ lis r6,-KERNELBASE@h
+ b 1f
+
+ .globl giveup_fpu
+giveup_fpu:
+ li r6,0
+1:
+ addis r3,r6,last_task_used_math@h/*a*/
+ lwz r4,last_task_used_math@l(r3)
+#if 0
+ addis r3,r6,fpu_tss@ha
+ lwz r4,fpu_tss@l(r3)
+#endif
+ mfmsr r5
+ ori r5,r5,MSR_FP
+ SYNC
+ mtmsr r5 /* enable use of fpu now */
+ SYNC
+ cmpi 0,r4,0
+ add r4,r4,r6
+ beqlr /* if no previous owner, done */
+ addi r4,r4,TSS /* want TSS of last_task_used_math */
+ li r5,0
+ stw r5,last_task_used_math@l(r3)
+#if 0
+ stw r5,fpu_tss@l(r3)
+#endif
+ SAVE_32FPRS(0, r4)
+ mffs fr0
+ stfd fr0,TSS_FPSCR-4(r4)
+ lwz r5,PT_REGS(r4)
+ lwz r5,PT_REGS(r4)
+ add r5,r5,r6
+ lwz r3,_MSR-STACK_FRAME_OVERHEAD(r5)
+ li r4,MSR_FP
+ andc r3,r3,r4 /* disable FP for previous task */
+ stw r3,_MSR-STACK_FRAME_OVERHEAD(r5)
blr
/*
+ * Handle a system call.
+ */
+DoSyscall:
+ stw r0,TSS+LAST_SYSCALL(r2)
+ lwz r11,_CCR(r1) /* Clear SO bit in CR */
+ lis r10,0x1000
+ andc r11,r11,r10
+ stw r11,_CCR(r1)
+#ifdef SHOW_SYSCALLS
+#ifdef SHOW_SYSCALLS_TASK
+ lis r31,show_syscalls_task@ha
+ lwz r31,show_syscalls_task@l(r31)
+ cmp 0,r2,r31
+ bne 1f
+#endif
+ 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)
+ mr r9,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)
+1:
+#endif /* SHOW_SYSCALLS */
+ cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */
+ beq- 10f
+ lwz r10,TASK_FLAGS(r2)
+ andi. r10,r10,PF_TRACESYS
+ bne- 50f
+ cmpli 0,r0,NR_syscalls
+ bge- 66f
+ lis r10,sys_call_table@h
+ ori r10,r10,sys_call_table@l
+ slwi r0,r0,2
+ lwzx r10,r10,r0 /* Fetch system call handler [ptr] */
+ cmpi 0,r10,0
+ beq- 66f
+ mtlr r10
+ addi r9,r1,STACK_FRAME_OVERHEAD
+ blrl /* Call handler */
+ .globl syscall_ret_1
+syscall_ret_1:
+20: stw r3,RESULT(r1) /* Save result */
+#ifdef SHOW_SYSCALLS
+#ifdef SHOW_SYSCALLS_TASK
+ cmp 0,r2,r31
+ bne 91f
+#endif
+ mr r4,r3
+ lis r3,79f@ha
+ addi r3,r3,79f@l
+ bl printk
+ lwz r3,RESULT(r1)
+91:
+#endif
+ li r10,-_LAST_ERRNO
+ cmpl 0,r3,r10
+ blt 30f
+ neg r3,r3
+ cmpi 0,r3,ERESTARTNOHAND
+ bne 22f
+ li r3,EINTR
+22: lwz r10,_CCR(r1) /* Set SO bit in CR */
+ oris r10,r10,0x1000
+ stw r10,_CCR(r1)
+30: stw r3,GPR3(r1) /* Update return value */
+ b int_return
+66: li r3,ENOSYS
+ b 22b
+/* sys_sigreturn */
+10: addi r3,r1,STACK_FRAME_OVERHEAD
+ bl _EXTERN(sys_sigreturn)
+ cmpi 0,r3,0 /* Check for restarted system call */
+ bge int_return
+ b 20b
+/* Traced system call support */
+50: bl _EXTERN(syscall_trace)
+ 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)
+ lwz r9,GPR9(r1)
+ cmpli 0,r0,NR_syscalls
+ bge- 66f
+ lis r10,sys_call_table@h
+ ori r10,r10,sys_call_table@l
+ slwi r0,r0,2
+ lwzx r10,r10,r0 /* Fetch system call handler [ptr] */
+ cmpi 0,r10,0
+ beq- 66f
+ mtlr r10
+ addi r9,r1,STACK_FRAME_OVERHEAD
+ blrl /* Call handler */
+ .globl syscall_ret_2
+syscall_ret_2:
+ stw r3,RESULT(r1) /* Save result */
+ stw r3,GPR0(r1) /* temporary gross hack to make strace work */
+ li r10,-_LAST_ERRNO
+ cmpl 0,r3,r10
+ blt 60f
+ neg r3,r3
+ cmpi 0,r3,ERESTARTNOHAND
+ bne 52f
+ li r3,EINTR
+52: lwz r10,_CCR(r1) /* Set SO bit in CR */
+ oris r10,r10,0x1000
+ stw r10,_CCR(r1)
+60: stw r3,GPR3(r1) /* Update return value */
+ bl _EXTERN(syscall_trace)
+ b int_return
+66: li r3,ENOSYS
+ b 52b
+#ifdef SHOW_SYSCALLS
+7: .string "syscall %d(%x, %x, %x, %x), current=%p\n"
+79: .string " -> %x\n"
+ .align 2
+#endif
+
+/*
* 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, via the 'return'.
+ * Finally, we can return to the second process, via int_return.
+ * On entry, r3 points to the TSS for the current task, r4
+ * points to the TSS for the new task, and r5 contains the
+ * MMU context number for the new task.
*
* 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 (or in particular, the
- * SAVE_ALL_REGS macro), you'll have to change the fork code also.
+ * SAVE_REGS macro), 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)
- mtspr SPR0,r1 /* SAVE_ALL_REGS prologue */
- mtspr SPR1,r2
- mflr r2 /* Return to switch caller */
- mtspr SPR2,r2
- mfmsr r2
- mtspr SPR3,r2
- SAVE_ALL_REGS(0x0FF0)
- SAVE_FP_REGS()
- CHECK_STACK()
- SYNC()
+ stwu r1,-INT_FRAME_SIZE-STACK_UNDERHEAD(r1)
+ stw r0,GPR0(r1)
+ lwz r0,0(r1)
+ stw r0,GPR1(r1)
+ SAVE_10GPRS(2, r1)
+ SAVE_10GPRS(12, r1)
+ SAVE_10GPRS(22, r1)
+ mflr r20 /* Return to switch caller */
+ mfmsr r22
+ li r0,MSR_FP /* Disable floating-point */
+ andc r22,r22,r0
+ stw r20,_NIP(r1)
+ stw r22,_MSR(r1)
+ stw r20,_LINK(r1)
+ mfcr r20
+ mfctr r22
+ mfspr r23,XER
+ stw r20,_CCR(r1)
+ stw r22,_CTR(r1)
+ stw r23,_XER(r1)
+ li r0,0x0ff0
+ stw r0,TRAP(r1)
stw r1,KSP(r3) /* Set old stack pointer */
- BUMP(__Context_Switches)
+ sync
+ addis r0,r4,-KERNELBASE@h
+ mtspr SPRG3,r0 /* Update current TSS phys addr */
+ SYNC
lwz r1,KSP(r4) /* Load new stack pointer */
- lwz r0,MMU_SEG0(r4)
- mtsr SR0,r0
- lwz r0,MMU_SEG1(r4)
- mtsr SR1,r0
- lwz r0,MMU_SEG2(r4)
- mtsr SR2,r0
- lwz r0,MMU_SEG3(r4)
- mtsr SR3,r0
- lwz r0,MMU_SEG4(r4)
- mtsr SR4,r0
- lwz r0,MMU_SEG5(r4)
- mtsr SR5,r0
- lwz r0,MMU_SEG6(r4)
- mtsr SR6,r0
- lwz r0,MMU_SEG7(r4)
- mtsr SR7,r0
-#if 0
- /* segs 8-15 are shared by everyone -- don't need to be changed */
- lwz r0,MMU_SEG8(r4)
- mtsr SR8,r0
- lwz r0,MMU_SEG9(r4)
- mtsr SR9,r0
- lwz r0,MMU_SEG10(r4)
- mtsr SR10,r0
- lwz r0,MMU_SEG11(r4)
- mtsr SR11,r0
- lwz r0,MMU_SEG12(r4)
- mtsr SR12,r0
- lwz r0,MMU_SEG13(r4)
- mtsr SR13,r0
- lwz r0,MMU_SEG14(r4)
- mtsr SR14,r0
- lwz r0,MMU_SEG15(r4)
- mtsr SR15,r0
-#endif
- /* no need to invalidate tlb since each process has a distinct
- set of vsid's. -- Cort */
-#if 0
- tlbia /* Invalidate entire TLB */
- BUMP(__TLBIAs)
-#endif
- /* p5.2 603 users manual - with addr transl. enabled,
- the memory access is performed under the control of
- the page table entry. I interpret this to mean that
- it is tagged with the vsid -- so no need to flush here
- since each process has a distinct set of vsid's.
- Of course, my intepretation may be wrong.
- -- Cort */
- /*bl _EXTERN(flush_instruction_cache)*/
- RETURN_FROM_INT(0x0f0f)
-
+ addi r2,r4,-TSS /* Update current */
+ /* Set up segment registers for new task */
+ rlwinm r5,r5,4,8,27 /* VSID = context << 4 */
+ addis r5,r5,0x6000 /* Set Ks, Ku bits */
+ li r0,8 /* TASK_SIZE / SEGMENT_SIZE */
+ mtctr r0
+ li r3,0
+3: mtsrin r5,r3
+ addi r5,r5,1 /* next VSID */
+ addis r3,r3,0x1000 /* address of next segment */
+ bdnz 3b
+ SYNC
+
+/* FALL THROUGH into int_return */
+
+/*
+ * Trap exit.
+ */
+ .globl int_return
+int_return:
+0: mfmsr r30 /* Disable interrupts */
+ li r4,0
+ ori r4,r4,MSR_EE
+ andc r30,r30,r4
+ SYNC /* Some chip revs need this... */
+ mtmsr r30
+ SYNC
+ lwz r5,_MSR(r1)
+ and. r5,r5,r4
+ beq 2f
+3: lis r4,lost_interrupts@ha
+ lwz r4,lost_interrupts@l(r4)
+ cmpi 0,r4,0
+ beq+ 1f
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl handle_IRQ
+ b 3b
+1: lis r4,bh_mask@ha
+ lwz r4,bh_mask@l(r4)
+ lis r5,bh_active@ha
+ lwz r5,bh_active@l(r5)
+ and. r4,r4,r5
+ beq+ 2f
+ ori r31,r30,MSR_EE /* re-enable interrupts */
+ SYNC
+ mtmsr r31
+ SYNC
+ bl _EXTERN(do_bottom_half)
+ SYNC
+ mtmsr r30 /* disable interrupts again */
+ SYNC
+2: lwz r3,_MSR(r1) /* Returning to user mode? */
+ andi. r3,r3,MSR_PR
+ beq+ 10f /* no - no need to mess with stack */
+ lis r3,need_resched@ha
+ lwz r3,need_resched@l(r3)
+ cmpi 0,r3,0 /* check need_resched flag */
+ beq+ 7f
+ bl _EXTERN(schedule)
+ b 0b
+7: lwz r3,BLOCKED(r2) /* Check for pending unblocked signals */
+ lwz r5,SIGNAL(r2)
+ andc. r0,r5,r3 /* Lets thru any unblocked */
+ beq+ 8f
+ addi r4,r1,STACK_FRAME_OVERHEAD
+ bl _EXTERN(do_signal)
+ b 0b
+8: addi r4,r1,INT_FRAME_SIZE+STACK_UNDERHEAD /* size of frame */
+ stw r4,TSS+KSP(r2) /* save kernel stack pointer */
+10:
+ lwz r2,_CTR(r1)
+ lwz r0,_LINK(r1)
+ mtctr r2
+ mtlr r0
+ lwz r2,_XER(r1)
+ lwz r0,_CCR(r1)
+ mtspr XER,r2
+ mtcrf 0xFF,r0
+ REST_10GPRS(3, r1)
+ REST_10GPRS(13, r1)
+ REST_8GPRS(23, r1)
+ REST_GPR(31, r1)
+ lwz r2,_NIP(r1) /* Restore environment */
+ lwz r0,_MSR(r1)
+ mtspr SRR0,r2
+ mtspr SRR1,r0
+ lwz r0,GPR0(r1)
+ lwz r2,GPR2(r1)
+ lwz r1,GPR1(r1)
+ SYNC
+ rfi
+
+/*
+ * Fake an interrupt from kernel mode.
+ * This is used when enable_irq loses an interrupt.
+ * We only fill in the stack frame minimally.
+ */
+_GLOBAL(fake_interrupt)
+ mflr r0
+ stw r0,4(r1)
+ stwu r1,-INT_FRAME_SIZE-STACK_UNDERHEAD(r1)
+ stw r0,_NIP(r1)
+ stw r0,_LINK(r1)
+ mfmsr r3
+ stw r3,_MSR(r1)
+ li r0,0x0fac
+ stw r0,TRAP(r1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl handle_IRQ
+ addi r1,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
+ lwz r0,4(r1)
+ mtlr r0
+ blr
+
+/*
+ * Set up the segment registers for a new context.
+ */
+_GLOBAL(set_context)
+ rlwinm r3,r3,4,8,27 /* VSID = context << 4 */
+ addis r3,r3,0x6000 /* Set Ks, Ku bits */
+ li r0,8 /* TASK_SIZE / SEGMENT_SIZE */
+ mtctr r0
+ li r4,0
+3: mtsrin r3,r4
+ addi r3,r3,1 /* next VSID */
+ addis r4,r4,0x1000 /* address of next segment */
+ bdnz 3b
+ SYNC
+ blr
+
+/*
+ * Flush instruction cache.
+ * This is a no-op on the 601.
+ */
+_GLOBAL(flush_instruction_cache)
+ mfspr r3,PVR
+ rlwinm r3,r3,16,16,31
+ cmpi 0,r3,1
+ beqlr /* for 601, do nothing */
+ /* 603/604 processor - use invalidate-all bit in HID0 */
+ mfspr r3,HID0
+ ori r3,r3,HID0_ICFI
+ mtspr HID0,r3
+ SYNC
+ 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.
+ *
+ * store_cache_range(unsigned long start, unsigned long stop)
+ */
+CACHE_LINE_SIZE = 32
+LG_CACHE_LINE_SIZE = 5
+_GLOBAL(store_cache_range)
+ mfspr r5,PVR
+ rlwinm r5,r5,16,16,31
+ cmpi 0,r5,1
+ beqlr /* for 601, do nothing */
+ li r5,CACHE_LINE_SIZE-1
+ andc r3,r3,r5
+ subf r4,r3,r4
+ add r4,r4,r5
+ srwi. r4,r4,LG_CACHE_LINE_SIZE
+ beqlr
+ mtctr r4
+ mr r6,r3
+1: dcbst 0,r3
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 1b
+ sync /* wait for dcbst's to get to ram */
+ mtctr r4
+2: icbi 0,r6
+ addi r6,r6,CACHE_LINE_SIZE
+ bdnz 2b
+ sync
+ isync
+ blr
+
+/*
+ * Flush a particular page from the DATA cache
+ * 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_page_to_ram(void *page)
+ */
+_GLOBAL(flush_page_to_ram)
+ mfspr r5,PVR
+ rlwinm r5,r5,16,16,31
+ cmpi 0,r5,1
+ beqlr /* for 601, do nothing */
+ li r4,0x0FFF
+ andc r3,r3,r4 /* Get page base address */
+ li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
+ mtctr r4
+ mr r6,r3
+0: dcbst 0,r3 /* Write line to ram */
+ addi r3,r3,CACHE_LINE_SIZE
+ bdnz 0b
+ sync
+ mtctr r4
+1: icbi 0,r6
+ addi r6,r6,CACHE_LINE_SIZE
+ bdnz 1b
+ sync
+ isync
+ blr
+
+/*
+ * Flush entries from the hash table with VSIDs in the range
+ * given.
+ */
+_GLOBAL(flush_hash_segments)
+ rlwinm r3,r3,7,1,24 /* put VSID lower limit in position */
+ oris r3,r3,0x8000 /* set V bit */
+ rlwinm r4,r4,7,1,24 /* put VSID upper limit in position */
+ oris r4,r4,0x8000
+ ori r4,r4,0x7f
+ lis r5,Hash@ha
+ lwz r5,Hash@l(r5) /* base of hash table */
+ lis r6,Hash_size@ha
+ lwz r6,Hash_size@l(r6) /* size in bytes */
+ srwi r6,r6,3 /* # PTEs */
+ mtctr r6
+ addi r5,r5,-8
+ li r0,0
+1: lwzu r6,8(r5) /* get next tag word */
+ cmplw 0,r6,r3
+ cmplw 1,r6,r4
+ cror 0,0,5 /* set cr0.lt if out of range */
+ blt 2f /* branch if out of range */
+ stw r0,0(r5) /* invalidate entry */
+2: bdnz 1b /* continue with loop */
+ sync
+ tlbia
+ isync
+ blr
+
+/*
+ * Flush the entry for a particular page from the hash table.
+ *
+ * flush_hash_page(unsigned context, unsigned long va)
+ */
+_GLOBAL(flush_hash_page)
+ rlwinm r3,r3,11,1,20 /* put context into vsid */
+ rlwimi r3,r4,11,21,24 /* put top 4 bits of va into vsid */
+ oris r3,r3,0x8000 /* set V (valid) bit */
+ rlwimi r3,r4,10,26,31 /* put in API (abbrev page index) */
+ rlwinm r7,r4,32-6,10,25 /* get page index << 6 */
+ rlwinm r5,r3,32-1,7,25 /* vsid << 6 */
+ xor r7,r7,r5 /* primary hash << 6 */
+ lis r5,Hash_mask@ha
+ lwz r5,Hash_mask@l(r5) /* hash mask */
+ slwi r5,r5,6 /* << 6 */
+ and r7,r7,r5
+ lis r6,Hash@ha
+ lwz r6,Hash@l(r6) /* hash table base */
+ add r6,r6,r7 /* address of primary PTEG */
+ li r8,8
+ mtctr r8
+ addi r7,r6,-8
+1: lwzu r0,8(r7) /* get next PTE */
+ cmpw 0,r0,r3 /* see if tag matches */
+ bdnzf 2,1b /* while --ctr != 0 && !cr0.eq */
+ beq 3f /* if we found it */
+ ori r3,r3,0x40 /* set H (alt. hash) bit */
+ xor r6,r6,r5 /* address of secondary PTEG */
+ mtctr r8
+ addi r7,r6,-8
+2: lwzu r0,8(r7) /* get next PTE */
+ cmpw 0,r0,r3 /* see if tag matches */
+ bdnzf 2,2b /* while --ctr != 0 && !cr0.eq */
+ bne 4f /* if we didn't find it */
+3: li r0,0
+ stw r0,0(r7) /* invalidate entry */
+4: sync
+ tlbie r4 /* in hw tlb too */
+ isync
+ blr
/*
* This routine is just here to keep GCC happy - sigh...
@@ -1415,18 +1521,212 @@ _GLOBAL(_switch)
_GLOBAL(__main)
blr
+#ifdef CONFIG_PMAC
+/*
+ * These exception handlers are used when we have called a prom
+ * routine after we have taken over the exception vectors and MMU.
+ */
+ .globl prom_exc_table
+prom_exc_table:
+ .long TOPHYS(prom_exception) /* 0 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 400 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 800 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* c00 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1000 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1400 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1800 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1c00 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1000 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1400 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1800 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception) /* 1c00 */
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+ .long TOPHYS(prom_exception)
+
+/*
+ * When we come in to these prom exceptions, r1 and lr have been
+ * saved in sprg1 and sprg2, and lr points to a word containing
+ * the vector offset.
+ */
+prom_exception:
+ mr r1,r21 /* save r21 */
+ lis r21,prom_sp@ha /* get a stack to use */
+ addis r21,r21,-KERNELBASE@h
+ lwz r21,prom_sp@l(r21)
+ addis r21,r21,-KERNELBASE@h /* convert to physical addr */
+ subi r21,r21,INT_FRAME_SIZE+STACK_UNDERHEAD
+ stw r0,GPR0(r21)
+ stw r2,GPR2(r21)
+ stw r3,GPR3(r21)
+ stw r4,GPR4(r21)
+ stw r5,GPR5(r21)
+ stw r6,GPR6(r21)
+ stw r20,GPR20(r21)
+ stw r1,GPR21(r21)
+ stw r22,GPR22(r21)
+ stw r23,GPR23(r21)
+ mfspr r1,SPRG1
+ stw r1,GPR1(r21)
+ mfcr r3
+ mfspr r4,SPRG2
+ stw r3,_CCR(r21)
+ stw r4,_LINK(r21)
+ mfctr r3
+ mfspr r4,XER
+ stw r3,_CTR(r21)
+ stw r4,_XER(r21)
+ mfspr r22,SRR0
+ mfspr r23,SRR1
+
+ /* at this point we have set things up pretty much exactly
+ how EXCEPTION_PROLOG does */
+ mflr r3
+ lwz r3,0(r3) /* get exception vector */
+ stw r3,TRAP(r21)
+ cmpi 0,r3,0x300 /* was it a dsi? */
+ bne 1f
+
+ mfspr r20,DSISR /* here on data access exc. */
+ andis. r0,r20,0x8470 /* weird error? */
+ bne 3f /* if not, try to put a PTE */
+ mfspr r3,DAR /* into the hash table */
+ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */
+ rlwimi r4,r20,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */
+ b 2f
+
+1: cmpi 0,r3,0x400 /* was it an isi? */
+ bne 3f
+ andis. r0,r23,0x4000 /* if so, check if no pte found */
+ beq 3f /* if so, try to put a PTE */
+ mr r3,r22 /* into the hash table */
+ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */
+ mr r20,r23 /* SRR1 has reason bits */
+2: lis r5,prom_tss@ha /* phys addr of TSS */
+ addis r5,r5,-KERNELBASE@h
+ lwz r5,prom_tss@l(r5)
+ bl hash_page
+
+3: addis r1,r21,KERNELBASE@h /* restore kernel stack ptr */
+ addi r3,r1,INT_FRAME_SIZE+STACK_UNDERHEAD
+ stw r3,0(r21) /* set stack chain pointer */
+ lis r5,prom_tss@ha
+ addis r5,r5,-KERNELBASE@h
+ lwz r5,prom_tss@l(r5)
+ mtspr SPRG3,r5 /* reset phys TSS pointer */
+ lwz r4,TRAP(r21) /* the real exception vector */
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ li r20,MSR_KERNEL
+ bl transfer_to_handler
+ .long PromException
+ .long prom_int_return
+
+ .comm prom_sp,4
+ .comm prom_tss,4
+
+ .globl prom_int_return
+prom_int_return:
+ lis r3,prom_exc_table@ha /* restore sprg3 for prom vectors */
+ addi r3,r3,prom_exc_table@l
+ addis r3,r3,-KERNELBASE@h
+ mtspr SPRG3,r3
+ b int_return
+
+/*
+ * When entering the prom, we have to change to using a different
+ * set of exception vectors.
+ */
+ .globl enter_prom
+enter_prom:
+ stwu r1,-32(r1)
+ mflr r0
+ stw r0,36(r1)
+ stw r29,20(r1)
+ stw r30,24(r1)
+ stw r31,28(r1)
+ lis r8,prom_entry@ha
+ lwz r8,prom_entry@l(r8)
+ mfmsr r31
+ andi. r0,r31,MSR_IP /* using our own vectors yet? */
+ beq 1f /* if so, have to switch */
+ mtlr r8
+ blrl /* if not, can just charge ahead */
+ b 2f
+1: lis r9,prom_sp@ha /* save sp for exception handler */
+ stw r1,prom_sp@l(r9)
+ mfspr r29,SPRG3 /* save physical tss pointer */
+ lis r9,prom_tss@ha
+ stw r29,prom_tss@l(r9)
+ li r9,0
+ ori r9,r9,MSR_EE
+ andc r30,r31,r9
+ lis r9,prom_exc_table@ha /* set pointer to exception table */
+ addi r9,r9,prom_exc_table@l
+ addis r9,r9,-KERNELBASE@h
+ ori r0,r31,MSR_IP
+ sync
+ mtmsr r30 /* disable interrupts */
+ mtspr SPRG3,r9 /* while we update MSR_IP and sprg3 */
+ sync
+ mtmsr r0 /* start using exc. vectors in prom */
+ mtlr r8
+ blrl /* call prom */
+ sync
+ mtmsr r30 /* disable interrupts again */
+ mtspr SPRG3,r29 /* while we restore MSR_IP and sprg3 */
+ sync
+ mtmsr r31 /* reenable interrupts */
+2: lwz r0,36(r1)
+ mtlr r0
+ lwz r29,20(r1)
+ lwz r30,24(r1)
+ lwz r31,28(r1)
+ lwz r1,0(r1)
+ 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:
.space 2*4096
-
-#if 0
-_GLOBAL(sys_stack)
-sys_stack:
- .space 4096
-#endif
-CPU1_stack:
-
.globl empty_zero_page
empty_zero_page:
.space 4096
@@ -1435,6 +1735,7 @@ empty_zero_page:
swapper_pg_dir:
.space 4096
+#ifdef CONFIG_PREP
/*
* 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.
@@ -1442,54 +1743,5 @@ swapper_pg_dir:
.globl cmd_line
cmd_line:
.space 512
-
-#ifdef STATS
-/*
- * Miscellaneous statistics - gathered just for performance info
- */
- .globl _INTR_stats
-_INTR_stats:
- .globl __Instruction_TLB_Misses
-__Instruction_TLB_Misses:
- .long 0,0 /* Instruction TLB misses */
- .globl __DataLoad_TLB_Misses
-__DataLoad_TLB_Misses:
- .long 0,0 /* Data [load] TLB misses */
- .globl __DataStore_TLB_Misses
-__DataStore_TLB_Misses:
- .long 0,0 /* Data [store] TLB misses */
- .globl __Instruction_Page_Faults
-__Instruction_Page_Faults:
- .long 0,0 /* Instruction page faults */
- .globl __Data_Page_Faults
-__Data_Page_Faults:
- .long 0,0 /* Data page faults */
- .globl __Cache_Flushes
-__Cache_Flushes:
- .long 0,0 /* Explicit cache flushes */
- .globl __Context_Switches
-__Context_Switches:
- .long 0,0 /* Context switches */
- .globl __Hardware_Interrupts
-__Hardware_Interrupts:
- .long 0,0 /* I/O interrupts (disk, timer, etc) */
- .globl __TLBIAs
- .globl __TLBIAs
-__TLBIAs:
- .long 0,0 /* TLB cache forceably flushed */
- .globl __TLBIEs
-__TLBIEs:
- .long 0,0 /* Specific TLB entry flushed */
-#endif
-
- .globl _TotalMemory
-_TotalMemory:
- .long 0,0
-
-/*
- * This location is used to break any outstanding "lock"s when
- * changing contexts.
- */
-_break_lwarx: .long 0
-
+#endif /* CONFIG_PREP */