root/stand/kboot/kboot/arch/powerpc64/kerneltramp.S
/*
 * This is the analog to the kexec "purgatory" code
 *
 * The goal here is to call the actual kernel entry point with the arguments it
 * expects when kexec calls into it with no arguments. The value of the kernel
 * entry point and arguments r3-r7 are copied into the trampoline text (which
 * can be executed from any address) at bytes 8-32. kexec begins execution
 * of APs at 0x60 bytes past the entry point, executing in a copy relocated
 * to the absolute address 0x60. Here we implement a loop waiting on the release
 * of a lock by the kernel at 0x40.
 * 
 */

#include <machine/asm.h>

        .globl  CNAME(kerneltramp),CNAME(szkerneltramp)
CNAME(kerneltramp):
        mflr %r9
        bl 2f
        .space 24       /* branch address, r3-r7 */

/*
 * MUST BE IN SYNC WITH:
 *  struct trampoline_data {
 *   uint32_t   kernel_entry;
 *   uint32_t   dtb;
 *   uint32_t   phys_mem_offset;
 *   uint32_t   of_entry;
 *   uint32_t   mdp;
 *   uint32_t   mdp_size;
 *  };
 */

. = kerneltramp + 0x40  /* AP spinlock */
        .long 0

. = kerneltramp + 0x60  /* AP entry point */
        li      %r3,0x40
1:      lwz     %r1,0(%r3)
        cmpwi   %r1,0
        beq     1b

        /* Jump into CPU reset */
        li      %r0,0x100
        icbi    0,%r0
        isync
        sync
        ba      0x100

2:      /* Continuation of kerneltramp */
        mflr    %r8
        mtlr    %r9

        mfmsr   %r10
        andi.   %r10, %r10, 1   /* test MSR_LE */
        bne     little_endian

/* We're starting in BE */
big_endian:
        lwz     %r3,4(%r8)
        lwz     %r4,8(%r8)
        lwz     %r5,12(%r8)
        lwz     %r6,16(%r8)
        lwz     %r7,20(%r8)

        lwz     %r10, 0(%r8)
        mtctr   %r10
        bctr

/* We're starting in LE */
little_endian:

        /* Entries are BE, swap them during load. */
        li      %r10, 4
        lwbrx   %r3, %r8, %r10
        li      %r10, 8
        lwbrx   %r4, %r8, %r10
        li      %r10, 12
        lwbrx   %r5, %r8, %r10
        li      %r10, 16
        lwbrx   %r6, %r8, %r10
        li      %r10, 20
        lwbrx   %r7, %r8, %r10

        /* Clear MSR_LE flag to enter the BE world */
        mfmsr   %r10
        clrrdi  %r10, %r10, 1
        mtsrr1  %r10

        /* Entry is at 0(%r8) */
        li      %r10, 0
        lwbrx   %r10, %r8, %r10
        mtsrr0  %r10

        rfid

endkerneltramp:

        .data
CNAME(szkerneltramp):
        .long endkerneltramp - CNAME(kerneltramp)

        .section .note.GNU-stack,"",%progbits