1/* $NetBSD: locore.S,v 1.14 2003/04/20 16:21:40 thorpej Exp $ */ 2 3/*- 4 * Copyright (C) 1994-1997 Mark Brinicombe 5 * Copyright (C) 1994 Brini 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Brini. 19 * 4. The name of Brini may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 */ 34 35#include "assym.s" 36#include <sys/syscall.h> 37#include <machine/asm.h> 38#include <machine/armreg.h> 39#include <machine/pte.h> 40 41__FBSDID("$FreeBSD$"); 42 43/* What size should this really be ? It is only used by initarm() */ 44#define INIT_ARM_STACK_SIZE 2048 45 46#define CPWAIT_BRANCH \ 47 sub pc, pc, #4 48 49#define CPWAIT(tmp) \ 50 mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\ 51 mov tmp, tmp /* wait for it to complete */ ;\ 52 CPWAIT_BRANCH /* branch to next insn */ 53 54/* 55 * This is for kvm_mkdb, and should be the address of the beginning 56 * of the kernel text segment (not necessarily the same as kernbase). 57 */ 58 .text 59 .align 0 60.globl kernbase 61.set kernbase,KERNBASE 62.globl physaddr 63.set physaddr,PHYSADDR 64 65/* 66 * On entry for FreeBSD boot ABI: 67 * r0 - metadata pointer or 0 (boothowto on AT91's boot2) 68 * r1 - if (r0 == 0) then metadata pointer 69 * On entry for Linux boot ABI: 70 * r0 - 0 71 * r1 - machine type (passed as arg2 to initarm) 72 * r2 - Pointer to a tagged list or dtb image (phys addr) (passed as arg1 initarm) 73 * 74 * For both types of boot we gather up the args, put them in a struct arm_boot_params 75 * structure and pass that to initarm. 76 */ 77ENTRY_NP(btext) 78ASENTRY_NP(_start) 79 mov r9, r0 /* 0 or boot mode from boot2 */ 80 mov r8, r1 /* Save Machine type */ 81 mov ip, r2 /* Save meta data */ 82 mov fp, r3 /* Future expantion */ 83 84 /* Make sure interrupts are disabled. */ 85 mrs r7, cpsr 86 orr r7, r7, #(I32_bit|F32_bit) 87 msr cpsr_c, r7 88 89#if defined (FLASHADDR) && defined(LOADERRAMADDR) 90 /* Check if we're running from flash. */ 91 ldr r7, =FLASHADDR 92 /* 93 * If we're running with MMU disabled, test against the 94 * physical address instead. 95 */ 96 mrc p15, 0, r2, c1, c0, 0 97 ands r2, r2, #CPU_CONTROL_MMU_ENABLE 98 ldreq r6, =PHYSADDR 99 ldrne r6, =LOADERRAMADDR 100 cmp r7, r6 101 bls flash_lower 102 cmp r7, pc 103 bhi from_ram 104 b do_copy 105 106flash_lower: 107 cmp r6, pc 108 bls from_ram 109do_copy: 110 ldr r7, =KERNBASE 111 adr r1, _start 112 ldr r0, Lreal_start 113 ldr r2, Lend 114 sub r2, r2, r0 115 sub r0, r0, r7 116 add r0, r0, r6 117 mov r4, r0 118 bl memcpy 119 ldr r0, Lram_offset 120 add pc, r4, r0 121Lram_offset: .word from_ram-_C_LABEL(_start) 122from_ram: 123 nop 124#endif 125 adr r7, Lunmapped 126 bic r7, r7, #0xf0000000 127 orr r7, r7, #PHYSADDR 128 129 130disable_mmu: 131 /* Disable MMU for a while */ 132 mrc p15, 0, r2, c1, c0, 0 133 bic r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\ 134 CPU_CONTROL_WBUF_ENABLE) 135 bic r2, r2, #(CPU_CONTROL_IC_ENABLE) 136 bic r2, r2, #(CPU_CONTROL_BPRD_ENABLE) 137 mcr p15, 0, r2, c1, c0, 0 138 139 nop 140 nop 141 nop 142 mov pc, r7 143Lunmapped: 144#ifdef STARTUP_PAGETABLE_ADDR 145 /* build page table from scratch */ 146 ldr r0, Lstartup_pagetable 147 adr r4, mmu_init_table 148 b 3f 149 1502: 151 str r3, [r0, r2] 152 add r2, r2, #4 153 add r3, r3, #(L1_S_SIZE) 154 adds r1, r1, #-1 155 bhi 2b 1563: 157 ldmia r4!, {r1,r2,r3} /* # of sections, VA, PA|attr */ 158 cmp r1, #0 159 adrne r5, 2b 160 bicne r5, r5, #0xf0000000 161 orrne r5, r5, #PHYSADDR 162 movne pc, r5 163 164 mcr p15, 0, r0, c2, c0, 0 /* Set TTB */ 165 mcr p15, 0, r0, c8, c7, 0 /* Flush TLB */ 166 167 /* Set the Domain Access register. Very important! */ 168 mov r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT) 169 mcr p15, 0, r0, c3, c0, 0 170 /* Enable MMU */ 171 mrc p15, 0, r0, c1, c0, 0 172 orr r0, r0, #CPU_CONTROL_MMU_ENABLE 173 mcr p15, 0, r0, c1, c0, 0 174 nop 175 nop 176 nop 177 CPWAIT(r0) 178 179#endif 180mmu_done: 181 nop 182 adr r1, .Lstart 183 ldmia r1, {r1, r2, sp} /* Set initial stack and */ 184 sub r2, r2, r1 /* get zero init data */ 185 mov r3, #0 186.L1: 187 str r3, [r1], #0x0004 /* get zero init data */ 188 subs r2, r2, #4 189 bgt .L1 190 ldr pc, .Lvirt_done 191 192virt_done: 193 mov r1, #20 /* loader info size is 20 bytes also second arg */ 194 subs sp, sp, r1 /* allocate arm_boot_params struct on stack */ 195 mov r0, sp /* loader info pointer is first arg */ 196 str r1, [r0] /* Store length of loader info */ 197 str r9, [r0, #4] /* Store r0 from boot loader */ 198 str r8, [r0, #8] /* Store r1 from boot loader */ 199 str ip, [r0, #12] /* store r2 from boot loader */ 200 str fp, [r0, #16] /* store r3 from boot loader */ 201 mov fp, #0 /* trace back starts here */ 202 bl _C_LABEL(initarm) /* Off we go */ 203 204 /* init arm will return the new stack pointer. */ 205 mov sp, r0 206 207 bl _C_LABEL(mi_startup) /* call mi_startup()! */ 208 209 adr r0, .Lmainreturned 210 b _C_LABEL(panic) 211 /* NOTREACHED */ 212#ifdef STARTUP_PAGETABLE_ADDR 213#define MMU_INIT(va,pa,n_sec,attr) \ 214 .word n_sec ; \ 215 .word 4*((va)>>L1_S_SHIFT) ; \ 216 .word (pa)|(attr) ; 217 218Lvirtaddr: 219 .word KERNVIRTADDR 220Lphysaddr: 221 .word KERNPHYSADDR 222Lreal_start: 223 .word _start 224Lend: 225 .word _edata 226Lstartup_pagetable: 227 .word STARTUP_PAGETABLE_ADDR 228mmu_init_table: 229 /* fill all table VA==PA */ 230 /* map SDRAM VA==PA, WT cacheable */ 231 MMU_INIT(PHYSADDR, PHYSADDR , 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)) 232 /* map VA 0xc0000000..0xc3ffffff to PA */ 233 MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)) 234 235 .word 0 /* end of table */ 236#endif 237.Lstart: 238 .word _edata 239 .word _end 240 .word svcstk + INIT_ARM_STACK_SIZE 241 242.Lvirt_done: 243 .word virt_done 244.Lmainreturned: 245 .asciz "main() returned" 246 .align 0 247 248 .bss 249svcstk: 250 .space INIT_ARM_STACK_SIZE 251 252 .text 253 .align 0 254 255.Lcpufuncs: 256 .word _C_LABEL(cpufuncs) 257 258ENTRY_NP(cpu_halt) 259 mrs r2, cpsr 260 bic r2, r2, #(PSR_MODE) 261 orr r2, r2, #(PSR_SVC32_MODE) 262 orr r2, r2, #(I32_bit | F32_bit) 263 msr cpsr_all, r2 264 265 ldr r4, .Lcpu_reset_address 266 ldr r4, [r4] 267 268 ldr r0, .Lcpufuncs 269 mov lr, pc 270 ldr pc, [r0, #CF_IDCACHE_WBINV_ALL] 271 mov lr, pc 272 ldr pc, [r0, #CF_L2CACHE_WBINV_ALL] 273 274 /* 275 * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's 276 * necessary. 277 */ 278 279 ldr r1, .Lcpu_reset_needs_v4_MMU_disable 280 ldr r1, [r1] 281 cmp r1, #0 282 mov r2, #0 283 284 /* 285 * MMU & IDC off, 32 bit program & data space 286 * Hurl ourselves into the ROM 287 */ 288 mov r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE) 289 mcr 15, 0, r0, c1, c0, 0 290 mcrne 15, 0, r2, c8, c7, 0 /* nail I+D TLB on ARMv4 and greater */ 291 mov pc, r4 292 293 /* 294 * _cpu_reset_address contains the address to branch to, to complete 295 * the cpu reset after turning the MMU off 296 * This variable is provided by the hardware specific code 297 */ 298.Lcpu_reset_address: 299 .word _C_LABEL(cpu_reset_address) 300 301 /* 302 * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the 303 * v4 MMU disable instruction needs executing... it is an illegal instruction 304 * on f.e. ARM6/7 that locks up the computer in an endless illegal 305 * instruction / data-abort / reset loop. 306 */ 307.Lcpu_reset_needs_v4_MMU_disable: 308 .word _C_LABEL(cpu_reset_needs_v4_MMU_disable) 309 310 311/* 312 * setjump + longjmp 313 */ 314ENTRY(setjmp) 315 stmia r0, {r4-r14} 316 mov r0, #0x00000000 317 RET 318 319ENTRY(longjmp) 320 ldmia r0, {r4-r14} 321 mov r0, #0x00000001 322 RET 323 324 .data 325 .global _C_LABEL(esym) 326_C_LABEL(esym): .word _C_LABEL(end) 327 328ENTRY_NP(abort) 329 b _C_LABEL(abort) 330 331ENTRY_NP(sigcode) 332 mov r0, sp 333 swi SYS_sigreturn 334 335 /* Well if that failed we better exit quick ! */ 336 337 swi SYS_exit 338 b . - 8 339 340 .align 0 341 .global _C_LABEL(esigcode) 342 _C_LABEL(esigcode): 343 344 .data 345 .global szsigcode 346szsigcode: 347 .long esigcode-sigcode 348/* End of locore.S */ 349