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 45empty_zero_page: 46 .space PAGE_SIZE 47.global swapper_pg_dir 48swapper_pg_dir: 49 .space PAGE_SIZE 50 51#endif /* CONFIG_MMU */ 52 53.section .rodata 54.align 4 55endian_check: 56 .word 1 57 58 __HEAD 59ENTRY(_start) 60#if CONFIG_KERNEL_BASE_ADDR == 0 61 brai TOPHYS(real_start) 62 .org 0x100 63real_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 */ 90big_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 */ 105no_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 194GT4: /* r11 contains the rest - will be either 1 or 4 */ 195 ori r9, r0, 0x400000 /* TLB0 is 4MB */ 196 bri TLB1 197GT16: /* TLB0 is 16MB */ 198 addik r9, r0, 0x1000000 /* means TLB0 is 16MB */ 199TLB1: 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 */ 207GT1: 208 addik r10, r0, 0x0100000 /* means TLB1 is 1MB */ 209 bri tlb_end 210GT2: /* TLB0 is 0 and TLB1 will be 4MB */ 211GT17: /* TLB1 is 4MB - kernel size <20MB */ 212 addik r10, r0, 0x0400000 /* means TLB1 is 4MB */ 213 bri tlb_end 214GT8: /* TLB0 is still zero that's why I can use only TLB1 */ 215GT20: /* TLB1 is 16MB - kernel size >20MB */ 216 addik r10, r0, 0x1000000 /* means TLB1 is 16MB */ 217tlb_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 235tlb0_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 2481: 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 2781: 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 296jump_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 */ 315turn_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 323start_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 */ 370kernel_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 */ 384