ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ppc / kernel / head_44x.S
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  */
32
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/ibm4xx.h>
39 #include <asm/ibm44x.h>
40 #include <asm/cputable.h>
41 #include <asm/thread_info.h>
42 #include <asm/ppc_asm.h>
43 #include <asm/offsets.h>
44
45 /*
46  * Macros
47  */
48
49 #define SET_IVOR(vector_number, vector_label)           \
50                 li      r26,vector_label@l;             \
51                 mtspr   SPRN_IVOR##vector_number,r26;   \
52                 sync
53                                 
54 /* As with the other PowerPC ports, it is expected that when code
55  * execution begins here, the following registers contain valid, yet
56  * optional, information:
57  *
58  *   r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.)
59  *   r4 - Starting address of the init RAM disk
60  *   r5 - Ending address of the init RAM disk
61  *   r6 - Start of kernel command line string (e.g. "mem=128")
62  *   r7 - End of kernel command line string
63  *
64  */
65         .text
66 _GLOBAL(_stext)
67 _GLOBAL(_start)
68         /*
69          * Reserve a word at a fixed location to store the address
70          * of abatron_pteptrs
71          */
72         nop
73 /*
74  * Save parameters we are passed
75  */
76         mr      r31,r3
77         mr      r30,r4
78         mr      r29,r5
79         mr      r28,r6
80         mr      r27,r7
81         li      r24,0           /* CPU number */
82
83 /*
84  * Set up the initial MMU state
85  *
86  * We are still executing code at the virtual address
87  * mappings set by the firmware for the base of RAM.
88  *
89  * We first invalidate all TLB entries but the one
90  * we are running from.  We then load the KERNELBASE
91  * mappings so we can begin to use kernel addresses
92  * natively and so the interrupt vector locations are
93  * permanently pinned (necessary since Book E
94  * implementations always have translation enabled).
95  *
96  * TODO: Use the known TLB entry we are running from to
97  *       determine which physical region we are located
98  *       in.  This can be used to determine where in RAM
99  *       (on a shared CPU system) or PCI memory space
100  *       (on a DRAMless system) we are located.
101  *       For now, we assume a perfect world which means
102  *       we are located at the base of DRAM (physical 0).
103  */
104
105 /*
106  * Search TLB for entry that we are currently using.
107  * Invalidate all entries but the one we are using.
108  */
109         /* Load our current PID->MMUCR TID and MSR IS->MMUCR STS */
110         mfspr   r3,SPRN_PID                     /* Get PID */
111         mfmsr   r4                              /* Get MSR */
112         andi.   r4,r4,MSR_IS@l                  /* TS=1? */
113         beq     wmmucr                          /* If not, leave STS=0 */
114         oris    r3,r3,PPC44x_MMUCR_STS@h        /* Set STS=1 */
115 wmmucr: mtspr   SPRN_MMUCR,r3                   /* Put MMUCR */
116         sync
117
118         bl      invstr                          /* Find our address */
119 invstr: mflr    r5                              /* Make it accessible */
120         tlbsx   r23,0,r5                        /* Find entry we are in */
121         li      r4,0                            /* Start at TLB entry 0 */
122         li      r3,0                            /* Set PAGEID inval value */
123 1:      cmpw    r23,r4                          /* Is this our entry? */
124         beq     skpinv                          /* If so, skip the inval */
125         tlbwe   r3,r4,PPC44x_TLB_PAGEID         /* If not, inval the entry */
126 skpinv: addi    r4,r4,1                         /* Increment */
127         cmpwi   r4,64                           /* Are we done? */
128         bne     1b                              /* If not, repeat */
129         isync                                   /* If so, context change */
130
131 /*
132  * Configure and load pinned entry into TLB slot 63.
133  */
134
135         lis     r3,KERNELBASE@h         /* Load the kernel virtual address */
136         ori     r3,r3,KERNELBASE@l
137
138         /* Kernel is at the base of RAM */
139         li r4, 0                        /* Load the kernel physical address */
140
141         /* Load the kernel PID = 0 */
142         li      r0,0
143         mtspr   SPRN_PID,r0
144         sync
145
146         /* Initialize MMUCR */
147         li      r5,0
148         mtspr   SPRN_MMUCR,r5
149         sync
150
151         /* pageid fields */
152         clrrwi  r3,r3,10                /* Mask off the effective page number */
153         ori     r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_256M
154
155         /* xlat fields */
156         clrrwi  r4,r4,10                /* Mask off the real page number */
157                                         /* ERPN is 0 for first 4GB page */
158
159         /* attrib fields */
160         /* Added guarded bit to protect against speculative loads/stores */
161         li      r5,0
162         ori     r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G)
163
164         li      r0,63                    /* TLB slot 63 */
165
166         tlbwe   r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */
167         tlbwe   r4,r0,PPC44x_TLB_XLAT   /* Load the translation fields */
168         tlbwe   r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */
169
170         /* Force context change */
171         mfmsr   r0
172         mtspr   SRR1, r0
173         lis     r0,3f@h
174         ori     r0,r0,3f@l
175         mtspr   SRR0,r0
176         sync
177         rfi
178
179         /* If necessary, invalidate original entry we used */
180 3:      cmpwi   r23,62
181         beq     4f
182         li      r6,0
183         tlbwe   r6,r23,PPC44x_TLB_PAGEID
184         sync
185
186 4:
187 #ifdef CONFIG_SERIAL_TEXT_DEBUG
188         /*
189          * Add temporary UART mapping for early debug.  This
190          * mapping must be identical to that used by the early
191          * bootloader code since the same asm/serial.h parameters
192          * are used for polled operation.
193          */
194         /* pageid fields */
195         lis     r3,0xe000       
196         ori     r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_256M
197
198         /* xlat fields */
199         lis     r4,0x4000               /* RPN is 0x40000000 */
200         ori     r4,r4,0x0001            /* ERPN is 1 for second 4GB page */
201
202         /* attrib fields */
203         li      r5,0
204         ori     r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_I | PPC44x_TLB_G)
205
206         li      r0,1                    /* TLB slot 1 */
207
208         tlbwe   r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */
209         tlbwe   r4,r0,PPC44x_TLB_XLAT   /* Load the translation fields */
210         tlbwe   r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */
211
212         ori     r3,r3,PPC44x_TLB_TS     /* Translation state 1 */
213
214         li      r0,1                    /* TLB slot 1 */
215
216         tlbwe   r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */
217         tlbwe   r4,r0,PPC44x_TLB_XLAT   /* Load the translation fields */
218         tlbwe   r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */
219
220         /* Force context change */
221         isync
222 #endif /* CONFIG_SERIAL_TEXT_DEBUG */
223
224         /* Establish the interrupt vector offsets */
225         SET_IVOR(0,  CriticalInput);
226         SET_IVOR(1,  MachineCheck);
227         SET_IVOR(2,  DataStorage);
228         SET_IVOR(3,  InstructionStorage);
229         SET_IVOR(4,  ExternalInput);
230         SET_IVOR(5,  Alignment);
231         SET_IVOR(6,  Program);
232         SET_IVOR(7,  FloatingPointUnavailable);
233         SET_IVOR(8,  SystemCall);
234         SET_IVOR(9,  AuxillaryProcessorUnavailable);
235         SET_IVOR(10, Decrementer);
236         SET_IVOR(11, FixedIntervalTimer);
237         SET_IVOR(12, WatchdogTimer);
238         SET_IVOR(13, DataTLBError);
239         SET_IVOR(14, InstructionTLBError);
240         SET_IVOR(15, Debug);
241
242         /* Establish the interrupt vector base */
243         lis     r4,interrupt_base@h     /* IVPR only uses the high 16-bits */
244         mtspr   SPRN_IVPR,r4
245
246         /*
247          * This is where the main kernel code starts.
248          */
249
250         /* ptr to current */
251         lis     r2,init_task@h
252         ori     r2,r2,init_task@l
253
254         /* ptr to current thread */
255         addi    r4,r2,THREAD    /* init task's THREAD */
256         mtspr   SPRG3,r4
257
258         /* stack */
259         lis     r1,init_thread_union@h
260         ori     r1,r1,init_thread_union@l
261         li      r0,0
262         stwu    r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
263
264         bl      early_init
265
266 /*
267  * Decide what sort of machine this is and initialize the MMU.
268  */
269         mr      r3,r31
270         mr      r4,r30
271         mr      r5,r29
272         mr      r6,r28
273         mr      r7,r27
274         bl      machine_init
275         bl      MMU_init
276
277         /* Setup PTE pointers for the Abatron bdiGDB */
278         lis     r6, swapper_pg_dir@h
279         ori     r6, r6, swapper_pg_dir@l
280         lis     r5, abatron_pteptrs@h
281         ori     r5, r5, abatron_pteptrs@l
282         lis     r4, KERNELBASE@h
283         ori     r4, r4, KERNELBASE@l
284         stw     r5, 0(r4)       /* Save abatron_pteptrs at a fixed location */
285         stw     r6, 0(r5)
286
287         /* Let's move on */
288         lis     r4,start_kernel@h
289         ori     r4,r4,start_kernel@l
290         lis     r3,MSR_KERNEL@h
291         ori     r3,r3,MSR_KERNEL@l
292         mtspr   SRR0,r4
293         mtspr   SRR1,r3
294         rfi                     /* change context and jump to start_kernel */
295
296 /*
297  * Interrupt vector entry code
298  *
299  * The Book E MMUs are always on so we don't need to handle
300  * interrupts in real mode as with previous PPC processors. In
301  * this case we handle interrupts in the kernel virtual address
302  * space.
303  *
304  * Interrupt vectors are dynamically placed relative to the
305  * interrupt prefix as determined by the address of interrupt_base.
306  * The interrupt vectors offsets are programmed using the labels
307  * for each interrupt vector entry.
308  *
309  * Interrupt vectors must be aligned on a 16 byte boundary.
310  * We align on a 32 byte cache line boundary for good measure.
311  */
312
313 #define NORMAL_EXCEPTION_PROLOG                                              \
314         mtspr   SPRN_SPRG0,r10;         /* save two registers to work with */\
315         mtspr   SPRN_SPRG1,r11;                                              \
316         mtspr   SPRN_SPRG2,r1;                                               \
317         mfcr    r10;                    /* save CR in r10 for now          */\
318         mfspr   r11,SPRN_SRR1;          /* check whether user or kernel    */\
319         andi.   r11,r11,MSR_PR;                                              \
320         beq     1f;                                                          \
321         mfspr   r1,SPRG3;               /* if from user, start at top of   */\
322         lwz     r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack   */\
323         addi    r1,r1,THREAD_SIZE;                                           \
324 1:      subi    r1,r1,INT_FRAME_SIZE;   /* Allocate an exception frame     */\
325         tophys(r11,r1);                                                      \
326         stw     r10,_CCR(r11);          /* save various registers          */\
327         stw     r12,GPR12(r11);                                              \
328         stw     r9,GPR9(r11);                                                \
329         mfspr   r10,SPRG0;                                                   \
330         stw     r10,GPR10(r11);                                              \
331         mfspr   r12,SPRG1;                                                   \
332         stw     r12,GPR11(r11);                                              \
333         mflr    r10;                                                         \
334         stw     r10,_LINK(r11);                                              \
335         mfspr   r10,SPRG2;                                                   \
336         mfspr   r12,SRR0;                                                    \
337         stw     r10,GPR1(r11);                                               \
338         mfspr   r9,SRR1;                                                     \
339         stw     r10,0(r11);                                                  \
340         rlwinm  r9,r9,0,14,12;          /* clear MSR_WE (necessary?)       */\
341         stw     r0,GPR0(r11);                                                \
342         SAVE_4GPRS(3, r11);                                                  \
343         SAVE_2GPRS(7, r11)
344
345 /*
346  * Exception prolog for critical exceptions.  This is a little different
347  * from the normal exception prolog above since a critical exception
348  * can potentially occur at any point during normal exception processing.
349  * Thus we cannot use the same SPRG registers as the normal prolog above.
350  * Instead we use a couple of words of memory at low physical addresses.
351  * This is OK since we don't support SMP on these processors.
352  */
353 /* XXX but we don't have RAM mapped at 0 in space 0  -- paulus. */
354 #define CRITICAL_EXCEPTION_PROLOG                                            \
355         stw     r10,crit_r10@l(0);      /* save two registers to work with */\
356         stw     r11,crit_r11@l(0);                                           \
357         mfspr   r10,SPRG0;                                                   \
358         stw     r10,crit_sprg0@l(0);                                         \
359         mfspr   r10,SPRG1;                                                   \
360         stw     r10,crit_sprg1@l(0);                                         \
361         mfspr   r10,SPRG4R;                                                  \
362         stw     r10,crit_sprg4@l(0);                                         \
363         mfspr   r10,SPRG5R;                                                  \
364         stw     r10,crit_sprg5@l(0);                                         \
365         mfspr   r10,SPRG6R;                                                  \
366         stw     r10,crit_sprg6@l(0);                                         \
367         mfspr   r10,SPRG7R;                                                  \
368         stw     r10,crit_sprg7@l(0);                                         \
369         mfspr   r10,SPRN_PID;                                                \
370         stw     r10,crit_pid@l(0);                                           \
371         mfspr   r10,SRR0;                                                    \
372         stw     r10,crit_srr0@l(0);                                          \
373         mfspr   r10,SRR1;                                                    \
374         stw     r10,crit_srr1@l(0);                                          \
375         mfcr    r10;                    /* save CR in r10 for now          */\
376         mfspr   r11,SPRN_CSRR1;         /* check whether user or kernel    */\
377         andi.   r11,r11,MSR_PR;                                              \
378         lis     r11,critical_stack_top@h;                                    \
379         ori     r11,r11,critical_stack_top@l;                                \
380         beq     1f;                                                          \
381         /* COMING FROM USER MODE */                                          \
382         mfspr   r11,SPRG3;              /* if from user, start at top of   */\
383         lwz     r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\
384         addi    r11,r11,THREAD_SIZE;                                         \
385 1:      subi    r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame     */\
386         tophys(r11,r11);                                                     \
387         stw     r10,_CCR(r11);          /* save various registers          */\
388         stw     r12,GPR12(r11);                                              \
389         stw     r9,GPR9(r11);                                                \
390         mflr    r10;                                                         \
391         stw     r10,_LINK(r11);                                              \
392         mfspr   r12,SPRN_DEAR;          /* save DEAR and ESR in the frame  */\
393         stw     r12,_DEAR(r11);         /* since they may have had stuff   */\
394         mfspr   r9,SPRN_ESR;            /* in them at the point where the  */\
395         stw     r9,_ESR(r11);           /* exception was taken             */\
396         mfspr   r12,CSRR0;                                                   \
397         stw     r1,GPR1(r11);                                                \
398         mfspr   r9,CSRR1;                                                    \
399         stw     r1,0(r11);                                                   \
400         tovirt(r1,r11);                                                      \
401         rlwinm  r9,r9,0,14,12;          /* clear MSR_WE (necessary?)       */\
402         stw     r0,GPR0(r11);                                                \
403         SAVE_4GPRS(3, r11);                                                  \
404         SAVE_2GPRS(7, r11)
405
406 /*
407  * Exception vectors.
408  */
409 #define START_EXCEPTION(label)                                               \
410         .align 5;                                                            \
411 label:
412
413 #define FINISH_EXCEPTION(func)                                  \
414         bl      transfer_to_handler_full;                       \
415         .long   func;                                           \
416         .long   ret_from_except_full
417
418 #define EXCEPTION(n, label, hdlr, xfer)                         \
419         START_EXCEPTION(label);                                 \
420         NORMAL_EXCEPTION_PROLOG;                                \
421         addi    r3,r1,STACK_FRAME_OVERHEAD;                     \
422         xfer(n, hdlr)
423
424 #define CRITICAL_EXCEPTION(n, label, hdlr)                      \
425         START_EXCEPTION(label);                                 \
426         CRITICAL_EXCEPTION_PROLOG;                              \
427         addi    r3,r1,STACK_FRAME_OVERHEAD;                     \
428         EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
429                           NOCOPY, transfer_to_handler_full, \
430                           ret_from_except_full)
431
432 #define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret)   \
433         li      r10,trap;                                       \
434         stw     r10,TRAP(r11);                                  \
435         lis     r10,msr@h;                                      \
436         ori     r10,r10,msr@l;                                  \
437         copyee(r10, r9);                                        \
438         bl      tfer;                                           \
439         .long   hdlr;                                           \
440         .long   ret
441
442 #define COPY_EE(d, s)           rlwimi d,s,0,16,16
443 #define NOCOPY(d, s)
444
445 #define EXC_XFER_STD(n, hdlr)           \
446         EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \
447                           ret_from_except_full)
448
449 #define EXC_XFER_LITE(n, hdlr)          \
450         EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \
451                           ret_from_except)
452
453 #define EXC_XFER_EE(n, hdlr)            \
454         EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \
455                           ret_from_except_full)
456
457 #define EXC_XFER_EE_LITE(n, hdlr)       \
458         EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \
459                           ret_from_except)
460
461 interrupt_base:
462         /* Critical Input Interrupt */
463         CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException)
464
465         /* Machine Check Interrupt */
466         CRITICAL_EXCEPTION(0x0200, MachineCheck, MachineCheckException)
467
468         /* Data Storage Interrupt */
469         START_EXCEPTION(DataStorage)
470         mtspr   SPRG0, r10              /* Save some working registers */
471         mtspr   SPRG1, r11
472         mtspr   SPRG4W, r12
473         mtspr   SPRG5W, r13
474         mtspr   SPRG6W, r14
475         mfcr    r11
476         mtspr   SPRG7W, r11
477
478         /*
479          * Check if it was a store fault, if not then bail
480          * because a user tried to access a kernel or
481          * read-protected page.  Otherwise, get the
482          * offending address and handle it.
483          */
484         mfspr   r10, SPRN_ESR
485         andis.  r10, r10, ESR_ST@h
486         beq     2f
487
488         mfspr   r10, SPRN_DEAR          /* Get faulting address */
489
490         /* If we are faulting a kernel address, we have to use the
491          * kernel page tables.
492          */
493         andis.  r11, r10, 0x8000
494         beq     3f
495         lis     r11, swapper_pg_dir@h
496         ori     r11, r11, swapper_pg_dir@l
497
498         mfspr   r12,SPRN_MMUCR
499         rlwinm  r12,r12,0,0,23          /* Clear TID */
500
501         b       4f
502
503         /* Get the PGD for the current thread */
504 3:
505         mfspr   r11,SPRG3
506         lwz     r11,PGDIR(r11)
507
508         /* Load PID into MMUCR TID */
509         mfspr   r12,SPRN_MMUCR          /* Get MMUCR */
510         mfspr   r13,SPRN_PID            /* Get PID */
511         rlwimi  r12,r13,0,24,31         /* Set TID */
512
513 4:
514         mtspr   SPRN_MMUCR,r12
515
516         rlwinm  r12, r10, 13, 19, 29    /* Compute pgdir/pmd offset */
517         lwzx    r11, r12, r11           /* Get pgd/pmd entry */
518         rlwinm. r12, r11, 0, 0, 20      /* Extract pt base address */
519         beq     2f                      /* Bail if no table */
520
521         rlwimi  r12, r10, 23, 20, 28    /* Compute pte address */
522         lwz     r11, 4(r12)             /* Get pte entry */
523
524         andi.   r13, r11, _PAGE_RW      /* Is it writeable? */
525         beq     2f                      /* Bail if not */
526
527         /* Update 'changed'.
528         */
529         ori     r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
530         stw     r11, 4(r12)             /* Update Linux page table */
531
532         li      r13, PPC44x_TLB_SR@l    /* Set SR */
533         rlwimi  r13, r11, 29, 29, 29    /* SX = _PAGE_HWEXEC */
534         rlwimi  r13, r11, 0, 30, 30     /* SW = _PAGE_RW */
535         rlwimi  r13, r11, 29, 28, 28    /* UR = _PAGE_USER */
536         rlwimi  r12, r11, 31, 26, 26    /* (_PAGE_USER>>1)->r12 */
537         rlwimi  r12, r11, 29, 30, 30    /* (_PAGE_USER>>3)->r12 */
538         and     r12, r12, r11           /* HWEXEC/RW & USER */
539         rlwimi  r13, r12, 0, 26, 26     /* UX = HWEXEC & USER */
540         rlwimi  r13, r12, 3, 27, 27     /* UW = RW & USER */
541
542         rlwimi  r11,r13,0,26,31         /* Insert static perms */
543
544         rlwinm  r11,r11,0,20,15         /* Clear U0-U3 */
545
546         /* find the TLB index that caused the fault.  It has to be here. */
547         tlbsx   r14, 0, r10
548
549         tlbwe   r11, r14, PPC44x_TLB_ATTRIB     /* Write ATTRIB */
550
551         /* Done...restore registers and get out of here.
552         */
553         mfspr   r11, SPRG7R
554         mtcr    r11
555         mfspr   r14, SPRG6R
556         mfspr   r13, SPRG5R
557         mfspr   r12, SPRG4R
558
559         mfspr   r11, SPRG1
560         mfspr   r10, SPRG0
561         rfi                     /* Force context change */
562
563 2:
564         /*
565          * The bailout.  Restore registers to pre-exception conditions
566          * and call the heavyweights to help us out.
567          */
568         mfspr   r11, SPRG7R
569         mtcr    r11
570         mfspr   r14, SPRG6R
571         mfspr   r13, SPRG5R
572         mfspr   r12, SPRG4R
573
574         mfspr   r11, SPRG1
575         mfspr   r10, SPRG0
576         b       data_access
577
578         /* Instruction Storage Interrupt */
579         START_EXCEPTION(InstructionStorage)
580         NORMAL_EXCEPTION_PROLOG
581         mr      r4,r12                  /* Pass SRR0 as arg2 */
582         li      r5,0                    /* Pass zero as arg3 */
583         addi    r3,r1,STACK_FRAME_OVERHEAD
584         EXC_XFER_EE_LITE(0x0400, do_page_fault)
585
586         /* External Input Interrupt */
587         EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE)
588
589         /* Alignment Interrupt */
590         START_EXCEPTION(Alignment)
591         NORMAL_EXCEPTION_PROLOG
592         mfspr   r4,SPRN_DEAR            /* Grab the DEAR and save it */
593         stw     r4,_DEAR(r11)
594         addi    r3,r1,STACK_FRAME_OVERHEAD
595         EXC_XFER_EE(0x0600, AlignmentException)
596
597         /* Program Interrupt */
598         START_EXCEPTION(Program)
599         NORMAL_EXCEPTION_PROLOG
600         mfspr   r4,SPRN_ESR             /* Grab the ESR and save it */
601         stw     r4,_ESR(r11)
602         addi    r3,r1,STACK_FRAME_OVERHEAD
603         EXC_XFER_EE(0x700, ProgramCheckException)
604
605         /* Floating Point Unavailable Interrupt */
606         EXCEPTION(0x2010, FloatingPointUnavailable, UnknownException, EXC_XFER_EE)
607
608         /* System Call Interrupt */
609         START_EXCEPTION(SystemCall)
610         NORMAL_EXCEPTION_PROLOG
611         EXC_XFER_EE_LITE(0x0c00, DoSyscall)
612
613         /* Auxillary Processor Unavailable Interrupt */
614         EXCEPTION(0x2020, AuxillaryProcessorUnavailable, UnknownException, EXC_XFER_EE)
615
616         /* Decrementer Interrupt */
617         START_EXCEPTION(Decrementer)
618         NORMAL_EXCEPTION_PROLOG
619         lis     r0,TSR_DIS@h            /* Setup the DEC interrupt mask */
620         mtspr   SPRN_TSR,r0             /* Clear the DEC interrupt */
621         addi    r3,r1,STACK_FRAME_OVERHEAD
622         EXC_XFER_LITE(0x1000, timer_interrupt)
623
624         /* Fixed Internal Timer Interrupt */
625         /* TODO: Add FIT support */
626         EXCEPTION(0x1010, FixedIntervalTimer, UnknownException, EXC_XFER_EE)
627
628         /* Watchdog Timer Interrupt */
629         /* TODO: Add watchdog support */
630         CRITICAL_EXCEPTION(0x1020, WatchdogTimer, UnknownException)
631
632         /* Data TLB Error Interrupt */
633         START_EXCEPTION(DataTLBError)
634         mtspr   SPRG0, r10              /* Save some working registers */
635         mtspr   SPRG1, r11
636         mtspr   SPRG4W, r12
637         mtspr   SPRG5W, r13
638         mtspr   SPRG6W, r14
639         mfcr    r11
640         mtspr   SPRG7W, r11
641         mfspr   r10, SPRN_DEAR          /* Get faulting address */
642
643         /* If we are faulting a kernel address, we have to use the
644          * kernel page tables.
645          */
646         andis.  r11, r10, 0x8000
647         beq     3f
648         lis     r11, swapper_pg_dir@h
649         ori     r11, r11, swapper_pg_dir@l
650
651         mfspr   r12,SPRN_MMUCR
652         rlwinm  r12,r12,0,0,23          /* Clear TID */
653
654         b       4f
655
656         /* Get the PGD for the current thread */
657 3:
658         mfspr   r11,SPRG3
659         lwz     r11,PGDIR(r11)
660
661         /* Load PID into MMUCR TID */
662         mfspr   r12,SPRN_MMUCR
663         mfspr   r13,SPRN_PID            /* Get PID */
664         rlwimi  r12,r13,0,24,31         /* Set TID */
665
666 4:
667         mtspr   SPRN_MMUCR,r12
668
669         rlwinm  r12, r10, 13, 19, 29    /* Compute pgdir/pmd offset */
670         lwzx    r11, r12, r11           /* Get pgd/pmd entry */
671         rlwinm. r12, r11, 0, 0, 20      /* Extract pt base address */
672         beq     2f                      /* Bail if no table */
673
674         rlwimi  r12, r10, 23, 20, 28    /* Compute pte address */
675         lwz     r11, 4(r12)             /* Get pte entry */
676         andi.   r13, r11, _PAGE_PRESENT /* Is the page present? */
677         beq     2f                      /* Bail if not present */
678
679         ori     r11, r11, _PAGE_ACCESSED
680         stw     r11, 4(r12)
681
682          /* Jump to common tlb load */
683         b       finish_tlb_load
684
685 2:
686         /* The bailout.  Restore registers to pre-exception conditions
687          * and call the heavyweights to help us out.
688          */
689         mfspr   r11, SPRG7R
690         mtcr    r11
691         mfspr   r14, SPRG6R
692         mfspr   r13, SPRG5R
693         mfspr   r12, SPRG4R
694         mfspr   r11, SPRG1
695         mfspr   r10, SPRG0
696         b       data_access
697
698         /* Instruction TLB Error Interrupt */
699         /*
700          * Nearly the same as above, except we get our
701          * information from different registers and bailout
702          * to a different point.
703          */
704         START_EXCEPTION(InstructionTLBError)
705         mtspr   SPRG0, r10              /* Save some working registers */
706         mtspr   SPRG1, r11
707         mtspr   SPRG4W, r12
708         mtspr   SPRG5W, r13
709         mtspr   SPRG6W, r14
710         mfcr    r11
711         mtspr   SPRG7W, r11
712         mfspr   r10, SRR0               /* Get faulting address */
713
714         /* If we are faulting a kernel address, we have to use the
715          * kernel page tables.
716          */
717         andis.  r11, r10, 0x8000
718         beq     3f
719         lis     r11, swapper_pg_dir@h
720         ori     r11, r11, swapper_pg_dir@l
721
722         mfspr   r12,SPRN_MMUCR
723         rlwinm  r12,r12,0,0,23          /* Clear TID */
724
725         b       4f
726
727         /* Get the PGD for the current thread */
728 3:
729         mfspr   r11,SPRG3
730         lwz     r11,PGDIR(r11)
731
732         /* Load PID into MMUCR TID */
733         mfspr   r12,SPRN_MMUCR
734         mfspr   r13,SPRN_PID            /* Get PID */
735         rlwimi  r12,r13,0,24,31         /* Set TID */
736
737 4:
738         mtspr   SPRN_MMUCR,r12
739
740         rlwinm  r12, r10, 13, 19, 29    /* Compute pgdir/pmd offset */
741         lwzx    r11, r12, r11           /* Get pgd/pmd entry */
742         rlwinm. r12, r11, 0, 0, 20      /* Extract pt base address */
743         beq     2f                      /* Bail if no table */
744
745         rlwimi  r12, r10, 23, 20, 28    /* Compute pte address */
746         lwz     r11, 4(r12)             /* Get pte entry */
747         andi.   r13, r11, _PAGE_PRESENT /* Is the page present? */
748         beq     2f                      /* Bail if not present */
749
750         ori     r11, r11, _PAGE_ACCESSED
751         stw     r11, 4(r12)
752
753         /* Jump to common TLB load point */
754         b       finish_tlb_load
755
756 2:
757         /* The bailout.  Restore registers to pre-exception conditions
758          * and call the heavyweights to help us out.
759          */
760         mfspr   r11, SPRG7R
761         mtcr    r11
762         mfspr   r14, SPRG6R
763         mfspr   r13, SPRG5R
764         mfspr   r12, SPRG4R
765         mfspr   r11, SPRG1
766         mfspr   r10, SPRG0
767         b       InstructionStorage
768
769 /* Check for a single step debug exception while in an exception
770  * handler before state has been saved.  This is to catch the case
771  * where an instruction that we are trying to single step causes
772  * an exception (eg ITLB/DTLB miss) and thus the first instruction of
773  * the exception handler generates a single step debug exception.
774  *
775  * If we get a debug trap on the first instruction of an exception handler,
776  * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is
777  * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR).
778  * The exception handler was handling a non-critical interrupt, so it will
779  * save (and later restore) the MSR via SPRN_SRR1, which will still have
780  * the MSR_DE bit set.
781  */
782         /* Debug Interrupt */
783         CRITICAL_EXCEPTION(0x2000, Debug, DebugException)
784 #if 0
785         START_EXCEPTION(Debug)
786         /* This first instruction was already executed by the exception
787          * handler and must be the first instruction of every exception
788          * handler.
789          */
790         mtspr   SPRN_SPRG0,r10          /* Save some working registers... */
791         mtspr   SPRN_SPRG1,r11
792         mtspr   SPRN_SPRG4W,r12
793         mfcr    r10                     /* ..and the cr because we change it */
794
795         mfspr   r11,SPRN_CSRR1          /* MSR at the time of fault */
796         andi.   r11,r11,MSR_PR
797         bne+    2f                      /* trapped from problem state */
798
799         mfspr   r11,SPRN_CSRR0          /* Faulting instruction address */
800         lis     r12, KERNELBASE@h
801         ori     r12, r12, KERNELBASE@l
802         cmplw   r11,r12
803         blt+    2f                      /* addr below exception vectors */
804
805         lis     r12, Debug@h
806         ori     r12, r12, Debug@l
807         cmplw   r11,r12
808         bgt+    2f                      /* addr above TLB exception vectors */
809
810         lis     r11,DBSR_IC@h           /* Remove the trap status */
811         mtspr   SPRN_DBSR,r11
812
813         mfspr   r11,SPRN_CSRR1
814         rlwinm  r11,r11,0,23,21         /* clear MSR_DE */
815         mtspr   SPRN_CSRR1, r11         /* restore MSR at rcfi without DE */
816
817         mtcrf   0xff,r10                /* restore registers */
818         mfspr   r12,SPRN_SPRG4R
819         mfspr   r11,SPRN_SPRG1
820         mfspr   r10,SPRN_SPRG0
821
822         sync
823         rfci                            /* return to the exception handler  */
824         b       .                       /* prevent prefetch past rfci */
825
826 2:
827         mtcrf   0xff,r10                /* restore registers */
828         mfspr   r12,SPRN_SPRG4R
829         mfspr   r11,SPRN_SPRG1
830         mfspr   r10,SPRN_SPRG0
831
832         CRIT_EXCEPTION_PROLOG
833         addi    r3,r1,STACK_FRAME_OVERHEAD
834         li      r7,CRIT_EXC;
835         li      r9,MSR_KERNEL
836         FINISH_EXCEPTION(DebugException)
837 #endif
838
839 /*
840  * Local functions
841  */
842         /*
843          * Data TLB exceptions will bail out to this point
844          * if they can't resolve the lightweight TLB fault.
845          */
846 data_access:
847         NORMAL_EXCEPTION_PROLOG
848         mfspr   r5,SPRN_ESR             /* Grab the ESR, save it, pass arg3 */
849         stw     r5,_ESR(r11)
850         mfspr   r4,SPRN_DEAR            /* Grab the DEAR, save it, pass arg2 */
851         stw     r4,_DEAR(r11)
852         addi    r3,r1,STACK_FRAME_OVERHEAD
853         EXC_XFER_EE_LITE(0x0300, do_page_fault)
854
855 /*
856
857  * Both the instruction and data TLB miss get to this
858  * point to load the TLB.
859  *      r10 - EA of fault
860  *      r11 - available to use
861  *      r12 - Pointer to the 64-bit PTE
862  *      r13 - available to use
863  *      r14 - available to use
864  *      MMUCR - loaded with proper value when we get here
865  *      Upon exit, we reload everything and RFI.
866  */
867 finish_tlb_load:
868         /*
869          * We set execute, because we don't have the granularity to
870          * properly set this at the page level (Linux problem).
871          * If shared is set, we cause a zero PID->TID load.
872          * Many of these bits are software only.  Bits we don't set
873          * here we (properly should) assume have the appropriate value.
874          */
875
876         /* Load the next available TLB index */
877         lis     r13, tlb_44x_index@ha
878         lwz     r14, tlb_44x_index@l(r13)
879         /* Load the TLB high watermark */
880         lis     r13, tlb_44x_hwater@ha
881         lwz     r11, tlb_44x_hwater@l(r13)
882
883         /* Increment, rollover, and store TLB index */
884         addi    r14, r14, 1
885         cmpw    0, r14, r11                     /* reserve entries */
886         ble     7f
887         li      r14, 0
888 7:
889         /* Store the next available TLB index */
890         lis     r13, tlb_44x_index@ha
891         stw     r14, tlb_44x_index@l(r13)
892
893         lwz     r13, 0(r12)                     /* Get MS word of PTE */
894         lwz     r11, 4(r12)                     /* Get LS word of PTE */
895         rlwimi  r13, r11, 0, 0 , 19             /* Insert RPN */
896         tlbwe   r13, r14, PPC44x_TLB_XLAT       /* Write XLAT */
897
898         /*
899          * Create PAGEID. This is the faulting address,
900          * page size, and valid flag.
901          */
902         li      r12, PPC44x_TLB_VALID | PPC44x_TLB_4K
903         rlwimi  r10, r12, 0, 20, 31             /* Insert valid and page size */
904         tlbwe   r10, r14, PPC44x_TLB_PAGEID     /* Write PAGEID */
905
906         li      r13, PPC44x_TLB_SR@l            /* Set SR */
907         rlwimi  r13, r11, 0, 30, 30             /* Set SW = _PAGE_RW */
908         rlwimi  r13, r11, 29, 29, 29            /* SX = _PAGE_HWEXEC */
909         rlwimi  r13, r11, 29, 28, 28            /* UR = _PAGE_USER */
910         rlwimi  r12, r11, 31, 26, 26            /* (_PAGE_USER>>1)->r12 */
911         and     r12, r12, r11                   /* HWEXEC & USER */
912         rlwimi  r13, r12, 0, 26, 26             /* UX = HWEXEC & USER */
913
914         rlwimi  r11, r13, 0, 26, 31             /* Insert static perms */
915         rlwinm  r11, r11, 0, 20, 15             /* Clear U0-U3 */
916         tlbwe   r11, r14, PPC44x_TLB_ATTRIB     /* Write ATTRIB */
917
918         /* Done...restore registers and get out of here.
919         */
920         mfspr   r11, SPRG7R
921         mtcr    r11
922         mfspr   r14, SPRG6R
923         mfspr   r13, SPRG5R
924         mfspr   r12, SPRG4R
925         mfspr   r11, SPRG1
926         mfspr   r10, SPRG0
927         rfi                                     /* Force context change */
928
929 /*
930  * Global functions
931  */
932
933 /*
934  * extern void giveup_altivec(struct task_struct *prev)
935  *
936  * The 44x core does not have an AltiVec unit.
937  */
938 _GLOBAL(giveup_altivec)
939         blr
940
941 /*
942  * extern void giveup_fpu(struct task_struct *prev)
943  *
944  * The 44x core does not have an FPU.
945  */
946 _GLOBAL(giveup_fpu)
947         blr
948
949 /*
950  * extern void abort(void)
951  *
952  * At present, this routine just applies a system reset.
953  */
954 _GLOBAL(abort)
955         mfspr   r13,SPRN_DBCR0
956         oris    r13,r13,DBCR0_RST_SYSTEM@h
957         mtspr   SPRN_DBCR0,r13
958
959 _GLOBAL(set_context)
960
961 #ifdef CONFIG_BDI_SWITCH
962         /* Context switch the PTE pointer for the Abatron BDI2000.
963          * The PGDIR is the second parameter.
964          */
965         lis     r5, abatron_pteptrs@h
966         ori     r5, r5, abatron_pteptrs@l
967         stw     r4, 0x4(r5)
968 #endif
969         mtspr   SPRN_PID,r3
970         isync                   /* Force context change */
971         blr
972
973 /*
974  * We put a few things here that have to be page-aligned. This stuff
975  * goes at the beginning of the data segment, which is page-aligned.
976  */
977         .data
978 _GLOBAL(sdata)
979 _GLOBAL(empty_zero_page)
980         .space  4096
981
982 /*
983  * To support >32-bit physical addresses, we use an 8KB pgdir.
984  */
985 _GLOBAL(swapper_pg_dir)
986         .space  8192
987
988 /* Stack for handling critical exceptions from kernel mode */
989         .section .bss
990 critical_stack_bottom:
991         .space 4096
992 critical_stack_top:
993         .previous
994
995 /*
996  * This space gets a copy of optional info passed to us by the bootstrap
997  * which is used to pass parameters into the kernel like root=/dev/sda1, etc.
998  */
999 _GLOBAL(cmd_line)
1000         .space  512
1001
1002 /*
1003  * Room for two PTE pointers, usually the kernel and current user pointers
1004  * to their respective root page table.
1005  */
1006 abatron_pteptrs:
1007         .space  8
1008
1009 /*
1010  * This area is used for temporarily saving registers during the
1011  * critical exception prolog.
1012  */
1013 crit_save:
1014 _GLOBAL(crit_r10)
1015         .space  4
1016 _GLOBAL(crit_r11)
1017         .space  4
1018 _GLOBAL(crit_sprg0)
1019         .space  4
1020 _GLOBAL(crit_sprg1)
1021         .space  4
1022 _GLOBAL(crit_sprg4)
1023         .space  4
1024 _GLOBAL(crit_sprg5)
1025         .space  4
1026 _GLOBAL(crit_sprg6)
1027         .space  4
1028 _GLOBAL(crit_sprg7)
1029         .space  4
1030 _GLOBAL(crit_pid)
1031         .space  4
1032 _GLOBAL(crit_srr0)
1033         .space  4
1034 _GLOBAL(crit_srr1)
1035         .space  4