linux/arch/cris/arch-v32/kernel/head.S
<<
>>
Prefs
   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