summaryrefslogtreecommitdiffstats
path: root/arch/arm/cpu/setupc.S
blob: 7fd5d012f0b14f8e0e60411f42064ff8f5042c54 (plain) (blame)
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
#include <linux/linkage.h>
#include <asm/sections.h>

.section .text.setupc

/*
 * setup_c: copy binary to link address, clear bss and
 * continue executing at new address.
 *
 * This function does not return to the address it is
 * called from, but to the same location in the copied
 * binary.
 */
ENTRY(setup_c)
	push	{r4, r5}
	mov	r5, lr
	bl	get_runtime_offset
	subs	r4, r0, #0
	beq	1f			/* skip memcpy if already at correct address */
	ldr	r0,=_text
	ldr	r2,=__bss_start
	sub	r2, r2, r0
	sub	r1, r0, r4
	bl	memcpy			/* memcpy(_text, _text - offset, __bss_start - _text) */
1:	ldr	r0, =__bss_start
	mov	r1, #0
	ldr	r2, =__bss_stop
	sub	r2, r2, r0
	bl	memset			/* clear bss */
#ifdef CONFIG_MMU
	bl	arm_early_mmu_cache_flush
#endif
	mov	r0, #0
	mcr	p15, 0, r0, c7, c5, 0	/* flush icache */
	add	lr, r5, r4		/* adjust return address to new location */
	pop	{r4, r5}
	mov	pc, lr
ENDPROC(setup_c)

#ifdef CONFIG_RELOCATABLE
/*
 * void relocate_to_adr(unsigned long targetadr)
 *
 * Copy binary to targetadr, relocate code, clear bss and continue
 * executing at new address.
 */
.section .text.relocate_to_adr
ENTRY(relocate_to_adr)
					/* r0: target address */
	push	{r3, r4, r5, r6, r7, r8}
	mov	r7, lr

	mov	r6, r0

	bl	get_runtime_offset

	mov	r5, r0

	ld_var	_text, r0, r4
	mov	r8, r0

	sub	r1, r0, r5		/* r1: from address */

	cmp	r1, r6			/* already at correct address? */
	beq	1f			/* yes, skip copy to new address */

	ld_var	__bss_start, r2, r4

	sub	r2, r2, r0		/* r2: size */
	mov	r0, r6			/* r0: target */

	add	r7, r7, r0		/* adjust return address */
	sub	r7, r7, r1		/* lr += offset */

	bl	memcpy			/* copy binary */

#ifdef CONFIG_MMU
	bl	arm_early_mmu_cache_flush
#endif
	mov	r0,#0
	mcr	p15, 0, r0, c7, c5, 0	/* flush icache */

	ldr	r0,=1f
	sub	r0, r0, r8
	add	r0, r0, r6
	mov	pc, r0			/* jump to relocated address */
1:
	bl	relocate_to_current_adr	/* relocate binary */

	mov	lr, r7

	pop	{r3, r4, r5, r6, r7, r8}
	mov	pc, lr

ENDPROC(relocate_to_adr)
#endif