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