Original kernel 2.4.37.5
[tomato.git] / release / src / linux / linux / arch / ppc / kernel / head_44x.S
blobcb65ccc2cfc8a5dc9719f778d9fe8c005fcd2cfe
1 /*
2  * arch/ppc/kernel/head_44x.S
3  *
4  * Kernel execution entry point code.
5  *
6  *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
7  *      Initial PowerPC version.
8  *    Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu>
9  *      Rewritten for PReP
10  *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
11  *      Low-level exception handers, MMU support, and rewrite.
12  *    Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
13  *      PowerPC 8xx modifications.
14  *    Copyright (c) 1998-1999 TiVo, Inc.
15  *      PowerPC 403GCX modifications.
16  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
17  *      PowerPC 403GCX/405GP modifications.
18  *    Copyright 2000 MontaVista Software Inc.
19  *      PPC405 modifications
20  *      PowerPC 403GCX/405GP modifications.
21  *      Author: MontaVista Software, Inc.
22  *              frank_rowand@mvista.com or source@mvista.com
23  *              debbie_chu@mvista.com
24  *    Copyright 2002-2004 MontaVista Software, Inc.
25  *      PowerPC 44x support, Matt Porter <mporter@kernel.crashing.org>
26  *
27  * This program is free software; you can redistribute  it and/or modify it
28  * under  the terms of  the GNU General Public License as published by the
29  * Free Software Foundation;  either version 2 of the  License, or (at your
30  * option) any later version.
31  */
33 #include <linux/config.h>
34 #include <asm/processor.h>
35 #include <asm/page.h>
36 #include <asm/mmu.h>
37 #include <asm/pgtable.h>
38 #include <asm/ibm44x.h>
39 #include <asm/cputable.h>
40 #include <asm/ppc_asm.h>
41 #include "ppc_defs.h"
44  * Preprocessor Defines
45  */
47 #define STND_EXC        0
48 #define CRIT_EXC        1
50 #ifdef CONFIG_440A
51 #define MCHK_EXC        2
52 #define __SPRN_MCSRR0   SPRN_MCSRR0
53 #define __SPRN_MCSRR1   SPRN_MCSRR1
54 #else
55 #define MCHK_EXC        CRIT_EXC
56 #define __SPRN_MCSRR0   SPRN_CSRR0
57 #define __SPRN_MCSRR1   SPRN_CSRR1
58 #endif
61  * Macros
62  */
64 #define SET_IVOR(vector_number, vector_label)           \
65                 li      r26,vector_label@l;             \
66                 mtspr   SPRN_IVOR##vector_number,r26;   \
67                 sync
68                                         
69 /* As with the other PowerPC ports, it is expected that when code
70  * execution begins here, the following registers contain valid, yet
71  * optional, information:
72  *
73  *   r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.)
74  *   r4 - Starting address of the init RAM disk
75  *   r5 - Ending address of the init RAM disk
76  *   r6 - Start of kernel command line string (e.g. "mem=128")
77  *   r7 - End of kernel command line string
78  *
79  */ 
80         .text
81 _GLOBAL(_stext)
82 _GLOBAL(_start)
83         /*
84          * Reserve a word at a fixed location to store the address
85          * of abatron_pteptrs
86          */
87         nop
90  * Save parameters we are passed
91  */
92         mr      r31,r3
93         mr      r30,r4
94         mr      r29,r5
95         mr      r28,r6
96         mr      r27,r7
97         li      r24,0           /* CPU number */
100  * Set up the initial MMU state
102  * We are still executing code at the virtual address
103  * mappings set by the firmware for the base of RAM.
105  * We first invalidate all TLB entries but the one
106  * we are running from.  We then load the KERNELBASE
107  * mappings so we can begin to use kernel addresses
108  * natively and so the interrupt vector locations are
109  * permanently pinned (necessary since Book E
110  * implementations always have translation enabled).
112  * TODO: Use the known TLB entry we are running from to
113  *       determine which physical region we are located
114  *       in.  This can be used to determine where in RAM
115  *       (on a shared CPU system) or PCI memory space
116  *       (on a DRAMless system) we are located.
117  *       For now, we assume a perfect world which means
118  *       we are located at the base of DRAM (physical 0).
119  */
122  * Search TLB for entry that we are currently using.
123  * Invalidate all entries but the one we are using.
124  */
125         /* Load our current PID->MMUCR TID and MSR IS->MMUCR STS */
126         mfspr   r3,SPRN_MMUCR                   /* Get MMUCR */
127         lis     r4,PPC44x_MMUCR_STS@h
128         ori     r4,r4,PPC44x_MMUCR_TID@l        /* Create mask */
129         andc    r3,r3,r4                        /* Clear out TID/STS bits */
130         mfspr   r4,SPRN_PID                     /* Get PID */
131         or      r3,r3,r4                        /* Set TID bits */
132         mfmsr   r5                              /* Get MSR */
133         andi.   r5,r5,MSR_IS@l                  /* TS=1? */
134         beq     wmmucr                          /* If not, leave STS=0 */
135         oris    r3,r3,PPC44x_MMUCR_STS@h        /* Set STS=1 */
136 wmmucr: mtspr   SPRN_MMUCR,r3                   /* Put MMUCR */
137         sync
138         
139         bl      invstr                          /* Find our address */
140 invstr: mflr    r5                              /* Make it accessible */
141         tlbsx   r23,0,r5                        /* Find entry we are in */
142         li      r4,0                            /* Start at TLB entry 0 */
143         li      r3,0                            /* Set PAGEID inval value */
144 1:      cmpw    r23,r4                          /* Is this our entry? */
145         beq     skpinv                          /* If so, skip the inval */
146         tlbwe   r3,r4,PPC44x_TLB_PAGEID         /* If not, inval the entry */
147 skpinv: addi    r4,r4,1                         /* Increment */
148         cmpwi   r4,64                           /* Are we done? */
149         bne     1b                              /* If not, repeat */
150         isync                                   /* If so, context change */
153  * Configure and load pinned entries into TLB slots 62 and 63.
154  */
156         lis     r3,KERNELBASE@h         /* Load the kernel virtual address */
157         ori     r3,r3,KERNELBASE@l
159         /* Kernel is at the base of RAM */
160         li r4, 0                        /* Load the kernel physical address */
162         /* Load the kernel PID = 0 */
163         li      r0,0
164         mtspr   SPRN_PID,r0
165         sync
167         /* Load the kernel TID  = 0 */
168         mfspr   r5,SPRN_MMUCR
169         lis     r6, PPC44x_MMUCR_TID@h
170         ori     r6,r6,PPC44x_MMUCR_TID@l
171         andc    r5,r5,r6
172         mtspr   SPRN_MMUCR,r5
173         sync
175         /* pageid fields */
176         clrrwi  r3,r3,10                /* Mask off the effective page number */
177         ori     r3,r3,(PPC44x_TLB_VALID | PPC44x_TLB_PAGESZ(PPC44x_PAGESZ_256M))
179         /* xlat fields */
180         clrrwi  r4,r4,10                /* Mask off the real page number */
181                                         /* ERPN is 0 for first 4GB page */
183         /* attrib fields */
184         /* Added guarded bit to protect against speculative loads/stores */
185         li      r5,0
186         ori     r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G)
188         li      r0,62                    /* TLB slot 62 */
190         tlbwe   r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */
191         tlbwe   r4,r0,PPC44x_TLB_XLAT   /* Load the translation fields */
192         tlbwe   r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */
194         /* Force context change */
195         mfmsr   r0
196         mtspr   SRR1, r0
197         lis     r0,3f@h
198         ori     r0,r0,3f@l
199         mtspr   SRR0,r0
200         sync
201         rfi
203         /* If necessary, invalidate original entry we used */
204 3:      cmpwi   r23,62
205         beq     4f
206         li      r6,0
207         tlbwe   r6,r23,PPC44x_TLB_PAGEID
208         sync
210 4:      ori     r3,r3,PPC44x_TLB_TS     /* TS = 1 */
212         li      r0,63                   /* TLB slot 63 */
214         tlbwe   r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */
215         tlbwe   r4,r0,PPC44x_TLB_XLAT   /* Load the translation fields */
216         tlbwe   r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */
218 #ifdef CONFIG_SERIAL_TEXT_DEBUG
219         /*
220          * Add temporary UART mapping for early debug.  This
221          * mapping must be identical to that used by the early
222          * bootloader code since the same asm/serial.h parameters
223          * are used for polled operation.
224          */
225         /* pageid fields */
226         lis     r3,0xe000               
227         ori     r3,r3,(PPC44x_TLB_VALID | PPC44x_TLB_PAGESZ(PPC44x_PAGESZ_256M))
229         /* xlat fields */
230         lis     r4,0x4000               /* RPN is 0x40000000 */
231         ori     r4,r4,0x0001            /* ERPN is 1 for second 4GB page */
233         /* attrib fields */
234         li      r5,0
235         ori     r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_I | PPC44x_TLB_G)
237         li      r0,60                    /* TLB slot 60 */
239         tlbwe   r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */
240         tlbwe   r4,r0,PPC44x_TLB_XLAT   /* Load the translation fields */
241         tlbwe   r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */
243         ori     r3,r3,PPC44x_TLB_TS     /* Translation state 1 */
245         li      r0,61                   /* TLB slot 61 */
247         tlbwe   r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */
248         tlbwe   r4,r0,PPC44x_TLB_XLAT   /* Load the translation fields */
249         tlbwe   r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */
250 #endif /* CONFIG_SERIAL_TEXT_DEBUG */
252         /* Force context change */
253         isync
255         /* Establish the interrupt vector offsets */
256         SET_IVOR(0,  CriticalInput);
257         SET_IVOR(1,  MachineCheck);
258         SET_IVOR(2,  DataStorage);
259         SET_IVOR(3,  InstructionStorage);
260         SET_IVOR(4,  ExternalInput);
261         SET_IVOR(5,  Alignment);
262         SET_IVOR(6,  Program);
263         SET_IVOR(7,  FloatingPointUnavailable);
264         SET_IVOR(8,  SystemCall);
265         SET_IVOR(9,  AuxillaryProcessorUnavailable);
266         SET_IVOR(10, Decrementer);
267         SET_IVOR(11, FixedIntervalTimer);
268         SET_IVOR(12, WatchdogTimer);
269         SET_IVOR(13, DataTLBError);
270         SET_IVOR(14, InstructionTLBError);
271         SET_IVOR(15, Debug);
273         /* Establish the interrupt vector base */
274         lis     r4,interrupt_base@h     /* IVPR only uses the high 16-bits */
275         mtspr   SPRN_IVPR,r4
277         /*
278          * This is where the main kernel code starts.
279          */ 
281         /* ptr to current */
282         lis     r2,init_task_union@h
283         ori     r2,r2,init_task_union@l
285         /* ptr to current thread */
286         addi    r4,r2,THREAD    /* init task's THREAD */
287         mtspr   SPRG3,r4
288         li      r3,0
289         mtspr   SPRG2,r3        /* 0 => r1 has kernel sp */
291         /* stack */
292         addi    r1,r2,TASK_UNION_SIZE
293         li      r0,0
294         stwu    r0,-STACK_FRAME_OVERHEAD(r1)
296         bl      early_init
299  * Decide what sort of machine this is and initialize the MMU.
300  */
301         mr      r3,r31
302         mr      r4,r30
303         mr      r5,r29
304         mr      r6,r28
305         mr      r7,r27
306         bl      machine_init
307         bl      MMU_init
309         /* Setup PTE pointers for the Abatron bdiGDB */
310         lis     r6, swapper_pg_dir@h
311         ori     r6, r6, swapper_pg_dir@l
312         lis     r5, abatron_pteptrs@h
313         ori     r5, r5, abatron_pteptrs@l
314         lis     r4, KERNELBASE@h
315         ori     r4, r4, KERNELBASE@l
316         stw     r5, 0(r4)       /* Save abatron_pteptrs at a fixed location */
317         stw     r6, 0(r5)
319         /* Let's move on */
320         lis     r4,start_kernel@h
321         ori     r4,r4,start_kernel@l
322         lis     r3,MSR_KERNEL@h
323         ori     r3,r3,MSR_KERNEL@l
324         mtspr   SRR0,r4
325         mtspr   SRR1,r3
326         rfi                     /* change context and jump to start_kernel */
329  * Interrupt vector entry code
331  * The Book E MMUs are always on so we don't need to handle
332  * interrupts in real mode as with previous PPC processors. In
333  * this case we handle interrupts in the kernel virtual address
334  * space.
336  * Interrupt vectors are dynamically placed relative to the 
337  * interrupt prefix as determined by the address of interrupt_base.
338  * The interrupt vectors offsets are programmed using the labels
339  * for each interrupt vector entry.
341  * Interrupt vectors must be aligned on a 16 byte boundary.
342  * We align on a 32 byte cache line boundary for good measure.
343  */
345 #define COMMON_PROLOG                                                        \
346 0:      mtspr   SPRN_SPRG0,r20;         /* We need r20, move it to SPRG0   */\
347         mtspr   SPRN_SPRG1,r21;         /* We need r21, move it to SPRG1   */\
348         mfcr    r20;                    /* We need the CR, move it to r20  */\
349         mfspr   r21,SPRN_SPRG2;         /* Exception stack to use          */\
350         cmpwi   cr0,r21,0;              /* From user mode or RTAS?         */\
351         bne     1f;                     /* Not RTAS, branch                */\
352         mr      r21, r1;                /* Move vka in r1 to r21           */\
353         subi    r21,r21,INT_FRAME_SIZE; /* Allocate an exception frame     */\
354 1:      stw     r20,_CCR(r21);          /* Save CR on the stack            */\
355         stw     r22,GPR22(r21);         /* Save r22 on the stack           */\
356         stw     r23,GPR23(r21);         /* r23 Save on the stack           */\
357         mfspr   r20,SPRN_SPRG0;         /* Get r20 back out of SPRG0       */\
358         stw     r20,GPR20(r21);         /* Save r20 on the stack           */\
359         mfspr   r22,SPRN_SPRG1;         /* Get r21 back out of SPRG0       */\
360         stw     r22,GPR21(r21);         /* Save r21 on the stack           */\
361         mflr    r20;                                                         \
362         stw     r20,_LINK(r21);         /* Save LR on the stack            */\
363         mfctr   r22;                                                         \
364         stw     r22,_CTR(r21);          /* Save CTR on the stack           */\
365         mfspr   r20,XER;                                                     \
366         stw     r20,_XER(r21);          /* Save XER on the stack           */
368 #define COMMON_EPILOG                                                        \
369         stw     r0,GPR0(r21);           /* Save r0 on the stack            */\
370         stw     r1,GPR1(r21);           /* Save r1 on the stack            */\
371         stw     r2,GPR2(r21);           /* Save r2 on the stack            */\
372         stw     r1,0(r21);                                                   \
373         mr      r1,r21;                 /* Set-up new kernel stack pointer */\
374         SAVE_4GPRS(3, r21);             /* Save r3 through r6 on the stack */\
375         SAVE_GPR(7, r21);               /* Save r7 on the stack            */
377 #define STND_EXCEPTION_PROLOG                                                \
378         COMMON_PROLOG;                                                       \
379         mfspr   r22,SPRN_SRR0;          /* Faulting instruction address    */\
380         lis     r20,MSR_WE@h;                                                \
381         mfspr   r23,SPRN_SRR1;          /* MSR at the time of fault        */\
382         andc    r23,r23,r20;            /* disable processor wait state    */\
383         COMMON_EPILOG;
385 #define CRIT_EXCEPTION_PROLOG                                                \
386         COMMON_PROLOG;                                                       \
387         mfspr   r22,SPRN_CSRR0;         /* Faulting instruction address    */\
388         lis     r20,MSR_WE@h;                                                \
389         mfspr   r23,SPRN_CSRR1;         /* MSR at the time of fault        */\
390         andc    r23,r23,r20;            /* disable processor wait state    */\
391         COMMON_EPILOG;
393 #define START_EXCEPTION(label) \
394         .align 5;              \
395 label:
397 #define FINISH_EXCEPTION(n, func)                                            \
398         bl      transfer_to_handler;                                         \
399         .long   func;                                                        \
400         .long   ret_from_except;                                             \
401         .long   n
403 #define STND_EXCEPTION(n, label, func)                                       \
404         START_EXCEPTION(label)                                               \
405         STND_EXCEPTION_PROLOG;                                               \
406         addi    r3,r1,STACK_FRAME_OVERHEAD;                                  \
407         li      r7,STND_EXC;                                                 \
408         li      r20,MSR_KERNEL;                                              \
409         FINISH_EXCEPTION(n, func)
411 #define CRIT_EXCEPTION(n, label, func)                                       \
412         START_EXCEPTION(label)                                               \
413         CRIT_EXCEPTION_PROLOG;                                               \
414         addi    r3,r1,STACK_FRAME_OVERHEAD;                                  \
415         li      r7,CRIT_EXC;                                                 \
416         li      r20,MSR_KERNEL;                                              \
417         FINISH_EXCEPTION(n, func)
419 interrupt_base:
421         /* Critical Input Interrupt */
422         CRIT_EXCEPTION(0x100, CriticalInput,UnknownException);
424         /* Machine Check Interrupt */
425         /* TODO: provide bus error register status */
426         START_EXCEPTION(MachineCheck)
427         COMMON_PROLOG;
428         mfspr   r22,__SPRN_MCSRR0       /* Faulting instruction address    */
429         lis     r20,MSR_WE@h
430         mfspr   r23,__SPRN_MCSRR1       /* MSR at the time of fault        */
431         andc    r23,r23,r20             /* disable processor wait state    */
432         COMMON_EPILOG;
433 #ifdef CONFIG_440A
434         lis     r20,MCSR_MCS@h
435         mfspr   r4,SPRN_MCSR            /* We may want to access original
436                                            MCSR as arg2 in the future. --ebs */
437         mtspr   SPRN_MCSR,r20           /* Clear Machine Check Summary field */
438 #endif  
439         mfspr   r5,SPRN_ESR             /* Grab the ESR, save it */
440         stw     r5,_ESR(r21)
441         addi    r3,r1,STACK_FRAME_OVERHEAD
442         li      r7,MCHK_EXC
443         li      r20,MSR_KERNEL
444         FINISH_EXCEPTION(0x200, MachineCheckException)
446         /* Data Storage Interrupt */
447         START_EXCEPTION(DataStorage)
448         mtspr   SPRG0, r20              /* Save some working registers */
449         mtspr   SPRG1, r21
450         mtspr   SPRG4W, r22
451         mtspr   SPRG5W, r23
452         mtspr   SPRG6W, r24
453         mfcr    r21
454         mtspr   SPRG7W, r21
456         /*
457          * Check if it was a store fault, if not then bail
458          * because a user tried to access a kernel or
459          * read-protected page.  Otherwise, get the
460          * offending address and handle it.
461          */
462         mfspr   r20, SPRN_ESR
463         andis.  r20, r20, ESR_DST@h
464         beq     2f
466         mfspr   r20, SPRN_DEAR          /* Get faulting address */
468         /* If we are faulting a kernel address, we have to use the
469          * kernel page tables.
470          */
471         andis.  r21, r20, 0x8000
472         beq     3f
473         lis     r21, swapper_pg_dir@h
474         ori     r21, r21, swapper_pg_dir@l
476         mfspr   r22,SPRN_MMUCR          /* Set TID to 0 */
477         li      r23,PPC44x_MMUCR_TID@l
478         andc    r22,r22,r23
479         mtspr   SPRN_MMUCR,r22
481         b       4f
483         /* Get the PGD for the current thread */
485         mfspr   r21,SPRG3
486         lwz     r21,PGDIR(r21)
488         /* Load MMUCR with our PID and STS=<current TS> */
489         mfspr   r22,SPRN_MMUCR                  /* Get MMUCR */
490         lis     r23,PPC44x_MMUCR_STS@h
491         ori     r23,r23,PPC44x_MMUCR_TID@l      /* Create mask */
492         andc    r22,r22,r23                     /* Clear out TID/STS bits */
493         mfspr   r23,SPRN_PID                    /* Get PID */
494         or      r22,r22,r23                     /* Set TID bits */
495         mfspr   r24,SPRN_SRR1                   /* Get SRR1 */
496         andi.   r24,r24,MSR_IS@l                /* TS=1? */
497         beq     4f                              /* If not, leave STS=0 */
498         oris    r22,r22,PPC44x_MMUCR_STS@h      /* Set STS=1 */
499         mtspr   SPRN_MMUCR,r22
501         rlwinm  r22, r20, 13, 19, 29    /* Compute pgdir/pmd offset */
502         lwzx    r21, r22, r21           /* Get pgd/pmd entry */
503         rlwinm. r22, r21, 0, 0, 20      /* Extract pt base address */
504         beq     2f                      /* Bail if no table */
506         rlwimi  r22, r20, 23, 20, 28    /* Compute pte address */
507         lwz     r21, 4(r22)             /* Get pte entry */
508         
509         andi.   r23, r21, _PAGE_RW      /* Is it writeable? */
510         beq     2f                      /* Bail if not */
512         /* Update 'changed'.
513         */
514         ori     r21, r21, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
515         stw     r21, 4(r22)             /* Update Linux page table */
517         /* FIXME: Staticly setting some permissions */
518         li      r23, 0x003f             /* Set UX,UW,UR,SX,SW,SR */
519         andi.   r21,r21,0xffff          /* Clear MS 16 bits */
520         /* FIXME: Force attributes */
521         ori     r21,r21, 0x0100         /* Set G */
522         /* FIXME: Already set in PTE */
523         rlwimi  r21,r23,0,26,31         /* Insert static perms */
525         lis     r23,0xffff
526         ori     r23,r23,0x0fff                  /* Set U0-U3 mask */
527         and     r21,r21,r23                     /* Clear U0-U3 */
529         /* find the TLB index that caused the fault.  It has to be here. */
530         tlbsx   r24, 0, r20
532         tlbwe   r21, r24, PPC44x_TLB_ATTRIB             /* Write ATTRIB */
534         /* Done...restore registers and get out of here.
535         */
536         mfspr   r21, SPRG7R
537         mtcr    r21
538         mfspr   r24, SPRG6R
539         mfspr   r23, SPRG5R
540         mfspr   r22, SPRG4R
542         mfspr   r21, SPRG1
543         mfspr   r20, SPRG0
544         rfi                     /* Force context change */
547         /*
548          * The bailout.  Restore registers to pre-exception conditions
549          * and call the heavyweights to help us out.
550          */
551         mfspr   r21, SPRG7R
552         mtcr    r21
553         mfspr   r24, SPRG6R
554         mfspr   r23, SPRG5R
555         mfspr   r22, SPRG4R
557         mfspr   r21, SPRG1
558         mfspr   r20, SPRG0
559         b       data_access
561         /* Instruction Storage Interrupt */
562         START_EXCEPTION(InstructionStorage)
563         STND_EXCEPTION_PROLOG
564         mfspr   r5,SPRN_ESR             /* Grab the ESR, save it */
565         stw     r5,_ESR(r21)
566         mr      r4,r22                  /* Pass SRR0 as arg2 */
567         li      r5,0                    /* Pass zero as arg3 */
568         addi    r3,r1,STACK_FRAME_OVERHEAD
569         li      r7,STND_EXC
570         li      r20,MSR_KERNEL
571         rlwimi  r20,r23,0,16,16         /* Copy EE bit from the saved MSR */
572         FINISH_EXCEPTION(0x400, do_page_fault)/* do_page_fault(regs, SRR0, SRR1) */
574         /* External Input Interrupt */
575         START_EXCEPTION(ExternalInput)
576         STND_EXCEPTION_PROLOG
577         addi    r3,r1,STACK_FRAME_OVERHEAD
578         li      r7,STND_EXC
579         li      r20,MSR_KERNEL
580         li      r4,0
581         bl      transfer_to_handler
582 _GLOBAL(do_IRQ_intercept)
583         .long   do_IRQ
584         .long   ret_from_intercept
585         .long   0x500
587         /* Alignment Interrupt */
588         START_EXCEPTION(Alignment)
589         STND_EXCEPTION_PROLOG
590         mfspr   r4,SPRN_DEAR            /* Grab the DEAR and save it */
591         stw     r4,_DEAR(r21)
592         addi    r3,r1,STACK_FRAME_OVERHEAD
593         li      r7,STND_EXC
594         li      r20,MSR_KERNEL
595         rlwimi  r20,r23,0,16,16         /* Copy EE bit from the saved MSR */
596         FINISH_EXCEPTION(0x600, AlignmentException)
598         /* Program Interrupt */
599         START_EXCEPTION(Program)
600         STND_EXCEPTION_PROLOG
601         mfspr   r4,SPRN_ESR             /* Grab the ESR, save it */
602         stw     r4,_ESR(r21)
603         addi    r3,r1,STACK_FRAME_OVERHEAD
604         li      r7,STND_EXC
605         li      r20,MSR_KERNEL
606         rlwimi  r20,r23,0,16,16         /* Copy EE bit from the saved MSR */
607         FINISH_EXCEPTION(0x700, ProgramCheckException)
609         /* Floating Point Unavailable Interrupt */
610         STND_EXCEPTION(0x2010, FloatingPointUnavailable,UnknownException);
612         /* System Call Interrupt */
613         START_EXCEPTION(SystemCall)
614         STND_EXCEPTION_PROLOG
615         stw     r3,ORIG_GPR3(r21)
616         li      r7,STND_EXC
617         li      r20,MSR_KERNEL
618         rlwimi  r20,r23,0,16,16         /* Copy EE bit from the saved MSR */
619         FINISH_EXCEPTION(0xc00, DoSyscall)
621         /* Auxillary Processor Unavailable */
622         STND_EXCEPTION(0x2020, AuxillaryProcessorUnavailable,UnknownException);
624         /* Decrementer Interrupt */
625         START_EXCEPTION(Decrementer)
626         STND_EXCEPTION_PROLOG
627         lis     r0,TSR_DIS@h            /* Setup the DEC interrupt mask */
628         mtspr   SPRN_TSR,r0            /* Clear the DEC interrupt */
629         addi    r3,r1,STACK_FRAME_OVERHEAD
630         li      r7,STND_EXC
631         li      r20,MSR_KERNEL
632         bl      transfer_to_handler
633 _GLOBAL(timer_interrupt_intercept)
634         .long   timer_interrupt
635         .long   ret_from_intercept
636         .long   0x1000
638         /* Fixed Internal Timer Interrupt */
639         /* TODO: Add FIT support */
640         STND_EXCEPTION(0x1010, FixedIntervalTimer,UnknownException);
642         /* Watchdog Timer Interrupt */
643         /* TODO: Add watchdog support */
644         CRIT_EXCEPTION(0x1020, WatchdogTimer,UnknownException);
646         /* Data TLB Error Interrupt */
647         START_EXCEPTION(DataTLBError)
648         mtspr   SPRG0, r20              /* Save some working registers */
649         mtspr   SPRG1, r21
650         mtspr   SPRG4W, r22
651         mtspr   SPRG5W, r23
652         mtspr   SPRG6W, r24
653         mfcr    r21
654         mtspr   SPRG7W, r21
655         mfspr   r20, SPRN_DEAR          /* Get faulting address */
657         /* If we are faulting a kernel address, we have to use the
658          * kernel page tables.
659          */
660         andis.  r21, r20, 0x8000
661         beq     3f
662         lis     r21, swapper_pg_dir@h
663         ori     r21, r21, swapper_pg_dir@l
665         mfspr   r22,SPRN_MMUCR          /* Set TID to 0 */
666         li      r23,PPC44x_MMUCR_TID@l
667         andc    r22,r22,r23
668         mtspr   SPRN_MMUCR,r22
670         b       4f
672         /* Get the PGD for the current thread */
674         mfspr   r21,SPRG3
675         lwz     r21,PGDIR(r21)
677         /* Load PID into MMUCR TID */
678         li      r23,PPC44x_MMUCR_TID@l           /* Create mask */
679         andc    r22,r22,r23                      /* Clear out TID/STS bits */
680         mfspr   r23,SPRN_PID                     /* Get PID */
681         or      r22,r22,r23
682         mtspr   SPRN_MMUCR,r22
684         rlwinm  r22, r20, 13, 19, 29    /* Compute pgdir/pmd offset */
685         lwzx    r21, r22, r21           /* Get pgd/pmd entry */
686         rlwinm. r22, r21, 0, 0, 20      /* Extract pt base address */
687         beq     2f                      /* Bail if no table */
689         rlwimi  r22, r20, 23, 20, 28    /* Compute pte address */
690         lwz     r21, 4(r22)             /* Get pte entry */
691         andi.   r23, r21, _PAGE_PRESENT /* Is the page present? */
692         beq     2f                      /* Bail if not present */
694         ori     r21, r21, _PAGE_ACCESSED
695         stw     r21, 4(r22)
697          /* Jump to common tlb load */
698         b       finish_tlb_load
701         /* The bailout.  Restore registers to pre-exception conditions
702          * and call the heavyweights to help us out.
703          */
704         mfspr   r21, SPRG7R
705         mtcr    r21
706         mfspr   r24, SPRG6R
707         mfspr   r23, SPRG5R
708         mfspr   r22, SPRG4R
709         mfspr   r21, SPRG1
710         mfspr   r20, SPRG0
711         b       data_access
713         /* Instruction TLB Error Interrupt */
714         /*
715          * Nearly the same as above, except we get our
716          * information from different registers and bailout
717          * to a different point.
718          */
719         START_EXCEPTION(InstructionTLBError)
720         mtspr   SPRG0, r20              /* Save some working registers */
721         mtspr   SPRG1, r21
722         mtspr   SPRG4W, r22
723         mtspr   SPRG5W, r23
724         mtspr   SPRG6W, r24
725         mfcr    r21
726         mtspr   SPRG7W, r21
727         mfspr   r20, SRR0               /* Get faulting address */
729         /* If we are faulting a kernel address, we have to use the
730          * kernel page tables.
731          */
732         andis.  r21, r20, 0x8000
733         beq     3f
734         lis     r21, swapper_pg_dir@h
735         ori     r21, r21, swapper_pg_dir@l
737         mfspr   r22,SPRN_MMUCR          /* Set TID to 0 */
738         li      r23,PPC44x_MMUCR_TID@l
739         andc    r22,r22,r23
740         mtspr   SPRN_MMUCR,r22
742         b       4f
744         /* Get the PGD for the current thread */
746         mfspr   r21,SPRG3
747         lwz     r21,PGDIR(r21)
749         /* Load PID into MMUCR TID */
750         li      r23,PPC44x_MMUCR_TID@l           /* Create mask */
751         andc    r22,r23,r23                      /* Clear out TID/STS bits */
752         mfspr   r23,SPRN_PID                     /* Get PID */
753         or      r22,r22,r23
754         mtspr   SPRN_MMUCR,r22
757         rlwinm  r22, r20, 13, 19, 29    /* Compute pgdir/pmd offset */
758         lwzx    r21, r22, r21           /* Get pgd/pmd entry */
759         rlwinm. r22, r21, 0, 0, 20      /* Extract pt base address */
760         beq     2f                      /* Bail if no table */
762         rlwimi  r22, r20, 23, 20, 28    /* Compute pte address */
763         lwz     r21, 4(r22)             /* Get pte entry */
764         andi.   r23, r21, _PAGE_PRESENT /* Is the page present? */
765         beq     2f                      /* Bail if not present */
767         ori     r21, r21, _PAGE_ACCESSED
768         stw     r21, 4(r22)
770         /* Jump to common TLB load point */
771         b       finish_tlb_load
774         /* The bailout.  Restore registers to pre-exception conditions
775          * and call the heavyweights to help us out.
776          */
777         mfspr   r21, SPRG7R
778         mtcr    r21
779         mfspr   r24, SPRG6R
780         mfspr   r23, SPRG5R
781         mfspr   r22, SPRG4R
782         mfspr   r21, SPRG1
783         mfspr   r20, SPRG0
784         b       InstructionStorage
786 /* Check for a single step debug exception while in an exception
787  * handler before state has been saved.  This is to catch the case
788  * where an instruction that we are trying to single step causes
789  * an exception (eg ITLB/DTLB miss) and thus the first instruction of
790  * the exception handler generates a single step debug exception.
792  * If we get a debug trap on the first instruction of an exception handler,
793  * we reset the MSR_DE in the _exception handlers_ MSR (the debug trap is
794  * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
795  * The exception handler was handling a non-critical interrupt, so it will
796  * save (and later restore) the MSR via SPRN_SRR1, which will still have
797  * the MSR_DE bit set.
798  */
799         /* Debug Interrupt */
800         START_EXCEPTION(Debug)
801         /* This first instruction was already executed by the exception
802          * handler and must be the first instruction of every exception
803          * handler.
804          */
805         mtspr   SPRN_SPRG0,r20          /* Save some working registers... */
806         mtspr   SPRN_SPRG1,r21
807         mtspr   SPRN_SPRG4W,r22
808         mfcr    r20                     /* ..and the cr because we change it */
810         mfspr   r21,SPRN_CSRR1          /* MSR at the time of fault */
811         andi.   r21,r21,MSR_PR
812         bne+    2f                      /* trapped from problem state */
814         mfspr   r21,SPRN_CSRR0          /* Faulting instruction address */
815         lis     r22, KERNELBASE@h
816         ori     r22, r22, KERNELBASE@l
817         cmplw   r21,r22
818         blt+    2f                      /* addr below exception vectors */
820         lis     r22, Debug@h
821         ori     r22, r22, Debug@l
822         cmplw   r21,r22
823         bgt+    2f                      /* addr above TLB exception vectors */
825         lis     r21,DBSR_IC@h           /* Remove the trap status */
826         mtspr   SPRN_DBSR,r21
828         mfspr   r21,SPRN_CSRR1
829         rlwinm  r21,r21,0,23,21         /* clear MSR_DE */
830         mtspr   SPRN_CSRR1, r21         /* restore MSR at rcfi without DE */
832         mtcrf   0xff,r20                /* restore registers */
833         mfspr   r22,SPRN_SPRG4R
834         mfspr   r21,SPRN_SPRG1
835         mfspr   r20,SPRN_SPRG0
837         sync
838         rfci                            /* return to the exception handler  */
839         b       .                       /* prevent prefetch past rfci */
842         mtcrf   0xff,r20                /* restore registers */
843         mfspr   r22,SPRN_SPRG4R
844         mfspr   r21,SPRN_SPRG1
845         mfspr   r20,SPRN_SPRG0
847         CRIT_EXCEPTION_PROLOG
848         addi    r3,r1,STACK_FRAME_OVERHEAD
849         li      r7,CRIT_EXC;
850         li      r20,MSR_KERNEL
851         FINISH_EXCEPTION(0x2000, DebugException)
854  * Local functions
855  */
857         /*
858          * Data TLB exceptions will bail out to this point
859          * if they can't resolve the lightweight TLB fault.
860          */
861 data_access:
862         STND_EXCEPTION_PROLOG
863         mfspr   r5,SPRN_ESR             /* Grab the ESR, save it, pass arg3 */
864         stw     r5,_ESR(r21)
865         mfspr   r4,SPRN_DEAR            /* Grab the DEAR, save it, pass arg2 */
866         stw     r4,_DEAR(r21)
867         addi    r3,r1,STACK_FRAME_OVERHEAD
868         li      r7,STND_EXC
869         li      r20,MSR_KERNEL
870         rlwimi  r20,r23,0,16,16         /* Copy EE bit from the saved MSR */
871         FINISH_EXCEPTION(0x800, do_page_fault) /* do_page_fault(regs, ESR, DEAR) */
874  * Both the instruction and data TLB miss get to this
875  * point to load the TLB.
876  *      r20 - EA of fault
877  *      r21 - available to use
878  *      r22 - Pointer to the 64-bit PTE
879  *      r23 - available to use
880  *      r24 - available to use
881  *      MMUCR - loaded with proper value when we get here
882  *      Upon exit, we reload everything and RFI.
883  */
884 finish_tlb_load:
885         /*
886          * We set execute, because we don't have the granularity to
887          * properly set this at the page level (Linux problem).
888          * If shared is set, we cause a zero PID->TID load.
889          * Many of these bits are software only.  Bits we don't set
890          * here we (properly should) assume have the appropriate value.
891          */
893         /* Load the next available TLB index */
894         lis     r23, tlb_44x_index@h
895         ori     r23, r23, tlb_44x_index@l
896         lwz     r24, 0(r23)
897         /* Load the TLB high watermark */
898         lis     r23, tlb_44x_hwater@h
899         ori     r23, r23, tlb_44x_hwater@l
900         lwz     r21, 0(r23)
902         
903         /* Increment, rollover, and store TLB index */
904         addi    r24, r24, 1
905         cmpw    0, r24, r21             /* reserve entries 62-63 for kernel */
906         ble     7f
907         li      r24, 0
909         /* Load the next available TLB index */
910         lis     r23, tlb_44x_index@h
911         ori     r23, r23, tlb_44x_index@l
912         stw     r24, 0(r23)
915         lwz     r23, 0(r22)                     /* Get MS word of PTE */
916         lwz     r21, 4(r22)                     /* Get LS word of PTE */
917         rlwimi  r23, r21, 0, 0 , 19             /* Insert RPN */
918         tlbwe   r23, r24, PPC44x_TLB_XLAT       /* Write XLAT */
920         /*
921          * Create PAGEID. This is the faulting address plus
922          * a set of static bits. The static bits are page
923          * size and valid. Bits 20  and 21 should be zero
924          * for a page size of 4KB.
925          */
926         li      r22, 0x0210                     /* Set size and valid */
927         mfspr   r23, SPRN_SRR1                  /* Get SRR1 */
928         andi.   r23, r23, MSR_IS@l
929         beq     7f
930         ori     r22, r22, PPC44x_TLB_TS@l       /* Set TS=1 */
931 7:      rlwimi  r20, r22, 0, 20, 31             /* Insert statics */
932         tlbwe   r20, r24, PPC44x_TLB_PAGEID     /* Write PAGEID */
934         /* FIXME: Staticly setting some permissions */
935         li      r23, 0x002d                     /* Set UX,UR,SX,SR */
936         andi.   r21, r21, 0xffff                /* Clear MS 16 bits */
937         andi.   r22, r21, 0x0002                /* _PAGE_HWWRITE? */
938         beq     8f
939         ori     r23, r23, 0x0002                /* Set SW */
940         /* FIXME: Force attributes */
941 8:      ori     r21, r21, 0x0100                /* Set G */
942         /* FIXME: Already set in PTE */
943         rlwimi  r21, r23, 0, 26, 31             /* Insert static perms */
945         lis     r23,0xffff
946         ori     r23,r23,0x0fff                  /* Set U0-U3 mask */
947         and     r21,r21,r23                     /* Clear U0-U3 */
948         tlbwe   r21, r24, PPC44x_TLB_ATTRIB     /* Write ATTRIB */
950         /* Done...restore registers and get out of here.
951         */
952         mfspr   r21, SPRG7R
953         mtcr    r21
954         mfspr   r24, SPRG6R
955         mfspr   r23, SPRG5R
956         mfspr   r22, SPRG4R
957         mfspr   r21, SPRG1
958         mfspr   r20, SPRG0
959         rfi                                     /* Force context change */
962  * Global functions
963  */
966  * extern void giveup_altivec(struct task_struct *prev)
968  * The 44x core does not have an AltiVec unit.
969  */
970 _GLOBAL(giveup_altivec)
971         blr
974  * extern void giveup_fpu(struct task_struct *prev)
976  * The 44x core does not have an FPU.
977  */
978 _GLOBAL(giveup_fpu)
979         blr
982  * extern void abort(void)
984  * At present, this routine just applies a system reset.
985  */ 
986 _GLOBAL(abort)
987         mfspr   r13,SPRN_DBCR0
988         oris    r13,r13,DBCR_RST(DBCR_RST_SYSTEM)@h
989         mtspr   SPRN_DBCR0,r13
991 _GLOBAL(set_context)
993 #ifdef CONFIG_BDI_SWITCH
994         /* Context switch the PTE pointer for the Abatron BDI2000.
995          * The PGDIR is the second parameter.
996          */
997         lis     r5, abatron_pteptrs@h
998         ori     r5, r5, abatron_pteptrs@l
999         stw     r4, 0x4(r5)
1000 #endif
1001         mtspr   SPRN_PID,r3
1002         isync                   /* Force context change */
1003         blr
1006  * This code finishes saving the registers to the exception frame
1007  * and jumps to the appropriate handler for the exception, turning
1008  * on address translation.
1009  */
1010 _GLOBAL(transfer_to_handler)
1011         stw     r22,_NIP(r21)           /* Save the faulting IP on the stack */
1012         stw     r23,_MSR(r21)           /* Save the exception MSR on stack */
1013         SAVE_4GPRS(8, r21)              /* Save r8 through r11 on the stack */
1014         SAVE_8GPRS(12, r21)             /* Save r12 through r19 on the stack */
1015         SAVE_8GPRS(24, r21)             /* Save r24 through r31 on the stack */
1016         andi.   r23,r23,MSR_PR          /* Is this from user space? */
1017         mfspr   r23,SPRN_SPRG3          /* If from user, fix up THREAD.regs */
1018         beq     2f                      /* No, it is from the kernel; branch. */
1019         mfspr   r24,SPRN_DBCR0
1020         stw     r24,THREAD_DBCR0(r23)   /* Save Debug Control in thread_struct */
1021         addi    r24,r1,STACK_FRAME_OVERHEAD
1022         stw     r24,PT_REGS(r23)
1023 2:      addi    r2,r23,-THREAD          /* Set r2 to current thread */
1024         mflr    r23
1025         lwz     r24,8(r23)              /* Emulate classic PPC vectors */
1026         stw     r24,TRAP(r21)
1027         li      r22,RESULT
1028         /* No need to put an erratum #77 workaround here
1029                 because interrupts are currently disabled */
1030         stwcx.  r22,r22,r21             /* Clear the reservation */
1031         li      r22,0
1032         stw     r22,RESULT(r21)
1033         mtspr   SPRN_SPRG2,r22          /* r1 is now the kernel stack pointer */
1034         addi    r24,r2,TASK_STRUCT_SIZE /* Check for kernel stack overflow */
1035         cmplw   cr0,r1,r2
1036         cmplw   cr1,r1,r24
1037         crand   cr1,cr1,cr4
1038         bgt-    stack_ovf               /* If r2 < r1 < r2 + TASK_STRUCT_SIZE */
1039         lwz     r24,0(r23)              /* Virtual address of the handler */
1040         lwz     r23,4(r23)              /* Handler return pointer */
1041         cmpwi   cr0,r7,STND_EXC         /* What type of exception is this? */
1042         bne     3f                      /* It is a critical/machine check exception... */
1044         /* Standard exception jump path
1045         */
1047         /* We have to recover r7 from the register save stack.
1048          * It was used to indicate standard/critical exception.  In
1049          * the case of a standard exception that is the system call
1050          * trap, it may have originally contained one of the syscall
1051          * parameters and we have to get it back now.
1052          */
1053         lwz     r7,GPR7(r21)
1054         mtspr   SPRN_SRR0,r24           /* Set up the instruction pointer */
1055         mtspr   SPRN_SRR1,r20           /* Set up the machine state register */
1056         mtlr    r23                     /* Set up the return pointer */
1057         SYNC
1058         rfi
1060         /* Critical/Machine check exception jump path
1061         */
1062 3:      cmpwi   r7,CRIT_EXC             /* Critical or machine check ? */
1063         mtlr    r23                     /* Set up the return pointer */
1064         bne     4f
1065         mtspr   SPRN_CSRR0,r24          /* Set up the instruction pointer */
1066         mtspr   SPRN_CSRR1,r20          /* Set up the machine state register */
1067         SYNC
1068         rfci
1070 4:      mtspr   SPRN_MCSRR0,r24         /* Set up the instruction pointer */
1071         mtspr   SPRN_MCSRR1,r20         /* Set up the machine state register */
1072         SYNC    
1073         RFMCI
1075 /* On kernel stack overlow, load up an initial stack pointer and call
1076  * StackOverflow(regs), which should NOT return.
1077  */ 
1079 stack_ovf:
1080         addi    r3,r1,STACK_FRAME_OVERHEAD
1081         lis     r1,init_task_union@ha
1082         addi    r1,r1,init_task_union@l
1083         addi    r1,r1,TASK_UNION_SIZE - STACK_FRAME_OVERHEAD
1084         lis     r24,StackOverflow@ha
1085         addi    r24,r24,StackOverflow@l
1086         li      r20,MSR_KERNEL
1087         mtspr   SPRN_SRR0,r24
1088         mtspr   SPRN_SRR1,r20
1089         SYNC
1090         rfi
1093  * We put a few things here that have to be page-aligned. This stuff
1094  * goes at the beginning of the data segment, which is page-aligned.
1095  */
1096         .data
1097 _GLOBAL(sdata)
1098 _GLOBAL(empty_zero_page)
1099         .space  4096
1102  * To support >32-bit physical addresses, we use an 8KB pgdir.
1103  */
1104 _GLOBAL(swapper_pg_dir)
1105         .space  8192
1108  * This space gets a copy of optional info passed to us by the bootstrap
1109  * which is used to pass parameters into the kernel like root=/dev/sda1, etc.
1110  */
1111 _GLOBAL(cmd_line)
1112         .space  512
1115  * Room for two PTE pointers, usually the kernel and current user pointers
1116  * to their respective root page table.
1117  */
1118 abatron_pteptrs:
1119         .space  8