summaryrefslogtreecommitdiffstats
path: root/arch/arm/include/asm/barebox-arm.h
blob: 15b3b6c4447932a920839d4ee35d5037e12d2f65 (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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * (C) Copyright 2002
 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
 * Marius Groeger <mgroeger@sysgo.de>
 *
 * (C) Copyright 2002
 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
 * Alex Zuepke <azu@sysgo.de>
 */

#ifndef _BAREBOX_ARM_H_
#define _BAREBOX_ARM_H_

#include <linux/sizes.h>
#include <asm-generic/memory_layout.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/compiler.h>
#include <asm/barebox-arm-head.h>
#include <asm/common.h>
#include <asm/sections.h>

/*
 * We have a 4GiB address space split into 1MiB sections, with each
 * section header taking 4 bytes
 */
#define ARM_TTB_SIZE	(SZ_4G / SZ_1M * sizeof(u32))

unsigned long get_runtime_offset(void);

/* global_variable_offset() - Access global variables when not running at link address
 *
 * Get the offset of global variables when not running at the address we are
 * linked at.
 */
static inline unsigned long global_variable_offset(void)
{
#ifdef CONFIG_CPU_V8
	unsigned long text;

	__asm__ __volatile__(
		"adr    %0, _text\n"
		: "=r" (text)
		:
		: "memory");
	return text - (unsigned long)_text;
#else
	return get_runtime_offset();
#endif
}

void setup_c(void);
void pbl_barebox_break(void);
void relocate_to_current_adr(void);
void relocate_to_adr(unsigned long target);
void relocate_to_adr_full(unsigned long target);
void __noreturn barebox_arm_entry(unsigned long membase, unsigned long memsize, void *boarddata);

struct barebox_arm_boarddata {
#define BAREBOX_ARM_BOARDDATA_MAGIC	0xabe742c3
	u32 magic;
	u32 machine; /* machine number to pass to barebox. This may or may
		      * not be a ARM machine number registered on arm.linux.org.uk.
		      * It must only be unique across barebox. Please use a number
		      * that do not potientially clashes with registered machines,
		      * i.e. use a number > 0x10000.
		      */
};

/*
 * Create a boarddata struct at given address. Suitable to be passed
 * as boarddata to barebox_arm_entry(). The machine can be retrieved
 * later with barebox_arm_machine().
 */
static inline void boarddata_create(void *adr, u32 machine)
{
	struct barebox_arm_boarddata *bd = adr;

	bd->magic = BAREBOX_ARM_BOARDDATA_MAGIC;
	bd->machine = machine;
}

u32 barebox_arm_machine(void);

unsigned long arm_mem_ramoops_get(void);
unsigned long arm_mem_endmem_get(void);

struct barebox_arm_boarddata *barebox_arm_get_boarddata(void);

#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_ARM_EXCEPTIONS)
void arm_fixup_vectors(void);
#else
static inline void arm_fixup_vectors(void)
{
}
#endif

void *barebox_arm_boot_dtb(void);

#define __arm_mem_stack_top(membase, endmem) ((endmem) - SZ_64K)

#if defined(CONFIG_BOOTM_OPTEE) || defined(CONFIG_PBL_OPTEE)
#define arm_mem_stack_top(membase, endmem) (__arm_mem_stack_top(membase, endmem) - OPTEE_SIZE)
#else
#define arm_mem_stack_top(membase, endmem)  __arm_mem_stack_top(membase, endmem)
#endif

static inline unsigned long arm_mem_stack(unsigned long membase,
					  unsigned long endmem)
{
	return arm_mem_stack_top(membase, endmem) - STACK_SIZE;
}

static inline unsigned long arm_mem_ttb(unsigned long membase,
					unsigned long endmem)
{
	endmem = arm_mem_stack(membase, endmem);
	endmem = ALIGN_DOWN(endmem, ARM_TTB_SIZE) - ARM_TTB_SIZE;

	return endmem;
}

static inline unsigned long arm_mem_early_malloc(unsigned long membase,
						 unsigned long endmem)
{
	return arm_mem_ttb(membase, endmem) - SZ_128K;
}

static inline unsigned long arm_mem_early_malloc_end(unsigned long membase,
						     unsigned long endmem)
{
	return arm_mem_ttb(membase, endmem);
}

static inline unsigned long arm_mem_ramoops(unsigned long membase,
					    unsigned long endmem)
{
	endmem = arm_mem_ttb(membase, endmem);
#ifdef CONFIG_FS_PSTORE_RAMOOPS
	endmem -= CONFIG_FS_PSTORE_RAMOOPS_SIZE;
	endmem = ALIGN_DOWN(endmem, SZ_4K);
#endif

	return endmem;
}

static inline unsigned long arm_mem_barebox_image(unsigned long membase,
						  unsigned long endmem,
						  unsigned long size)
{
	endmem = arm_mem_ramoops(membase, endmem);

	if (IS_ENABLED(CONFIG_RELOCATABLE)) {
		return ALIGN_DOWN(endmem - size, SZ_1M);
	} else {
		if (TEXT_BASE >= membase && TEXT_BASE < endmem)
			return TEXT_BASE;
		else
			return endmem;
	}
}

#ifdef CONFIG_CPU_64

#define ____emit_entry_prologue(instr, ...) do { \
	static __attribute__ ((unused,section(".text_head_prologue"))) \
		const u32 __entry_prologue[] = {(instr), ##__VA_ARGS__}; \
	barrier_data(__entry_prologue); \
} while(0)

#define __emit_entry_prologue(instr1, instr2, instr3, instr4, instr5) \
	____emit_entry_prologue(instr1, instr2, instr3, instr4, instr5)

#define __ARM_SETUP_STACK(stack_top) \
	__emit_entry_prologue(0x14000002	/* b pc+0x8 */,		\
			      stack_top		/* 32-bit literal */,	\
			      0x18ffffe9	/* ldr w9, top */,	\
			      0xb4000049	/* cbz x9, pc+0x8 */,	\
			      0x9100013f	/* mov sp, x9 */)
#else
#define __ARM_SETUP_STACK(stack_top) if (stack_top) arm_setup_stack(stack_top)
#endif

/*
 * Unlike ENTRY_FUNCTION, this can be used to setup stack for a C entry
 * point on both ARM32 and ARM64. ENTRY_FUNCTION on ARM64 can only be used
 * if preceding boot stage has initialized the stack pointer.
 *
 * Stack top of 0 means stack is already set up. In that case, the follow-up
 * code block will not be inlined and may spill to stack right away.
 */
#ifdef CONFIG_CPU_64
#define ENTRY_FUNCTION_WITHSTACK(name, stack_top, arg0, arg1, arg2)	\
	void name(ulong r0, ulong r1, ulong r2);			\
									\
	static void __##name(ulong, ulong, ulong);			\
									\
	void __section(.text_head_entry_##name)	name			\
				(ulong r0, ulong r1, ulong r2)		\
		{							\
			__barebox_arm_head();				\
			__ARM_SETUP_STACK(stack_top);			\
			__##name(r0, r1, r2);				\
		}							\
		static void noinline __##name				\
			(ulong arg0, ulong arg1, ulong arg2)
#else
#define ENTRY_FUNCTION_WITHSTACK(name, stack_top, arg0, arg1, arg2)	\
	static void ____##name(ulong, ulong, ulong);			\
	ENTRY_FUNCTION(name, arg0, arg1, arg2)				\
	{								\
		__ARM_SETUP_STACK(stack_top);				\
		____##name(arg0, arg1, arg2);				\
	}								\
	static void noinline ____##name					\
		(ulong arg0, ulong arg1, ulong arg2)
#endif


#define ENTRY_FUNCTION(name, arg0, arg1, arg2)				\
	void name(ulong r0, ulong r1, ulong r2);			\
									\
	static void __##name(ulong, ulong, ulong);			\
									\
	void NAKED __section(.text_head_entry_##name)	name		\
				(ulong r0, ulong r1, ulong r2)		\
		{							\
			__barebox_arm_head();				\
			__ARM_SETUP_STACK(0);				\
			__##name(r0, r1, r2);				\
		}							\
		static void NAKED noinline __##name			\
			(ulong arg0, ulong arg1, ulong arg2)

/*
 * When using compressed images in conjunction with relocatable images
 * the PBL code must pick a suitable place where to uncompress the barebox
 * image. For doing this the PBL code must know the size of the final
 * image including the BSS segment. The BSS size is unknown to the PBL
 * code, so define a maximum BSS size here.
 */
#define MAX_BSS_SIZE SZ_1M

#define barebox_image_size (__image_end - __image_start)

#ifdef CONFIG_CPU_32
#define NAKED __naked
#else
/*
 * There is no naked support for aarch64, so do not rely on it.
 * This basically means we must have a stack configured when a
 * function with the naked attribute is entered. On nowadays hardware
 * the ROM should have some basic stack already. If not, set one
 * up before jumping into the barebox entry functions.
 */
#define NAKED
#endif

#endif	/* _BAREBOX_ARM_H_ */