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