summaryrefslogtreecommitdiffstats
path: root/arch/arm/cpu/common.c
blob: bc5d9b588251395d5906d2ae0a900fc65bbe030b (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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
 * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <common.h>
#include <init.h>
#include <elf.h>
#include <linux/sizes.h>
#include <asm/system_info.h>
#include <asm/barebox-arm.h>
#include <asm/barebox-arm-head.h>
#include <asm-generic/memory_layout.h>
#include <asm/secure.h>
#include <asm/sections.h>
#include <asm/cache.h>
#include <debug_ll.h>

/**
 * sync_caches_for_execution - synchronize caches for code execution
 *
 * Code has been modified in memory, call this before executing it.
 * This function flushes the data cache up to the point of unification
 * and invalidates the instruction cache.
 */
void sync_caches_for_execution(void)
{
	/*
	 * Despite the name arm_early_mmu_cache_flush not only flushes the
	 * data cache, but also invalidates the instruction cache.
	 */
	arm_early_mmu_cache_flush();
}

#define R_ARM_RELATIVE 23
#define R_AARCH64_RELATIVE 1027

void pbl_barebox_break(void)
{
	__asm__ __volatile__ (
#ifdef CONFIG_PBL_BREAK
#ifdef CONFIG_CPU_V8
		"brk #17\n"
#else
		"bkpt #17\n"
#endif
		"nop\n"
#else
		"nop\n"
		"nop\n"
#endif
	);
}

/*
 * relocate binary to the currently running address
 */
void relocate_to_current_adr(void)
{
	unsigned long offset, offset_var;
	unsigned long __maybe_unused *dynsym, *dynend;
	void *dstart, *dend;

	/* Get offset between linked address and runtime address */
	offset = get_runtime_offset();
	offset_var = global_variable_offset();

	dstart = (void *)__rel_dyn_start + offset_var;
	dend = (void *)__rel_dyn_end + offset_var;

#if defined(CONFIG_CPU_64)
	while (dstart < dend) {
		struct elf64_rela *rel = dstart;

		if (ELF64_R_TYPE(rel->r_info) == R_AARCH64_RELATIVE) {
			unsigned long *fixup = (unsigned long *)(rel->r_offset + offset);

			*fixup = rel->r_addend + offset;
			rel->r_addend += offset;
			rel->r_offset += offset;
		} else {
			putc_ll('>');
			puthex_ll(rel->r_info);
			putc_ll(' ');
			puthex_ll(rel->r_offset);
			putc_ll(' ');
			puthex_ll(rel->r_addend);
			putc_ll('\n');
			panic("");
		}

		dstart += sizeof(*rel);
	}
#elif defined(CONFIG_CPU_32)
	dynsym = (void *)__dynsym_start + offset_var;
	dynend = (void *)__dynsym_end + offset_var;

	while (dstart < dend) {
		struct elf32_rel *rel = dstart;

		if (ELF32_R_TYPE(rel->r_info) == R_ARM_RELATIVE) {
			unsigned long *fixup = (unsigned long *)(rel->r_offset + offset);

			*fixup = *fixup + offset;

			rel->r_offset += offset;
		} else if (ELF32_R_TYPE(rel->r_info) == R_ARM_ABS32) {
			unsigned long r = dynsym[ELF32_R_SYM(rel->r_info) * 4 + 1];
			unsigned long *fixup = (unsigned long *)(rel->r_offset + offset);

			*fixup = *fixup + r + offset;
			rel->r_offset += offset;
		} else {
			putc_ll('>');
			puthex_ll(rel->r_info);
			putc_ll(' ');
			puthex_ll(rel->r_offset);
			putc_ll('\n');
			panic("");
		}

		dstart += sizeof(*rel);
	}

	memset(dynsym, 0, (unsigned long)dynend - (unsigned long)dynsym);
#else
#error "Architecture not specified"
#endif

	sync_caches_for_execution();
}

#ifdef ARM_MULTIARCH

int __cpu_architecture;

int __pure cpu_architecture(void)
{
	if(__cpu_architecture == CPU_ARCH_UNKNOWN)
		__cpu_architecture = arm_early_get_cpu_architecture();

	return __cpu_architecture;
}
#endif

extern int __boot_cpu_mode;

int boot_cpu_mode(void)
{
	return __boot_cpu_mode;
}