/* $NetBSD: start.S,v 1.6 2024/02/09 17:39:33 andvar Exp $ */ /* * Copyright (c) 2002 Reinoud Zandijk * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include /* ----------------------------------------------------------------------- */ ENTRY(relocate_code) /* - r0 pointer to configuration structure - r1 pointer to physical restart point - r3 pointer to physical new L1 page address (P) - r4 kernel entry point */ /* save registers / move args up in register bank later */ /* r8-r12 becomes r0-r4 */ stmfd sp!, {r0-r4} ldmfd sp!, {r8-r12} /* * determine processor architecture version. This is necessary for the * correct coprocessor instruction. */ mrc p15, 0, r0, c0, c0, 0 /* read CPU id in r0 */ mov r3, r0 /* store in r3 */ /* assume its ARMv4 instruction set */ mov r14, #1 /* check ARM6. It needs a special mask */ mov r0, #0x0000ff00 mov r1, #0x00000600 /* check for 0xxxxx06xx => ARM6 */ and r2, r3, r0 cmp r2, r1 moveq r14, #0 /* mark v3 */ /* newer ARM's need a different mask */ mov r0, #0x0000f000 /* check for ARM7 and derivatives like the ARM 7500 and ARM 7500FE */ mov r1, #0x00007000 /* check for 0xxxxx7xxx => ARM 7 */ and r2, r3, r0 cmp r2, r1 moveq r14, #0 /* mark v3 */ /* flush everything out before we turn off the MMU */ /* flush ID cache */ mov r0, #0 cmp r14, #0 mcreq p15, 0, r0, c7, c0, 0 /* flush v3 ID cache */ mcrne p15, 0, r0, c7, c7, 0 /* flush v4 ID cache */ mcrne p15, 0, r0, c7, c10, 4 /* drain WB (v4) */ /* flush TLB */ mcr p15, 0, r0, c5, c0, 0 /* flush TLB for v3 and v4 */ /* switch off MMU, IDcache and WB and branch to physical code space */ cmp r14, #0 mrcne p15, 0, r0, c1, c0, 0 /* read processor control register if v4*/ bic r0, r0, #0x3f /* clear only known bits */ moveq r0, #0 /* for v3 just set to zero */ orr r0, r0, #CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_32BP_ENABLE mov r13, r0 /* save this control value in r13 */ cmp r14, #0 mcr p15, 0, r0, c1, c0, 0 /* write control register! */ /*1*/ mcrne p15, 0, r1, c7, c5, 0 /* write zero in ARMv4 MMU disable */ /*2*/ mov pc, r9 /* branch to physical address */ relocate_code_physical_restart: /* we are running in physical flat 1:1 space now */ /* make the screen border red */ mov r4, #0x03400000 mov r0, #0x40000000 orr r0, r0, #0xff str r0, [r4] adr r5, relocate_table_start ldr r6, [r5], #4 /* r6 = number of relocated pages */ loop_relocate_pages: ldr r2, [r5], #4 /* r2 = from address */ ldr r3, [r5], #4 /* r3 = to address */ ldr r7, [r5], #4 /* r7 = number of bytes to travel */ /* its slow ... we dont know anything about alignment here */ loop_one_page: ldr r0, [r2], #4 str r0, [r3], #4 subs r7, r7, #4 bgt loop_one_page subs r6, r6, #1 bne loop_relocate_pages /* make the screen border go green */ mov r0, #0x40000000 orr r0, r0, #0xff00 str r0, [r4] /* OK! all is relocated... now switch over to the new L1 pages */ /* flush ID cache */ mov r0, #0 cmp r14, #0 mcreq p15, 0, r0, c7, c0, 0 /* flush v3 ID cache */ mcrne p15, 0, r0, c7, c7, 0 /* flush v4 ID cache */ /* drain write buffer (v4) */ mov r0, #0 cmp r14, #0 mcrne p15, 0, r0, c7, c10, 4 /* drain WB (v4) */ /* flush TLB */ mcr p15, 0, r0, c5, c0, 0 /* flush TLB for v3 and v4 */ /* set new TLB address */ mov r0, r11 mcr p15, 0, r0, c2, c0, 0 /* write TLB address */ /* Switch on MMU, IDCache and WB and keep on running on flat translated memory */ orr r0, r13, #CPU_CONTROL_LABT_ENABLE | CPU_CONTROL_32BD_ENABLE | CPU_CONTROL_32BP_ENABLE orr r0, r0, #CPU_CONTROL_WBUF_ENABLE | CPU_CONTROL_DC_ENABLE | CPU_CONTROL_MMU_ENABLE mcr p15, 0, r0, c1, c0, 0 /* write register !!! */ mov r0, r0 /* flat */ mov r0, r0 /* flat */ /* not flat anymore but we just continue */ /* make the screen border go blue */ mov r0, #0x40000000 orr r0, r0, #0xff0000 str r0, [r4] /* call the kernel! */ mov r0, r8 /* saved configuration structure */ mov pc, r12 /* entry point ..... bye bye! */ relocate_code_end: b relocate_code_end relocate_table_start: /* relocation table is copied here, so it must be kept small */ /* ----------------------------------------------------------------------- */ /* we are not expected to ever return from here */ ENTRY(start_kernel) /* entry conditions : - on RISC OS page tables in usr26 mode on virtual space - r0 relocation code page (V) - r1 relocation pv offset - r2 configuration structure - r3 relocation table (V) - r4 L1 page descriptor (P) - r5 kernel entry point */ mov ip, sp stmfd sp!, {r4-r9, fp, ip, lr, pc} sub fp, ip, #4 /* get stuff out of the calling frame */ ldr r4, [ip, #0] ldr r5, [ip, #4] /* relocate the relocation routine to the given page */ adr r6, relocate_code ldr r7, =relocate_table_start - relocate_code /* get length to copy */ mov r8, r0 relocate_code_loop: ldr r9, [r6], #4 str r9, [r8], #4 subs r7, r7, #4 bne relocate_code_loop /* now relocate the relocate table onto the same page */ /* next we need to copy the table over */ ldr r6, [r3], #4 /* r6 has number of threes to copy */ str r6, [r8], #4 relocate_table_loop: ldr r9, [r3], #4 str r9, [r8], #4 ldr r9, [r3], #4 str r9, [r8], #4 ldr r9, [r3], #4 str r9, [r8], #4 subs r6, r6, #1 bne relocate_table_loop /* we messed up the data cache : lets read a 64 or 128 kb <-- GROSS */ mov r7, #128*1024 mov r6, #0x8000 /* start of RISCOS application area */ flush_ID_cache_try: ldr r9, [r6], #4 subs r7, r7, #4 bne flush_ID_cache_try /* enter sub26 mode */ swi OS_EnterOS /* go to sup32 mode with ICQ and FIQ disabled */ mrs r6, cpsr bic r6, r6, #PSR_MODE /* clear processor mode */ orr r6, r6, #(I32_bit | F32_bit) /* disable ICQ + FIQ */ orr r6, r6, #PSR_SVC32_MODE /* go to 32 bit supervisor mode */ msr cpsr, r6 mov r0, r0 /* nops ... just in case */ mov r0, r0 /* set up info */ mov r9, r0 /* save relocated page address */ ldr r7, =relocate_code_physical_restart - relocate_code /* get offset */ add r1, r0, r1 /* get physical address */ add r1, r1, r7 /* add offset */ mov r0, r2 /* put configuration structure in r0 */ mov r2, r3 mov r3, r4 /* L1 page descriptor */ mov r4, r5 /* kernel entry point */ mov pc, r9 /* jump to page addr == relocate_code */ emergency_exit: ldmdb fp, {r4-r9, fp, sp, pc}