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__FBSDID("$FreeBSD$"); 41 42/* What size should this really be ? It is only used by initarm() */ 43#define INIT_ARM_STACK_SIZE 2048 44 45/* 46 * This is for kvm_mkdb, and should be the address of the beginning 47 * of the kernel text segment (not necessarily the same as kernbase). 48 */ 49 50 51#define CPWAIT_BRANCH \ 52 sub pc, pc, #4 53 54#define CPWAIT(tmp) \ 55 mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\ 56 mov tmp, tmp /* wait for it to complete */ ;\ 57 CPWAIT_BRANCH /* branch to next insn */ 58 59 .text 60 .align 0 61.globl kernbase 62.set kernbase,KERNBASE 63.globl physaddr 64.set physaddr,PHYSADDR 65 66ENTRY_NP(btext) 67 68ASENTRY_NP(_start) 69#if defined (FLASHADDR) && defined(LOADERRAMADDR) 70 /* Check if we're running from flash. */ 71 ldr r7, =FLASHADDR 72 /* 73 * If we're running with MMU disabled, test against the 74 * physical address instead. 75 */ 76 mrc p15, 0, r2, c1, c0, 0 77 ands r2, r2, #CPU_CONTROL_MMU_ENABLE 78 ldreq r8, =PHYSADDR 79 ldrne r8, =LOADERRAMADDR 80 cmp r7, r8 81 bls flash_lower 82 cmp r7, pc 83 bhi from_ram 84 b do_copy 85 86flash_lower: 87 cmp r8, pc 88 bls from_ram 89do_copy: 90 ldr r9, =KERNBASE 91 adr r1, _start 92 ldr r0, Lreal_start 93 ldr r2, Lend 94 sub r2, r2, r0 95 sub r0, r0, r9 96 add r0, r0, r8 97 mov r4, r0 98 /* Make sure _arm_memcpy is NULL */ 99 ldr r3, .L_arm_memcpy 100 ldr r3, [r3] 101 mov r5, #0 102 str r5, [r3] 103 bl memcpy 104 ldr r0, Lram_offset 105 add pc, r4, r0 106Lram_offset: .word from_ram-_C_LABEL(_start) 107from_ram: 108 nop 109#endif 110 adr r7, Lunmapped 111 bic r7, r7, #0xff000000 112 orr r7, r7, #PHYSADDR 113 114 115disable_mmu: 116 /* Disable MMU for a while */ 117 mrc p15, 0, r2, c1, c0, 0 118 bic r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\ 119 CPU_CONTROL_WBUF_ENABLE) 120 bic r2, r2, #(CPU_CONTROL_IC_ENABLE) 121 bic r2, r2, #(CPU_CONTROL_BPRD_ENABLE) 122 mcr p15, 0, r2, c1, c0, 0 123 124 nop 125 nop 126 nop 127 mov pc, r7 128Lunmapped: 129#ifdef STARTUP_PAGETABLE_ADDR 130 /* build page table from scratch */ 131 ldr r0, Lstartup_pagetable 132 adr r4, mmu_init_table 133 b 3f 134 1352: 136 str r3, [r0, r2] 137 add r2, r2, #4 138 add r3, r3, #(L1_S_SIZE) 139 adds r1, r1, #-1 140 bhi 2b 1413: 142 ldmia r4!, {r1,r2,r3} /* # of sections, PA|attr, VA */ 143 cmp r1, #0 144 adrne r5, 2b 145 bicne r5, r5, #0xff000000 146 orrne r5, r5, #PHYSADDR 147 movne pc, r5 148 149 mcr p15, 0, r0, c2, c0, 0 /* Set TTB */ 150 mcr p15, 0, r0, c8, c7, 0 /* Flush TLB */ 151 152 /* Set the Domain Access register. Very important! */ 153 mov r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT) 154 mcr p15, 0, r0, c3, c0, 0 155 /* Enable MMU */ 156 mrc p15, 0, r0, c1, c0, 0 157 orr r0, r0, #CPU_CONTROL_MMU_ENABLE 158 mcr p15, 0, r0, c1, c0, 0 159 nop 160 nop 161 nop 162 CPWAIT(r0) 163 164#endif 165mmu_done: 166 nop 167 adr r1, .Lstart 168 ldmia r1, {r1, r2, sp} /* Set initial stack and */ 169 sub r2, r2, r1 /* get zero init data */ 170 mov r3, #0 171.L1: 172 str r3, [r1], #0x0004 /* get zero init data */ 173 subs r2, r2, #4 174 bgt .L1 175 ldr pc, .Lvirt_done 176 177virt_done: 178 mov fp, #0 /* trace back starts here */ 179 bl _C_LABEL(initarm) /* Off we go */ 180 181 /* init arm will return the new stack pointer. */ 182 mov sp, r0 183 184 bl _C_LABEL(mi_startup) /* call mi_startup()! */ 185 186 adr r0, .Lmainreturned 187 b _C_LABEL(panic) 188 /* NOTEACHED */ 189#ifdef STARTUP_PAGETABLE_ADDR 190#define MMU_INIT(va,pa,n_sec,attr) \ 191 .word n_sec ; \ 192 .word 4*((va)>>L1_S_SHIFT) ; \ 193 .word (pa)|(attr) ; 194 195Lvirtaddr: 196 .word KERNVIRTADDR 197Lphysaddr: 198 .word KERNPHYSADDR 199Lreal_start: 200 .word _start 201Lend: 202 .word _edata 203Lstartup_pagetable: 204 .word STARTUP_PAGETABLE_ADDR 205mmu_init_table: 206 /* fill all table VA==PA */ 207 /* map SDRAM VA==PA, WT cacheable */ 208 MMU_INIT(PHYSADDR, PHYSADDR , 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)) 209 /* map VA 0xc0000000..0xc3ffffff to PA */ 210 MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)) 211 212 .word 0 /* end of table */ 213#endif 214.Lstart: 215 .word _edata 216 .word _end 217 .word svcstk + INIT_ARM_STACK_SIZE 218 219#if defined(FLASHADDR) && defined(LOADERRAMADDR) 220.L_arm_memcpy: 221 .word _C_LABEL(_arm_memcpy) 222#endif 223 224.Lvirt_done: 225 .word virt_done 226.Lmainreturned: 227 .asciz "main() returned" 228 .align 0 229 230 .bss 231svcstk: 232 .space INIT_ARM_STACK_SIZE 233 234 .text 235 .align 0 236 237#ifndef OFW 238 /* OFW based systems will used OF_boot() */ 239 240.Lcpufuncs: 241 .word _C_LABEL(cpufuncs) 242 243ENTRY_NP(cpu_halt) 244 mrs r2, cpsr 245 bic r2, r2, #(PSR_MODE) 246 orr r2, r2, #(PSR_SVC32_MODE) 247 orr r2, r2, #(I32_bit | F32_bit) 248 msr cpsr_all, r2 249 250 ldr r4, .Lcpu_reset_address 251 ldr r4, [r4] 252 253 ldr r0, .Lcpufuncs 254 mov lr, pc 255 ldr pc, [r0, #CF_IDCACHE_WBINV_ALL] 256 257 /* 258 * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's 259 * necessary. 260 */ 261 262 ldr r1, .Lcpu_reset_needs_v4_MMU_disable 263 ldr r1, [r1] 264 cmp r1, #0 265 mov r2, #0 266 267 /* 268 * MMU & IDC off, 32 bit program & data space 269 * Hurl ourselves into the ROM 270 */ 271 mov r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE) 272 mcr 15, 0, r0, c1, c0, 0 273 mcrne 15, 0, r2, c8, c7, 0 /* nail I+D TLB on ARMv4 and greater */ 274 mov pc, r4 275 276 /* 277 * _cpu_reset_address contains the address to branch to, to complete 278 * the cpu reset after turning the MMU off 279 * This variable is provided by the hardware specific code 280 */ 281.Lcpu_reset_address: 282 .word _C_LABEL(cpu_reset_address) 283 284 /* 285 * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the 286 * v4 MMU disable instruction needs executing... it is an illegal instruction 287 * on f.e. ARM6/7 that locks up the computer in an endless illegal 288 * instruction / data-abort / reset loop. 289 */ 290.Lcpu_reset_needs_v4_MMU_disable: 291 .word _C_LABEL(cpu_reset_needs_v4_MMU_disable) 292 293#endif /* OFW */ 294 295#ifdef IPKDB 296/* 297 * Execute(inst, psr, args, sp) 298 * 299 * Execute INSTruction with PSR and ARGS[0] - ARGS[3] making 300 * available stack at SP for next undefined instruction trap. 301 * 302 * Move the instruction onto the stack and jump to it. 303 */ 304ENTRY_NP(Execute) 305 mov ip, sp 306 stmfd sp!, {r2, r4-r7, fp, ip, lr, pc} 307 sub fp, ip, #4 308 mov ip, r3 309 ldr r7, .Lreturn 310 stmfd sp!, {r0, r7} 311 adr r7, #.LExec 312 mov r5, r1 313 mrs r4, cpsr 314 ldmia r2, {r0-r3} 315 mov r6, sp 316 mov sp, ip 317 msr cpsr_all, r5 318 mov pc, r6 319.LExec: 320 mrs r5, cpsr 321/* XXX Cannot switch thus easily back from user mode */ 322 msr cpsr_all, r4 323 add sp, r6, #8 324 ldmfd sp!, {r6} 325 stmia r6, {r0-r3} 326 mov r0, r5 327 ldmdb fp, {r4-r7, fp, sp, pc} 328.Lreturn: 329 mov pc, r7 330#endif 331 332/* 333 * setjump + longjmp 334 */ 335ENTRY(setjmp) 336 stmia r0, {r4-r14} 337 mov r0, #0x00000000 338 RET 339 340ENTRY(longjmp) 341 ldmia r0, {r4-r14} 342 mov r0, #0x00000001 343 RET 344 345 .data 346 .global _C_LABEL(esym) 347_C_LABEL(esym): .word _C_LABEL(end) 348 349ENTRY_NP(abort) 350 b _C_LABEL(abort) 351 352ENTRY_NP(sigcode) 353 mov r0, sp 354 swi SYS_sigreturn 355 356 /* Well if that failed we better exit quick ! */ 357 358 swi SYS_exit 359 b . - 8 360 361 .align 0 362 .global _C_LABEL(esigcode) 363 _C_LABEL(esigcode): 364 365 .data 366 .global szsigcode 367szsigcode: 368 .long esigcode-sigcode 369/* End of locore.S */ 370