diff options
Diffstat (limited to 'sys/boot/powerpc/ps3/start.S')
-rw-r--r-- | sys/boot/powerpc/ps3/start.S | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/sys/boot/powerpc/ps3/start.S b/sys/boot/powerpc/ps3/start.S new file mode 100644 index 000000000000..570b3f52cc68 --- /dev/null +++ b/sys/boot/powerpc/ps3/start.S @@ -0,0 +1,169 @@ +/*- + * Copyright (C) 2010 Nathan Whitehorn + * 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. + * + * 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 TOOLS GMBH 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. + * + * $FreeBSD$ + */ + +#define LOCORE + +#include <machine/trap.h> + +/* + * KBoot and simulators will start this program from the _start symbol, with + * r3 pointing to a flattened device tree (kexec), r4 the physical address + * at which we were loaded, and r5 0 (kexec) or a pointer to Open Firmware + * (simulator). If r4 is non-zero, the first order of business is relocating + * ourselves to 0. In the kboot case, the PPE secondary thread will enter + * at 0x60. + * + * If started directly by the LV1 hypervisor, we are loaded to address 0 + * and execution on both threads begins at 0x100 (EXC_RST). + */ + +#define CACHELINE_SIZE 128 +#define SPR_CTRL 136 + +/* KBoot thread 0 entry -- do relocation, then jump to main */ +.global _start +_start: + mfmsr %r31 + clrldi %r31,%r31,1 + mtmsrd %r31 + isync + cmpwi %r4,0 + bne relocate_self +relocated_start: + lis %r1,0x100 + bl main + +. = 0x40 +.global secondary_spin_sem +secondary_spin_sem: + .long 0 + +. = 0x60 +thread1_start_kboot: + mfmsr %r31 + clrldi %r31,%r31,1 + mtmsrd %r31 + isync + + ba thread1_start /* kboot copies the first 256 bytes to + * address 0, so we are safe to jump + * (and stay) there */ + +thread1_start: + li %r3,secondary_spin_sem@l +1: lwz %r1,0(%r3) /* Spin on SECONDARY_SPIN_SEM_ADDRESS */ + cmpwi %r1,0 + beq 1b /* If the semaphore is still zero, spin again */ + + /* We have been woken up by thread 0 */ + li %r0,0x100 /* Invalidate reset vector cache line */ + icbi 0,%r0 + isync + sync + ba 0x100 /* Jump to the reset vector */ + +. = EXC_RST +exc_rst: + mfmsr %r31 + clrldi %r31,%r31,1 + mtmsrd %r31 + isync + + mfspr %r3,SPR_CTRL + /* The first two bits of r0 are 01 (thread 1) or 10 (thread 0) */ + cntlzw %r3,%r3 /* Now 0 for thread 0, 1 for thread 1 */ + + cmpwi %r3,0 + bne thread1_start /* Send thread 1 to wait */ + + b relocated_start /* Main entry point for thread 0 */ + +#define EXCEPTION_HANDLER(exc) \ +. = exc; \ + li %r3, exc; \ + mfsrr0 %r4; \ + mfmsr %r5; \ + clrldi %r6,%r5,1; \ + mtmsrd %r6; \ + isync; \ + lis %r1,0x100; \ + bl ppc_exception + +EXCEPTION_HANDLER(EXC_MCHK) +EXCEPTION_HANDLER(EXC_DSI) +EXCEPTION_HANDLER(EXC_DSE) +EXCEPTION_HANDLER(EXC_ISI) +EXCEPTION_HANDLER(EXC_ISE) +EXCEPTION_HANDLER(EXC_EXI) +EXCEPTION_HANDLER(EXC_ALI) +EXCEPTION_HANDLER(EXC_PGM) +EXCEPTION_HANDLER(EXC_FPU) +EXCEPTION_HANDLER(EXC_DECR) +EXCEPTION_HANDLER(EXC_SC) + +relocate_self: + /* We enter this with r4 the physical offset for our relocation */ + lis %r8,_end@ha /* r8: copy length */ + addi %r8,%r8,_end@l + li %r5,0x100 /* r5: dest address */ +1: add %r6,%r4,%r5 /* r6: source address */ + ld %r7,0(%r6) + std %r7,0(%r5) + addi %r5,%r5,8 + cmpw %r5,%r8 + blt 1b + + /* + * Now invalidate the cacheline with the second half of relocate_self, + * and do an absolute branch there in case we overwrote part of + * ourselves. + */ + + lis %r9,relocate_self_cache@ha + addi %r9,%r9,relocate_self_cache@l + dcbst 0,%r9 + sync + icbi 0,%r9 + sync + isync + ba relocate_self_cache + +relocate_self_cache: + /* Now invalidate the icache */ + li %r5,0x100 +2: dcbst 0,%r5 + sync + icbi 0,%r5 + sync + isync + cmpw %r5,%r8 + addi %r5,%r5,CACHELINE_SIZE + blt 2b + + /* All done: absolute jump to relocated entry point */ + ba relocated_start + |