| 1 | /*
|
| 2 | * arch/xtensa/kernel/head.S
|
| 3 | *
|
| 4 | * Xtensa Processor startup code.
|
| 5 | *
|
| 6 | * This file is subject to the terms and conditions of the GNU General Public
|
| 7 | * License. See the file "COPYING" in the main directory of this archive
|
| 8 | * for more details.
|
| 9 | *
|
| 10 | * Copyright (C) 2001 - 2008 Tensilica Inc.
|
| 11 | *
|
| 12 | * Chris Zankel <chris@zankel.net>
|
| 13 | * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
|
| 14 | * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
|
| 15 | * Kevin Chea
|
| 16 | */
|
| 17 |
|
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 |
|
| 25 | |
| 26 | |
| 27 |
|
| 28 | /*
|
| 29 | * This module contains the entry code for kernel images. It performs the
|
| 30 | * minimal setup needed to call the generic C routines.
|
| 31 | *
|
| 32 | * Prerequisites:
|
| 33 | *
|
| 34 | * - The kernel image has been loaded to the actual address where it was
|
| 35 | * compiled to.
|
| 36 | * - a2 contains either 0 or a pointer to a list of boot parameters.
|
| 37 | * (see setup.c for more details)
|
| 38 | *
|
| 39 | */
|
| 40 |
|
| 41 | /*
|
| 42 | * _start
|
| 43 | *
|
| 44 | * The bootloader passes a pointer to a list of boot parameters in a2.
|
| 45 | */
|
| 46 |
|
| 47 | /* The first bytes of the kernel image must be an instruction, so we
|
| 48 | * manually allocate and define the literal constant we need for a jx
|
| 49 | * instruction.
|
| 50 | */
|
| 51 |
|
| 52 | __HEAD
|
| 53 | .begin no-absolute-literals
|
| 54 |
|
| 55 | ENTRY(_start)
|
| 56 |
|
| 57 | /* Preserve the pointer to the boot parameter list in EXCSAVE_1 */
|
| 58 | wsr a2, excsave1
|
| 59 | _j _SetupOCD
|
| 60 |
|
| 61 | .align 4
|
| 62 | .literal_position
|
| 63 | _SetupOCD:
|
| 64 | /*
|
| 65 | * Initialize WB, WS, and clear PS.EXCM (to allow loop instructions).
|
| 66 | * Set Interrupt Level just below XCHAL_DEBUGLEVEL to allow
|
| 67 | * xt-gdb to single step via DEBUG exceptions received directly
|
| 68 | * by ocd.
|
| 69 | */
|
| 70 | |
| 71 | movi a1, 1
|
| 72 | movi a0, 0
|
| 73 | wsr a1, windowstart
|
| 74 | wsr a0, windowbase
|
| 75 | rsync
|
| 76 | |
| 77 |
|
| 78 | movi a1, LOCKLEVEL
|
| 79 | wsr a1, ps
|
| 80 | rsync
|
| 81 |
|
| 82 | .global _SetupMMU
|
| 83 | _SetupMMU:
|
| 84 | Offset = _SetupMMU - _start
|
| 85 |
|
| 86 | |
| 87 | initialize_mmu
|
| 88 | |
| 89 | rsr a2, excsave1
|
| 90 | movi a3, XCHAL_KSEG_PADDR
|
| 91 | bltu a2, a3, 1f
|
| 92 | sub a2, a2, a3
|
| 93 | movi a3, XCHAL_KSEG_SIZE
|
| 94 | bgeu a2, a3, 1f
|
| 95 | movi a3, XCHAL_KSEG_CACHED_VADDR
|
| 96 | add a2, a2, a3
|
| 97 | wsr a2, excsave1
|
| 98 | 1:
|
| 99 | |
| 100 | |
| 101 |
|
| 102 | movi a0, _startup
|
| 103 | jx a0
|
| 104 |
|
| 105 | ENDPROC(_start)
|
| 106 | .end no-absolute-literals
|
| 107 |
|
| 108 | __REF
|
| 109 | .literal_position
|
| 110 |
|
| 111 | ENTRY(_startup)
|
| 112 |
|
| 113 | /* Set a0 to 0 for the remaining initialization. */
|
| 114 |
|
| 115 | movi a0, 0
|
| 116 |
|
| 117 | |
| 118 | movi a2, VECBASE_VADDR
|
| 119 | wsr a2, vecbase
|
| 120 | |
| 121 |
|
| 122 | /* Clear debugging registers. */
|
| 123 |
|
| 124 | |
| 125 | |
| 126 | wsr a0, ibreakenable
|
| 127 | |
| 128 | wsr a0, icount
|
| 129 | movi a1, 15
|
| 130 | wsr a0, icountlevel
|
| 131 |
|
| 132 | .set _index, 0
|
| 133 | .rept XCHAL_NUM_DBREAK
|
| 134 | wsr a0, SREG_DBREAKC + _index
|
| 135 | .set _index, _index + 1
|
| 136 | .endr
|
| 137 | |
| 138 |
|
| 139 | /* Clear CCOUNT (not really necessary, but nice) */
|
| 140 |
|
| 141 | wsr a0, ccount |
| 142 |
|
| 143 | /* Disable zero-loops. */
|
| 144 |
|
| 145 | |
| 146 | wsr a0, lcount
|
| 147 | |
| 148 |
|
| 149 | /* Disable all timers. */
|
| 150 |
|
| 151 | .set _index, 0
|
| 152 | .rept XCHAL_NUM_TIMERS
|
| 153 | wsr a0, SREG_CCOMPARE + _index
|
| 154 | .set _index, _index + 1
|
| 155 | .endr
|
| 156 |
|
| 157 | /* Interrupt initialization. */
|
| 158 |
|
| 159 | movi a2, XCHAL_INTTYPE_MASK_SOFTWARE | XCHAL_INTTYPE_MASK_EXTERN_EDGE
|
| 160 | wsr a0, intenable
|
| 161 | wsr a2, intclear
|
| 162 |
|
| 163 | /* Disable coprocessors. */
|
| 164 |
|
| 165 | |
| 166 | wsr a0, cpenable
|
| 167 | |
| 168 |
|
| 169 | /* Initialize the caches.
|
| 170 | * a2, a3 are just working registers (clobbered).
|
| 171 | */
|
| 172 |
|
| 173 | |
| 174 | ___unlock_dcache_all a2 a3
|
| 175 | |
| 176 |
|
| 177 | |
| 178 | ___unlock_icache_all a2 a3
|
| 179 | |
| 180 |
|
| 181 | ___invalidate_dcache_all a2 a3
|
| 182 | ___invalidate_icache_all a2 a3
|
| 183 |
|
| 184 | isync
|
| 185 |
|
| 186 | initialize_cacheattr
|
| 187 |
|
| 188 | |
| 189 | movi a2, CCON |
| 190 | movi a3, 1
|
| 191 | wer a3, a2
|
| 192 | |
| 193 |
|
| 194 | /* Setup stack and enable window exceptions (keep irqs disabled) */
|
| 195 |
|
| 196 | movi a1, start_info
|
| 197 | l32i a1, a1, 0
|
| 198 |
|
| 199 | /* Disable interrupts. */
|
| 200 | /* Enable window exceptions if kernel is built with windowed ABI. */
|
| 201 | movi a2, KERNEL_PS_WOE_MASK | LOCKLEVEL
|
| 202 | wsr a2, ps
|
| 203 | rsync
|
| 204 |
|
| 205 | |
| 206 | /*
|
| 207 | * Notice that we assume with SMP that cores have PRID
|
| 208 | * supported by the cores.
|
| 209 | */
|
| 210 | rsr a2, prid
|
| 211 | bnez a2, .Lboot_secondary
|
| 212 |
|
| 213 | |
| 214 |
|
| 215 | /* Unpack data sections
|
| 216 | *
|
| 217 | * The linker script used to build the Linux kernel image
|
| 218 | * creates a table located at __boot_reloc_table_start
|
| 219 | * that contains the information what data needs to be unpacked.
|
| 220 | *
|
| 221 | * Uses a2-a7.
|
| 222 | */
|
| 223 |
|
| 224 | movi a2, __boot_reloc_table_start
|
| 225 | movi a3, __boot_reloc_table_end
|
| 226 |
|
| 227 | 1: beq a2, a3, 3f |
| 228 | l32i a4, a2, 0 |
| 229 | l32i a5, a2, 4 |
| 230 | l32i a6, a2, 8 |
| 231 | addi a2, a2, 12 |
| 232 | beq a4, a5, 1b |
| 233 | beq a4, a6, 1b |
| 234 |
|
| 235 | 2: l32i a7, a6, 0 |
| 236 | addi a6, a6, 4
|
| 237 | s32i a7, a4, 0 |
| 238 | addi a4, a4, 4
|
| 239 | bltu a4, a5, 2b
|
| 240 | j 1b
|
| 241 |
|
| 242 | 3:
|
| 243 | /* All code and initialized data segments have been copied.
|
| 244 | * Now clear the BSS segment.
|
| 245 | */
|
| 246 |
|
| 247 | movi a2, __bss_start |
| 248 | movi a3, __bss_stop |
| 249 |
|
| 250 | __loopt a2, a3, a4, 2
|
| 251 | s32i a0, a2, 0
|
| 252 | __endla a2, a3, 4
|
| 253 |
|
| 254 | |
| 255 |
|
| 256 | /* After unpacking, flush the writeback cache to memory so the
|
| 257 | * instructions/data are available.
|
| 258 | */
|
| 259 |
|
| 260 | ___flush_dcache_all a2 a3
|
| 261 | |
| 262 | memw
|
| 263 | isync
|
| 264 | ___invalidate_icache_all a2 a3
|
| 265 | isync
|
| 266 |
|
| 267 | |
| 268 | /* Setup bootstrap CPU stack in XIP kernel */
|
| 269 |
|
| 270 | movi a1, start_info
|
| 271 | l32i a1, a1, 0
|
| 272 | |
| 273 |
|
| 274 | movi abi_arg0, 0
|
| 275 | xsr abi_arg0, excsave1
|
| 276 |
|
| 277 | /* init_arch kick-starts the linux kernel */
|
| 278 |
|
| 279 | abi_call init_arch
|
| 280 | abi_call start_kernel
|
| 281 |
|
| 282 | should_never_return:
|
| 283 | j should_never_return
|
| 284 |
|
| 285 | |
| 286 | .Lboot_secondary:
|
| 287 |
|
| 288 | movi a2, cpu_start_ccount
|
| 289 | 1:
|
| 290 | memw
|
| 291 | l32i a3, a2, 0
|
| 292 | beqi a3, 0, 1b
|
| 293 | movi a3, 0
|
| 294 | s32i a3, a2, 0
|
| 295 | 1:
|
| 296 | memw
|
| 297 | l32i a3, a2, 0
|
| 298 | beqi a3, 0, 1b
|
| 299 | wsr a3, ccount
|
| 300 | movi a3, 0
|
| 301 | s32i a3, a2, 0
|
| 302 | memw
|
| 303 |
|
| 304 | movi abi_arg0, 0
|
| 305 | wsr abi_arg0, excsave1
|
| 306 |
|
| 307 | abi_call secondary_start_kernel
|
| 308 | j should_never_return
|
| 309 |
|
| 310 | |
| 311 |
|
| 312 | ENDPROC(_startup)
|
| 313 |
|
| 314 | |
| 315 |
|
| 316 | ENTRY(cpu_restart)
|
| 317 |
|
| 318 | |
| 319 | ___flush_invalidate_dcache_all a2 a3
|
| 320 | |
| 321 | ___invalidate_dcache_all a2 a3
|
| 322 | |
| 323 | memw
|
| 324 | movi a2, CCON |
| 325 | movi a3, 0
|
| 326 | wer a3, a2
|
| 327 | extw
|
| 328 |
|
| 329 | rsr a0, prid
|
| 330 | neg a2, a0
|
| 331 | movi a3, cpu_start_id
|
| 332 | memw
|
| 333 | s32i a2, a3, 0
|
| 334 | |
| 335 | dhwbi a3, 0
|
| 336 | |
| 337 | 1:
|
| 338 | memw
|
| 339 | l32i a2, a3, 0
|
| 340 | dhi a3, 0
|
| 341 | bne a2, a0, 1b
|
| 342 |
|
| 343 | /*
|
| 344 | * Initialize WB, WS, and clear PS.EXCM (to allow loop instructions).
|
| 345 | * Set Interrupt Level just below XCHAL_DEBUGLEVEL to allow
|
| 346 | * xt-gdb to single step via DEBUG exceptions received directly
|
| 347 | * by ocd.
|
| 348 | */
|
| 349 | movi a1, 1
|
| 350 | movi a0, 0
|
| 351 | wsr a1, windowstart
|
| 352 | wsr a0, windowbase
|
| 353 | rsync
|
| 354 |
|
| 355 | movi a1, LOCKLEVEL
|
| 356 | wsr a1, ps
|
| 357 | rsync
|
| 358 |
|
| 359 | j _startup
|
| 360 |
|
| 361 | ENDPROC(cpu_restart)
|
| 362 |
|
| 363 | |
| 364 |
|
| 365 | /*
|
| 366 | * DATA section
|
| 367 | */
|
| 368 |
|
| 369 | __REFDATA
|
| 370 | .align 4
|
| 371 | ENTRY(start_info)
|
| 372 | .long init_thread_union + KERNEL_STACK_SIZE
|
| 373 |
|
| 374 | /*
|
| 375 | * BSS section
|
| 376 | */
|
| 377 |
|
| 378 | __PAGE_ALIGNED_BSS
|
| 379 | |
| 380 | ENTRY(swapper_pg_dir)
|
| 381 | .fill PAGE_SIZE, 1, 0
|
| 382 | END(swapper_pg_dir)
|
| 383 | |