summaryrefslogtreecommitdiffstats
path: root/arch/arm/cpu/setupc.S
blob: 8ae7c89a2cd01272f58e2cf9a64f65216c18535e (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
#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
	add	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 */
	bl	sync_caches_for_execution
	sub	lr, r5, r4		/* adjust return address to new location */
	pop	{r4, r5}
	mov	pc, lr
ENDPROC(setup_c)

/*
 * void relocate_to_adr(unsigned long targetadr)
 *
 * Copy binary to targetadr, relocate code 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

	ldr	r8, =_text

	add	r1, r8, r5		/* r1: from address */

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

	ldr	r2, =__bss_start

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

	/* adjust return address */
	sub	r7, r7, r1		/* sub address where we are actually running */
	add	r7, r7, r0		/* add address where we are going to run */

	bl	memcpy			/* copy binary */

	bl	sync_caches_for_execution

	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)