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