summaryrefslogtreecommitdiffstats
path: root/arch/arm/include/asm/barebox-arm.h
blob: 7a7e5a2403171853210898387c8328176c87f4a6 (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
/* 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/pagemap.h>
#include <linux/types.h>
#include <linux/compiler.h>
#include <asm/barebox-arm-head.h>
#include <asm/common.h>
#include <asm/sections.h>
#include <asm/reloc.h>
#include <linux/stringify.h>
#include <boarddata.h>

#define ARM_EARLY_PAGETABLE_SIZE	SZ_64K

void __noreturn barebox_arm_entry(unsigned long membase, unsigned long memsize, void *boarddata);

#define barebox_arm_boarddata		barebox_boarddata
#define BAREBOX_ARM_BOARDDATA_MAGIC	BAREBOX_BOARDDATA_MAGIC

u32 barebox_arm_machine(void);

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

struct barebox_arm_boarddata *barebox_arm_get_boarddata(void);

#define barebox_arm_get_boarddata barebox_get_boarddata

#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);

static inline unsigned long arm_mem_optee(unsigned long endmem)
{
	return endmem - OPTEE_SIZE;
}

static inline unsigned long arm_mem_scratch(unsigned long endmem)
{
	return arm_mem_optee(endmem) - SZ_32K;
}

static inline unsigned long arm_mem_stack(unsigned long endmem)
{
	return arm_mem_scratch(endmem) - STACK_SIZE;
}

static inline unsigned long arm_mem_guard_page(unsigned long endmem)
{
	endmem = arm_mem_stack(endmem);

	if (!IS_ENABLED(CONFIG_STACK_GUARD_PAGE))
		return endmem;

	return ALIGN_DOWN(endmem, PAGE_SIZE) - PAGE_SIZE;
}

static inline unsigned long arm_mem_ttb(unsigned long endmem)
{
	endmem = arm_mem_guard_page(endmem);
	endmem = ALIGN_DOWN(endmem, ARM_EARLY_PAGETABLE_SIZE) - ARM_EARLY_PAGETABLE_SIZE;

	return endmem;
}

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

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

static inline unsigned long arm_mem_ramoops(unsigned long endmem)
{
	endmem = arm_mem_ttb(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_stack_top(unsigned long endmem)
{
	return arm_mem_stack(endmem) + STACK_SIZE;
}

static inline const void *arm_mem_scratch_get(void)
{
	return (const void *)arm_mem_scratch(arm_mem_endmem_get());
}

static inline unsigned long arm_mem_guard_page_get(void)
{
	return arm_mem_guard_page(arm_mem_endmem_get());
}

static inline unsigned long arm_mem_barebox_image(unsigned long membase,
						  unsigned long endmem,
						  unsigned long size)
{
	endmem = arm_mem_ramoops(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;
	}
}

/*
 * 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

void __barebox_arm64_head(ulong x0, ulong x1, ulong x2);

#define ENTRY_FUNCTION_WITHSTACK_HEAD(name, stack_top, head, 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)		\
		{							\
			static __section(.pbl_board_stack_top_##name)	\
				const ulong __stack_top = (stack_top);	\
			__keep_symbolref(head);				\
			__keep_symbolref(__stack_top);			\
			__##name(r0, r1, r2);				\
		}							\
		static void noinline __##name				\
			(ulong arg0, ulong arg1, ulong arg2)

#define ENTRY_FUNCTION_WITHSTACK(name, stack_top, arg0, arg1, arg2)	\
	ENTRY_FUNCTION_WITHSTACK_HEAD(name, stack_top,			\
			      __barebox_arm64_head, arg0, arg1, arg2)

#define ENTRY_FUNCTION(name, arg0, arg1, arg2)				\
	ENTRY_FUNCTION_WITHSTACK(name, 0, arg0, arg1, arg2)

#else
#define ENTRY_FUNCTION_WITHSTACK_HEAD(name, stack_top, head, arg0, arg1, arg2)	\
	static void ____##name(ulong, ulong, ulong);			\
	__ENTRY_FUNCTION_HEAD(name, head, arg0, arg1, arg2)		\
	{								\
		if (stack_top)						\
			arm_setup_stack(stack_top);			\
		____##name(arg0, arg1, arg2);				\
	}								\
	static void noinline ____##name					\
		(ulong arg0, ulong arg1, ulong arg2)

#define __ENTRY_FUNCTION_HEAD(name, head, 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)		\
		{							\
			head();				\
			__##name(r0, r1, r2);				\
		}							\
	static void __naked noinline __##name				\
		(ulong arg0, ulong arg1, ulong arg2)

#define ENTRY_FUNCTION(name, arg0, arg1, arg2)		\
	__ENTRY_FUNCTION_HEAD(name, __barebox_arm_head, arg0, arg1, arg2)

#define ENTRY_FUNCTION_WITHSTACK(name, stack_top, arg0, arg1, arg2)	\
	ENTRY_FUNCTION_WITHSTACK_HEAD(name, stack_top, \
			      __barebox_arm_head, arg0, arg1, arg2)
#endif

/*
 * 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_ */