aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/kernel/relocate_kernel.S
blob: f5342939d95ae9b4784cf4051567da688403b716 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 * relocate_kernel.S - put the kernel image in place to boot
 */

#include <asm/kexec.h>

#ifdef CONFIG_KEXEC_HARDBOOT
#include <asm/memory.h>
#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
  #include <mach/iomap.h>
#elif defined(CONFIG_ARCH_APQ8064)
  #include <mach/msm_iomap.h>
#endif
#endif

	.globl relocate_new_kernel
relocate_new_kernel:

	ldr	r0,kexec_indirection_page
	ldr	r1,kexec_start_address

	/*
	 * If there is no indirection page (we are doing crashdumps)
	 * skip any relocation.
	 */
	cmp	r0, #0
	beq	2f

0:	/* top, read another word for the indirection page */
	ldr	r3, [r0],#4

	/* Is it a destination page. Put destination address to r4 */
	tst	r3,#1,0
	beq	1f
	bic	r4,r3,#1
	b	0b
1:
	/* Is it an indirection page */
	tst	r3,#2,0
	beq	1f
	bic	r0,r3,#2
	b	0b
1:

	/* are we done ? */
	tst	r3,#4,0
	beq	1f
	b	2f

1:
	/* is it source ? */
	tst	r3,#8,0
	beq	0b
	bic r3,r3,#8
	mov r6,#1024
9:
	ldr r5,[r3],#4
	str r5,[r4],#4
	subs r6,r6,#1
	bne 9b
	b 0b

2:
#ifdef CONFIG_KEXEC_HARDBOOT
	ldr	r0, kexec_hardboot
	teq	r0, #0
	bne	hardboot
#endif

	/* Jump to relocated kernel */
	mov lr,r1
	mov r0,#0
	ldr r1,kexec_mach_type
	ldr r2,kexec_boot_atags
 ARM(	mov pc, lr	)
 THUMB(	bx lr		)

#ifdef CONFIG_KEXEC_HARDBOOT
hardboot:
	/* Stash boot arguments in hardboot page:
	 *  0: KEXEC_HB_PAGE_MAGIC
	 *  4: kexec_start_address
	 *  8: kexec_mach_type
	 * 12: kexec_boot_atags */
	ldr	r0, =KEXEC_HB_PAGE_ADDR
	str	r1, [r0, #4]
	ldr	r1, kexec_mach_type
	str	r1, [r0, #8]
	ldr	r1, kexec_boot_atags
	str	r1, [r0, #12]
	ldr	r1, =KEXEC_HB_PAGE_MAGIC
	str	r1, [r0]

#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
	ldr     r0, =TEGRA_PMC_BASE
	ldr	r1, [r0]
	orr	r1, r1, #0x10
	str	r1, [r0]
loop:	b	loop
#elif defined(CONFIG_ARCH_APQ8064)
	/* Restart using the PMIC chip, see mach-msm/restart.c */
	ldr	r0, =APQ8064_TLMM_PHYS
	mov	r1, #0
	str	r1, [r0, #0x820]  @ PSHOLD_CTL_SU
loop:	b	loop
#else
#error "No reboot method defined for hardboot."
#endif

	.ltorg
#endif
	.align

	.globl kexec_start_address
kexec_start_address:
	.long	0x0

	.globl kexec_indirection_page
kexec_indirection_page:
	.long	0x0

	.globl kexec_mach_type
kexec_mach_type:
	.long	0x0

	/* phy addr of the atags for the new kernel */
	.globl kexec_boot_atags
kexec_boot_atags:
	.long	0x0

#ifdef CONFIG_KEXEC_HARDBOOT
	.globl kexec_hardboot
kexec_hardboot:
	.long	0x0
#endif

relocate_new_kernel_end:

	.globl relocate_new_kernel_size
relocate_new_kernel_size:
	.long relocate_new_kernel_end - relocate_new_kernel