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 <machine/asm.h> 37#include <machine/armreg.h> 38#include <machine/pte.h> 39__FBSDID("$FreeBSD$"); 40 41/* What size should this really be ? It is only used by init_arm() */ 42#define INIT_ARM_STACK_SIZE 2048 43 44/* 45 * This is for kvm_mkdb, and should be the address of the beginning 46 * of the kernel text segment (not necessarily the same as kernbase). 47 */ 48 49 50#define CPWAIT_BRANCH \ 51 sub pc, pc, #4 52 53#define CPWAIT(tmp) \ 54 mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\ 55 mov tmp, tmp /* wait for it to complete */ ;\ 56 CPWAIT_BRANCH /* branch to next insn */ 57 58 .text 59 .align 0 60.globl kernbase 61.set kernbase,KERNBASE 62 63ENTRY_NP(btext) 64 65ASENTRY_NP(_start) 66 /* Check if we are running on RAM, if not move ourself to RAM */ 67 cmp pc, #KERNPHYSADDR 68 bhi start_inram /* XXX: This is wrong */ 69 70 /* move me to RAM 71 * XXX: we can use memcpy if it is PIC 72 */ 73 ldr r1, Lcopy_size 74 adr r0, _C_LABEL(_start) 75 add r1, r1, #3 76 mov r1, r1, LSR #2 77 mov r2, #KERNPHYSADDR 78 add r2, r2, #0x00200000 79 mov r4, r2 80 815: ldr r3,[r0],#4 82 str r3,[r2],#4 83 subs r1,r1,#1 84 bhi 5b 85 86 /* Jump to RAM */ 87 ldr r0, Lstart_off 88 add pc, r4, r0 89 90Lcopy_size: .word _edata-_C_LABEL(_start) 91Lstart_off: .word start_inram-_C_LABEL(_start) 92start_inram: 93#ifdef STARTUP_PAGETABLE_ADDR 94 adr r4, mmu_init_table2 95 96 mrc p15, 0, r2, c1, c0, 0 97 tst r2, #CPU_CONTROL_MMU_ENABLE /* we already have a page table? */ 98 bne 3f 99 100 /* build page table from scratch */ 101 ldr r0, Lstartup_pagetable 102 adr r4, mmu_init_table 103 b 3f 104 1052: 106 str r3, [r0, r2] 107 add r2, r2, #4 108 add r3, r3, #(L1_S_SIZE) 109 adds r1, r1, #-1 110 bhi 2b 1113: 112 ldmia r4!, {r1,r2,r3} /* # of sections, PA|attr, VA */ 113 cmp r1, #0 114 bne 2b 115 116 mcr p15, 0, r0, c2, c0, 0 /* Set TTB */ 117 mcr p15, 0, r0, c8, c7, 0 /* Flush TLB */ 118 119 /* Set the Domain Access register. Very important! */ 120 mov r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT) 121 mcr p15, 0, r0, c3, c0, 0 122 123 /* Enable MMU */ 124 mrc p15, 0, r0, c1, c0, 0 125 orr r0, r0, #CPU_CONTROL_MMU_ENABLE 126 mcr p15, 0, r0, c1, c0, 0 127 CPWAIT(r0) 128 129 bl mmu_done 130 131mmu_done: 132#endif 133 adr r1, .Lstart 134 ldmia r1, {r1, r2, sp} /* Set initial stack and */ 135 sub r2, r2, r1 /* get zero init data */ 136 mov r3, #0 137 138.L1: 139 str r3, [r1], #0x0004 /* Zero the bss */ 140 subs r2, r2, #4 141 bgt .L1 142 143 mov fp, #0xc0000000 /* trace back starts here */ 144 bl _C_LABEL(initarm) /* Off we go */ 145 146 /* init arm will return the new stack pointer. */ 147 mov sp, r0 148 mov fp, #0x00000000 /* trace back starts here */ 149 mov ip, sp 150 stmfd sp!, {fp, ip, lr, pc} 151 sub fp, ip, #4 152 153 bl _C_LABEL(mi_startup) /* call mi_startup()! */ 154 155 adr r0, .Lmainreturned 156 adr r1, .LFile 157 mov r2, #__LINE__ 158 b _C_LABEL(__panic) 159 /* NOTEACHED */ 160#ifdef STARTUP_PAGETABLE_ADDR 161#define MMU_INIT(va,pa,n_sec,attr) \ 162 .word n_sec ; \ 163 .word 4*((va)>>L1_S_SHIFT) ; \ 164 .word (pa)|(attr) ; 165 166Lstartup_pagetable: 167 .word STARTUP_PAGETABLE_ADDR 168mmu_init_table: 169 /* fill all table VA==PA */ 170 MMU_INIT(0x00000000, 0x00000000, 1<<(32-L1_S_SHIFT), L1_TYPE_S|L1_S_AP(AP_KRW)) 171 /* map SDRAM VA==PA, WT cacheable */ 172 MMU_INIT(KERNPHYSADDR, KERNPHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)) 173mmu_init_table2: 174 /* map VA 0xc0000000..0xc3ffffff to PA 0xa0000000..0xa3ffffff */ 175 MMU_INIT(0xc0000000, KERNPHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)) 176 177 .word 0 /* end of table */ 178#endif 179.Lstart: 180 .word _edata 181 .word _end 182 .word svcstk + INIT_ARM_STACK_SIZE 183 184.LFile: 185 .asciz __FILE__ 186.Lmainreturned: 187 .asciz "main() returned" 188 .align 0 189 190 .bss 191svcstk: 192 .space INIT_ARM_STACK_SIZE 193 194 .text 195 .align 0 196 197#ifndef OFW 198 /* OFW based systems will used OF_boot() */ 199 200.Lcpufuncs: 201 .word _C_LABEL(cpufuncs) 202 203ENTRY_NP(cpu_reset) 204 mrs r2, cpsr 205 bic r2, r2, #(PSR_MODE) 206 orr r2, r2, #(PSR_SVC32_MODE) 207 orr r2, r2, #(I32_bit | F32_bit) 208 msr cpsr_all, r2 209 210 ldr r4, .Lcpu_reset_address 211 ldr r4, [r4] 212 213 ldr r0, .Lcpufuncs 214 mov lr, pc 215 ldr pc, [r0, #CF_IDCACHE_WBINV_ALL] 216 217 /* 218 * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's 219 * necessary. 220 */ 221 222 ldr r1, .Lcpu_reset_needs_v4_MMU_disable 223 ldr r1, [r1] 224 cmp r1, #0 225 mov r2, #0 226 227 /* 228 * MMU & IDC off, 32 bit program & data space 229 * Hurl ourselves into the ROM 230 */ 231 mov r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE) 232 mcr 15, 0, r0, c1, c0, 0 233 mcrne 15, 0, r2, c8, c7, 0 /* nail I+D TLB on ARMv4 and greater */ 234 mov pc, r4 235 236 /* 237 * _cpu_reset_address contains the address to branch to, to complete 238 * the cpu reset after turning the MMU off 239 * This variable is provided by the hardware specific code 240 */ 241.Lcpu_reset_address: 242 .word _C_LABEL(cpu_reset_address) 243 244 /* 245 * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the 246 * v4 MMU disable instruction needs executing... it is an illegal instruction 247 * on f.e. ARM6/7 that locks up the computer in an endless illegal 248 * instruction / data-abort / reset loop. 249 */ 250.Lcpu_reset_needs_v4_MMU_disable: 251 .word _C_LABEL(cpu_reset_needs_v4_MMU_disable) 252 253#endif /* OFW */ 254 255#ifdef IPKDB 256/* 257 * Execute(inst, psr, args, sp) 258 * 259 * Execute INSTruction with PSR and ARGS[0] - ARGS[3] making 260 * available stack at SP for next undefined instruction trap. 261 * 262 * Move the instruction onto the stack and jump to it. 263 */ 264ENTRY_NP(Execute) 265 mov ip, sp 266 stmfd sp!, {r2, r4-r7, fp, ip, lr, pc} 267 sub fp, ip, #4 268 mov ip, r3 269 ldr r7, .Lreturn 270 stmfd sp!, {r0, r7} 271 adr r7, #.LExec 272 mov r5, r1 273 mrs r4, cpsr 274 ldmia r2, {r0-r3} 275 mov r6, sp 276 mov sp, ip 277 msr cpsr_all, r5 278 mov pc, r6 279.LExec: 280 mrs r5, cpsr 281/* XXX Cannot switch thus easily back from user mode */ 282 msr cpsr_all, r4 283 add sp, r6, #8 284 ldmfd sp!, {r6} 285 stmia r6, {r0-r3} 286 mov r0, r5 287 ldmdb fp, {r4-r7, fp, sp, pc} 288.Lreturn: 289 mov pc, r7 290#endif 291 292/* 293 * setjump + longjmp 294 */ 295ENTRY(setjmp) 296 stmia r0, {r4-r14} 297 mov r0, #0x00000000 298 mov pc, lr 299 300ENTRY(longjmp) 301 ldmia r0, {r4-r14} 302 mov r0, #0x00000001 303 mov pc, lr 304 305 .data 306 .global _C_LABEL(esym) 307_C_LABEL(esym): .word _C_LABEL(end) 308 309ENTRY_NP(abort) 310 b _C_LABEL(abort) 311 312/* End of locore.S */ 313