1276413Snwhitehorn/*
2276413Snwhitehorn * This is the analog to the kexec "purgatory" code
3276413Snwhitehorn *
4276413Snwhitehorn * The goal here is to call the actual kernel entry point with the arguments it
5276413Snwhitehorn * expects when kexec calls into it with no arguments. The value of the kernel
6276687Snwhitehorn * entry point and arguments r3-r7 are copied into the trampoline text (which
7276687Snwhitehorn * can be executed from any address) at bytes 8-32. kexec begins execution
8276687Snwhitehorn * of APs at 0x60 bytes past the entry point, executing in a copy relocated
9276687Snwhitehorn * to the absolute address 0x60. Here we implement a loop waiting on the release
10276687Snwhitehorn * of a lock by the kernel at 0x40.
11276413Snwhitehorn *
12277997Snwhitehorn * $FreeBSD: stable/11/stand/powerpc/kboot/kerneltramp.S 329183 2018-02-12 20:51:28Z kevans $
13276413Snwhitehorn */
14276413Snwhitehorn
15276413Snwhitehorn#include <machine/asm.h>
16276413Snwhitehorn
17276413Snwhitehorn        .globl  CNAME(kerneltramp),CNAME(szkerneltramp)
18276413SnwhitehornCNAME(kerneltramp):
19276413Snwhitehorn	mflr %r9
20276687Snwhitehorn	bl 2f
21276413Snwhitehorn	.space 24	/* branch address, r3-r7 */
22276687Snwhitehorn
23329183Skevans/*
24329183Skevans * MUST BE IN SYNC WITH:
25329183Skevans *  struct trampoline_data {
26329183Skevans *   uint32_t	kernel_entry;
27329183Skevans *   uint32_t	dtb;
28329183Skevans *   uint32_t	phys_mem_offset;
29329183Skevans *   uint32_t	of_entry;
30329183Skevans *   uint32_t	mdp;
31329183Skevans *   uint32_t	mdp_size;
32329183Skevans *  };
33329183Skevans */
34329183Skevans
35276687Snwhitehorn. = kerneltramp + 0x40	/* AP spinlock */
36276687Snwhitehorn	.long 0
37276687Snwhitehorn
38276687Snwhitehorn. = kerneltramp + 0x60	/* AP entry point */
39276687Snwhitehorn	li	%r3,0x40
40276687Snwhitehorn1:	lwz	%r1,0(%r3)
41276687Snwhitehorn	cmpwi	%r1,0
42276687Snwhitehorn	beq	1b
43276687Snwhitehorn
44276687Snwhitehorn	/* Jump into CPU reset */
45276687Snwhitehorn	li	%r0,0x100
46276687Snwhitehorn	icbi	0,%r0
47276687Snwhitehorn	isync
48276687Snwhitehorn	sync
49276687Snwhitehorn	ba	0x100
50276687Snwhitehorn
51329183Skevans2:	/* Continuation of kerneltramp */
52276413Snwhitehorn	mflr	%r8
53276413Snwhitehorn	mtlr	%r9
54329183Skevans
55329183Skevans	mfmsr	%r10
56329183Skevans	andi.	%r10, %r10, 1	/* test MSR_LE */
57329183Skevans	bne	little_endian
58329183Skevans
59329183Skevans/* We're starting in BE */
60329183Skevansbig_endian:
61276413Snwhitehorn	lwz	%r3,4(%r8)
62276413Snwhitehorn	lwz	%r4,8(%r8)
63276413Snwhitehorn	lwz	%r5,12(%r8)
64276413Snwhitehorn	lwz	%r6,16(%r8)
65276413Snwhitehorn	lwz	%r7,20(%r8)
66329183Skevans
67329183Skevans	lwz	%r10, 0(%r8)
68329183Skevans	mtctr	%r10
69276413Snwhitehorn	bctr
70329183Skevans
71329183Skevans/* We're starting in LE */
72329183Skevanslittle_endian:
73329183Skevans
74329183Skevans	/* Entries are BE, swap them during load. */
75329183Skevans	li	%r10, 4
76329183Skevans	lwbrx	%r3, %r8, %r10
77329183Skevans	li	%r10, 8
78329183Skevans	lwbrx	%r4, %r8, %r10
79329183Skevans	li	%r10, 12
80329183Skevans	lwbrx	%r5, %r8, %r10
81329183Skevans	li	%r10, 16
82329183Skevans	lwbrx	%r6, %r8, %r10
83329183Skevans	li	%r10, 20
84329183Skevans	lwbrx	%r7, %r8, %r10
85329183Skevans
86329183Skevans	/* Clear MSR_LE flag to enter the BE world */
87329183Skevans	mfmsr	%r10
88329183Skevans	clrrdi	%r10, %r10, 1
89329183Skevans	mtsrr1	%r10
90329183Skevans
91329183Skevans	/* Entry is at 0(%r8) */
92329183Skevans	li	%r10, 0
93329183Skevans	lwbrx	%r10, %r8, %r10
94329183Skevans	mtsrr0	%r10
95329183Skevans
96329183Skevans	rfid
97329183Skevans
98276413Snwhitehornendkerneltramp:
99276413Snwhitehorn
100276413Snwhitehorn	.data
101276413SnwhitehornCNAME(szkerneltramp):
102276413Snwhitehorn	.long endkerneltramp - CNAME(kerneltramp)
103