locore-v4.S revision 140683
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> 40129198Scognet__FBSDID("$FreeBSD: head/sys/arm/arm/locore.S 140683 2005-01-23 22:08:31Z cognet $"); 41129198Scognet 42129198Scognet/* What size should this really be ? It is only used by init_arm() */ 43129198Scognet#define INIT_ARM_STACK_SIZE 2048 44129198Scognet 45129198Scognet/* 46129198Scognet * This is for kvm_mkdb, and should be the address of the beginning 47129198Scognet * of the kernel text segment (not necessarily the same as kernbase). 48129198Scognet */ 49129198Scognet 50129198Scognet 51129198Scognet#define CPWAIT_BRANCH \ 52129198Scognet sub pc, pc, #4 53129198Scognet 54129198Scognet#define CPWAIT(tmp) \ 55129198Scognet mrc p15, 0, tmp, c2, c0, 0 /* arbitrary read of CP15 */ ;\ 56129198Scognet mov tmp, tmp /* wait for it to complete */ ;\ 57129198Scognet CPWAIT_BRANCH /* branch to next insn */ 58129198Scognet 59129198Scognet .text 60129198Scognet .align 0 61129198Scognet.globl kernbase 62129198Scognet.set kernbase,KERNBASE 63129198Scognet 64129198ScognetENTRY_NP(btext) 65129198Scognet 66129198ScognetASENTRY_NP(_start) 67135640Scognet 68140683Scognet 69129198Scognet /* Check if we are running on RAM, if not move ourself to RAM */ 70135640Scognet#if 0 71135640Scognet cmp pc, #PHYSADDR 72129198Scognet bhi start_inram /* XXX: This is wrong */ 73135640Scognet#endif 74135640Scognet b start_inram /* 75135640Scognet * XXX: this is even more wrong, but RedBoot 76135640Scognet * use 0x00000000-0x100000000 as virtual 77135640Scognet * addresses for the RAM. 78135640Scognet */ 79129198Scognet 80129198Scognet /* move me to RAM 81129198Scognet * XXX: we can use memcpy if it is PIC 82129198Scognet */ 83129198Scognet ldr r1, Lcopy_size 84129198Scognet adr r0, _C_LABEL(_start) 85129198Scognet add r1, r1, #3 86129198Scognet mov r1, r1, LSR #2 87135640Scognet mov r2, #PHYSADDR 88129198Scognet add r2, r2, #0x00200000 89129198Scognet mov r4, r2 90129198Scognet 91129198Scognet5: ldr r3,[r0],#4 92129198Scognet str r3,[r2],#4 93129198Scognet subs r1,r1,#1 94129198Scognet bhi 5b 95129198Scognet 96129198Scognet /* Jump to RAM */ 97129198Scognet ldr r0, Lstart_off 98129198Scognet add pc, r4, r0 99129198Scognet 100129198ScognetLcopy_size: .word _edata-_C_LABEL(_start) 101129198ScognetLstart_off: .word start_inram-_C_LABEL(_start) 102129198Scognetstart_inram: 103135640Scognet adr r7, Lunmapped 104135640Scognet bic r7, r7, #0xff000000 105135640Scognet orr r7, r7, #PHYSADDR 106129198Scognet 107135640Scognet /* Disable MMU for a while */ 108135640Scognet mrc p15, 0, r2, c1, c0, 0 109135640Scognet bic r2, r2, #CPU_CONTROL_MMU_ENABLE 110135640Scognet mcr p15, 0, r2, c1, c0, 0 111129198Scognet 112135640Scognet nop 113135640Scognet nop 114135640Scognet nop 115135640Scognet mov pc, r7 116135640ScognetLunmapped: 117135640Scognet 118135640Scognet#ifdef STARTUP_PAGETABLE_ADDR 119129198Scognet /* build page table from scratch */ 120129198Scognet ldr r0, Lstartup_pagetable 121129198Scognet adr r4, mmu_init_table 122129198Scognet b 3f 123129198Scognet 124129198Scognet2: 125129198Scognet str r3, [r0, r2] 126129198Scognet add r2, r2, #4 127129198Scognet add r3, r3, #(L1_S_SIZE) 128129198Scognet adds r1, r1, #-1 129129198Scognet bhi 2b 130129198Scognet3: 131129198Scognet ldmia r4!, {r1,r2,r3} /* # of sections, PA|attr, VA */ 132129198Scognet cmp r1, #0 133140683Scognet adrne r5, 2b 134140683Scognet bicne r5, r5, #0xff000000 135140683Scognet orrne r5, r5, #PHYSADDR 136140683Scognet movne pc, r5 137129198Scognet 138129198Scognet mcr p15, 0, r0, c2, c0, 0 /* Set TTB */ 139129198Scognet mcr p15, 0, r0, c8, c7, 0 /* Flush TLB */ 140129198Scognet 141129198Scognet /* Set the Domain Access register. Very important! */ 142129198Scognet mov r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT) 143129198Scognet mcr p15, 0, r0, c3, c0, 0 144129198Scognet 145129198Scognet /* Enable MMU */ 146129198Scognet mrc p15, 0, r0, c1, c0, 0 147129198Scognet orr r0, r0, #CPU_CONTROL_MMU_ENABLE 148129198Scognet mcr p15, 0, r0, c1, c0, 0 149129198Scognet CPWAIT(r0) 150129198Scognet 151129198Scognet bl mmu_done 152129198Scognetmmu_done: 153129198Scognet#endif 154129198Scognet adr r1, .Lstart 155129198Scognet ldmia r1, {r1, r2, sp} /* Set initial stack and */ 156129198Scognet sub r2, r2, r1 /* get zero init data */ 157129198Scognet mov r3, #0 158129198Scognet 159129198Scognet.L1: 160129198Scognet str r3, [r1], #0x0004 /* Zero the bss */ 161129198Scognet subs r2, r2, #4 162129198Scognet bgt .L1 163129198Scognet 164137273Scognet ldr r4, =KERNVIRTADDR 165137273Scognet cmp pc, r4 166137273Scognet#if KERNVIRTADDR > KERNPHYSADDR 167137273Scognet ldrlt r4, =KERNVIRTADDR 168137273Scognet ldrlt r5, =KERNPHYSADDR 169137273Scognet sublt r4, r4, r5 170137273Scognet addlt pc, pc, r4 171137273Scognet#else 172137273Scognet ldrgt r4, =KERNPHYSADDR 173137273Scognet ldrgt r5, =KERNVIRTADDR 174137273Scognet subgt r4, r4, r5 175137273Scognet sublt pc, pc, r4 176137273Scognet#endif 177135640Scognet ldr fp, =KERNVIRTADDR /* trace back starts here */ 178129198Scognet bl _C_LABEL(initarm) /* Off we go */ 179129198Scognet 180129198Scognet /* init arm will return the new stack pointer. */ 181129198Scognet mov sp, r0 182129198Scognet 183129198Scognet bl _C_LABEL(mi_startup) /* call mi_startup()! */ 184129198Scognet 185129198Scognet adr r0, .Lmainreturned 186130164Sphk b _C_LABEL(panic) 187129198Scognet /* NOTEACHED */ 188129198Scognet#ifdef STARTUP_PAGETABLE_ADDR 189129198Scognet#define MMU_INIT(va,pa,n_sec,attr) \ 190129198Scognet .word n_sec ; \ 191129198Scognet .word 4*((va)>>L1_S_SHIFT) ; \ 192129198Scognet .word (pa)|(attr) ; 193129198Scognet 194129198ScognetLstartup_pagetable: 195129198Scognet .word STARTUP_PAGETABLE_ADDR 196129198Scognetmmu_init_table: 197129198Scognet /* fill all table VA==PA */ 198129198Scognet MMU_INIT(0x00000000, 0x00000000, 1<<(32-L1_S_SHIFT), L1_TYPE_S|L1_S_AP(AP_KRW)) 199129198Scognet /* map SDRAM VA==PA, WT cacheable */ 200135640Scognet MMU_INIT(PHYSADDR, PHYSADDR , 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)) 201135640Scognet /* map VA 0xc0000000..0xc3ffffff to PA */ 202135640Scognet MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW)) 203135640Scognet MMU_INIT(0xfe800000, 0xfe800000, 1<<(32-L1_S_SHIFT), L1_TYPE_S|L1_S_AP(AP_KRW)) 204129198Scognet 205129198Scognet .word 0 /* end of table */ 206129198Scognet#endif 207129198Scognet.Lstart: 208129198Scognet .word _edata 209129198Scognet .word _end 210129198Scognet .word svcstk + INIT_ARM_STACK_SIZE 211129198Scognet 212129198Scognet.Lmainreturned: 213129198Scognet .asciz "main() returned" 214129198Scognet .align 0 215129198Scognet 216129198Scognet .bss 217129198Scognetsvcstk: 218129198Scognet .space INIT_ARM_STACK_SIZE 219129198Scognet 220129198Scognet .text 221129198Scognet .align 0 222129198Scognet 223129198Scognet#ifndef OFW 224129198Scognet /* OFW based systems will used OF_boot() */ 225129198Scognet 226129198Scognet.Lcpufuncs: 227129198Scognet .word _C_LABEL(cpufuncs) 228129198Scognet 229135640ScognetENTRY_NP(cpu_halt) 230129198Scognet mrs r2, cpsr 231129198Scognet bic r2, r2, #(PSR_MODE) 232129198Scognet orr r2, r2, #(PSR_SVC32_MODE) 233129198Scognet orr r2, r2, #(I32_bit | F32_bit) 234129198Scognet msr cpsr_all, r2 235129198Scognet 236129198Scognet ldr r4, .Lcpu_reset_address 237129198Scognet ldr r4, [r4] 238129198Scognet 239129198Scognet ldr r0, .Lcpufuncs 240129198Scognet mov lr, pc 241129198Scognet ldr pc, [r0, #CF_IDCACHE_WBINV_ALL] 242129198Scognet 243129198Scognet /* 244129198Scognet * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's 245129198Scognet * necessary. 246129198Scognet */ 247129198Scognet 248129198Scognet ldr r1, .Lcpu_reset_needs_v4_MMU_disable 249129198Scognet ldr r1, [r1] 250129198Scognet cmp r1, #0 251129198Scognet mov r2, #0 252129198Scognet 253129198Scognet /* 254129198Scognet * MMU & IDC off, 32 bit program & data space 255129198Scognet * Hurl ourselves into the ROM 256129198Scognet */ 257129198Scognet mov r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE) 258129198Scognet mcr 15, 0, r0, c1, c0, 0 259129198Scognet mcrne 15, 0, r2, c8, c7, 0 /* nail I+D TLB on ARMv4 and greater */ 260129198Scognet mov pc, r4 261129198Scognet 262129198Scognet /* 263129198Scognet * _cpu_reset_address contains the address to branch to, to complete 264129198Scognet * the cpu reset after turning the MMU off 265129198Scognet * This variable is provided by the hardware specific code 266129198Scognet */ 267129198Scognet.Lcpu_reset_address: 268129198Scognet .word _C_LABEL(cpu_reset_address) 269129198Scognet 270129198Scognet /* 271129198Scognet * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the 272129198Scognet * v4 MMU disable instruction needs executing... it is an illegal instruction 273129198Scognet * on f.e. ARM6/7 that locks up the computer in an endless illegal 274129198Scognet * instruction / data-abort / reset loop. 275129198Scognet */ 276129198Scognet.Lcpu_reset_needs_v4_MMU_disable: 277129198Scognet .word _C_LABEL(cpu_reset_needs_v4_MMU_disable) 278129198Scognet 279129198Scognet#endif /* OFW */ 280129198Scognet 281129198Scognet#ifdef IPKDB 282129198Scognet/* 283129198Scognet * Execute(inst, psr, args, sp) 284129198Scognet * 285129198Scognet * Execute INSTruction with PSR and ARGS[0] - ARGS[3] making 286129198Scognet * available stack at SP for next undefined instruction trap. 287129198Scognet * 288129198Scognet * Move the instruction onto the stack and jump to it. 289129198Scognet */ 290129198ScognetENTRY_NP(Execute) 291129198Scognet mov ip, sp 292129198Scognet stmfd sp!, {r2, r4-r7, fp, ip, lr, pc} 293129198Scognet sub fp, ip, #4 294129198Scognet mov ip, r3 295129198Scognet ldr r7, .Lreturn 296129198Scognet stmfd sp!, {r0, r7} 297129198Scognet adr r7, #.LExec 298129198Scognet mov r5, r1 299129198Scognet mrs r4, cpsr 300129198Scognet ldmia r2, {r0-r3} 301129198Scognet mov r6, sp 302129198Scognet mov sp, ip 303129198Scognet msr cpsr_all, r5 304129198Scognet mov pc, r6 305129198Scognet.LExec: 306129198Scognet mrs r5, cpsr 307129198Scognet/* XXX Cannot switch thus easily back from user mode */ 308129198Scognet msr cpsr_all, r4 309129198Scognet add sp, r6, #8 310129198Scognet ldmfd sp!, {r6} 311129198Scognet stmia r6, {r0-r3} 312129198Scognet mov r0, r5 313129198Scognet ldmdb fp, {r4-r7, fp, sp, pc} 314129198Scognet.Lreturn: 315129198Scognet mov pc, r7 316129198Scognet#endif 317129198Scognet 318129198Scognet/* 319129198Scognet * setjump + longjmp 320129198Scognet */ 321129198ScognetENTRY(setjmp) 322129198Scognet stmia r0, {r4-r14} 323129198Scognet mov r0, #0x00000000 324137463Scognet RET 325129198Scognet 326129198ScognetENTRY(longjmp) 327129198Scognet ldmia r0, {r4-r14} 328129198Scognet mov r0, #0x00000001 329137463Scognet RET 330129198Scognet 331129198Scognet .data 332129198Scognet .global _C_LABEL(esym) 333129198Scognet_C_LABEL(esym): .word _C_LABEL(end) 334129198Scognet 335129198ScognetENTRY_NP(abort) 336129198Scognet b _C_LABEL(abort) 337129198Scognet 338135640ScognetENTRY_NP(sigcode) 339135640Scognet mov r0, sp 340135640Scognet swi SYS_sigreturn 341135640Scognet 342135640Scognet /* Well if that failed we better exit quick ! */ 343135640Scognet 344135640Scognet swi SYS_exit 345135640Scognet b . - 8 346135640Scognet 347135640Scognet .align 0 348135640Scognet .global _C_LABEL(esigcode) 349135640Scognet _C_LABEL(esigcode): 350135640Scognet 351135640Scognet .data 352135640Scognet .global szsigcode 353135640Scognetszsigcode: 354135640Scognet .long esigcode-sigcode 355129198Scognet/* End of locore.S */ 356