locore-v4.S revision 236524
1129198Scognet/* $NetBSD: locore.S,v 1.14 2003/04/20 16:21:40 thorpej Exp $ */ 2129198Scognet 3139735Simp/*- 4129198Scognet * Copyright (C) 1994-1997 Mark Brinicombe 5129198Scognet * Copyright (C) 1994 Brini 6129198Scognet * All rights reserved. 7129198Scognet * 8129198Scognet * Redistribution and use in source and binary forms, with or without 9129198Scognet * modification, are permitted provided that the following conditions 10129198Scognet * are met: 11129198Scognet * 1. Redistributions of source code must retain the above copyright 12129198Scognet * notice, this list of conditions and the following disclaimer. 13129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 14129198Scognet * notice, this list of conditions and the following disclaimer in the 15129198Scognet * documentation and/or other materials provided with the distribution. 16129198Scognet * 3. All advertising materials mentioning features or use of this software 17129198Scognet * must display the following acknowledgement: 18129198Scognet * This product includes software developed by Brini. 19129198Scognet * 4. The name of Brini may not be used to endorse or promote products 20129198Scognet * derived from this software without specific prior written permission. 21129198Scognet * 22129198Scognet * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR 23129198Scognet * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24129198Scognet * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25129198Scognet * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26129198Scognet * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 27129198Scognet * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 28129198Scognet * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29129198Scognet * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 30129198Scognet * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 31129198Scognet * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32129198Scognet * 33129198Scognet */ 34129198Scognet 35129198Scognet#include "assym.s" 36135640Scognet#include <sys/syscall.h> 37129198Scognet#include <machine/asm.h> 38129198Scognet#include <machine/armreg.h> 39129198Scognet#include <machine/pte.h> 40236524Simp 41129198Scognet__FBSDID("$FreeBSD: head/sys/arm/arm/locore.S 236524 2012-06-03 18:34:32Z imp $"); 42129198Scognet 43159849Simp/* What size should this really be ? It is only used by initarm() */ 44129198Scognet#define INIT_ARM_STACK_SIZE 2048 45129198Scognet 46129198Scognet#define CPWAIT_BRANCH \ 47129198Scognet sub pc, pc, #4 48129198Scognet 49129198Scognet#define CPWAIT(tmp) \ 50129198Scognet mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\ 51129198Scognet mov tmp, tmp /* wait for it to complete */ ;\ 52129198Scognet CPWAIT_BRANCH /* branch to next insn */ 53129198Scognet 54235277Simp/* 55235277Simp * This is for kvm_mkdb, and should be the address of the beginning 56235277Simp * of the kernel text segment (not necessarily the same as kernbase). 57235277Simp */ 58129198Scognet .text 59129198Scognet .align 0 60129198Scognet.globl kernbase 61129198Scognet.set kernbase,KERNBASE 62150863Scognet.globl physaddr 63150863Scognet.set physaddr,PHYSADDR 64129198Scognet 65183878Sraj/* 66236524Simp * On entry for FreeBSD boot ABI: 67236524Simp * r0 - metadata pointer or 0 (boothowto on AT91's boot2) 68218227Smarcel * r1 - if (r0 == 0) then metadata pointer 69236524Simp * On entry for Linux boot ABI: 70236524Simp * r0 - 0 71236524Simp * r1 - machine type (passed as arg2 to initarm) 72236524Simp * r2 - Pointer to a tagged list or dtb image (phys addr) (passed as arg1 initarm) 73236524Simp * 74236524Simp * For both types of boot we gather up the args, put them in a struct arm_boot_params 75236524Simp * structure and pass that to initarm. 76183878Sraj */ 77236524SimpENTRY_NP(btext) 78218227SmarcelASENTRY_NP(_start) 79236524Simp mov r9, r0 /* 0 or boot mode from boot2 */ 80236524Simp mov r8, r1 /* Save Machine type */ 81236524Simp mov ip, r2 /* Save meta data */ 82236524Simp mov fp, r3 /* Future expantion */ 83183878Sraj 84193846Smarcel /* Make sure interrupts are disabled. */ 85193846Smarcel mrs r7, cpsr 86193846Smarcel orr r7, r7, #(I32_bit|F32_bit) 87193846Smarcel msr cpsr_c, r7 88193846Smarcel 89166819Scognet#if defined (FLASHADDR) && defined(LOADERRAMADDR) 90166819Scognet /* Check if we're running from flash. */ 91166819Scognet ldr r7, =FLASHADDR 92175983Sraj /* 93166819Scognet * If we're running with MMU disabled, test against the 94166819Scognet * physical address instead. 95166819Scognet */ 96166819Scognet mrc p15, 0, r2, c1, c0, 0 97166819Scognet ands r2, r2, #CPU_CONTROL_MMU_ENABLE 98236524Simp ldreq r6, =PHYSADDR 99236524Simp ldrne r6, =LOADERRAMADDR 100236524Simp cmp r7, r6 101166819Scognet bls flash_lower 102166819Scognet cmp r7, pc 103166819Scognet bhi from_ram 104166819Scognet b do_copy 105166819Scognet 106166819Scognetflash_lower: 107236524Simp cmp r6, pc 108166819Scognet bls from_ram 109166819Scognetdo_copy: 110236524Simp ldr r7, =KERNBASE 111175983Sraj adr r1, _start 112166819Scognet ldr r0, Lreal_start 113166819Scognet ldr r2, Lend 114166819Scognet sub r2, r2, r0 115236524Simp sub r0, r0, r7 116236524Simp add r0, r0, r6 117166819Scognet mov r4, r0 118166819Scognet bl memcpy 119166819Scognet ldr r0, Lram_offset 120166819Scognet add pc, r4, r0 121166819ScognetLram_offset: .word from_ram-_C_LABEL(_start) 122166819Scognetfrom_ram: 123166819Scognet nop 124135640Scognet#endif 125135640Scognet adr r7, Lunmapped 126190602Scognet bic r7, r7, #0xf0000000 127153616Scognet orr r7, r7, #PHYSADDR 128143681Sjmg 129175983Sraj 130166819Scognetdisable_mmu: 131135640Scognet /* Disable MMU for a while */ 132143681Sjmg mrc p15, 0, r2, c1, c0, 0 133153550Scognet bic r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\ 134153550Scognet CPU_CONTROL_WBUF_ENABLE) 135153550Scognet bic r2, r2, #(CPU_CONTROL_IC_ENABLE) 136153550Scognet bic r2, r2, #(CPU_CONTROL_BPRD_ENABLE) 137135640Scognet mcr p15, 0, r2, c1, c0, 0 138129198Scognet 139135640Scognet nop 140135640Scognet nop 141135640Scognet nop 142135640Scognet mov pc, r7 143135640ScognetLunmapped: 144135640Scognet#ifdef STARTUP_PAGETABLE_ADDR 145129198Scognet /* build page table from scratch */ 146129198Scognet ldr r0, Lstartup_pagetable 147129198Scognet adr r4, mmu_init_table 148129198Scognet b 3f 149129198Scognet 150129198Scognet2: 151129198Scognet str r3, [r0, r2] 152129198Scognet add r2, r2, #4 153129198Scognet add r3, r3, #(L1_S_SIZE) 154129198Scognet adds r1, r1, #-1 155129198Scognet bhi 2b 156143681Sjmg3: 157172356Scognet ldmia r4!, {r1,r2,r3} /* # of sections, VA, PA|attr */ 158129198Scognet cmp r1, #0 159140683Scognet adrne r5, 2b 160190602Scognet bicne r5, r5, #0xf0000000 161140683Scognet orrne r5, r5, #PHYSADDR 162140683Scognet movne pc, r5 163129198Scognet 164129198Scognet mcr p15, 0, r0, c2, c0, 0 /* Set TTB */ 165129198Scognet mcr p15, 0, r0, c8, c7, 0 /* Flush TLB */ 166129198Scognet 167129198Scognet /* Set the Domain Access register. Very important! */ 168143681Sjmg mov r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT) 169129198Scognet mcr p15, 0, r0, c3, c0, 0 170129198Scognet /* Enable MMU */ 171129198Scognet mrc p15, 0, r0, c1, c0, 0 172129198Scognet orr r0, r0, #CPU_CONTROL_MMU_ENABLE 173129198Scognet mcr p15, 0, r0, c1, c0, 0 174153550Scognet nop 175153550Scognet nop 176153550Scognet nop 177129198Scognet CPWAIT(r0) 178129198Scognet 179153550Scognet#endif 180129198Scognetmmu_done: 181153550Scognet nop 182129198Scognet adr r1, .Lstart 183129198Scognet ldmia r1, {r1, r2, sp} /* Set initial stack and */ 184129198Scognet sub r2, r2, r1 /* get zero init data */ 185129198Scognet mov r3, #0 186129198Scognet.L1: 187150863Scognet str r3, [r1], #0x0004 /* get zero init data */ 188129198Scognet subs r2, r2, #4 189129198Scognet bgt .L1 190153550Scognet ldr pc, .Lvirt_done 191129198Scognet 192142145Scognetvirt_done: 193236524Simp mov r1, #20 /* loader info size is 20 bytes also second arg */ 194236524Simp subs sp, sp, r1 /* allocate arm_boot_params struct on stack */ 195236524Simp mov r0, sp /* loader info pointer is first arg */ 196236524Simp str r1, [r0] /* Store length of loader info */ 197236524Simp str r9, [r0, #4] /* Store r0 from boot loader */ 198236524Simp str r8, [r0, #8] /* Store r1 from boot loader */ 199236524Simp str ip, [r0, #12] /* store r2 from boot loader */ 200236524Simp str fp, [r0, #16] /* store r3 from boot loader */ 201175983Sraj mov fp, #0 /* trace back starts here */ 202129198Scognet bl _C_LABEL(initarm) /* Off we go */ 203129198Scognet 204129198Scognet /* init arm will return the new stack pointer. */ 205129198Scognet mov sp, r0 206129198Scognet 207129198Scognet bl _C_LABEL(mi_startup) /* call mi_startup()! */ 208129198Scognet 209129198Scognet adr r0, .Lmainreturned 210130164Sphk b _C_LABEL(panic) 211175983Sraj /* NOTREACHED */ 212129198Scognet#ifdef STARTUP_PAGETABLE_ADDR 213129198Scognet#define MMU_INIT(va,pa,n_sec,attr) \ 214129198Scognet .word n_sec ; \ 215129198Scognet .word 4*((va)>>L1_S_SHIFT) ; \ 216129198Scognet .word (pa)|(attr) ; 217129198Scognet 218150863ScognetLvirtaddr: 219150863Scognet .word KERNVIRTADDR 220150863ScognetLphysaddr: 221150863Scognet .word KERNPHYSADDR 222166819ScognetLreal_start: 223166819Scognet .word _start 224166819ScognetLend: 225166819Scognet .word _edata 226129198ScognetLstartup_pagetable: 227129198Scognet .word STARTUP_PAGETABLE_ADDR 228143681Sjmgmmu_init_table: 229129198Scognet /* fill all table VA==PA */ 230129198Scognet /* map SDRAM VA==PA, WT cacheable */ 231135640Scognet MMU_INIT(PHYSADDR, PHYSADDR , 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)) 232135640Scognet /* map VA 0xc0000000..0xc3ffffff to PA */ 233135640Scognet MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)) 234129198Scognet 235129198Scognet .word 0 /* end of table */ 236129198Scognet#endif 237129198Scognet.Lstart: 238129198Scognet .word _edata 239129198Scognet .word _end 240129198Scognet .word svcstk + INIT_ARM_STACK_SIZE 241129198Scognet 242153550Scognet.Lvirt_done: 243153550Scognet .word virt_done 244129198Scognet.Lmainreturned: 245129198Scognet .asciz "main() returned" 246129198Scognet .align 0 247129198Scognet 248129198Scognet .bss 249129198Scognetsvcstk: 250129198Scognet .space INIT_ARM_STACK_SIZE 251129198Scognet 252129198Scognet .text 253129198Scognet .align 0 254129198Scognet 255143681Sjmg.Lcpufuncs: 256129198Scognet .word _C_LABEL(cpufuncs) 257129198Scognet 258135640ScognetENTRY_NP(cpu_halt) 259129198Scognet mrs r2, cpsr 260129198Scognet bic r2, r2, #(PSR_MODE) 261129198Scognet orr r2, r2, #(PSR_SVC32_MODE) 262129198Scognet orr r2, r2, #(I32_bit | F32_bit) 263129198Scognet msr cpsr_all, r2 264129198Scognet 265129198Scognet ldr r4, .Lcpu_reset_address 266129198Scognet ldr r4, [r4] 267129198Scognet 268129198Scognet ldr r0, .Lcpufuncs 269129198Scognet mov lr, pc 270129198Scognet ldr pc, [r0, #CF_IDCACHE_WBINV_ALL] 271183839Sraj mov lr, pc 272183839Sraj ldr pc, [r0, #CF_L2CACHE_WBINV_ALL] 273129198Scognet 274129198Scognet /* 275129198Scognet * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's 276129198Scognet * necessary. 277129198Scognet */ 278129198Scognet 279129198Scognet ldr r1, .Lcpu_reset_needs_v4_MMU_disable 280129198Scognet ldr r1, [r1] 281129198Scognet cmp r1, #0 282129198Scognet mov r2, #0 283129198Scognet 284129198Scognet /* 285175983Sraj * MMU & IDC off, 32 bit program & data space 286129198Scognet * Hurl ourselves into the ROM 287129198Scognet */ 288129198Scognet mov r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE) 289129198Scognet mcr 15, 0, r0, c1, c0, 0 290129198Scognet mcrne 15, 0, r2, c8, c7, 0 /* nail I+D TLB on ARMv4 and greater */ 291129198Scognet mov pc, r4 292129198Scognet 293129198Scognet /* 294129198Scognet * _cpu_reset_address contains the address to branch to, to complete 295129198Scognet * the cpu reset after turning the MMU off 296129198Scognet * This variable is provided by the hardware specific code 297129198Scognet */ 298129198Scognet.Lcpu_reset_address: 299129198Scognet .word _C_LABEL(cpu_reset_address) 300129198Scognet 301129198Scognet /* 302129198Scognet * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the 303129198Scognet * v4 MMU disable instruction needs executing... it is an illegal instruction 304129198Scognet * on f.e. ARM6/7 that locks up the computer in an endless illegal 305129198Scognet * instruction / data-abort / reset loop. 306129198Scognet */ 307129198Scognet.Lcpu_reset_needs_v4_MMU_disable: 308129198Scognet .word _C_LABEL(cpu_reset_needs_v4_MMU_disable) 309129198Scognet 310129198Scognet 311129198Scognet/* 312129198Scognet * setjump + longjmp 313129198Scognet */ 314129198ScognetENTRY(setjmp) 315129198Scognet stmia r0, {r4-r14} 316129198Scognet mov r0, #0x00000000 317137463Scognet RET 318129198Scognet 319129198ScognetENTRY(longjmp) 320129198Scognet ldmia r0, {r4-r14} 321129198Scognet mov r0, #0x00000001 322137463Scognet RET 323129198Scognet 324129198Scognet .data 325129198Scognet .global _C_LABEL(esym) 326129198Scognet_C_LABEL(esym): .word _C_LABEL(end) 327129198Scognet 328129198ScognetENTRY_NP(abort) 329129198Scognet b _C_LABEL(abort) 330129198Scognet 331135640ScognetENTRY_NP(sigcode) 332135640Scognet mov r0, sp 333135640Scognet swi SYS_sigreturn 334135640Scognet 335135640Scognet /* Well if that failed we better exit quick ! */ 336135640Scognet 337135640Scognet swi SYS_exit 338135640Scognet b . - 8 339135640Scognet 340135640Scognet .align 0 341135640Scognet .global _C_LABEL(esigcode) 342135640Scognet _C_LABEL(esigcode): 343143681Sjmg 344135640Scognet .data 345135640Scognet .global szsigcode 346135640Scognetszsigcode: 347135640Scognet .long esigcode-sigcode 348129198Scognet/* End of locore.S */ 349