]> Pileus Git - ~andy/linux/blob - arch/microblaze/kernel/head.S
Merge tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
[~andy/linux] / arch / microblaze / kernel / head.S
1 /*
2  * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3  * Copyright (C) 2007-2009 PetaLogix
4  * Copyright (C) 2006 Atmark Techno, Inc.
5  *
6  * MMU code derived from arch/ppc/kernel/head_4xx.S:
7  *    Copyright (c) 1995-1996 Gary Thomas <gdt@linuxppc.org>
8  *      Initial PowerPC version.
9  *    Copyright (c) 1996 Cort Dougan <cort@cs.nmt.edu>
10  *      Rewritten for PReP
11  *    Copyright (c) 1996 Paul Mackerras <paulus@cs.anu.edu.au>
12  *      Low-level exception handers, MMU support, and rewrite.
13  *    Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
14  *      PowerPC 8xx modifications.
15  *    Copyright (c) 1998-1999 TiVo, Inc.
16  *      PowerPC 403GCX modifications.
17  *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
18  *      PowerPC 403GCX/405GP modifications.
19  *    Copyright 2000 MontaVista Software Inc.
20  *      PPC405 modifications
21  *      PowerPC 403GCX/405GP modifications.
22  *      Author: MontaVista Software, Inc.
23  *              frank_rowand@mvista.com or source@mvista.com
24  *              debbie_chu@mvista.com
25  *
26  * This file is subject to the terms and conditions of the GNU General Public
27  * License. See the file "COPYING" in the main directory of this archive
28  * for more details.
29  */
30
31 #include <linux/init.h>
32 #include <linux/linkage.h>
33 #include <asm/thread_info.h>
34 #include <asm/page.h>
35 #include <linux/of_fdt.h>               /* for OF_DT_HEADER */
36
37 #ifdef CONFIG_MMU
38 #include <asm/setup.h> /* COMMAND_LINE_SIZE */
39 #include <asm/mmu.h>
40 #include <asm/processor.h>
41
42 .section .data
43 .global empty_zero_page
44 .align 12
45 empty_zero_page:
46         .space  PAGE_SIZE
47 .global swapper_pg_dir
48 swapper_pg_dir:
49         .space  PAGE_SIZE
50
51 #endif /* CONFIG_MMU */
52
53 .section .rodata
54 .align 4
55 endian_check:
56         .word   1
57
58         __HEAD
59 ENTRY(_start)
60 #if CONFIG_KERNEL_BASE_ADDR == 0
61         brai    TOPHYS(real_start)
62         .org    0x100
63 real_start:
64 #endif
65
66         mts     rmsr, r0
67 /*
68  * According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc'
69  * if the msrclr instruction is not enabled. We use this to detect
70  * if the opcode is available, by issuing msrclr and then testing the result.
71  * r8 == 0 - msr instructions are implemented
72  * r8 != 0 - msr instructions are not implemented
73  */
74         mfs     r1, rmsr
75         msrclr  r8, 0 /* clear nothing - just read msr for test */
76         cmpu    r8, r8, r1 /* r1 must contain msr reg content */
77
78 /* r7 may point to an FDT, or there may be one linked in.
79    if it's in r7, we've got to save it away ASAP.
80    We ensure r7 points to a valid FDT, just in case the bootloader
81    is broken or non-existent */
82         beqi    r7, no_fdt_arg                  /* NULL pointer?  don't copy */
83 /* Does r7 point to a valid FDT? Load HEADER magic number */
84         /* Run time Big/Little endian platform */
85         /* Save 1 as word and load byte - 0 - BIG, 1 - LITTLE */
86         lbui    r11, r0, TOPHYS(endian_check)
87         beqid   r11, big_endian /* DO NOT break delay stop dependency */
88         lw      r11, r0, r7 /* Big endian load in delay slot */
89         lwr     r11, r0, r7 /* Little endian load */
90 big_endian:
91         rsubi   r11, r11, OF_DT_HEADER  /* Check FDT header */
92         beqi    r11, _prepare_copy_fdt
93         or      r7, r0, r0              /* clear R7 when not valid DTB */
94         bnei    r11, no_fdt_arg                 /* No - get out of here */
95 _prepare_copy_fdt:
96         or      r11, r0, r0 /* incremment */
97         ori     r4, r0, TOPHYS(_fdt_start)
98         ori     r3, r0, (0x8000 - 4)
99 _copy_fdt:
100         lw      r12, r7, r11 /* r12 = r7 + r11 */
101         sw      r12, r4, r11 /* addr[r4 + r11] = r12 */
102         addik   r11, r11, 4 /* increment counting */
103         bgtid   r3, _copy_fdt /* loop for all entries */
104         addik   r3, r3, -4 /* descrement loop */
105 no_fdt_arg:
106
107 #ifdef CONFIG_MMU
108
109 #ifndef CONFIG_CMDLINE_BOOL
110 /*
111  * handling command line
112  * copy command line to __init_end. There is space for storing command line.
113  */
114         or      r6, r0, r0              /* incremment */
115         ori     r4, r0, __init_end      /* load address of command line */
116         tophys(r4,r4)                   /* convert to phys address */
117         ori     r3, r0, COMMAND_LINE_SIZE - 1 /* number of loops */
118 _copy_command_line:
119         lbu     r2, r5, r6 /* r2=r5+r6 - r5 contain pointer to command line */
120         sb      r2, r4, r6              /* addr[r4+r6]= r2*/
121         addik   r6, r6, 1               /* increment counting */
122         bgtid   r3, _copy_command_line  /* loop for all entries       */
123         addik   r3, r3, -1              /* descrement loop */
124         addik   r5, r4, 0               /* add new space for command line */
125         tovirt(r5,r5)
126 #endif /* CONFIG_CMDLINE_BOOL */
127
128 #ifdef NOT_COMPILE
129 /* save bram context */
130         or      r6, r0, r0                              /* incremment */
131         ori     r4, r0, TOPHYS(_bram_load_start)        /* save bram context */
132         ori     r3, r0, (LMB_SIZE - 4)
133 _copy_bram:
134         lw      r7, r0, r6              /* r7 = r0 + r6 */
135         sw      r7, r4, r6              /* addr[r4 + r6] = r7*/
136         addik   r6, r6, 4               /* increment counting */
137         bgtid   r3, _copy_bram          /* loop for all entries */
138         addik   r3, r3, -4              /* descrement loop */
139 #endif
140         /* We have to turn on the MMU right away. */
141
142         /*
143          * Set up the initial MMU state so we can do the first level of
144          * kernel initialization.  This maps the first 16 MBytes of memory 1:1
145          * virtual to physical.
146          */
147         nop
148         addik   r3, r0, MICROBLAZE_TLB_SIZE -1  /* Invalidate all TLB entries */
149 _invalidate:
150         mts     rtlbx, r3
151         mts     rtlbhi, r0                      /* flush: ensure V is clear   */
152         mts     rtlblo, r0
153         bgtid   r3, _invalidate         /* loop for all entries       */
154         addik   r3, r3, -1
155         /* sync */
156
157         /* Setup the kernel PID */
158         mts     rpid,r0                 /* Load the kernel PID */
159         nop
160         bri     4
161
162         /*
163          * We should still be executing code at physical address area
164          * RAM_BASEADDR at this point. However, kernel code is at
165          * a virtual address. So, set up a TLB mapping to cover this once
166          * translation is enabled.
167          */
168
169         addik   r3,r0, CONFIG_KERNEL_START /* Load the kernel virtual address */
170         tophys(r4,r3)                   /* Load the kernel physical address */
171
172         /* start to do TLB calculation */
173         addik   r12, r0, _end
174         rsub    r12, r3, r12
175         addik   r12, r12, CONFIG_KERNEL_PAD /* that's the pad */
176
177         or r9, r0, r0 /* TLB0 = 0 */
178         or r10, r0, r0 /* TLB1 = 0 */
179
180         addik   r11, r12, -0x1000000
181         bgei    r11, GT16 /* size is greater than 16MB */
182         addik   r11, r12, -0x0800000
183         bgei    r11, GT8 /* size is greater than 8MB */
184         addik   r11, r12, -0x0400000
185         bgei    r11, GT4 /* size is greater than 4MB */
186         /* size is less than 4MB */
187         addik   r11, r12, -0x0200000
188         bgei    r11, GT2 /* size is greater than 2MB */
189         addik   r9, r0, 0x0100000 /* TLB0 must be 1MB */
190         addik   r11, r12, -0x0100000
191         bgei    r11, GT1 /* size is greater than 1MB */
192         /* TLB1 is 0 which is setup above */
193         bri tlb_end
194 GT4: /* r11 contains the rest - will be either 1 or 4 */
195         ori r9, r0, 0x400000 /* TLB0 is 4MB */
196         bri TLB1
197 GT16: /* TLB0 is 16MB */
198         addik   r9, r0, 0x1000000 /* means TLB0 is 16MB */
199 TLB1:
200         /* must be used r2 because of substract if failed */
201         addik   r2, r11, -0x0400000
202         bgei    r2, GT20 /* size is greater than 16MB */
203         /* size is >16MB and <20MB */
204         addik   r11, r11, -0x0100000
205         bgei    r11, GT17 /* size is greater than 17MB */
206         /* kernel is >16MB and < 17MB */
207 GT1:
208         addik   r10, r0, 0x0100000 /* means TLB1 is 1MB */
209         bri tlb_end
210 GT2: /* TLB0 is 0 and TLB1 will be 4MB */
211 GT17: /* TLB1 is 4MB - kernel size <20MB */
212         addik   r10, r0, 0x0400000 /* means TLB1 is 4MB */
213         bri tlb_end
214 GT8: /* TLB0 is still zero that's why I can use only TLB1 */
215 GT20: /* TLB1 is 16MB - kernel size >20MB */
216         addik   r10, r0, 0x1000000 /* means TLB1 is 16MB */
217 tlb_end:
218
219         /*
220          * Configure and load two entries into TLB slots 0 and 1.
221          * In case we are pinning TLBs, these are reserved in by the
222          * other TLB functions.  If not reserving, then it doesn't
223          * matter where they are loaded.
224          */
225         andi    r4,r4,0xfffffc00        /* Mask off the real page number */
226         ori     r4,r4,(TLB_WR | TLB_EX) /* Set the write and execute bits */
227
228         /*
229          * TLB0 is always used - check if is not zero (r9 stores TLB0 value)
230          * if is use TLB1 value and clear it (r10 stores TLB1 value)
231          */
232         bnei    r9, tlb0_not_zero
233         add     r9, r10, r0
234         add     r10, r0, r0
235 tlb0_not_zero:
236
237         /* look at the code below */
238         ori     r30, r0, 0x200
239         andi    r29, r9, 0x100000
240         bneid   r29, 1f
241         addik   r30, r30, 0x80
242         andi    r29, r9, 0x400000
243         bneid   r29, 1f
244         addik   r30, r30, 0x80
245         andi    r29, r9, 0x1000000
246         bneid   r29, 1f
247         addik   r30, r30, 0x80
248 1:
249         andi    r3,r3,0xfffffc00        /* Mask off the effective page number */
250         ori     r3,r3,(TLB_VALID)
251         or      r3, r3, r30
252
253         /* Load tlb_skip size value which is index to first unused TLB entry */
254         lwi     r11, r0, TOPHYS(tlb_skip)
255         mts     rtlbx,r11               /* TLB slow 0 */
256
257         mts     rtlblo,r4               /* Load the data portion of the entry */
258         mts     rtlbhi,r3               /* Load the tag portion of the entry */
259
260         /* Increase tlb_skip size */
261         addik   r11, r11, 1
262         swi     r11, r0, TOPHYS(tlb_skip)
263
264         /* TLB1 can be zeroes that's why we not setup it */
265         beqi    r10, jump_over2
266
267         /* look at the code below */
268         ori     r30, r0, 0x200
269         andi    r29, r10, 0x100000
270         bneid   r29, 1f
271         addik   r30, r30, 0x80
272         andi    r29, r10, 0x400000
273         bneid   r29, 1f
274         addik   r30, r30, 0x80
275         andi    r29, r10, 0x1000000
276         bneid   r29, 1f
277         addik   r30, r30, 0x80
278 1:
279         addk    r4, r4, r9      /* previous addr + TLB0 size */
280         addk    r3, r3, r9
281
282         andi    r3,r3,0xfffffc00        /* Mask off the effective page number */
283         ori     r3,r3,(TLB_VALID)
284         or      r3, r3, r30
285
286         lwi     r11, r0, TOPHYS(tlb_skip)
287         mts     rtlbx, r11              /* r11 is used from TLB0 */
288
289         mts     rtlblo,r4               /* Load the data portion of the entry */
290         mts     rtlbhi,r3               /* Load the tag portion of the entry */
291
292         /* Increase tlb_skip size */
293         addik   r11, r11, 1
294         swi     r11, r0, TOPHYS(tlb_skip)
295
296 jump_over2:
297         /*
298          * Load a TLB entry for LMB, since we need access to
299          * the exception vectors, using a 4k real==virtual mapping.
300          */
301         /* Use temporary TLB_ID for LMB - clear this temporary mapping later */
302         ori     r6, r0, MICROBLAZE_LMB_TLB_ID
303         mts     rtlbx,r6
304
305         ori     r4,r0,(TLB_WR | TLB_EX)
306         ori     r3,r0,(TLB_VALID | TLB_PAGESZ(PAGESZ_4K))
307
308         mts     rtlblo,r4               /* Load the data portion of the entry */
309         mts     rtlbhi,r3               /* Load the tag portion of the entry */
310
311         /*
312          * We now have the lower 16 Meg of RAM mapped into TLB entries, and the
313          * caches ready to work.
314          */
315 turn_on_mmu:
316         ori     r15,r0,start_here
317         ori     r4,r0,MSR_KERNEL_VMS
318         mts     rmsr,r4
319         nop
320         rted    r15,0                   /* enables MMU */
321         nop
322
323 start_here:
324 #endif /* CONFIG_MMU */
325
326         /* Initialize small data anchors */
327         addik   r13, r0, _KERNEL_SDA_BASE_
328         addik   r2, r0, _KERNEL_SDA2_BASE_
329
330         /* Initialize stack pointer */
331         addik   r1, r0, init_thread_union + THREAD_SIZE - 4
332
333         /* Initialize r31 with current task address */
334         addik   r31, r0, init_task
335
336         /*
337          * Call platform dependent initialize function.
338          * Please see $(ARCH)/mach-$(SUBARCH)/setup.c for
339          * the function.
340          */
341         addik   r11, r0, machine_early_init
342         brald   r15, r11
343         nop
344
345 #ifndef CONFIG_MMU
346         addik   r15, r0, machine_halt
347         braid   start_kernel
348         nop
349 #else
350         /*
351          * Initialize the MMU.
352          */
353         bralid  r15, mmu_init
354         nop
355
356         /* Go back to running unmapped so we can load up new values
357          * and change to using our exception vectors.
358          * On the MicroBlaze, all we invalidate the used TLB entries to clear
359          * the old 16M byte TLB mappings.
360          */
361         ori     r15,r0,TOPHYS(kernel_load_context)
362         ori     r4,r0,MSR_KERNEL
363         mts     rmsr,r4
364         nop
365         bri     4
366         rted    r15,0
367         nop
368
369         /* Load up the kernel context */
370 kernel_load_context:
371         ori     r5, r0, MICROBLAZE_LMB_TLB_ID
372         mts     rtlbx,r5
373         nop
374         mts     rtlbhi,r0
375         nop
376         addi    r15, r0, machine_halt
377         ori     r17, r0, start_kernel
378         ori     r4, r0, MSR_KERNEL_VMS
379         mts     rmsr, r4
380         nop
381         rted    r17, 0          /* enable MMU and jump to start_kernel */
382         nop
383 #endif /* CONFIG_MMU */