Merge nommu tree
[linux-2.6] / arch / ppc / kernel / head_44x.S
1 /*
2  * Kernel execution entry point code.
3  *
4  *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
5  *      Initial PowerPC version.
6  *    Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu>
7  *      Rewritten for PReP
8  *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
9  *      Low-level exception handers, MMU support, and rewrite.
10  *    Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
11  *      PowerPC 8xx modifications.
12  *    Copyright (c) 1998-1999 TiVo, Inc.
13  *      PowerPC 403GCX modifications.
14  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
15  *      PowerPC 403GCX/405GP modifications.
16  *    Copyright 2000 MontaVista Software Inc.
17  *      PPC405 modifications
18  *      PowerPC 403GCX/405GP modifications.
19  *      Author: MontaVista Software, Inc.
20  *              frank_rowand@mvista.com or source@mvista.com
21  *              debbie_chu@mvista.com
22  *    Copyright 2002-2005 MontaVista Software, Inc.
23  *      PowerPC 44x support, Matt Porter <mporter@kernel.crashing.org>
24  *
25  * This program is free software; you can redistribute  it and/or modify it
26  * under  the terms of  the GNU General  Public License as published by the
27  * Free Software Foundation;  either version 2 of the  License, or (at your
28  * option) any later version.
29  */
30
31 #include <linux/config.h>
32 #include <asm/processor.h>
33 #include <asm/page.h>
34 #include <asm/mmu.h>
35 #include <asm/pgtable.h>
36 #include <asm/ibm4xx.h>
37 #include <asm/ibm44x.h>
38 #include <asm/cputable.h>
39 #include <asm/thread_info.h>
40 #include <asm/ppc_asm.h>
41 #include <asm/asm-offsets.h>
42 #include "head_booke.h"
43
44
45 /* As with the other PowerPC ports, it is expected that when code
46  * execution begins here, the following registers contain valid, yet
47  * optional, information:
48  *
49  *   r3 - Board info structure pointer (DRAM, frequency, MAC address, etc.)
50  *   r4 - Starting address of the init RAM disk
51  *   r5 - Ending address of the init RAM disk
52  *   r6 - Start of kernel command line string (e.g. "mem=128")
53  *   r7 - End of kernel command line string
54  *
55  */
56         .text
57 _GLOBAL(_stext)
58 _GLOBAL(_start)
59         /*
60          * Reserve a word at a fixed location to store the address
61          * of abatron_pteptrs
62          */
63         nop
64 /*
65  * Save parameters we are passed
66  */
67         mr      r31,r3
68         mr      r30,r4
69         mr      r29,r5
70         mr      r28,r6
71         mr      r27,r7
72         li      r24,0           /* CPU number */
73
74 /*
75  * Set up the initial MMU state
76  *
77  * We are still executing code at the virtual address
78  * mappings set by the firmware for the base of RAM.
79  *
80  * We first invalidate all TLB entries but the one
81  * we are running from.  We then load the KERNELBASE
82  * mappings so we can begin to use kernel addresses
83  * natively and so the interrupt vector locations are
84  * permanently pinned (necessary since Book E
85  * implementations always have translation enabled).
86  *
87  * TODO: Use the known TLB entry we are running from to
88  *       determine which physical region we are located
89  *       in.  This can be used to determine where in RAM
90  *       (on a shared CPU system) or PCI memory space
91  *       (on a DRAMless system) we are located.
92  *       For now, we assume a perfect world which means
93  *       we are located at the base of DRAM (physical 0).
94  */
95
96 /*
97  * Search TLB for entry that we are currently using.
98  * Invalidate all entries but the one we are using.
99  */
100         /* Load our current PID->MMUCR TID and MSR IS->MMUCR STS */
101         mfspr   r3,SPRN_PID                     /* Get PID */
102         mfmsr   r4                              /* Get MSR */
103         andi.   r4,r4,MSR_IS@l                  /* TS=1? */
104         beq     wmmucr                          /* If not, leave STS=0 */
105         oris    r3,r3,PPC44x_MMUCR_STS@h        /* Set STS=1 */
106 wmmucr: mtspr   SPRN_MMUCR,r3                   /* Put MMUCR */
107         sync
108
109         bl      invstr                          /* Find our address */
110 invstr: mflr    r5                              /* Make it accessible */
111         tlbsx   r23,0,r5                        /* Find entry we are in */
112         li      r4,0                            /* Start at TLB entry 0 */
113         li      r3,0                            /* Set PAGEID inval value */
114 1:      cmpw    r23,r4                          /* Is this our entry? */
115         beq     skpinv                          /* If so, skip the inval */
116         tlbwe   r3,r4,PPC44x_TLB_PAGEID         /* If not, inval the entry */
117 skpinv: addi    r4,r4,1                         /* Increment */
118         cmpwi   r4,64                           /* Are we done? */
119         bne     1b                              /* If not, repeat */
120         isync                                   /* If so, context change */
121
122 /*
123  * Configure and load pinned entry into TLB slot 63.
124  */
125
126         lis     r3,KERNELBASE@h         /* Load the kernel virtual address */
127         ori     r3,r3,KERNELBASE@l
128
129         /* Kernel is at the base of RAM */
130         li r4, 0                        /* Load the kernel physical address */
131
132         /* Load the kernel PID = 0 */
133         li      r0,0
134         mtspr   SPRN_PID,r0
135         sync
136
137         /* Initialize MMUCR */
138         li      r5,0
139         mtspr   SPRN_MMUCR,r5
140         sync
141
142         /* pageid fields */
143         clrrwi  r3,r3,10                /* Mask off the effective page number */
144         ori     r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_256M
145
146         /* xlat fields */
147         clrrwi  r4,r4,10                /* Mask off the real page number */
148                                         /* ERPN is 0 for first 4GB page */
149
150         /* attrib fields */
151         /* Added guarded bit to protect against speculative loads/stores */
152         li      r5,0
153         ori     r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G)
154
155         li      r0,63                    /* TLB slot 63 */
156
157         tlbwe   r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */
158         tlbwe   r4,r0,PPC44x_TLB_XLAT   /* Load the translation fields */
159         tlbwe   r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */
160
161         /* Force context change */
162         mfmsr   r0
163         mtspr   SPRN_SRR1, r0
164         lis     r0,3f@h
165         ori     r0,r0,3f@l
166         mtspr   SPRN_SRR0,r0
167         sync
168         rfi
169
170         /* If necessary, invalidate original entry we used */
171 3:      cmpwi   r23,63
172         beq     4f
173         li      r6,0
174         tlbwe   r6,r23,PPC44x_TLB_PAGEID
175         isync
176
177 4:
178 #ifdef CONFIG_SERIAL_TEXT_DEBUG
179         /*
180          * Add temporary UART mapping for early debug.
181          * We can map UART registers wherever we want as long as they don't
182          * interfere with other system mappings (e.g. with pinned entries).
183          * For an example of how we handle this - see ocotea.h.       --ebs
184          */
185         /* pageid fields */
186         lis     r3,UART0_IO_BASE@h
187         ori     r3,r3,PPC44x_TLB_VALID | PPC44x_TLB_4K
188
189         /* xlat fields */
190         lis     r4,UART0_PHYS_IO_BASE@h         /* RPN depends on SoC */
191 #ifdef UART0_PHYS_ERPN
192         ori     r4,r4,UART0_PHYS_ERPN           /* Add ERPN if above 4GB */
193 #endif
194
195         /* attrib fields */
196         li      r5,0
197         ori     r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_I | PPC44x_TLB_G)
198
199         li      r0,0                    /* TLB slot 0 */
200
201         tlbwe   r3,r0,PPC44x_TLB_PAGEID /* Load the pageid fields */
202         tlbwe   r4,r0,PPC44x_TLB_XLAT   /* Load the translation fields */
203         tlbwe   r5,r0,PPC44x_TLB_ATTRIB /* Load the attrib/access fields */
204
205         /* Force context change */
206         isync
207 #endif /* CONFIG_SERIAL_TEXT_DEBUG */
208
209         /* Establish the interrupt vector offsets */
210         SET_IVOR(0,  CriticalInput);
211         SET_IVOR(1,  MachineCheck);
212         SET_IVOR(2,  DataStorage);
213         SET_IVOR(3,  InstructionStorage);
214         SET_IVOR(4,  ExternalInput);
215         SET_IVOR(5,  Alignment);
216         SET_IVOR(6,  Program);
217         SET_IVOR(7,  FloatingPointUnavailable);
218         SET_IVOR(8,  SystemCall);
219         SET_IVOR(9,  AuxillaryProcessorUnavailable);
220         SET_IVOR(10, Decrementer);
221         SET_IVOR(11, FixedIntervalTimer);
222         SET_IVOR(12, WatchdogTimer);
223         SET_IVOR(13, DataTLBError);
224         SET_IVOR(14, InstructionTLBError);
225         SET_IVOR(15, Debug);
226
227         /* Establish the interrupt vector base */
228         lis     r4,interrupt_base@h     /* IVPR only uses the high 16-bits */
229         mtspr   SPRN_IVPR,r4
230
231 #ifdef CONFIG_440EP
232         /* Clear DAPUIB flag in CCR0 (enable APU between CPU and FPU) */
233         mfspr   r2,SPRN_CCR0
234         lis     r3,0xffef
235         ori     r3,r3,0xffff
236         and     r2,r2,r3
237         mtspr   SPRN_CCR0,r2
238         isync
239 #endif
240
241         /*
242          * This is where the main kernel code starts.
243          */
244
245         /* ptr to current */
246         lis     r2,init_task@h
247         ori     r2,r2,init_task@l
248
249         /* ptr to current thread */
250         addi    r4,r2,THREAD    /* init task's THREAD */
251         mtspr   SPRN_SPRG3,r4
252
253         /* stack */
254         lis     r1,init_thread_union@h
255         ori     r1,r1,init_thread_union@l
256         li      r0,0
257         stwu    r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
258
259         bl      early_init
260
261 /*
262  * Decide what sort of machine this is and initialize the MMU.
263  */
264         mr      r3,r31
265         mr      r4,r30
266         mr      r5,r29
267         mr      r6,r28
268         mr      r7,r27
269         bl      machine_init
270         bl      MMU_init
271
272         /* Setup PTE pointers for the Abatron bdiGDB */
273         lis     r6, swapper_pg_dir@h
274         ori     r6, r6, swapper_pg_dir@l
275         lis     r5, abatron_pteptrs@h
276         ori     r5, r5, abatron_pteptrs@l
277         lis     r4, KERNELBASE@h
278         ori     r4, r4, KERNELBASE@l
279         stw     r5, 0(r4)       /* Save abatron_pteptrs at a fixed location */
280         stw     r6, 0(r5)
281
282         /* Let's move on */
283         lis     r4,start_kernel@h
284         ori     r4,r4,start_kernel@l
285         lis     r3,MSR_KERNEL@h
286         ori     r3,r3,MSR_KERNEL@l
287         mtspr   SPRN_SRR0,r4
288         mtspr   SPRN_SRR1,r3
289         rfi                     /* change context and jump to start_kernel */
290
291 /*
292  * Interrupt vector entry code
293  *
294  * The Book E MMUs are always on so we don't need to handle
295  * interrupts in real mode as with previous PPC processors. In
296  * this case we handle interrupts in the kernel virtual address
297  * space.
298  *
299  * Interrupt vectors are dynamically placed relative to the
300  * interrupt prefix as determined by the address of interrupt_base.
301  * The interrupt vectors offsets are programmed using the labels
302  * for each interrupt vector entry.
303  *
304  * Interrupt vectors must be aligned on a 16 byte boundary.
305  * We align on a 32 byte cache line boundary for good measure.
306  */
307
308 interrupt_base:
309         /* Critical Input Interrupt */
310         CRITICAL_EXCEPTION(0x0100, CriticalInput, unknown_exception)
311
312         /* Machine Check Interrupt */
313 #ifdef CONFIG_440A
314         MCHECK_EXCEPTION(0x0200, MachineCheck, machine_check_exception)
315 #else
316         CRITICAL_EXCEPTION(0x0200, MachineCheck, machine_check_exception)
317 #endif
318
319         /* Data Storage Interrupt */
320         START_EXCEPTION(DataStorage)
321         mtspr   SPRN_SPRG0, r10         /* Save some working registers */
322         mtspr   SPRN_SPRG1, r11
323         mtspr   SPRN_SPRG4W, r12
324         mtspr   SPRN_SPRG5W, r13
325         mfcr    r11
326         mtspr   SPRN_SPRG7W, r11
327
328         /*
329          * Check if it was a store fault, if not then bail
330          * because a user tried to access a kernel or
331          * read-protected page.  Otherwise, get the
332          * offending address and handle it.
333          */
334         mfspr   r10, SPRN_ESR
335         andis.  r10, r10, ESR_ST@h
336         beq     2f
337
338         mfspr   r10, SPRN_DEAR          /* Get faulting address */
339
340         /* If we are faulting a kernel address, we have to use the
341          * kernel page tables.
342          */
343         lis     r11, TASK_SIZE@h
344         cmplw   r10, r11
345         blt+    3f
346         lis     r11, swapper_pg_dir@h
347         ori     r11, r11, swapper_pg_dir@l
348
349         mfspr   r12,SPRN_MMUCR
350         rlwinm  r12,r12,0,0,23          /* Clear TID */
351
352         b       4f
353
354         /* Get the PGD for the current thread */
355 3:
356         mfspr   r11,SPRN_SPRG3
357         lwz     r11,PGDIR(r11)
358
359         /* Load PID into MMUCR TID */
360         mfspr   r12,SPRN_MMUCR          /* Get MMUCR */
361         mfspr   r13,SPRN_PID            /* Get PID */
362         rlwimi  r12,r13,0,24,31         /* Set TID */
363
364 4:
365         mtspr   SPRN_MMUCR,r12
366
367         rlwinm  r12, r10, 13, 19, 29    /* Compute pgdir/pmd offset */
368         lwzx    r11, r12, r11           /* Get pgd/pmd entry */
369         rlwinm. r12, r11, 0, 0, 20      /* Extract pt base address */
370         beq     2f                      /* Bail if no table */
371
372         rlwimi  r12, r10, 23, 20, 28    /* Compute pte address */
373         lwz     r11, 4(r12)             /* Get pte entry */
374
375         andi.   r13, r11, _PAGE_RW      /* Is it writeable? */
376         beq     2f                      /* Bail if not */
377
378         /* Update 'changed'.
379         */
380         ori     r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE
381         stw     r11, 4(r12)             /* Update Linux page table */
382
383         li      r13, PPC44x_TLB_SR@l    /* Set SR */
384         rlwimi  r13, r11, 29, 29, 29    /* SX = _PAGE_HWEXEC */
385         rlwimi  r13, r11, 0, 30, 30     /* SW = _PAGE_RW */
386         rlwimi  r13, r11, 29, 28, 28    /* UR = _PAGE_USER */
387         rlwimi  r12, r11, 31, 26, 26    /* (_PAGE_USER>>1)->r12 */
388         rlwimi  r12, r11, 29, 30, 30    /* (_PAGE_USER>>3)->r12 */
389         and     r12, r12, r11           /* HWEXEC/RW & USER */
390         rlwimi  r13, r12, 0, 26, 26     /* UX = HWEXEC & USER */
391         rlwimi  r13, r12, 3, 27, 27     /* UW = RW & USER */
392
393         rlwimi  r11,r13,0,26,31         /* Insert static perms */
394
395         rlwinm  r11,r11,0,20,15         /* Clear U0-U3 */
396
397         /* find the TLB index that caused the fault.  It has to be here. */
398         tlbsx   r10, 0, r10
399
400         tlbwe   r11, r10, PPC44x_TLB_ATTRIB     /* Write ATTRIB */
401
402         /* Done...restore registers and get out of here.
403         */
404         mfspr   r11, SPRN_SPRG7R
405         mtcr    r11
406         mfspr   r13, SPRN_SPRG5R
407         mfspr   r12, SPRN_SPRG4R
408
409         mfspr   r11, SPRN_SPRG1
410         mfspr   r10, SPRN_SPRG0
411         rfi                     /* Force context change */
412
413 2:
414         /*
415          * The bailout.  Restore registers to pre-exception conditions
416          * and call the heavyweights to help us out.
417          */
418         mfspr   r11, SPRN_SPRG7R
419         mtcr    r11
420         mfspr   r13, SPRN_SPRG5R
421         mfspr   r12, SPRN_SPRG4R
422
423         mfspr   r11, SPRN_SPRG1
424         mfspr   r10, SPRN_SPRG0
425         b       data_access
426
427         /* Instruction Storage Interrupt */
428         INSTRUCTION_STORAGE_EXCEPTION
429
430         /* External Input Interrupt */
431         EXCEPTION(0x0500, ExternalInput, do_IRQ, EXC_XFER_LITE)
432
433         /* Alignment Interrupt */
434         ALIGNMENT_EXCEPTION
435
436         /* Program Interrupt */
437         PROGRAM_EXCEPTION
438
439         /* Floating Point Unavailable Interrupt */
440 #ifdef CONFIG_PPC_FPU
441         FP_UNAVAILABLE_EXCEPTION
442 #else
443         EXCEPTION(0x2010, FloatingPointUnavailable, unknown_exception, EXC_XFER_EE)
444 #endif
445
446         /* System Call Interrupt */
447         START_EXCEPTION(SystemCall)
448         NORMAL_EXCEPTION_PROLOG
449         EXC_XFER_EE_LITE(0x0c00, DoSyscall)
450
451         /* Auxillary Processor Unavailable Interrupt */
452         EXCEPTION(0x2020, AuxillaryProcessorUnavailable, unknown_exception, EXC_XFER_EE)
453
454         /* Decrementer Interrupt */
455         DECREMENTER_EXCEPTION
456
457         /* Fixed Internal Timer Interrupt */
458         /* TODO: Add FIT support */
459         EXCEPTION(0x1010, FixedIntervalTimer, unknown_exception, EXC_XFER_EE)
460
461         /* Watchdog Timer Interrupt */
462         /* TODO: Add watchdog support */
463 #ifdef CONFIG_BOOKE_WDT
464         CRITICAL_EXCEPTION(0x1020, WatchdogTimer, WatchdogException)
465 #else
466         CRITICAL_EXCEPTION(0x1020, WatchdogTimer, unknown_exception)
467 #endif
468
469         /* Data TLB Error Interrupt */
470         START_EXCEPTION(DataTLBError)
471         mtspr   SPRN_SPRG0, r10         /* Save some working registers */
472         mtspr   SPRN_SPRG1, r11
473         mtspr   SPRN_SPRG4W, r12
474         mtspr   SPRN_SPRG5W, r13
475         mfcr    r11
476         mtspr   SPRN_SPRG7W, r11
477         mfspr   r10, SPRN_DEAR          /* Get faulting address */
478
479         /* If we are faulting a kernel address, we have to use the
480          * kernel page tables.
481          */
482         lis     r11, TASK_SIZE@h
483         cmplw   r10, r11
484         blt+    3f
485         lis     r11, swapper_pg_dir@h
486         ori     r11, r11, swapper_pg_dir@l
487
488         mfspr   r12,SPRN_MMUCR
489         rlwinm  r12,r12,0,0,23          /* Clear TID */
490
491         b       4f
492
493         /* Get the PGD for the current thread */
494 3:
495         mfspr   r11,SPRN_SPRG3
496         lwz     r11,PGDIR(r11)
497
498         /* Load PID into MMUCR TID */
499         mfspr   r12,SPRN_MMUCR
500         mfspr   r13,SPRN_PID            /* Get PID */
501         rlwimi  r12,r13,0,24,31         /* Set TID */
502
503 4:
504         mtspr   SPRN_MMUCR,r12
505
506         rlwinm  r12, r10, 13, 19, 29    /* Compute pgdir/pmd offset */
507         lwzx    r11, r12, r11           /* Get pgd/pmd entry */
508         rlwinm. r12, r11, 0, 0, 20      /* Extract pt base address */
509         beq     2f                      /* Bail if no table */
510
511         rlwimi  r12, r10, 23, 20, 28    /* Compute pte address */
512         lwz     r11, 4(r12)             /* Get pte entry */
513         andi.   r13, r11, _PAGE_PRESENT /* Is the page present? */
514         beq     2f                      /* Bail if not present */
515
516         ori     r11, r11, _PAGE_ACCESSED
517         stw     r11, 4(r12)
518
519          /* Jump to common tlb load */
520         b       finish_tlb_load
521
522 2:
523         /* The bailout.  Restore registers to pre-exception conditions
524          * and call the heavyweights to help us out.
525          */
526         mfspr   r11, SPRN_SPRG7R
527         mtcr    r11
528         mfspr   r13, SPRN_SPRG5R
529         mfspr   r12, SPRN_SPRG4R
530         mfspr   r11, SPRN_SPRG1
531         mfspr   r10, SPRN_SPRG0
532         b       data_access
533
534         /* Instruction TLB Error Interrupt */
535         /*
536          * Nearly the same as above, except we get our
537          * information from different registers and bailout
538          * to a different point.
539          */
540         START_EXCEPTION(InstructionTLBError)
541         mtspr   SPRN_SPRG0, r10         /* Save some working registers */
542         mtspr   SPRN_SPRG1, r11
543         mtspr   SPRN_SPRG4W, r12
544         mtspr   SPRN_SPRG5W, r13
545         mfcr    r11
546         mtspr   SPRN_SPRG7W, r11
547         mfspr   r10, SPRN_SRR0          /* Get faulting address */
548
549         /* If we are faulting a kernel address, we have to use the
550          * kernel page tables.
551          */
552         lis     r11, TASK_SIZE@h
553         cmplw   r10, r11
554         blt+    3f
555         lis     r11, swapper_pg_dir@h
556         ori     r11, r11, swapper_pg_dir@l
557
558         mfspr   r12,SPRN_MMUCR
559         rlwinm  r12,r12,0,0,23          /* Clear TID */
560
561         b       4f
562
563         /* Get the PGD for the current thread */
564 3:
565         mfspr   r11,SPRN_SPRG3
566         lwz     r11,PGDIR(r11)
567
568         /* Load PID into MMUCR TID */
569         mfspr   r12,SPRN_MMUCR
570         mfspr   r13,SPRN_PID            /* Get PID */
571         rlwimi  r12,r13,0,24,31         /* Set TID */
572
573 4:
574         mtspr   SPRN_MMUCR,r12
575
576         rlwinm  r12, r10, 13, 19, 29    /* Compute pgdir/pmd offset */
577         lwzx    r11, r12, r11           /* Get pgd/pmd entry */
578         rlwinm. r12, r11, 0, 0, 20      /* Extract pt base address */
579         beq     2f                      /* Bail if no table */
580
581         rlwimi  r12, r10, 23, 20, 28    /* Compute pte address */
582         lwz     r11, 4(r12)             /* Get pte entry */
583         andi.   r13, r11, _PAGE_PRESENT /* Is the page present? */
584         beq     2f                      /* Bail if not present */
585
586         ori     r11, r11, _PAGE_ACCESSED
587         stw     r11, 4(r12)
588
589         /* Jump to common TLB load point */
590         b       finish_tlb_load
591
592 2:
593         /* The bailout.  Restore registers to pre-exception conditions
594          * and call the heavyweights to help us out.
595          */
596         mfspr   r11, SPRN_SPRG7R
597         mtcr    r11
598         mfspr   r13, SPRN_SPRG5R
599         mfspr   r12, SPRN_SPRG4R
600         mfspr   r11, SPRN_SPRG1
601         mfspr   r10, SPRN_SPRG0
602         b       InstructionStorage
603
604         /* Debug Interrupt */
605         DEBUG_EXCEPTION
606
607 /*
608  * Local functions
609  */
610         /*
611          * Data TLB exceptions will bail out to this point
612          * if they can't resolve the lightweight TLB fault.
613          */
614 data_access:
615         NORMAL_EXCEPTION_PROLOG
616         mfspr   r5,SPRN_ESR             /* Grab the ESR, save it, pass arg3 */
617         stw     r5,_ESR(r11)
618         mfspr   r4,SPRN_DEAR            /* Grab the DEAR, save it, pass arg2 */
619         EXC_XFER_EE_LITE(0x0300, handle_page_fault)
620
621 /*
622
623  * Both the instruction and data TLB miss get to this
624  * point to load the TLB.
625  *      r10 - EA of fault
626  *      r11 - available to use
627  *      r12 - Pointer to the 64-bit PTE
628  *      r13 - available to use
629  *      MMUCR - loaded with proper value when we get here
630  *      Upon exit, we reload everything and RFI.
631  */
632 finish_tlb_load:
633         /*
634          * We set execute, because we don't have the granularity to
635          * properly set this at the page level (Linux problem).
636          * If shared is set, we cause a zero PID->TID load.
637          * Many of these bits are software only.  Bits we don't set
638          * here we (properly should) assume have the appropriate value.
639          */
640
641         /* Load the next available TLB index */
642         lis     r13, tlb_44x_index@ha
643         lwz     r13, tlb_44x_index@l(r13)
644         /* Load the TLB high watermark */
645         lis     r11, tlb_44x_hwater@ha
646         lwz     r11, tlb_44x_hwater@l(r11)
647
648         /* Increment, rollover, and store TLB index */
649         addi    r13, r13, 1
650         cmpw    0, r13, r11                     /* reserve entries */
651         ble     7f
652         li      r13, 0
653 7:
654         /* Store the next available TLB index */
655         lis     r11, tlb_44x_index@ha
656         stw     r13, tlb_44x_index@l(r11)
657
658         lwz     r11, 0(r12)                     /* Get MS word of PTE */
659         lwz     r12, 4(r12)                     /* Get LS word of PTE */
660         rlwimi  r11, r12, 0, 0 , 19             /* Insert RPN */
661         tlbwe   r11, r13, PPC44x_TLB_XLAT       /* Write XLAT */
662
663         /*
664          * Create PAGEID. This is the faulting address,
665          * page size, and valid flag.
666          */
667         li      r11, PPC44x_TLB_VALID | PPC44x_TLB_4K
668         rlwimi  r10, r11, 0, 20, 31             /* Insert valid and page size */
669         tlbwe   r10, r13, PPC44x_TLB_PAGEID     /* Write PAGEID */
670
671         li      r10, PPC44x_TLB_SR@l            /* Set SR */
672         rlwimi  r10, r12, 0, 30, 30             /* Set SW = _PAGE_RW */
673         rlwimi  r10, r12, 29, 29, 29            /* SX = _PAGE_HWEXEC */
674         rlwimi  r10, r12, 29, 28, 28            /* UR = _PAGE_USER */
675         rlwimi  r11, r12, 31, 26, 26            /* (_PAGE_USER>>1)->r12 */
676         and     r11, r12, r11                   /* HWEXEC & USER */
677         rlwimi  r10, r11, 0, 26, 26             /* UX = HWEXEC & USER */
678
679         rlwimi  r12, r10, 0, 26, 31             /* Insert static perms */
680         rlwinm  r12, r12, 0, 20, 15             /* Clear U0-U3 */
681         tlbwe   r12, r13, PPC44x_TLB_ATTRIB     /* Write ATTRIB */
682
683         /* Done...restore registers and get out of here.
684         */
685         mfspr   r11, SPRN_SPRG7R
686         mtcr    r11
687         mfspr   r13, SPRN_SPRG5R
688         mfspr   r12, SPRN_SPRG4R
689         mfspr   r11, SPRN_SPRG1
690         mfspr   r10, SPRN_SPRG0
691         rfi                                     /* Force context change */
692
693 /*
694  * Global functions
695  */
696
697 /*
698  * extern void giveup_altivec(struct task_struct *prev)
699  *
700  * The 44x core does not have an AltiVec unit.
701  */
702 _GLOBAL(giveup_altivec)
703         blr
704
705 /*
706  * extern void giveup_fpu(struct task_struct *prev)
707  *
708  * The 44x core does not have an FPU.
709  */
710 #ifndef CONFIG_PPC_FPU
711 _GLOBAL(giveup_fpu)
712         blr
713 #endif
714
715 /*
716  * extern void abort(void)
717  *
718  * At present, this routine just applies a system reset.
719  */
720 _GLOBAL(abort)
721         mfspr   r13,SPRN_DBCR0
722         oris    r13,r13,DBCR0_RST_SYSTEM@h
723         mtspr   SPRN_DBCR0,r13
724
725 _GLOBAL(set_context)
726
727 #ifdef CONFIG_BDI_SWITCH
728         /* Context switch the PTE pointer for the Abatron BDI2000.
729          * The PGDIR is the second parameter.
730          */
731         lis     r5, abatron_pteptrs@h
732         ori     r5, r5, abatron_pteptrs@l
733         stw     r4, 0x4(r5)
734 #endif
735         mtspr   SPRN_PID,r3
736         isync                   /* Force context change */
737         blr
738
739 /*
740  * We put a few things here that have to be page-aligned. This stuff
741  * goes at the beginning of the data segment, which is page-aligned.
742  */
743         .data
744         .align  12
745         .globl  sdata
746 sdata:
747         .globl  empty_zero_page
748 empty_zero_page:
749         .space  4096
750
751 /*
752  * To support >32-bit physical addresses, we use an 8KB pgdir.
753  */
754         .globl  swapper_pg_dir
755 swapper_pg_dir:
756         .space  8192
757
758 /* Reserved 4k for the critical exception stack & 4k for the machine
759  * check stack per CPU for kernel mode exceptions */
760         .section .bss
761         .align 12
762 exception_stack_bottom:
763         .space  BOOKE_EXCEPTION_STACK_SIZE
764         .globl  exception_stack_top
765 exception_stack_top:
766
767 /*
768  * This space gets a copy of optional info passed to us by the bootstrap
769  * which is used to pass parameters into the kernel like root=/dev/sda1, etc.
770  */
771         .globl  cmd_line
772 cmd_line:
773         .space  512
774
775 /*
776  * Room for two PTE pointers, usually the kernel and current user pointers
777  * to their respective root page table.
778  */
779 abatron_pteptrs:
780         .space  8