1 /* $NetBSD: armv6_start.S,v 1.41 2025/10/09 06:15:16 skrll Exp $ */ 2 3 /*- 4 * Copyright (c) 2012, 2017, 2018 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Matt Thomas of 3am Software Foundry and Nick Hudson. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "opt_arm_debug.h" 33 #include "opt_console.h" 34 #include "opt_cpuoptions.h" 35 #include "opt_cputypes.h" 36 #include "opt_fdt.h" 37 #include "opt_kasan.h" 38 #include "opt_multiprocessor.h" 39 40 #include <sys/cdefs.h> 41 42 #include <arm/asm.h> 43 #include <arm/armreg.h> 44 #include <arm/locore.h> 45 46 #include "assym.h" 47 48 #if defined(CONSADDR) && defined(CONADDR) 49 #error Only one of CONSADDR and CONADDR should be defined 50 #endif 51 52 #if defined(CONSADDR) 53 #define START_CONSADDR CONSADDR 54 #endif 55 #if defined(CONADDR) 56 #define START_CONSADDR CONADDR 57 #endif 58 59 #if defined(VERBOSE_INIT_ARM) 60 #define XPUTC(n) mov r0, n; bl uartputc 61 #define VPRINTF(string) bl generic_vprint; .asciz string; .align 2 62 #define VPRINTX(regno) mov r0, regno; bl generic_printx 63 #else 64 #define XPUTC(c) /* nothing */ 65 #define VPRINTF(string) /* nothing */ 66 #define VPRINTX(regno) /* nothing */ 67 #endif 68 69 #if defined(FDT) 70 #define MD_CPU_HATCH arm_fdt_cpu_hatch 71 #endif 72 73 #if defined(_ARM_ARCH_6) 74 #define L1_S_KRW_NOCACHE (L1_S_PROTO | L1_S_AP_KRW | L1_S_NOCACHE_armv6n) 75 #else 76 #define L1_S_KRW_NOCACHE (L1_S_PROTO | L1_S_AP_KRW | L1_S_NOCACHE_generic) 77 #endif 78 79 /* 80 * A generic kernel start routine. 81 * 82 * At this point, this code has been loaded into SDRAM and the MMU should be off 83 * with data caches disabled. 84 * 85 * linux image type should be used in uboot images to ensure this is the case. 86 */ 87 88 // Use callee saved registers 89 R_L1TABLE .req r4 90 R_VA .req r5 91 R_PA .req r6 92 R_NSEC .req r7 93 R_ATTR .req r8 94 R_DEVATTR .req r9 95 96 R_TMP1 .req r8 97 R_TMP2 .req r9 98 R_VTOPDIFF .req r10 99 R_FDTADDR .req r11 100 R_INDEX .req r11 101 102 .text 103 104 ENTRY_NP(generic_start) 105 106 #if defined(__ARMEB__) 107 /* Make sure sctlr.u = 1 when cpsr.e = 1. */ 108 mrc p15, 0, R_TMP1, c1, c0, 0 109 orr R_TMP1, R_TMP1, #CPU_CONTROL_UNAL_ENABLE 110 mcr p15, 0, R_TMP1, c1, c0, 0 111 112 setend be /* force big endian */ 113 #endif 114 115 /* disable IRQs/FIQs. */ 116 INTERRUPT_DISABLE(r0) 117 118 adr R_TMP1, generic_start 119 ldr R_VTOPDIFF, =generic_start 120 sub R_VTOPDIFF, R_VTOPDIFF, R_TMP1 121 122 ldr R_TMP1, =start_stacks_top 123 sub sp, R_TMP1, R_VTOPDIFF 124 125 mov r4, r0 126 mov r5, r1 127 mov r6, r2 128 mov r7, r3 129 130 // We can now call functions 131 132 VPRINTF("\n\rpc : ") 133 VPRINTX(pc) 134 135 VPRINTF("\n\roff : ") 136 VPRINTX(R_VTOPDIFF) 137 138 VPRINTF("\n\rsp : ") 139 VPRINTX(sp) 140 141 ldr R_TMP1, =(L1_S_SIZE - 1) 142 ands R_TMP2, R_VTOPDIFF, R_TMP1 143 bne arm_bad_vtopdiff 144 145 #if defined(FDTBASE) 146 /* 147 * ARM boot protocol has FDT address in r2 which is now in r6 148 */ 149 VPRINTF("\n\rfdt : ") 150 mov R_FDTADDR, r6 // Save fdt_addr_r for mapping later 151 152 VPRINTX(r6) 153 #endif 154 155 #if defined(VERBOSE_INIT_ARM) 156 VPRINTF("\n\rmidr : ") 157 mrc p15, 0, r0, c0, c0, 0 // MIDR 158 VPRINTX(r0) 159 VPRINTF("\n\rrevidr: ") 160 mrc p15, 0, r0, c0, c0, 6 // REVIDR 161 VPRINTX(r0) 162 VPRINTF("\n\rmpidr : ") 163 mrc p15, 0, r0, c0, c0, 5 // MPIDR 164 VPRINTX(r0) 165 VPRINTF("\n\rttb0 : ") 166 mrc p15, 0, r0, c2, c0, 0 // TTBR0 read 167 VPRINTX(r0) 168 #if defined(_ARM_ARCH_6) 169 VPRINTF("\n\rttb1 : ") 170 mrc p15, 0, r0, c2, c0, 1 // TTBR1 read 171 VPRINTX(r0) 172 VPRINTF("\n\rttcr : ") 173 mrc p15, 0, r0, c2, c0, 2 // TTBCR read 174 VPRINTX(r0) 175 #endif 176 VPRINTF("\n\r") 177 #endif 178 179 #if defined(_ARM_ARCH_7) 180 b generic_startv7 181 #elif defined(_ARM_ARCH_6) 182 b generic_startv6 183 #elif defined(_ARM_ARCH_5) 184 b generic_startv5 185 #else 186 #error Unsupported CPU 187 #endif 188 arm_bad_vtopdiff: 189 VPRINTF("\n\rpanic: vtop not L1_FRAME aligned (") 190 VPRINTX(R_VTOPDIFF) 191 VPRINTF(")\n\r") 192 1: b 1b 193 ASEND(generic_start) 194 195 /* 196 * Save the u-boot arguments (including FDT address) and the virtual to physical 197 * offset. 198 * 199 * Uses the following callee saved registers: 200 * 201 * r8 (R_TMP1), r9 (R_TMP2) 202 */ 203 generic_savevars: 204 mov R_TMP1, lr 205 /* 206 * Store virtual to physical address difference 207 */ 208 ldr R_TMP2, =kern_vtopdiff 209 sub R_TMP2, R_TMP2, R_VTOPDIFF 210 str R_VTOPDIFF, [R_TMP2] 211 212 /* 213 * store uboot arguments to uboot_args[4] 214 */ 215 ldr R_TMP2, =uboot_args 216 sub R_TMP2, R_VTOPDIFF 217 218 VPRINTF("\n\ruboot : ") 219 VPRINTX(R_TMP2) 220 str r4, [R_TMP2, #(4*0)] 221 str r5, [R_TMP2, #(4*1)] 222 str r6, [R_TMP2, #(4*2)] 223 str r7, [R_TMP2, #(4*3)] 224 225 #if defined(FDTBASE) 226 /* 227 * ARM boot protocol has FDT address in r2 which is now in r6 228 */ 229 VPRINTF("\n\rfdt : ") 230 ldr R_TMP2, =fdt_addr_r 231 sub R_TMP2, R_VTOPDIFF 232 str r6, [R_TMP2] 233 234 VPRINTX(r6) 235 #endif 236 237 RETr(R_TMP1) 238 239 .ltorg 240 241 /* 242 * Allocate some memory after the kernel image for stacks and 243 * bootstrap L1PT 244 */ 245 .section "_init_memory", "aw", %nobits 246 .p2align INIT_ARM_STACK_SHIFT 247 .global start_stacks_bottom 248 .global start_stacks_top 249 start_stacks_bottom: 250 .space INIT_ARM_TOTAL_STACK 251 start_stacks_top: 252 253 .section "_init_memory", "aw", %nobits 254 .p2align 14 /* 16KiB aligned */ 255 .global ARM_BOOTSTRAP_LxPT 256 ARM_BOOTSTRAP_LxPT: 257 TEMP_L1_TABLE: 258 .space L1_TABLE_SIZE 259 TEMP_L1_TABLE_END: 260 261 .text 262 .align 2 263 264 arm_build_translation_table: 265 push {r0, lr} 266 /* 267 * Initialise the l1pt for identity mapping of the kernel with caches 268 * off. This will be updated further with additional mappings to form 269 * the bootstrap table. 270 */ 271 ldr R_L1TABLE, =TEMP_L1_TABLE 272 sub R_L1TABLE, R_VTOPDIFF 273 274 // PA of kernel rounded down to nearest L1_S boundary 275 adr R_PA, generic_start 276 ldr r0, =(L1_S_SIZE - 1) 277 bic R_PA, R_PA, r0 278 279 // attribute to map kernel 280 ldr R_ATTR, =L1_S_KRW_NOCACHE 281 bl arm_boot_l1pt_init 282 283 /* 284 * Set up a preliminary mapping in the MMU to allow us to run 285 * at KERNEL_BASE_VIRT (determined from generic_start) with caches off. 286 */ 287 ldr R_L1TABLE, =TEMP_L1_TABLE 288 sub R_L1TABLE, R_VTOPDIFF 289 290 // Calculate kernel size plus 1M to grow into 291 ldr r0, =generic_start // kernel start VA 292 ldr r1, =TEMP_L1_TABLE_END // kernel end VA 293 add r1, #L1_S_SIZE // Make sure we have 1M to grow into 294 295 ldr r2, =(L1_S_SIZE - 1) 296 297 bic r0, r2 // trunc kernel start to 1M boundary 298 add r1, r2 299 bic r1, r2 // round kernel end to 1M boundary 300 301 sub r1, r0 // kernel size plus 1M to grow into 302 mov R_NSEC, r1, lsr #(L1_S_SHIFT) 303 304 ldr R_VA, =generic_start // VA of kernel 305 bic R_VA, r2 // ...rounded down to L1_S boundary 306 adr R_PA, generic_start // PA of kernel 307 bic R_PA, r2 // ...rounded down to L1_S boundary 308 309 // attribute to map kernel 310 ldr R_ATTR, =L1_S_KRW_NOCACHE 311 bl arm_boot_l1pt_entry 312 313 #if defined(FDTBASE) 314 VPRINTF("\n\rDTB") 315 316 /* 317 * Add DTB identity mapping (1MB) from originally r2 (but saved in 318 * R_FDTADDR) 319 */ 320 ldr r0, =(L1_S_SIZE - 1) /* align DTB PA to 1M */ 321 bic R_VA, R_FDTADDR, r0 322 mov R_PA, R_VA 323 mov R_NSEC, #1 /* 1MB mapping */ 324 325 ldr R_L1TABLE, =TEMP_L1_TABLE 326 sub R_L1TABLE, R_VTOPDIFF 327 bl arm_boot_l1pt_entry 328 #endif 329 330 #if defined(START_CONSADDR) 331 /* If START_CONSADDR exists add its identity mapping (1MB) */ 332 VPRINTF("\n\rCONSADDR") 333 ldr r0, =(L1_S_SIZE - 1) /* align DTB PA to 1M */ 334 ldr R_VA, =START_CONSADDR 335 bic R_VA, R_VA, r0 336 mov R_PA, R_VA 337 mov R_NSEC, #1 338 339 ldr R_ATTR, =(L1_S_PROTO | L1_S_AP_KRW) 340 orr R_ATTR, R_DEVATTR 341 342 ldr R_L1TABLE, =TEMP_L1_TABLE 343 sub R_L1TABLE, R_VTOPDIFF 344 bl arm_boot_l1pt_entry 345 #endif 346 347 XPUTC(#'M') 348 349 pop {r0, pc} 350 351 .ltorg 352 353 /* 354 * Set up a preliminary mapping in the MMU to allow us to run at 355 * KERNEL_BASE_VIRT (determined from generic_start) 356 * 357 * On Entry 358 * 359 * R_L1TABLE is the PA of the temporary L1PT 360 * R_ATTR is the attribute bits to set for each section mapping 361 * 362 * No R_VA/R_PA/R_NSEC needed here as we use 'generic_start' and 363 * 'TEMP_L1_TABLE_END' to calculate the initial direct VA:PA mapping 364 */ 365 366 /* We push r0 to maintain stack alignment only */ 367 arm_boot_l1pt_init: 368 push {r0, lr} 369 370 // Start address to clear memory. 371 mov r0, R_L1TABLE 372 373 // Zero the entire table so all virtual addresses are invalid. 374 add r1, r0, #L1_TABLE_SIZE // Ending address 375 mov r2, #0 376 mov r3, #0 377 1: stmia r0!, {r2-r3} 378 stmia r0!, {r2-r3} // 16 bytes per loop 379 cmp r0, r1 380 blt 1b 381 382 // Calculate the size of the kernel in L1_S_SIZE sections 383 ldr r0, =generic_start 384 ldr r1, =TEMP_L1_TABLE_END 385 386 ldr r2, =(L1_S_SIZE - 1) 387 388 bic r0, r2 // trunc kernel start to 1M boundary 389 add r1, r2 390 bic r1, r2 // round kernel end to 1M boundary 391 392 sub r1, r0 // kernel size plus 1M to grow into 393 mov R_NSEC, r1, lsr #(L1_S_SHIFT) 394 395 // identity mapping for size of kernel 396 adr R_VA, generic_start 397 bic R_VA, r2 398 mov R_PA, R_VA 399 400 pop {r0, lr} 401 /* Fallthrough */ 402 403 // We push r0 to maintain stack alignment only 404 arm_boot_l1pt_entry: 405 push {r0, lr} 406 407 VPRINTF("\n\r") 408 VPRINTX(R_L1TABLE) 409 410 VPRINTF(" va:") 411 VPRINTX(R_VA) 412 413 VPRINTF(" pa:") 414 VPRINTX(R_PA) 415 416 VPRINTF(" nsec:") 417 VPRINTX(R_NSEC) 418 419 VPRINTF(" attr:") 420 VPRINTX(R_ATTR) 421 422 VPRINTF("\n\r") 423 lsr R_VA, R_VA, #L1_S_SHIFT 424 orr R_PA, R_ATTR 425 426 2: 427 VPRINTX(R_L1TABLE) 428 XPUTC('[') 429 VPRINTX(R_VA) 430 XPUTC(']') 431 XPUTC('=') 432 VPRINTX(R_PA) 433 434 ldr r0, [R_L1TABLE, R_VA, lsl #2] 435 cmp r0, #0 436 cmpne r0, R_PA 437 bne arm_boot_overlap 438 439 str R_PA, [R_L1TABLE, R_VA, lsl #2] 440 add R_VA, R_VA, #1 441 add R_PA, R_PA, #(L1_S_SIZE) 442 443 VPRINTF("\n\r") 444 445 subs R_NSEC, R_NSEC, #1 446 bhi 2b 447 448 pop {r0, pc} 449 450 arm_boot_overlap: 451 VPRINTF("\n\rpanic: overlapping mappings\n\r") 452 3: 453 b 3b 454 455 #if defined(_ARM_ARCH_7) 456 generic_startv7: 457 458 .arch armv7a 459 .arch_extension sec 460 .arch_extension virt 461 462 VPRINTF("v7 : ") 463 464 bl armv7_init 465 bl generic_savevars 466 467 mov R_DEVATTR, #L1_S_V6_XN 468 bl arm_build_translation_table 469 470 /* 471 * Turn on the MMU. Return to virtual address space. 472 */ 473 movw r0, #:lower16:TEMP_L1_TABLE 474 movt r0, #:upper16:TEMP_L1_TABLE 475 sub r0, R_VTOPDIFF 476 477 // Return to virtual address after the call to armv7_mmuinit 478 movw lr, #:lower16:generic_vstartv7 479 movt lr, #:upper16:generic_vstartv7 480 b armv7_mmuinit 481 482 generic_vstartv7: 483 // Stack to KVA address 484 add sp, sp, R_VTOPDIFF 485 486 VPRINTF("virtual\n\r") 487 488 VPRINTF("prrr : ") 489 mrc p15, 0, r0, c10, c2, 0 // Primary Region Remap Register (PRRR) 490 VPRINTX(r0) 491 VPRINTF("\n\rnmrr : ") 492 mrc p15, 0, r0, c10, c2, 1 // Normal Memory Remap Register (NMRR) 493 VPRINTX(r0) 494 VPRINTF("\n\r") 495 496 #if defined(KASAN) 497 ldr r0, =start_stacks_bottom 498 bl _C_LABEL(kasan_early_init) 499 500 VPRINTF("kasan\n\r") 501 #endif 502 503 /* r0 = &cpu_info_store[0] */ 504 movw r0, #:lower16:cpu_info_store 505 movt r0, #:upper16:cpu_info_store 506 507 mrc p15, 0, r1, c0, c0, 0 // MIDR get 508 str r1, [r0, #CI_MIDR] 509 mrc p15, 0, r1, c0, c0, 5 // MPIDR get 510 str r1, [r0, #CI_MPIDR] 511 512 bl arm_cpu_topology_set 513 514 VPRINTF("go\n\r") 515 516 /* 517 * Jump to start in locore.S, which in turn will call initarm and main. 518 */ 519 b start 520 521 /* NOTREACHED */ 522 .ltorg 523 #elif defined(_ARM_ARCH_6) 524 generic_startv6: 525 VPRINTF("v6 : ") 526 527 bl armv6_init 528 bl generic_savevars 529 530 #if defined(ARM_MMU_EXTENDED) 531 mov R_DEVATTR, #L1_S_V6_XN 532 #else 533 mov R_DEVATTR, #0 534 #endif 535 bl arm_build_translation_table 536 537 XPUTC(#'E') 538 539 /* 540 * Turn on the MMU. Return to new enabled address space. 541 */ 542 ldr r0, =TEMP_L1_TABLE 543 sub r0, R_VTOPDIFF 544 545 ldr lr, =generic_vstartv6 546 b armv6_mmuinit 547 548 generic_vstartv6: 549 // Stack to KVA address 550 add sp, sp, R_VTOPDIFF 551 552 VPRINTF("virtual\n\r") 553 554 #if defined(KASAN) 555 ldr r0, =start_stacks_bottom 556 bl _C_LABEL(kasan_early_init) 557 558 VPRINTF("kasan\n\r") 559 #endif 560 561 VPRINTF("go\n\r") 562 563 /* 564 * Jump to start in locore.S, which in turn will call initarm and main. 565 */ 566 b start 567 568 /* NOTREACHED */ 569 .ltorg 570 571 #elif defined(_ARM_ARCH_5) 572 573 generic_startv5: 574 VPRINTF("v5 : ") 575 576 bl armv5_init 577 bl generic_savevars 578 579 mov R_DEVATTR, #0 580 bl arm_build_translation_table 581 582 XPUTC(#'E') 583 584 /* 585 * Turn on the MMU. Return to new enabled address space. 586 */ 587 ldr r0, =TEMP_L1_TABLE 588 sub r0, R_VTOPDIFF 589 590 ldr lr, =generic_vstartv5 591 b armv5_mmuinit 592 593 generic_vstartv5: 594 // convert stack back to virtual address 595 add sp, sp, R_VTOPDIFF 596 597 VPRINTF("virtual\n\r") 598 599 #if defined(KASAN) 600 ldr r0, =start_stacks_bottom 601 bl _C_LABEL(kasan_early_init) 602 603 VPRINTF("kasan\n\r") 604 #endif 605 606 VPRINTF("rgo\n\r") 607 608 //Jump to start in locore.S, which in turn will call initarm and main. 609 b start 610 611 .ltorg // not reached 612 #endif 613 614 #if defined(_ARM_ARCH_7) 615 616 // 617 // SCTLR register initialization values 618 // 619 #if defined(__ARMEL__) 620 #define CPU_CONTROL_EX_BEND_SET 0 621 #else 622 #define CPU_CONTROL_EX_BEND_SET CPU_CONTROL_EX_BEND 623 #endif 624 625 #if defined(ARM32_DISABLE_ALIGNMENT_FAULTS) 626 #define CPU_CONTROL_AFLT_ENABLE_CLR CPU_CONTROL_AFLT_ENABLE 627 #define CPU_CONTROL_AFLT_ENABLE_SET 0 628 #else 629 #define CPU_CONTROL_AFLT_ENABLE_CLR 0 630 #define CPU_CONTROL_AFLT_ENABLE_SET CPU_CONTROL_AFLT_ENABLE 631 #endif 632 633 #if defined(ARM_MMU_EXTENDED) 634 #define CPU_CONTROL_XP_ENABLE_CLR 0 635 #define CPU_CONTROL_XP_ENABLE_SET CPU_CONTROL_XP_ENABLE 636 #else 637 #define CPU_CONTROL_XP_ENABLE_CLR CPU_CONTROL_XP_ENABLE 638 #define CPU_CONTROL_XP_ENABLE_SET 0 639 #endif 640 641 /* SWP is only usable on uni-processor ARMv7 systems. */ 642 #ifdef MULTIPROCESSOR 643 #define CPU_CONTROL_XP_SWP_ENABLE 0 644 #else 645 #define CPU_CONTROL_XP_SWP_ENABLE CPU_CONTROL_SWP_ENABLE 646 #endif 647 648 // bits to set in the Control Register 649 // 650 #define CPU_CONTROL_SET ( \ 651 CPU_CONTROL_MMU_ENABLE | \ 652 CPU_CONTROL_UNAL_ENABLE | \ 653 CPU_CONTROL_EX_BEND_SET | \ 654 CPU_CONTROL_AFLT_ENABLE_SET | \ 655 CPU_CONTROL_XP_ENABLE_SET | \ 656 0) 657 658 // bits to clear in the Control Register 659 // 660 #define CPU_CONTROL_CLR ( \ 661 CPU_CONTROL_AFLT_ENABLE_CLR | \ 662 CPU_CONTROL_XP_ENABLE_CLR | \ 663 0) 664 665 /* 666 * Perform the initialization of the an ARMv7 core required by NetBSD. 667 * 668 * Uses the following callee saved registers: 669 * 670 * r8 (R_TMP1), r9 (R_TMP2) 671 */ 672 armv7_init: 673 674 .arch armv7a 675 .arch_extension sec 676 .arch_extension virt 677 678 mov R_TMP1, lr 679 mov R_TMP2, sp 680 681 /* 682 * Leave HYP mode and move into supervisor mode with IRQs/FIQs 683 * disabled. 684 */ 685 mrs r0, cpsr 686 and r0, r0, #(PSR_MODE) /* Mode is in the low 5 bits of CPSR */ 687 teq r0, #(PSR_HYP32_MODE) /* Hyp Mode? */ 688 bne 1f 689 690 XPUTC('h') 691 692 mov sp, #0 693 694 /* Set CNTVOFF to 0 */ 695 mov r1, #0 696 mcrr p15, 4, r1, r1, c14 697 698 /* Ensure that IRQ, and FIQ will be disabled after eret */ 699 mrs r0, cpsr 700 bic r0, r0, #(PSR_MODE) 701 orr r0, r0, #(PSR_SVC32_MODE) 702 orr r0, r0, #(I32_bit | F32_bit) 703 msr spsr_cxsf, r0 704 /* Exit hypervisor mode */ 705 adr lr, 2f 706 msr elr_hyp, lr 707 eret 708 709 1: 710 cpsid if, #PSR_SVC32_MODE // SVC32 with no interrupts 711 712 2: 713 mov r0, #0 714 msr spsr_sxc, r0 // set SPSR[23:8] to known value 715 716 mov sp, R_TMP2 717 718 XPUTC('A') 719 720 mrc p15, 0, r0, c1, c0, 0 721 tst r0, #CPU_CONTROL_DC_ENABLE 722 blne armv7_dcache_wbinv_all 723 724 // TeX remap 725 726 #define ARMV7_SCTLR_CLEAR ( \ 727 CPU_CONTROL_IC_ENABLE | \ 728 CPU_CONTROL_DC_ENABLE | \ 729 CPU_CONTROL_MMU_ENABLE | \ 730 CPU_CONTROL_BPRD_ENABLE | \ 731 CPU_CONTROL_TR_ENABLE | \ 732 0) 733 734 #define ARMV7_SCTLR_SET ( \ 735 CPU_CONTROL_UNAL_ENABLE | \ 736 CPU_CONTROL_XP_SWP_ENABLE | \ 737 0) 738 739 mrc p15, 0, r0, c1, c0, 0 740 movw r1, #:lower16:ARMV7_SCTLR_CLEAR 741 movt r1, #:upper16:ARMV7_SCTLR_CLEAR 742 movw r2, #:lower16:ARMV7_SCTLR_SET 743 movt r2, #:upper16:ARMV7_SCTLR_SET 744 745 mov R_TMP2, r0 // save for printing 746 bic r0, r0, r1 // disable icache/dcache/mmu 747 orr r0, r0, r2 // enable unaligned access 748 749 mcr p15, 0, r0, c1, c0, 0 // SCTLR write 750 dsb 751 isb 752 753 bl armv7_dcache_inv_all 754 mcr p15, 0, r0, c7, c5, 0 /* ICIALLU */ 755 dsb 756 isb 757 758 #if defined(VERBOSE_INIT_ARM) 759 XPUTC(#'B') 760 761 VPRINTF(" sctlr:") 762 VPRINTX(R_TMP2) 763 VPRINTF("/") 764 mrc p15, 0, r0, c1, c0, 0 765 VPRINTX(r0) 766 VPRINTF(" ") 767 768 XPUTC(#'C') 769 #endif 770 771 bx R_TMP1 // return 772 773 .ltorg 774 775 /* 776 * Transitions the CPU to using the TTB passed in r0. 777 * 778 * Uses the following callee saved registers: 779 * 780 * Callee saved: 781 * r4, r5 782 */ 783 784 armv7_mmuinit: 785 // Because the MMU may already be on do a typical sequence to set 786 // the Translation Table Base(s). 787 mov r4, lr 788 mov r5, r0 // save TTBR 789 790 XPUTC(#'F') 791 dsb // Drain the write buffers. 792 793 XPUTC(#'G') 794 mrc p15, 0, r1, c0, c0, 5 // MPIDR read 795 cmp r1, #0 796 orrlt r5, r5, #TTBR_MPATTR // MP, cachable (Normal WB) 797 orrge r5, r5, #TTBR_UPATTR // Non-MP, cacheable, normal WB 798 799 XPUTC(#'0') 800 mcr p15, 0, r5, c2, c0, 0 // TTBR0 write 801 802 #if defined(ARM_MMU_EXTENDED) 803 // When using split TTBRs, we need to set both since the physical 804 // addresses we were/are using might be in either. 805 XPUTC(#'1') 806 mcr p15, 0, r5, c2, c0, 1 // TTBR1 write 807 #endif 808 809 XPUTC(#'H') 810 #if defined(ARM_MMU_EXTENDED) 811 XPUTC(#'1') 812 mov r1, #TTBCR_S_N_1 // make sure TTBCR_S_N is 1 813 #else 814 XPUTC(#'0') 815 mov r1, #0 // make sure TTBCR is 0 816 #endif 817 mcr p15, 0, r1, c2, c0, 2 // TTBCR write 818 819 XPUTC(#'J') 820 mov r1, #0 // get KERNEL_PID 821 mcr p15, 0, r1, c13, c0, 1 // CONTEXTIDR write 822 823 isb 824 825 // Set the Domain Access register. Very important! 826 XPUTC(#'K') 827 mov r1, #DOMAIN_DEFAULT 828 mcr p15, 0, r1, c3, c0, 0 // DACR write 829 830 #if 0 831 832 /* 833 * Set TEX remap registers 834 * - All is set to uncacheable memory 835 */ 836 ldr r0, =0xAAAAA 837 mcr CP15_PRRR(r0) 838 mov r0, #0 839 mcr CP15_NMRR(r0) 840 #endif 841 842 XPUTC(#'I') 843 mov r1, #0 844 mcr p15, 0, r1, c8, c7, 0 // TLBIALL (just this core) 845 dsb 846 isb 847 848 // 849 // Enable the MMU, etc. 850 // 851 XPUTC(#'L') 852 XPUTC(#'\n') 853 XPUTC(#'\r') 854 mrc p15, 0, r1, c1, c0, 0 // SCTLR read 855 856 movw r3, #:lower16:CPU_CONTROL_SET 857 movt r3, #:upper16:CPU_CONTROL_SET 858 movw r2, #:lower16:CPU_CONTROL_CLR 859 movt r2, #:upper16:CPU_CONTROL_CLR 860 orr r0, r1, r3 861 bic r0, r0, r2 862 863 mcr p15, 0, r0, c1, c0, 0 /* SCTLR write */ 864 865 dsb 866 isb 867 868 mcr p15, 0, r0, c8, c7, 0 /* TLBIALL - Flush TLB */ 869 mcr p15, 0, r0, c7, c5, 6 /* BPIALL - Branch predictor invalidate all */ 870 dsb 871 isb 872 873 VPRINTF("MMU\n\r") 874 bx r4 // return 875 876 .p2align 2 877 878 .text 879 880 ENTRY_NP(cpu_mpstart) 881 #ifndef MULTIPROCESSOR 882 // 883 // If not MULTIPROCESSOR, drop CPU into power saving state. 884 // 885 3: wfi 886 b 3b 887 #else 888 #if defined(__ARMEB__) 889 setend be // switch to BE now 890 #endif 891 892 /* disable IRQs/FIQs. */ 893 cpsid if 894 895 adr R_TMP2, cpu_mpstart 896 ldr R_VTOPDIFF, =cpu_mpstart 897 sub R_VTOPDIFF, R_VTOPDIFF, R_TMP2 898 899 mrc p15, 0, r4, c0, c0, 5 // MPIDR get 900 and r4, #(MPIDR_AFF2|MPIDR_AFF1|MPIDR_AFF0) 901 902 mov r0, #0 903 ldr r1, =cpu_mpidr 904 sub r1, R_VTOPDIFF 905 1: 906 ldr r2, [r1, r0, lsl #2] // r2 = cpu_mpidr[r0] 907 cmp r2, r4 908 beq 2f // found our mpidr 909 910 add r0, #1 911 cmp r0, #MAXCPUS 912 bne 1b 913 914 // Not found our mpidr in the list - use Aff0 for cpuindex 915 and r0, r4, #7 916 2: 917 mov R_INDEX, r0 // save cpu_index for later 918 919 ldr R_TMP1, =start_stacks_top 920 sub sp, R_TMP1, R_VTOPDIFF 921 922 mov r5, R_INDEX 923 lsl r5, #INIT_ARM_STACK_SHIFT 924 sub sp, sp, r5 925 926 #if defined(VERBOSE_INIT_ARM) 927 VPRINTF("\n\rmidr : ") 928 mrc p15, 0, r0, c0, c0, 0 // MIDR 929 VPRINTX(r0) 930 VPRINTF("\n\rrevidr: ") 931 mrc p15, 0, r0, c0, c0, 6 // REVIDR 932 VPRINTX(r0) 933 VPRINTF("\n\rmpidr : ") 934 mrc p15, 0, r0, c0, c0, 5 // MPIDR 935 VPRINTX(r0) 936 #endif 937 VPRINTF("\n\rindex : ") 938 VPRINTX(R_INDEX) 939 VPRINTF("\n\rsp : ") 940 VPRINTX(sp) 941 XPUTC('\n') 942 XPUTC('\r') 943 944 // disables and clears caches 945 bl armv7_init 946 947 movw r0, #:lower16:TEMP_L1_TABLE 948 movt r0, #:upper16:TEMP_L1_TABLE 949 sub r0, R_VTOPDIFF 950 951 movw lr, #:lower16:armv7_mpcontinuation 952 movt lr, #:upper16:armv7_mpcontinuation 953 b armv7_mmuinit 954 ASEND(cpu_mpstart) 955 956 /* 957 * Now running with real kernel VA via bootstrap tables 958 */ 959 armv7_mpcontinuation: 960 // Stack to KVA address 961 add sp, sp, R_VTOPDIFF 962 963 VPRINTF("virtual\n\r") 964 965 // index into cpu_mpidr[] or cpu_number if not found 966 mov r0, R_INDEX 967 bl cpu_init_secondary_processor 968 969 /* 970 * Wait for cpu_boot_secondary_processors 971 */ 972 973 /* r6 = &arm_cpu_mbox[0] */ 974 movw r6, #:lower16:arm_cpu_mbox 975 movt r6, #:upper16:arm_cpu_mbox 976 977 mov r5, #1 // bitmask... 978 lsl r5, R_INDEX // ... for our cpu 979 980 /* wait for the mailbox start bit to become true */ 981 1: ldr r2, [r6] // load mbox 982 dmb // make it a load-acquire 983 tst r2, r5 // is our bit set? 984 wfeeq // no, back to waiting 985 beq 1b // no, and try again 986 987 movw r0, #:lower16:cpu_info 988 movt r0, #:upper16:cpu_info // get pointer to cpu_info 989 ldr r5, [r0, R_INDEX, lsl #2] // load our cpu_info 990 ldr r6, [r5, #CI_IDLELWP] // get the idlelwp 991 ldr r7, [r6, #L_PCB] // now get its pcb 992 ldr sp, [r7, #PCB_KSP] // finally, we can load our SP 993 #if defined(TPIDRPRW_IS_CURCPU) 994 mcr p15, 0, r5, c13, c0, 4 // squirrel away curcpu() 995 #elif defined(TPIDRPRW_IS_CURLWP) 996 mcr p15, 0, r6, c13, c0, 4 // squirrel away curlwp() 997 #else 998 #error either TPIDRPRW_IS_CURCPU or TPIDRPRW_IS_CURLWP must be defined 999 #endif 1000 /* 1001 * No membar needed because we're not switching from a 1002 * previous lwp, and the idle lwp we're switching to can't be 1003 * holding locks already; see cpu_switchto. 1004 */ 1005 str r6, [r5, #CI_CURLWP] // and note we are running on it 1006 1007 mov r0, r5 // pass cpu_info 1008 mov r1, R_INDEX // pass cpu_index 1009 movw r2, #:lower16:MD_CPU_HATCH // pass md_cpu_hatch 1010 movt r2, #:upper16:MD_CPU_HATCH // pass md_cpu_hatch 1011 bl _C_LABEL(cpu_hatch) 1012 b _C_LABEL(idle_loop) // never to return 1013 ASEND(armv7_mpcontinuation) 1014 #endif // MULTIPROCESSOR 1015 1016 #elif defined(_ARM_ARCH_6) 1017 1018 ENTRY_NP(armv6_init) 1019 /* 1020 * Workaround Erratum 411920 1021 * 1022 * - value of arg 'reg' Should Be Zero 1023 */ 1024 #define Invalidate_I_cache(reg) \ 1025 .p2align 5; \ 1026 mcr p15, 0, reg, c7, c5, 0; /* Invalidate Entire I cache */ \ 1027 mcr p15, 0, reg, c7, c5, 0; /* Invalidate Entire I cache */ \ 1028 mcr p15, 0, reg, c7, c5, 0; /* Invalidate Entire I cache */ \ 1029 mcr p15, 0, reg, c7, c5, 0; /* Invalidate Entire I cache */ \ 1030 nop; \ 1031 nop; \ 1032 nop; \ 1033 nop; \ 1034 nop; \ 1035 nop; \ 1036 nop; \ 1037 nop; \ 1038 nop; \ 1039 nop; \ 1040 nop; 1041 1042 mov R_TMP1, lr 1043 mov r0, #0 /* SBZ */ 1044 Invalidate_I_cache(r0) 1045 1046 mcr p15, 0, r0, c7, c14, 0 /* Clean and Invalidate Entire Data Cache */ 1047 1048 ldr r2, =(CPU_CONTROL_IC_ENABLE|CPU_CONTROL_DC_ENABLE) 1049 /* Disable I+D caches */ 1050 mrc p15, 0, r1, c1, c0, 0 /* " " " */ 1051 mov R_TMP2, r1 1052 bic r1, r1, r2 /* " " " */ 1053 mcr p15, 0, r1, c1, c0, 0 /* " " " */ 1054 1055 mcr p15, 0, r0, c7, c10, 4 /* Drain the write buffers. */ 1056 1057 #if defined(VERBOSE_INIT_ARM) 1058 XPUTC(#'B') 1059 1060 VPRINTF(" sctlr:") 1061 VPRINTX(R_TMP2) 1062 VPRINTF("/") 1063 mrc p15, 0, r0, c1, c0, 0 1064 VPRINTX(r0) 1065 VPRINTF(" ") 1066 1067 XPUTC(#'C') 1068 #endif 1069 1070 bx R_TMP1 1071 1072 .ltorg 1073 1074 armv6_mmuinit: 1075 mov r4, lr 1076 mov r5, r0 1077 1078 XPUTC(#'0') 1079 mcr p15, 0, r5, c2, c0, 0 // TTBR0 write 1080 1081 #if defined(ARM_MMU_EXTENDED) 1082 // When using split TTBRs, we need to set both since the physical 1083 // addresses we were/are using might be in either. 1084 XPUTC(#'1') 1085 mcr p15, 0, r5, c2, c0, 1 /* TTBR1 write */ 1086 #endif 1087 1088 XPUTC(#'H') 1089 #if defined(ARM_MMU_EXTENDED) 1090 XPUTC(#'1') 1091 mov r1, #TTBCR_S_N_1 /* make sure TTBCR_S_N is 1 */ 1092 #else 1093 XPUTC(#'0') 1094 mov r1, #0 /* make sure TTBCR is 0 */ 1095 #endif 1096 mcr p15, 0, r1, c2, c0, 2 /* TTBCR write */ 1097 1098 XPUTC(#'I') 1099 1100 mov r0, #0 1101 mcr p15, 0, r0, c8, c7, 0 /* Invalidate TLBs */ 1102 1103 XPUTC(#'K') 1104 /* Set the Domain Access register. Very important! */ 1105 mov r0, #DOMAIN_DEFAULT 1106 mcr p15, 0, r0, c3, c0, 0 1107 1108 /* 1109 * Enable the MMU, etc. 1110 */ 1111 1112 #if defined(VERBOSE_INIT_ARM) 1113 VPRINTF(" sctlr:") 1114 mrc p15, 0, r0, c1, c0, 0 1115 VPRINTX(r0) 1116 VPRINTF("/") 1117 #endif 1118 1119 mrc p15, 0, r0, c1, c0, 0 1120 1121 ldr r1, Lcontrol_wax 1122 and r0, r0, r1 1123 ldr r1, Lcontrol_clr 1124 bic r0, r0, r1 1125 ldr r1, Lcontrol_set 1126 orr r0, r0, r1 1127 1128 mov r6, r0 1129 VPRINTX(r6) 1130 VPRINTF(" ") 1131 1132 .align 5 1133 /* turn mmu on! */ 1134 mov r0, r6 1135 mcr p15, 0, r0, c1, c0, 0 1136 1137 /* 1138 * Ensure that the coprocessor has finished turning on the MMU. 1139 */ 1140 mrc p15, 0, r0, c0, c0, 0 /* Read an arbitrary value. */ 1141 mov r0, r0 /* Stall until read completes. */ 1142 1143 nop 1144 nop 1145 nop 1146 nop 1147 nop 1148 1149 mov pc, r4 1150 1151 .ltorg 1152 1153 /* bits to set in the Control Register */ 1154 Lcontrol_set: 1155 #if defined(ARM_MMU_EXTENDED) 1156 #define CPU_CONTROL_EXTRA CPU_CONTROL_XP_ENABLE 1157 #else 1158 #define CPU_CONTROL_EXTRA CPU_CONTROL_SYST_ENABLE 1159 #endif 1160 #if defined(__ARMEL__) 1161 #define CPU_CONTROL_EX_BEND_SET 0 1162 #else 1163 #define CPU_CONTROL_EX_BEND_SET CPU_CONTROL_EX_BEND 1164 #endif 1165 .word CPU_CONTROL_MMU_ENABLE | \ 1166 CPU_CONTROL_WBUF_ENABLE | /* not defined in 1176 (SBO) */ \ 1167 CPU_CONTROL_32BP_ENABLE | /* SBO */ \ 1168 CPU_CONTROL_32BD_ENABLE | /* SBO */ \ 1169 CPU_CONTROL_LABT_ENABLE | /* SBO */ \ 1170 (1 << 16) | /* SBO - Global enable for data tcm */ \ 1171 (1 << 18) | /* SBO - Global enable for insn tcm */ \ 1172 CPU_CONTROL_UNAL_ENABLE | \ 1173 CPU_CONTROL_EXTRA | \ 1174 CPU_CONTROL_EX_BEND_SET 1175 1176 /* bits to clear in the Control Register */ 1177 Lcontrol_clr: 1178 .word 0 1179 1180 /* bits to "write as existing" in the Control Register */ 1181 Lcontrol_wax: 1182 .word (3 << 30) | \ 1183 (1 << 29) | \ 1184 (1 << 28) | \ 1185 (3 << 26) | \ 1186 (3 << 19) | \ 1187 (1 << 17) | \ 1188 (1 << 10) 1189 #elif defined(_ARM_ARCH_5) 1190 armv5_init: 1191 bx lr 1192 1193 .ltorg 1194 1195 armv5_mmu_enable_bits: 1196 .word CPU_CONTROL_MMU_ENABLE | \ 1197 CPU_CONTROL_WBUF_ENABLE | /* should be one */ \ 1198 CPU_CONTROL_32BP_ENABLE | /* should be one */ \ 1199 CPU_CONTROL_32BD_ENABLE | /* should be one */ \ 1200 CPU_CONTROL_LABT_ENABLE | /* should be one */ \ 1201 (1 << 16) | /* should be one */ \ 1202 (1 << 18) /* should be one */ 1203 1204 1205 armv5_mmuinit: 1206 mov r4, lr 1207 mov r5, r0 // contains the vtop-corrected translation table address 1208 1209 /* write translation table base register */ 1210 mcr p15, 0, r5, c2, c0, 0 1211 VPRINTF("\n\rTTBR : ") 1212 VPRINTX(r5) 1213 1214 /* Invalidate TLBs */ 1215 mov r1, #0 1216 mcr p15, 0, r1, c8, c7, 0 1217 1218 /* Set the Domain Access register. Very important! */ 1219 mov r5, #DOMAIN_DEFAULT 1220 mcr p15, 0, r5, c3, c0, 0 1221 VPRINTF("\n\rDACR : ") 1222 VPRINTX(r5) 1223 1224 /* 1225 * Enable the MMU, etc. 1226 */ 1227 1228 VPRINTF("\n\rSCTLR: ") 1229 #if defined(VERBOSE_INIT_ARM) 1230 mrc p15, 0, r5, c1, c0, 0 // read status+control register 1231 VPRINTX(r5) 1232 VPRINTF("/") 1233 #endif 1234 1235 mrc p15, 0, r0, c1, c0, 0 // read control register 1236 mov r5, r0 1237 ldr r1, armv5_mmu_enable_bits 1238 orr r0, r0, r1 // set MMU bits 1239 1240 mov r6, r0 1241 VPRINTX(r6) 1242 1243 mcr p15, 0, r6, c1, c0, 0 // actually enable mmu 1244 nop // wait for mmu to have turned on 1245 nop 1246 nop 1247 1248 VPRINTF("\n\rMMU") 1249 1250 bx r4 // return 1251 #endif 1252 1253 ENTRY_NP(generic_vprint) 1254 push {r4, lr} 1255 1256 mov r4, lr 1257 b 2f 1258 1: 1259 bl uartputc 1260 1261 2: 1262 ldrb r0, [r4], #1 1263 cmp r0, #0 1264 bne 1b 1265 1266 add lr, r4, #3 1267 bic lr, #3 1268 1269 pop {r4} 1270 add sp, sp, #4 1271 mov pc, lr 1272 ASEND(generic_vprint) 1273 1274 ENTRY_NP(generic_prints) 1275 push {r4, lr} 1276 1277 mov r4, r0 1278 1: 1279 ldrb r0, [r4], #1 1280 cmp r0, #0 1281 popeq {r4, pc} 1282 1283 bl uartputc 1284 b 1b 1285 ASEND(generic_prints) 1286 1287 ENTRY_NP(generic_printx) 1288 push {r4, r5, r6, lr} 1289 mov r5, r0 1290 1291 mov r0, #'0' 1292 bl uartputc 1293 mov r0, #'x' 1294 bl uartputc 1295 1296 // Word size in bits 1297 mov r4, #32 1298 1: 1299 sub r4, r4, #4 // nibble shift 1300 lsr r3, r5, r4 // extract ... 1301 and r3, r3, #0xf // ... nibble 1302 1303 cmp r3, #9 1304 add r0, r3, #'0' 1305 addgt r0, r3, #'a' - 10 1306 bl uartputc 1307 1308 cmp r4, #0 1309 bne 1b 1310 pop {r4, r5, r6, pc} 1311 ASEND(generic_printx) 1312