]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/booke/locore.S
Fix flags field decoding in ACPI_NFIT_CONTROL_REGION.
[FreeBSD/FreeBSD.git] / sys / powerpc / booke / locore.S
1 /*-
2  * Copyright (C) 2007-2009 Semihalf, Rafal Jaworowski <raj@semihalf.com>
3  * Copyright (C) 2006 Semihalf, Marian Balakowicz <m8@semihalf.com>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
18  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
20  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
22  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
23  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include "assym.s"
30
31 #include "opt_hwpmc_hooks.h"
32
33 #include <machine/asm.h>
34 #include <machine/hid.h>
35 #include <machine/param.h>
36 #include <machine/spr.h>
37 #include <machine/pte.h>
38 #include <machine/trap.h>
39 #include <machine/vmparam.h>
40 #include <machine/tlb.h>
41
42 #define TMPSTACKSZ      16384
43
44 #ifdef __powerpc64__
45 #define GET_TOCBASE(r)  \
46         mfspr   r, SPR_SPRG8
47 #define TOC_RESTORE     nop
48 #define CMPI    cmpdi
49 #define CMPL    cmpld
50 #define LOAD    ld
51 #define LOADX   ldarx
52 #define STORE   std
53 #define STOREX  stdcx.
54 #define STU     stdu
55 #define CALLSIZE        48
56 #define REDZONE         288
57 #define THREAD_REG      %r13
58 #define ADDR(x) \
59         .llong  x
60 #else
61 #define GET_TOCBASE(r)
62 #define TOC_RESTORE
63 #define CMPI    cmpwi
64 #define CMPL    cmplw
65 #define LOAD    lwz
66 #define LOADX   lwarx
67 #define STOREX  stwcx.
68 #define STORE   stw
69 #define STU     stwu
70 #define CALLSIZE        8
71 #define REDZONE         0
72 #define THREAD_REG      %r2
73 #define ADDR(x) \
74         .long   x
75 #endif
76
77         .text
78         .globl  btext
79 btext:
80
81 /*
82  * This symbol is here for the benefit of kvm_mkdb, and is supposed to
83  * mark the start of kernel text.
84  */
85         .globl  kernel_text
86 kernel_text:
87
88 /*
89  * Startup entry.  Note, this must be the first thing in the text segment!
90  */
91         .text
92         .globl  __start
93 __start:
94
95 /*
96  * Assumptions on the boot loader:
97  *  - System memory starts from physical address 0
98  *  - It's mapped by a single TLB1 entry
99  *  - TLB1 mapping is 1:1 pa to va
100  *  - Kernel is loaded at 64MB boundary
101  *  - All PID registers are set to the same value
102  *  - CPU is running in AS=0
103  *
104  * Registers contents provided by the loader(8):
105  *      r1      : stack pointer
106  *      r3      : metadata pointer
107  *
108  * We rearrange the TLB1 layout as follows:
109  *  - Find TLB1 entry we started in
110  *  - Make sure it's protected, invalidate other entries
111  *  - Create temp entry in the second AS (make sure it's not TLB[1])
112  *  - Switch to temp mapping
113  *  - Map 64MB of RAM in TLB1[1]
114  *  - Use AS=1, set EPN to KERNBASE and RPN to kernel load address
115  *  - Switch to to TLB1[1] mapping
116  *  - Invalidate temp mapping
117  *
118  * locore registers use:
119  *      r1      : stack pointer
120  *      r2      : trace pointer (AP only, for early diagnostics)
121  *      r3-r27  : scratch registers
122  *      r28     : temp TLB1 entry
123  *      r29     : initial TLB1 entry we started in
124  *      r30-r31 : arguments (metadata pointer)
125  */
126
127 /*
128  * Keep arguments in r30 & r31 for later use.
129  */
130         mr      %r30, %r3
131         mr      %r31, %r4
132
133 /*
134  * Initial cleanup
135  */
136         li      %r3, PSL_DE     /* Keep debug exceptions for CodeWarrior. */
137 #ifdef __powerpc64__
138         oris    %r3, %r3, PSL_CM@h
139 #endif
140         mtmsr   %r3
141         isync
142
143 /*
144  * Initial HIDs configuration
145  */
146 1:
147         mfpvr   %r3
148         rlwinm  %r3, %r3, 16, 16, 31
149
150         lis     %r4, HID0_E500_DEFAULT_SET@h
151         ori     %r4, %r4, HID0_E500_DEFAULT_SET@l
152
153         /* Check for e500mc and e5500 */
154         cmpli   0, 0, %r3, FSL_E500mc
155         bne     2f
156
157         lis     %r4, HID0_E500MC_DEFAULT_SET@h
158         ori     %r4, %r4, HID0_E500MC_DEFAULT_SET@l
159         b       3f
160 2:
161         cmpli   0, 0, %r3, FSL_E5500
162         bne     3f
163
164         lis     %r4, HID0_E5500_DEFAULT_SET@h
165         ori     %r4, %r4, HID0_E5500_DEFAULT_SET@l
166
167 3:
168         mtspr   SPR_HID0, %r4
169         isync
170
171 /*
172  * E500mc and E5500 do not have HID1 register, so skip HID1 setup on
173  * this core.
174  */
175         cmpli   0, 0, %r3, FSL_E500mc
176         beq     1f
177         cmpli   0, 0, %r3, FSL_E5500
178         beq     1f
179         cmpli   0, 0, %r3, FSL_E6500
180         beq     1f
181
182         lis     %r3, HID1_E500_DEFAULT_SET@h
183         ori     %r3, %r3, HID1_E500_DEFAULT_SET@l
184         mtspr   SPR_HID1, %r3
185         isync
186 1:
187         /* Invalidate all entries in TLB0 */
188         li      %r3, 0
189         bl      tlb_inval_all
190
191         cmpwi   %r30, 0
192         beq     done_mapping
193
194 /*
195  * Locate the TLB1 entry that maps this code
196  */
197         bl      1f
198 1:      mflr    %r3
199         bl      tlb1_find_current       /* the entry found is returned in r29 */
200
201         bl      tlb1_inval_all_but_current
202
203 /*
204  * Create temporary mapping in AS=1 and switch to it
205  */
206         bl      tlb1_temp_mapping_as1
207
208         mfmsr   %r3
209         ori     %r3, %r3, (PSL_IS | PSL_DS)
210         bl      2f
211 2:      mflr    %r4
212         addi    %r4, %r4, (3f - 2b)
213         mtspr   SPR_SRR0, %r4
214         mtspr   SPR_SRR1, %r3
215         rfi                             /* Switch context */
216
217 /*
218  * Invalidate initial entry
219  */
220 3:
221         mr      %r3, %r29
222         bl      tlb1_inval_entry
223
224 /*
225  * Setup final mapping in TLB1[1] and switch to it
226  */
227         /* Final kernel mapping, map in 64 MB of RAM */
228         lis     %r3, MAS0_TLBSEL1@h     /* Select TLB1 */
229         li      %r4, 0                  /* Entry 0 */
230         rlwimi  %r3, %r4, 16, 10, 15
231         mtspr   SPR_MAS0, %r3
232         isync
233
234         li      %r3, (TLB_SIZE_64M << MAS1_TSIZE_SHIFT)@l
235         oris    %r3, %r3, (MAS1_VALID | MAS1_IPROT)@h
236         mtspr   SPR_MAS1, %r3           /* note TS was not filled, so it's TS=0 */
237         isync
238
239         LOAD_ADDR(%r3, KERNBASE)
240         ori     %r3, %r3, (_TLB_ENTRY_SHARED | MAS2_M)@l /* WIMGE = 0b00100 */
241         mtspr   SPR_MAS2, %r3
242         isync
243
244         /* Discover phys load address */
245         bl      3f
246 3:      mflr    %r4                     /* Use current address */
247         rlwinm  %r4, %r4, 0, 0, 5       /* 64MB alignment mask */
248         ori     %r4, %r4, (MAS3_SX | MAS3_SW | MAS3_SR)@l
249         mtspr   SPR_MAS3, %r4           /* Set RPN and protection */
250         isync
251         bl      zero_mas7
252         bl      zero_mas8
253         tlbwe
254         isync
255         msync
256
257         /* Switch to the above TLB1[1] mapping */
258         bl      4f
259 4:      mflr    %r4
260 #ifdef __powerpc64__
261         clrldi  %r4, %r4, 38
262         clrrdi  %r3, %r3, 12
263 #else
264         rlwinm  %r4, %r4, 0, 6, 31      /* Current offset from kernel load address */
265         rlwinm  %r3, %r3, 0, 0, 19
266 #endif
267         add     %r4, %r4, %r3           /* Convert to kernel virtual address */
268         addi    %r4, %r4, (5f - 4b)
269         li      %r3, PSL_DE             /* Note AS=0 */
270 #ifdef __powerpc64__
271         oris    %r3, %r3, PSL_CM@h
272 #endif
273         mtspr   SPR_SRR0, %r4
274         mtspr   SPR_SRR1, %r3
275         rfi
276
277 /*
278  * Invalidate temp mapping
279  */
280 5:
281         mr      %r3, %r28
282         bl      tlb1_inval_entry
283
284 done_mapping:
285
286 #ifdef __powerpc64__
287         /* Set up the TOC pointer */
288         b       0f
289         .align 3
290 0:      nop
291         bl      1f
292         .llong  __tocbase + 0x8000 - .
293 1:      mflr    %r2
294         ld      %r1,0(%r2)
295         add     %r2,%r1,%r2
296         mtspr   SPR_SPRG8, %r2
297
298         /* Get load offset */
299         ld      %r31,-0x8000(%r2) /* First TOC entry is TOC base */
300         subf    %r31,%r31,%r2   /* Subtract from real TOC base to get base */
301
302         /* Set up the stack pointer */
303         ld      %r1,TOC_REF(tmpstack)(%r2)
304         addi    %r1,%r1,TMPSTACKSZ-96
305         add     %r1,%r1,%r31
306         bl      1f
307         .llong _DYNAMIC-.
308 1:      mflr    %r3
309         ld      %r4,0(%r3)
310         add     %r3,%r4,%r3
311         mr      %r4,%r31
312 #else
313 /*
314  * Setup a temporary stack
315  */
316         bl      1f
317         .long tmpstack-.
318 1:      mflr    %r1
319         lwz     %r2,0(%r1)
320         add     %r1,%r1,%r2
321         addi    %r1, %r1, (TMPSTACKSZ - 16)
322
323 /*
324  * Relocate kernel
325  */
326         bl      1f
327         .long   _DYNAMIC-.
328         .long   _GLOBAL_OFFSET_TABLE_-.
329 1:      mflr    %r5
330         lwz     %r3,0(%r5)      /* _DYNAMIC in %r3 */
331         add     %r3,%r3,%r5
332         lwz     %r4,4(%r5)      /* GOT pointer */
333         add     %r4,%r4,%r5
334         lwz     %r4,4(%r4)      /* got[0] is _DYNAMIC link addr */
335         subf    %r4,%r4,%r3     /* subtract to calculate relocbase */
336 #endif
337         bl      CNAME(elf_reloc_self)
338         TOC_RESTORE
339
340 /*
341  * Initialise exception vector offsets
342  */
343         bl      CNAME(ivor_setup)
344         TOC_RESTORE
345
346 /*
347  * Set up arguments and jump to system initialization code
348  */
349         mr      %r3, %r30
350         mr      %r4, %r31
351
352         /* Prepare core */
353         bl      CNAME(booke_init)
354         TOC_RESTORE
355
356         /* Switch to thread0.td_kstack now */
357         mr      %r1, %r3
358         li      %r3, 0
359         STORE   %r3, 0(%r1)
360
361         /* Machine independet part, does not return */
362         bl      CNAME(mi_startup)
363         TOC_RESTORE
364         /* NOT REACHED */
365 5:      b       5b
366
367
368 #ifdef SMP
369 /************************************************************************/
370 /* AP Boot page */
371 /************************************************************************/
372         .text
373         .globl  __boot_page
374         .align  12
375 __boot_page:
376         bl      1f
377
378         .globl  bp_trace
379 bp_trace:
380         .long   0
381
382         .globl  bp_kernload
383 bp_kernload:
384         .long   0
385
386 /*
387  * Initial configuration
388  */
389 1:
390         mflr    %r31            /* r31 hold the address of bp_trace */
391
392         /* Set HIDs */
393         mfpvr   %r3
394         rlwinm  %r3, %r3, 16, 16, 31
395
396         /* HID0 for E500 is default */
397         lis     %r4, HID0_E500_DEFAULT_SET@h
398         ori     %r4, %r4, HID0_E500_DEFAULT_SET@l
399
400         cmpli   0, 0, %r3, FSL_E500mc
401         bne     2f
402         lis     %r4, HID0_E500MC_DEFAULT_SET@h
403         ori     %r4, %r4, HID0_E500MC_DEFAULT_SET@l
404         b       3f
405 2:
406         cmpli   0, 0, %r3, FSL_E5500
407         bne     3f
408         lis     %r4, HID0_E5500_DEFAULT_SET@h
409         ori     %r4, %r4, HID0_E5500_DEFAULT_SET@l
410 3:
411         mtspr   SPR_HID0, %r4
412         isync
413
414         /* Enable branch prediction */
415         li      %r3, BUCSR_BPEN
416         mtspr   SPR_BUCSR, %r3
417         isync
418
419         /* Invalidate all entries in TLB0 */
420         li      %r3, 0
421         bl      tlb_inval_all
422
423 /*
424  * Find TLB1 entry which is translating us now
425  */
426         bl      2f
427 2:      mflr    %r3
428         bl      tlb1_find_current       /* the entry number found is in r29 */
429
430         bl      tlb1_inval_all_but_current
431
432 /*
433  * Create temporary translation in AS=1 and switch to it
434  */
435
436         bl      tlb1_temp_mapping_as1
437
438         mfmsr   %r3
439         ori     %r3, %r3, (PSL_IS | PSL_DS)
440 #ifdef __powerpc64__
441         oris    %r3, %r3, PSL_CM@h
442 #endif
443         bl      3f
444 3:      mflr    %r4
445         addi    %r4, %r4, (4f - 3b)
446         mtspr   SPR_SRR0, %r4
447         mtspr   SPR_SRR1, %r3
448         rfi                             /* Switch context */
449
450 /*
451  * Invalidate initial entry
452  */
453 4:
454         mr      %r3, %r29
455         bl      tlb1_inval_entry
456
457 /*
458  * Setup final mapping in TLB1[1] and switch to it
459  */
460         /* Final kernel mapping, map in 64 MB of RAM */
461         lis     %r3, MAS0_TLBSEL1@h     /* Select TLB1 */
462         li      %r4, 0                  /* Entry 0 */
463         rlwimi  %r3, %r4, 16, 4, 15
464         mtspr   SPR_MAS0, %r3
465         isync
466
467         li      %r3, (TLB_SIZE_64M << MAS1_TSIZE_SHIFT)@l
468         oris    %r3, %r3, (MAS1_VALID | MAS1_IPROT)@h
469         mtspr   SPR_MAS1, %r3           /* note TS was not filled, so it's TS=0 */
470         isync
471
472         LOAD_ADDR(%r3, KERNBASE)
473         ori     %r3, %r3, (_TLB_ENTRY_SHARED | MAS2_M)@l /* WIMGE = 0b00100 */
474         mtspr   SPR_MAS2, %r3
475         isync
476
477         /* Retrieve kernel load [physical] address from bp_kernload */
478 #ifdef __powerpc64__
479         b       0f
480         .align  3
481 0:
482         nop
483 #endif
484         bl 5f
485         ADDR(bp_kernload)
486         ADDR(__boot_page)
487 5:      mflr    %r3
488 #ifdef __powerpc64__
489         ld      %r4, 0(%r3)
490         ld      %r5, 8(%r3)
491         clrrdi  %r3, %r3, 12
492 #else
493         lwz     %r4, 0(%r3)
494         lwz     %r5, 4(%r3)
495         rlwinm  %r3, %r3, 0, 0, 19
496 #endif
497         sub     %r4, %r4, %r5   /* offset of bp_kernload within __boot_page */
498         lwzx    %r3, %r4, %r3
499
500         /* Set RPN and protection */
501         ori     %r3, %r3, (MAS3_SX | MAS3_SW | MAS3_SR)@l
502         mtspr   SPR_MAS3, %r3
503         isync
504         bl      zero_mas7
505         bl      zero_mas8
506         tlbwe
507         isync
508         msync
509
510         /* Switch to the final mapping */
511         bl      6f
512 6:      mflr    %r3
513         rlwinm  %r3, %r3, 0, 0xfff      /* Offset from boot page start */
514         add     %r3, %r3, %r5           /* Make this virtual address */
515         addi    %r3, %r3, (7f - 6b)
516 #ifdef __powerpc64__
517         lis     %r4, PSL_CM@h           /* Note AS=0 */
518 #else
519         li      %r4, 0                  /* Note AS=0 */
520 #endif
521         mtspr   SPR_SRR0, %r3
522         mtspr   SPR_SRR1, %r4
523         rfi
524 7:
525
526 /*
527  * At this point we're running at virtual addresses KERNBASE and beyond so
528  * it's allowed to directly access all locations the kernel was linked
529  * against.
530  */
531
532 /*
533  * Invalidate temp mapping
534  */
535         mr      %r3, %r28
536         bl      tlb1_inval_entry
537
538 #ifdef __powerpc64__
539         /* Set up the TOC pointer */
540         b       0f
541         .align 3
542 0:      nop
543         bl      1f
544         .llong  __tocbase + 0x8000 - .
545 1:      mflr    %r2
546         ld      %r1,0(%r2)
547         add     %r2,%r1,%r2
548         mtspr   SPR_SPRG8, %r2
549
550         /* Get load offset */
551         ld      %r31,-0x8000(%r2) /* First TOC entry is TOC base */
552         subf    %r31,%r31,%r2   /* Subtract from real TOC base to get base */
553
554         /* Set up the stack pointer */
555         ld      %r1,TOC_REF(tmpstack)(%r2)
556         addi    %r1,%r1,TMPSTACKSZ-96
557         add     %r1,%r1,%r31
558 #else
559 /*
560  * Setup a temporary stack
561  */
562         bl      1f
563         .long tmpstack-.
564 1:      mflr    %r1
565         lwz     %r2,0(%r1)
566         add     %r1,%r1,%r2
567         stw     %r1, 0(%r1)
568         addi    %r1, %r1, (TMPSTACKSZ - 16)
569 #endif
570
571 /*
572  * Initialise exception vector offsets
573  */
574         bl      CNAME(ivor_setup)
575         TOC_RESTORE
576
577         /*
578          * Assign our pcpu instance
579          */
580         bl      1f
581         .long ap_pcpu-.
582 1:      mflr    %r4
583         lwz     %r3, 0(%r4)
584         add     %r3, %r3, %r4
585         LOAD    %r3, 0(%r3)
586         mtsprg0 %r3
587
588         bl      CNAME(pmap_bootstrap_ap)
589         TOC_RESTORE
590
591         bl      CNAME(cpudep_ap_bootstrap)
592         TOC_RESTORE
593         /* Switch to the idle thread's kstack */
594         mr      %r1, %r3
595         
596         bl      CNAME(machdep_ap_bootstrap)
597         TOC_RESTORE
598
599         /* NOT REACHED */
600 6:      b       6b
601 #endif /* SMP */
602
603 #if defined (BOOKE_E500)
604 /*
605  * Invalidate all entries in the given TLB.
606  *
607  * r3   TLBSEL
608  */
609 tlb_inval_all:
610         rlwinm  %r3, %r3, 3, (1 << 3)   /* TLBSEL */
611         ori     %r3, %r3, (1 << 2)      /* INVALL */
612         tlbivax 0, %r3
613         isync
614         msync
615
616         tlbsync
617         msync
618         blr
619
620 /*
621  * expects address to look up in r3, returns entry number in r29
622  *
623  * FIXME: the hidden assumption is we are now running in AS=0, but we should
624  * retrieve actual AS from MSR[IS|DS] and put it in MAS6[SAS]
625  */
626 tlb1_find_current:
627         mfspr   %r17, SPR_PID0
628         slwi    %r17, %r17, MAS6_SPID0_SHIFT
629         mtspr   SPR_MAS6, %r17
630         isync
631         tlbsx   0, %r3
632         mfspr   %r17, SPR_MAS0
633         rlwinm  %r29, %r17, 16, 26, 31          /* MAS0[ESEL] -> r29 */
634
635         /* Make sure we have IPROT set on the entry */
636         mfspr   %r17, SPR_MAS1
637         oris    %r17, %r17, MAS1_IPROT@h
638         mtspr   SPR_MAS1, %r17
639         isync
640         tlbwe
641         isync
642         msync
643         blr
644
645 /*
646  * Invalidates a single entry in TLB1.
647  *
648  * r3           ESEL
649  * r4-r5        scratched
650  */
651 tlb1_inval_entry:
652         lis     %r4, MAS0_TLBSEL1@h     /* Select TLB1 */
653         rlwimi  %r4, %r3, 16, 10, 15    /* Select our entry */
654         mtspr   SPR_MAS0, %r4
655         isync
656         tlbre
657         li      %r5, 0                  /* MAS1[V] = 0 */
658         mtspr   SPR_MAS1, %r5
659         isync
660         tlbwe
661         isync
662         msync
663         blr
664
665 /*
666  * r29          current entry number
667  * r28          returned temp entry
668  * r3-r5        scratched
669  */
670 tlb1_temp_mapping_as1:
671         /* Read our current translation */
672         lis     %r3, MAS0_TLBSEL1@h     /* Select TLB1 */
673         rlwimi  %r3, %r29, 16, 10, 15   /* Select our current entry */
674         mtspr   SPR_MAS0, %r3
675         isync
676         tlbre
677
678         /*
679          * Prepare and write temp entry
680          *
681          * FIXME this is not robust against overflow i.e. when the current
682          * entry is the last in TLB1
683          */
684         lis     %r3, MAS0_TLBSEL1@h     /* Select TLB1 */
685         addi    %r28, %r29, 1           /* Use next entry. */
686         rlwimi  %r3, %r28, 16, 10, 15   /* Select temp entry */
687         mtspr   SPR_MAS0, %r3
688         isync
689         mfspr   %r5, SPR_MAS1
690         li      %r4, 1                  /* AS=1 */
691         rlwimi  %r5, %r4, 12, 19, 19
692         li      %r4, 0                  /* Global mapping, TID=0 */
693         rlwimi  %r5, %r4, 16, 8, 15
694         oris    %r5, %r5, (MAS1_VALID | MAS1_IPROT)@h
695         mtspr   SPR_MAS1, %r5
696         isync
697         mflr    %r3
698         bl      zero_mas7
699         bl      zero_mas8
700         mtlr    %r3
701         tlbwe
702         isync
703         msync
704         blr
705
706 /*
707  * Loops over TLB1, invalidates all entries skipping the one which currently
708  * maps this code.
709  *
710  * r29          current entry
711  * r3-r5        scratched
712  */
713 tlb1_inval_all_but_current:
714         mfspr   %r3, SPR_TLB1CFG        /* Get number of entries */
715         andi.   %r3, %r3, TLBCFG_NENTRY_MASK@l
716         li      %r4, 0                  /* Start from Entry 0 */
717 1:      lis     %r5, MAS0_TLBSEL1@h
718         rlwimi  %r5, %r4, 16, 10, 15
719         mtspr   SPR_MAS0, %r5
720         isync
721         tlbre
722         mfspr   %r5, SPR_MAS1
723         cmpw    %r4, %r29               /* our current entry? */
724         beq     2f
725         rlwinm  %r5, %r5, 0, 2, 31      /* clear VALID and IPROT bits */
726         mtspr   SPR_MAS1, %r5
727         isync
728         tlbwe
729         isync
730         msync
731 2:      addi    %r4, %r4, 1
732         cmpw    %r4, %r3                /* Check if this is the last entry */
733         bne     1b
734         blr
735
736 /*
737  * MAS7 and MAS8 conditional zeroing.
738  */
739 .globl zero_mas7
740 zero_mas7:
741         mfpvr   %r20
742         rlwinm  %r20, %r20, 16, 16, 31
743         cmpli   0, 0, %r20, FSL_E500v1
744         beq     1f
745
746         li      %r20, 0
747         mtspr   SPR_MAS7, %r20
748         isync
749 1:
750         blr
751
752 .globl zero_mas8
753 zero_mas8:
754         mfpvr   %r20
755         rlwinm  %r20, %r20, 16, 16, 31
756         cmpli   0, 0, %r20, FSL_E500mc
757         beq     1f
758         cmpli   0, 0, %r20, FSL_E5500
759         beq     1f
760
761         blr
762 1:
763         li      %r20, 0
764         mtspr   SPR_MAS8, %r20
765         isync
766         blr
767 #endif
768
769 #ifdef SMP
770 .globl __boot_tlb1
771         /*
772          * The __boot_tlb1 table is used to hold BSP TLB1 entries
773          * marked with _TLB_ENTRY_SHARED flag during AP bootstrap.
774          * The BSP fills in the table in tlb_ap_prep() function. Next,
775          * AP loads its contents to TLB1 hardware in pmap_bootstrap_ap().
776          */
777 __boot_tlb1:
778         .space TLB1_MAX_ENTRIES * TLB_ENTRY_SIZE
779
780 __boot_page_padding:
781         /*
782          * Boot page needs to be exactly 4K, with the last word of this page
783          * acting as the reset vector, so we need to stuff the remainder.
784          * Upon release from holdoff CPU fetches the last word of the boot
785          * page.
786          */
787         .space  4092 - (__boot_page_padding - __boot_page)
788         b       __boot_page
789 #endif /* SMP */
790
791 /************************************************************************/
792 /* locore subroutines */
793 /************************************************************************/
794
795 /*
796  * Cache disable/enable/inval sequences according
797  * to section 2.16 of E500CORE RM.
798  */
799 ENTRY(dcache_inval)
800         /* Invalidate d-cache */
801         mfspr   %r3, SPR_L1CSR0
802         ori     %r3, %r3, (L1CSR0_DCFI | L1CSR0_DCLFR)@l
803         msync
804         isync
805         mtspr   SPR_L1CSR0, %r3
806         isync
807 1:      mfspr   %r3, SPR_L1CSR0
808         andi.   %r3, %r3, L1CSR0_DCFI
809         bne     1b
810         blr
811
812 ENTRY(dcache_disable)
813         /* Disable d-cache */
814         mfspr   %r3, SPR_L1CSR0
815         li      %r4, L1CSR0_DCE@l
816         not     %r4, %r4
817         and     %r3, %r3, %r4
818         msync
819         isync
820         mtspr   SPR_L1CSR0, %r3
821         isync
822         blr
823
824 ENTRY(dcache_enable)
825         /* Enable d-cache */
826         mfspr   %r3, SPR_L1CSR0
827         oris    %r3, %r3, (L1CSR0_DCPE | L1CSR0_DCE)@h
828         ori     %r3, %r3, (L1CSR0_DCPE | L1CSR0_DCE)@l
829         msync
830         isync
831         mtspr   SPR_L1CSR0, %r3
832         isync
833         blr
834
835 ENTRY(icache_inval)
836         /* Invalidate i-cache */
837         mfspr   %r3, SPR_L1CSR1
838         ori     %r3, %r3, (L1CSR1_ICFI | L1CSR1_ICLFR)@l
839         isync
840         mtspr   SPR_L1CSR1, %r3
841         isync
842 1:      mfspr   %r3, SPR_L1CSR1
843         andi.   %r3, %r3, L1CSR1_ICFI
844         bne     1b
845         blr
846
847 ENTRY(icache_disable)
848         /* Disable i-cache */
849         mfspr   %r3, SPR_L1CSR1
850         li      %r4, L1CSR1_ICE@l
851         not     %r4, %r4
852         and     %r3, %r3, %r4
853         isync
854         mtspr   SPR_L1CSR1, %r3
855         isync
856         blr
857
858 ENTRY(icache_enable)
859         /* Enable i-cache */
860         mfspr   %r3, SPR_L1CSR1
861         oris    %r3, %r3, (L1CSR1_ICPE | L1CSR1_ICE)@h
862         ori     %r3, %r3, (L1CSR1_ICPE | L1CSR1_ICE)@l
863         isync
864         mtspr   SPR_L1CSR1, %r3
865         isync
866         blr
867
868 /*
869  * L2 cache disable/enable/inval sequences for E500mc.
870  */
871
872 ENTRY(l2cache_inval)
873         mfspr   %r3, SPR_L2CSR0
874         oris    %r3, %r3, (L2CSR0_L2FI | L2CSR0_L2LFC)@h
875         ori     %r3, %r3, (L2CSR0_L2FI | L2CSR0_L2LFC)@l
876         isync
877         mtspr   SPR_L2CSR0, %r3
878         isync
879 1:      mfspr   %r3, SPR_L2CSR0
880         andis.  %r3, %r3, L2CSR0_L2FI@h
881         bne     1b
882         blr
883
884 ENTRY(l2cache_enable)
885         mfspr   %r3, SPR_L2CSR0
886         oris    %r3, %r3, (L2CSR0_L2E | L2CSR0_L2PE)@h
887         isync
888         mtspr   SPR_L2CSR0, %r3
889         isync
890         blr
891
892 /*
893  * Branch predictor setup.
894  */
895 ENTRY(bpred_enable)
896         mfspr   %r3, SPR_BUCSR
897         ori     %r3, %r3, BUCSR_BBFI
898         isync
899         mtspr   SPR_BUCSR, %r3
900         isync
901         ori     %r3, %r3, BUCSR_BPEN
902         isync
903         mtspr   SPR_BUCSR, %r3
904         isync
905         blr
906
907 ENTRY(dataloss_erratum_access)
908         /* Lock two cache lines into I-Cache */
909         sync
910         mfspr   %r11, SPR_L1CSR1
911         rlwinm  %r11, %r11, 0, ~L1CSR1_ICUL
912         sync
913         isync
914         mtspr   SPR_L1CSR1, %r11
915         isync
916
917         lis     %r8, 2f@h
918         ori     %r8, %r8, 2f@l
919         icbtls  0, 0, %r8
920         addi    %r9, %r8, 64
921
922         sync
923         mfspr   %r11, SPR_L1CSR1
924 3:      andi.   %r11, %r11, L1CSR1_ICUL
925         bne     3b
926
927         icbtls  0, 0, %r9
928
929         sync
930         mfspr   %r11, SPR_L1CSR1
931 3:      andi.   %r11, %r11, L1CSR1_ICUL
932         bne     3b
933
934         b       2f
935         .align  6
936         /* Inside a locked cacheline, wait a while, write, then wait a while */
937 2:      sync
938
939         mfspr   %r5, TBR_TBL
940 4:      addis   %r11, %r5, 0x100000@h   /* wait around one million timebase ticks */
941         mfspr   %r5, TBR_TBL
942         subf.   %r5, %r5, %r11
943         bgt     4b
944
945         stw     %r4, 0(%r3)
946
947         mfspr   %r5, TBR_TBL
948 4:      addis   %r11, %r5, 0x100000@h   /* wait around one million timebase ticks */
949         mfspr   %r5, TBR_TBL
950         subf.   %r5, %r5, %r11
951         bgt     4b
952
953         sync
954
955         /*
956          * Fill out the rest of this cache line and the next with nops,
957          * to ensure that nothing outside the locked area will be
958          * fetched due to a branch.
959          */
960         .rept 19
961         nop
962         .endr
963
964         icblc   0, 0, %r8
965         icblc   0, 0, %r9
966
967         blr
968
969 /*
970  * XXX: This should be moved to a shared AIM/booke asm file, if one ever is
971  * created.
972  */
973 ENTRY(get_spr)
974         mfspr   %r3, 0
975         blr
976
977 /************************************************************************/
978 /* Data section                                                         */
979 /************************************************************************/
980         .data
981         .align 3
982 GLOBAL(__startkernel)
983         ADDR(begin)
984 GLOBAL(__endkernel)
985         ADDR(end)
986         .align  4
987 tmpstack:
988         .space  TMPSTACKSZ
989 tmpstackbound:
990         .space 10240    /* XXX: this really should not be necessary */
991 #ifdef __powerpc64__
992 TOC_ENTRY(tmpstack)
993 TOC_ENTRY(bp_kernload)
994 #endif
995
996 /*
997  * Compiled KERNBASE locations
998  */
999         .globl  kernbase
1000         .set    kernbase, KERNBASE
1001
1002 #include <powerpc/booke/trap_subr.S>