1/* 2 * CRISv32 kernel startup code. 3 * 4 * Copyright (C) 2003, Axis Communications AB 5 */ 6 7#define ASSEMBLER_MACROS_ONLY 8 9/* 10 * The macros found in mmu_defs_asm.h uses the ## concatenation operator, so 11 * -traditional must not be used when assembling this file. 12 */ 13#include <arch/memmap.h> 14#include <hwregs/reg_rdwr.h> 15#include <hwregs/intr_vect.h> 16#include <hwregs/asm/mmu_defs_asm.h> 17#include <hwregs/asm/reg_map_asm.h> 18#include <mach/startup.inc> 19 20#define CRAMFS_MAGIC 0x28cd3d45 21#define JHEAD_MAGIC 0x1FF528A6 22#define JHEAD_SIZE 8 23#define RAM_INIT_MAGIC 0x56902387 24#define COMMAND_LINE_MAGIC 0x87109563 25#define NAND_BOOT_MAGIC 0x9a9db001 26 27 ;; NOTE: R8 and R9 carry information from the decompressor (if the 28 ;; kernel was compressed). They must not be used in the code below 29 ;; until they are read! 30 31 ;; Exported symbols. 32 .global etrax_irv 33 .global romfs_start 34 .global romfs_length 35 .global romfs_in_flash 36 .global nand_boot 37 .global swapper_pg_dir 38 39 ;; Dummy section to make it bootable with current VCS simulator 40#ifdef CONFIG_ETRAX_VCS_SIM 41 .section ".boot", "ax" 42 ba tstart 43 nop 44#endif 45 46 .text 47tstart: 48 ;; This is the entry point of the kernel. The CPU is currently in 49 ;; supervisor mode. 50 ;; 51 ;; 0x00000000 if flash. 52 ;; 0x40004000 if DRAM. 53 ;; 54 di 55 56 START_CLOCKS 57 58 SETUP_WAIT_STATES 59 60 GIO_INIT 61 62#ifdef CONFIG_SMP 63secondary_cpu_entry: /* Entry point for secondary CPUs */ 64 di 65#endif 66 67 ;; Setup and enable the MMU. Use same configuration for both the data 68 ;; and the instruction MMU. 69 ;; 70 ;; Note; 3 cycles is needed for a bank-select to take effect. Further; 71 ;; bank 1 is the instruction MMU, bank 2 is the data MMU. 72 73#ifdef CONFIG_CRIS_MACH_ARTPEC3 74 move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \ 75 | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4) \ 76 | REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 5) \ 77 | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0 78#elif !defined(CONFIG_ETRAX_VCS_SIM) 79 move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \ 80 | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4) \ 81 | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0 82#else 83 ;; Map the virtual DRAM to the RW eprom area at address 0. 84 ;; Also map 0xa for the hook calls, 85 move.d REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8) \ 86 | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4) \ 87 | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) \ 88 | REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa), $r0 89#endif 90 91 ;; Temporary map of 0x40 -> 0x40 and 0x00 -> 0x00. 92 move.d REG_FIELD(mmu, rw_mm_kbase_lo, base_4, 4) \ 93 | REG_FIELD(mmu, rw_mm_kbase_lo, base_0, 0), $r1 94 95 ;; Enable certain page protections and setup linear mapping 96 ;; for f,e,c,b,4,0. 97 98 ;; ARTPEC-3: 99 ;; c,d used for linear kernel mapping, up to 512 MB 100 ;; e used for vmalloc 101 ;; f unused, but page mapped to get page faults 102 103 ;; ETRAX FS: 104 ;; c used for linear kernel mapping, up to 256 MB 105 ;; d used for vmalloc 106 ;; e,f used for memory-mapped NOR flash 107 108#ifdef CONFIG_CRIS_MACH_ARTPEC3 109 move.d REG_STATE(mmu, rw_mm_cfg, we, on) \ 110 | REG_STATE(mmu, rw_mm_cfg, acc, on) \ 111 | REG_STATE(mmu, rw_mm_cfg, ex, on) \ 112 | REG_STATE(mmu, rw_mm_cfg, inv, on) \ 113 | REG_STATE(mmu, rw_mm_cfg, seg_f, page) \ 114 | REG_STATE(mmu, rw_mm_cfg, seg_e, page) \ 115 | REG_STATE(mmu, rw_mm_cfg, seg_d, linear) \ 116 | REG_STATE(mmu, rw_mm_cfg, seg_c, linear) \ 117 | REG_STATE(mmu, rw_mm_cfg, seg_b, linear) \ 118 | REG_STATE(mmu, rw_mm_cfg, seg_a, page) \ 119 | REG_STATE(mmu, rw_mm_cfg, seg_9, page) \ 120 | REG_STATE(mmu, rw_mm_cfg, seg_8, page) \ 121 | REG_STATE(mmu, rw_mm_cfg, seg_7, page) \ 122 | REG_STATE(mmu, rw_mm_cfg, seg_6, page) \ 123 | REG_STATE(mmu, rw_mm_cfg, seg_5, page) \ 124 | REG_STATE(mmu, rw_mm_cfg, seg_4, linear) \ 125 | REG_STATE(mmu, rw_mm_cfg, seg_3, page) \ 126 | REG_STATE(mmu, rw_mm_cfg, seg_2, page) \ 127 | REG_STATE(mmu, rw_mm_cfg, seg_1, page) \ 128 | REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2 129#elif !defined(CONFIG_ETRAX_VCS_SIM) 130 move.d REG_STATE(mmu, rw_mm_cfg, we, on) \ 131 | REG_STATE(mmu, rw_mm_cfg, acc, on) \ 132 | REG_STATE(mmu, rw_mm_cfg, ex, on) \ 133 | REG_STATE(mmu, rw_mm_cfg, inv, on) \ 134 | REG_STATE(mmu, rw_mm_cfg, seg_f, linear) \ 135 | REG_STATE(mmu, rw_mm_cfg, seg_e, linear) \ 136 | REG_STATE(mmu, rw_mm_cfg, seg_d, page) \ 137 | REG_STATE(mmu, rw_mm_cfg, seg_c, linear) \ 138 | REG_STATE(mmu, rw_mm_cfg, seg_b, linear) \ 139 | REG_STATE(mmu, rw_mm_cfg, seg_a, page) \ 140 | REG_STATE(mmu, rw_mm_cfg, seg_9, page) \ 141 | REG_STATE(mmu, rw_mm_cfg, seg_8, page) \ 142 | REG_STATE(mmu, rw_mm_cfg, seg_7, page) \ 143 | REG_STATE(mmu, rw_mm_cfg, seg_6, page) \ 144 | REG_STATE(mmu, rw_mm_cfg, seg_5, page) \ 145 | REG_STATE(mmu, rw_mm_cfg, seg_4, linear) \ 146 | REG_STATE(mmu, rw_mm_cfg, seg_3, page) \ 147 | REG_STATE(mmu, rw_mm_cfg, seg_2, page) \ 148 | REG_STATE(mmu, rw_mm_cfg, seg_1, page) \ 149 | REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2 150#else 151 move.d REG_STATE(mmu, rw_mm_cfg, we, on) \ 152 | REG_STATE(mmu, rw_mm_cfg, acc, on) \ 153 | REG_STATE(mmu, rw_mm_cfg, ex, on) \ 154 | REG_STATE(mmu, rw_mm_cfg, inv, on) \ 155 | REG_STATE(mmu, rw_mm_cfg, seg_f, linear) \ 156 | REG_STATE(mmu, rw_mm_cfg, seg_e, linear) \ 157 | REG_STATE(mmu, rw_mm_cfg, seg_d, page) \ 158 | REG_STATE(mmu, rw_mm_cfg, seg_c, linear) \ 159 | REG_STATE(mmu, rw_mm_cfg, seg_b, linear) \ 160 | REG_STATE(mmu, rw_mm_cfg, seg_a, linear) \ 161 | REG_STATE(mmu, rw_mm_cfg, seg_9, page) \ 162 | REG_STATE(mmu, rw_mm_cfg, seg_8, page) \ 163 | REG_STATE(mmu, rw_mm_cfg, seg_7, page) \ 164 | REG_STATE(mmu, rw_mm_cfg, seg_6, page) \ 165 | REG_STATE(mmu, rw_mm_cfg, seg_5, page) \ 166 | REG_STATE(mmu, rw_mm_cfg, seg_4, linear) \ 167 | REG_STATE(mmu, rw_mm_cfg, seg_3, page) \ 168 | REG_STATE(mmu, rw_mm_cfg, seg_2, page) \ 169 | REG_STATE(mmu, rw_mm_cfg, seg_1, page) \ 170 | REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2 171#endif 172 173 ;; Update instruction MMU. 174 move 1, $srs 175 nop 176 nop 177 nop 178 move $r0, $s2 ; kbase_hi. 179 move $r1, $s1 ; kbase_lo. 180 move $r2, $s0 ; mm_cfg, virtual memory configuration. 181 182 ;; Update data MMU. 183 move 2, $srs 184 nop 185 nop 186 nop 187 move $r0, $s2 ; kbase_hi. 188 move $r1, $s1 ; kbase_lo 189 move $r2, $s0 ; mm_cfg, virtual memory configuration. 190 191 ;; Enable data and instruction MMU. 192 move 0, $srs 193 moveq 0xf, $r0 ; IMMU, DMMU, DCache, Icache on 194 nop 195 nop 196 nop 197 move $r0, $s0 198 nop 199 nop 200 nop 201 202#ifdef CONFIG_SMP 203 ;; Read CPU ID 204 move 0, $srs 205 nop 206 nop 207 nop 208 move $s12, $r0 209 cmpq 0, $r0 210 beq master_cpu 211 nop 212slave_cpu: 213 ; Time to boot-up. Get stack location provided by master CPU. 214 move.d smp_init_current_idle_thread, $r1 215 move.d [$r1], $sp 216 add.d 8192, $sp 217 move.d ebp_start, $r0 ; Defined in linker-script. 218 move $r0, $ebp 219 jsr smp_callin 220 nop 221master_cpu: 222 /* Set up entry point for secondary CPUs. The boot ROM has set up 223 * EBP at start of internal memory. The CPU will get there 224 * later when we issue an IPI to them... */ 225 move.d MEM_INTMEM_START + IPI_INTR_VECT * 4, $r0 226 move.d secondary_cpu_entry, $r1 227 move.d $r1, [$r0] 228#endif 229#ifndef CONFIG_ETRAX_VCS_SIM 230 ; Check if starting from DRAM (network->RAM boot or unpacked 231 ; compressed kernel), or directly from flash. 232 lapcq ., $r0 233 and.d 0x7fffffff, $r0 ; Mask off the non-cache bit. 234 cmp.d 0x10000, $r0 ; Arbitrary, something above this code. 235 blo _inflash0 236 nop 237#endif 238 239 jump _inram ; Jump to cached RAM. 240 nop 241 242 ;; Jumpgate. 243_inflash0: 244 jump _inflash 245 nop 246 247 ;; Put the following in a section so that storage for it can be 248 ;; reclaimed after init is finished. 249 .section ".init.text", "ax" 250 251_inflash: 252 253 ;; Initialize DRAM. 254 cmp.d RAM_INIT_MAGIC, $r8 ; Already initialized? 255 beq _dram_initialized 256 nop 257 258#if defined CONFIG_ETRAXFS 259#include "../mach-fs/dram_init.S" 260#elif defined CONFIG_CRIS_MACH_ARTPEC3 261#include "../mach-a3/dram_init.S" 262#else 263#error Only ETRAXFS and ARTPEC-3 supported! 264#endif 265 266 267_dram_initialized: 268 ;; Copy the text and data section to DRAM. This depends on that the 269 ;; variables used below are correctly set up by the linker script. 270 ;; The calculated value stored in R4 is used below. 271 ;; Leave the cramfs file system (piggybacked after the kernel) in flash. 272 moveq 0, $r0 ; Source. 273 move.d text_start, $r1 ; Destination. 274 move.d __vmlinux_end, $r2 275 move.d $r2, $r4 276 sub.d $r1, $r4 2771: move.w [$r0+], $r3 278 move.w $r3, [$r1+] 279 cmp.d $r2, $r1 280 blo 1b 281 nop 282 283 ;; Check for cramfs. 284 moveq 0, $r0 285 move.d romfs_length, $r1 286 move.d $r0, [$r1] 287 move.d [$r4], $r0 ; cramfs_super.magic 288 cmp.d CRAMFS_MAGIC, $r0 289 bne 1f 290 nop 291 292 ;; Set length and start of cramfs, set romfs_in_flash flag 293 addoq +4, $r4, $acr 294 move.d [$acr], $r0 295 move.d romfs_length, $r1 296 move.d $r0, [$r1] 297 add.d 0xf0000000, $r4 ; Add cached flash start in virtual memory. 298 move.d romfs_start, $r1 299 move.d $r4, [$r1] 3001: moveq 1, $r0 301 move.d romfs_in_flash, $r1 302 move.d $r0, [$r1] 303 304 jump _start_it ; Jump to cached code. 305 nop 306 307_inram: 308 ;; Check if booting from NAND flash; if so, set appropriate flags 309 ;; and move on. 310 cmp.d NAND_BOOT_MAGIC, $r12 311 bne move_cramfs ; not nand, jump 312 moveq 1, $r0 313 move.d nand_boot, $r1 ; tell axisflashmap we're booting from NAND 314 move.d $r0, [$r1] 315 moveq 0, $r0 ; tell axisflashmap romfs is not in 316 move.d romfs_in_flash, $r1 ; (directly accessed) flash 317 move.d $r0, [$r1] 318 jump _start_it ; continue with boot 319 nop 320 321move_cramfs: 322 ;; kernel is in DRAM. 323 ;; Must figure out if there is a piggybacked rootfs image or not. 324 ;; Set romfs_length to 0 => no rootfs image available by default. 325 moveq 0, $r0 326 move.d romfs_length, $r1 327 move.d $r0, [$r1] 328 329#ifndef CONFIG_ETRAX_VCS_SIM 330 ;; The kernel could have been unpacked to DRAM by the loader, but 331 ;; the cramfs image could still be in the flash immediately 332 ;; following the compressed kernel image. The loader passes the address 333 ;; of the byte succeeding the last compressed byte in the flash in 334 ;; register R9 when starting the kernel. 335 cmp.d 0x0ffffff8, $r9 336 bhs _no_romfs_in_flash ; R9 points outside the flash area. 337 nop 338#else 339 ba _no_romfs_in_flash 340 nop 341#endif 342 ;; cramfs rootfs might to be in flash. Check for it. 343 move.d [$r9], $r0 ; cramfs_super.magic 344 cmp.d CRAMFS_MAGIC, $r0 345 bne _no_romfs_in_flash 346 nop 347 348 ;; found cramfs in flash. set address and size, and romfs_in_flash flag. 349 addoq +4, $r9, $acr 350 move.d [$acr], $r0 351 move.d romfs_length, $r1 352 move.d $r0, [$r1] 353 add.d 0xf0000000, $r9 ; Add cached flash start in virtual memory. 354 move.d romfs_start, $r1 355 move.d $r9, [$r1] 356 moveq 1, $r0 357 move.d romfs_in_flash, $r1 358 move.d $r0, [$r1] 359 360 jump _start_it ; Jump to cached code. 361 nop 362 363_no_romfs_in_flash: 364 ;; No romfs in flash, so look for cramfs, or jffs2 with jhead, 365 ;; after kernel in RAM, as is the case with network->RAM boot. 366 ;; For cramfs, partition starts with magic and length. 367 ;; For jffs2, a jhead is prepended which contains with magic and length. 368 ;; The jhead is not part of the jffs2 partition however. 369#ifndef CONFIG_ETRAXFS_SIM 370 move.d __bss_start, $r0 371#else 372 move.d __end, $r0 373#endif 374 move.d [$r0], $r1 375 cmp.d CRAMFS_MAGIC, $r1 ; cramfs magic? 376 beq 2f ; yes, jump 377 nop 378 cmp.d JHEAD_MAGIC, $r1 ; jffs2 (jhead) magic? 379 bne 4f ; no, skip copy 380 nop 381 addq 4, $r0 ; location of jffs2 size 382 move.d [$r0+], $r2 ; fetch jffs2 size -> r2 383 ; r0 now points to start of jffs2 384 ba 3f 385 nop 3862: 387 addoq +4, $r0, $acr ; location of cramfs size 388 move.d [$acr], $r2 ; fetch cramfs size -> r2 389 ; r0 still points to start of cramfs 3903: 391 ;; Now, move the root fs to after kernel's BSS 392 393 move.d _end, $r1 ; start of cramfs -> r1 394 move.d romfs_start, $r3 395 move.d $r1, [$r3] ; store at romfs_start (for axisflashmap) 396 move.d romfs_length, $r3 397 move.d $r2, [$r3] ; store size at romfs_length 398 399#ifndef CONFIG_ETRAX_VCS_SIM 400 add.d $r2, $r0 ; copy from end and downwards 401 add.d $r2, $r1 402 403 lsrq 1, $r2 ; Size is in bytes, we copy words. 404 addq 1, $r2 4051: 406 move.w [$r0], $r3 407 move.w $r3, [$r1] 408 subq 2, $r0 409 subq 2, $r1 410 subq 1, $r2 411 bne 1b 412 nop 413#endif 414 4154: 416 ;; BSS move done. 417 ;; Clear romfs_in_flash flag, as we now know romfs is in DRAM 418 ;; Also clear nand_boot flag; if we got here, we know we've not 419 ;; booted from NAND flash. 420 moveq 0, $r0 421 move.d romfs_in_flash, $r1 422 move.d $r0, [$r1] 423 moveq 0, $r0 424 move.d nand_boot, $r1 425 move.d $r0, [$r1] 426 427 jump _start_it ; Jump to cached code. 428 nop 429 430_start_it: 431 432 ;; Check if kernel command line is supplied 433 cmp.d COMMAND_LINE_MAGIC, $r10 434 bne no_command_line 435 nop 436 437 move.d 256, $r13 438 move.d cris_command_line, $r10 439 or.d 0x80000000, $r11 ; Make it virtual 4401: 441 move.b [$r11+], $r1 442 move.b $r1, [$r10+] 443 subq 1, $r13 444 bne 1b 445 nop 446 447no_command_line: 448 449 ;; The kernel stack contains a task structure for each task. This 450 ;; the initial kernel stack is in the same page as the init_task, 451 ;; but starts at the top of the page, i.e. + 8192 bytes. 452 move.d init_thread_union + 8192, $sp 453 move.d ebp_start, $r0 ; Defined in linker-script. 454 move $r0, $ebp 455 move.d etrax_irv, $r1 ; Set the exception base register and pointer. 456 move.d $r0, [$r1] 457 458#ifndef CONFIG_ETRAX_VCS_SIM 459 ;; Clear the BSS region from _bss_start to _end. 460 move.d __bss_start, $r0 461 move.d _end, $r1 4621: clear.d [$r0+] 463 cmp.d $r1, $r0 464 blo 1b 465 nop 466#endif 467 468#ifdef CONFIG_ETRAX_VCS_SIM 469 /* Set the watchdog timeout to something big. Will be removed when */ 470 /* watchdog can be disabled with command line option */ 471 move.d 0x7fffffff, $r10 472 jsr CPU_WATCHDOG_TIMEOUT 473 nop 474#endif 475 476 ; Initialize registers to increase determinism 477 move.d __bss_start, $r0 478 movem [$r0], $r13 479 480#ifdef CONFIG_ETRAX_L2CACHE 481 jsr l2cache_init 482 nop 483#endif 484 485 jump start_kernel ; Jump to start_kernel() in init/main.c. 486 nop 487 488 .data 489etrax_irv: 490 .dword 0 491 492; Variables for communication with the Axis flash map driver (axisflashmap), 493; and for setting up memory in arch/cris/kernel/setup.c . 494 495; romfs_start is set to the start of the root file system, if it exists 496; in directly accessible memory (i.e. NOR Flash when booting from Flash, 497; or RAM when booting directly from a network-downloaded RAM image) 498romfs_start: 499 .dword 0 500 501; romfs_length is set to the size of the root file system image, if it exists 502; in directly accessible memory (see romfs_start). Otherwise it is set to 0. 503romfs_length: 504 .dword 0 505 506; romfs_in_flash is set to 1 if the root file system resides in directly 507; accessible flash memory (i.e. NOR flash). It is set to 0 for RAM boot 508; or NAND flash boot. 509romfs_in_flash: 510 .dword 0 511 512; nand_boot is set to 1 when the kernel has been booted from NAND flash 513nand_boot: 514 .dword 0 515 516swapper_pg_dir = 0xc0002000 517 518 .section ".init.data", "aw" 519 520#if defined CONFIG_ETRAXFS 521#include "../mach-fs/hw_settings.S" 522#elif defined CONFIG_CRIS_MACH_ARTPEC3 523#include "../mach-a3/hw_settings.S" 524#else 525#error Only ETRAXFS and ARTPEC-3 supported! 526#endif 527