freebsd-dev/stand/powerpc/kboot/kerneltramp.S

103 lines
2.0 KiB
ArmAsm
Raw Normal View History

/*
* 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.
*
* $FreeBSD$
*/
#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)