162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_POWERPC_HEAD_64_H
362306a36Sopenharmony_ci#define _ASM_POWERPC_HEAD_64_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <asm/cache.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#ifdef __ASSEMBLY__
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * We can't do CPP stringification and concatination directly into the section
1062306a36Sopenharmony_ci * name for some reason, so these macros can do it for us.
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci.macro define_ftsec name
1362306a36Sopenharmony_ci	.section ".head.text.\name\()","ax",@progbits
1462306a36Sopenharmony_ci.endm
1562306a36Sopenharmony_ci.macro define_data_ftsec name
1662306a36Sopenharmony_ci	.section ".head.data.\name\()","a",@progbits
1762306a36Sopenharmony_ci.endm
1862306a36Sopenharmony_ci.macro use_ftsec name
1962306a36Sopenharmony_ci	.section ".head.text.\name\()","ax",@progbits
2062306a36Sopenharmony_ci.endm
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/*
2362306a36Sopenharmony_ci * Fixed (location) sections are used by opening fixed sections and emitting
2462306a36Sopenharmony_ci * fixed section entries into them before closing them. Multiple fixed sections
2562306a36Sopenharmony_ci * can be open at any time.
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * Each fixed section created in a .S file must have corresponding linkage
2862306a36Sopenharmony_ci * directives including location, added to  arch/powerpc/kernel/vmlinux.lds.S
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * For each fixed section, code is generated into it in the order which it
3162306a36Sopenharmony_ci * appears in the source.  Fixed section entries can be placed at a fixed
3262306a36Sopenharmony_ci * location within the section using _LOCATION postifx variants. These must
3362306a36Sopenharmony_ci * be ordered according to their relative placements within the section.
3462306a36Sopenharmony_ci *
3562306a36Sopenharmony_ci * OPEN_FIXED_SECTION(section_name, start_address, end_address)
3662306a36Sopenharmony_ci * FIXED_SECTION_ENTRY_BEGIN(section_name, label1)
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * USE_FIXED_SECTION(section_name)
3962306a36Sopenharmony_ci * label3:
4062306a36Sopenharmony_ci *     li  r10,128
4162306a36Sopenharmony_ci *     mv  r11,r10
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci * FIXED_SECTION_ENTRY_BEGIN_LOCATION(section_name, label2, start_address, size)
4462306a36Sopenharmony_ci * FIXED_SECTION_ENTRY_END_LOCATION(section_name, label2, start_address, size)
4562306a36Sopenharmony_ci * CLOSE_FIXED_SECTION(section_name)
4662306a36Sopenharmony_ci *
4762306a36Sopenharmony_ci * ZERO_FIXED_SECTION can be used to emit zeroed data.
4862306a36Sopenharmony_ci *
4962306a36Sopenharmony_ci * Troubleshooting:
5062306a36Sopenharmony_ci * - If the build dies with "Error: attempt to move .org backwards" at
5162306a36Sopenharmony_ci *   CLOSE_FIXED_SECTION() or elsewhere, there may be something
5262306a36Sopenharmony_ci *   unexpected being added there. Remove the '. = x_len' line, rebuild, and
5362306a36Sopenharmony_ci *   check what is pushing the section down.
5462306a36Sopenharmony_ci * - If the build dies in linking, check arch/powerpc/tools/head_check.sh
5562306a36Sopenharmony_ci *   comments.
5662306a36Sopenharmony_ci * - If the kernel crashes or hangs in very early boot, it could be linker
5762306a36Sopenharmony_ci *   stubs at the start of the main text.
5862306a36Sopenharmony_ci */
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define OPEN_FIXED_SECTION(sname, start, end)			\
6162306a36Sopenharmony_ci	sname##_start = (start);				\
6262306a36Sopenharmony_ci	sname##_end = (end);					\
6362306a36Sopenharmony_ci	sname##_len = (end) - (start);				\
6462306a36Sopenharmony_ci	define_ftsec sname;					\
6562306a36Sopenharmony_ci	. = 0x0;						\
6662306a36Sopenharmony_cistart_##sname:
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/*
6962306a36Sopenharmony_ci * .linker_stub_catch section is used to catch linker stubs from being
7062306a36Sopenharmony_ci * inserted in our .text section, above the start_text label (which breaks
7162306a36Sopenharmony_ci * the ABS_ADDR calculation). See kernel/vmlinux.lds.S and tools/head_check.sh
7262306a36Sopenharmony_ci * for more details. We would prefer to just keep a cacheline (0x80), but
7362306a36Sopenharmony_ci * 0x100 seems to be how the linker aligns branch stub groups.
7462306a36Sopenharmony_ci */
7562306a36Sopenharmony_ci#ifdef CONFIG_LD_HEAD_STUB_CATCH
7662306a36Sopenharmony_ci#define OPEN_TEXT_SECTION(start)				\
7762306a36Sopenharmony_ci	.section ".linker_stub_catch","ax",@progbits;		\
7862306a36Sopenharmony_cilinker_stub_catch:						\
7962306a36Sopenharmony_ci	. = 0x4;						\
8062306a36Sopenharmony_ci	text_start = (start) + 0x100;				\
8162306a36Sopenharmony_ci	.section ".text","ax",@progbits;			\
8262306a36Sopenharmony_ci	.balign 0x100;						\
8362306a36Sopenharmony_cistart_text:
8462306a36Sopenharmony_ci#else
8562306a36Sopenharmony_ci#define OPEN_TEXT_SECTION(start)				\
8662306a36Sopenharmony_ci	text_start = (start);					\
8762306a36Sopenharmony_ci	.section ".text","ax",@progbits;			\
8862306a36Sopenharmony_ci	. = 0x0;						\
8962306a36Sopenharmony_cistart_text:
9062306a36Sopenharmony_ci#endif
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define ZERO_FIXED_SECTION(sname, start, end)			\
9362306a36Sopenharmony_ci	sname##_start = (start);				\
9462306a36Sopenharmony_ci	sname##_end = (end);					\
9562306a36Sopenharmony_ci	sname##_len = (end) - (start);				\
9662306a36Sopenharmony_ci	define_data_ftsec sname;				\
9762306a36Sopenharmony_ci	. = 0x0;						\
9862306a36Sopenharmony_ci	. = sname##_len;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define USE_FIXED_SECTION(sname)				\
10162306a36Sopenharmony_ci	use_ftsec sname;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#define USE_TEXT_SECTION()					\
10462306a36Sopenharmony_ci	.text
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci#define CLOSE_FIXED_SECTION(sname)				\
10762306a36Sopenharmony_ci	USE_FIXED_SECTION(sname);				\
10862306a36Sopenharmony_ci	. = sname##_len;					\
10962306a36Sopenharmony_ciend_##sname:
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci#define __FIXED_SECTION_ENTRY_BEGIN(sname, name, __align)	\
11362306a36Sopenharmony_ci	USE_FIXED_SECTION(sname);				\
11462306a36Sopenharmony_ci	.balign __align;					\
11562306a36Sopenharmony_ci	.global name;						\
11662306a36Sopenharmony_ciname:
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci#define FIXED_SECTION_ENTRY_BEGIN(sname, name)			\
11962306a36Sopenharmony_ci	__FIXED_SECTION_ENTRY_BEGIN(sname, name, IFETCH_ALIGN_BYTES)
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci#define FIXED_SECTION_ENTRY_BEGIN_LOCATION(sname, name, start, size) \
12262306a36Sopenharmony_ci	USE_FIXED_SECTION(sname);				\
12362306a36Sopenharmony_ci	name##_start = (start);					\
12462306a36Sopenharmony_ci	.if ((start) % (size) != 0);				\
12562306a36Sopenharmony_ci	.error "Fixed section exception vector misalignment";	\
12662306a36Sopenharmony_ci	.endif;							\
12762306a36Sopenharmony_ci	.if ((size) != 0x20) && ((size) != 0x80) && ((size) != 0x100) && ((size) != 0x1000); \
12862306a36Sopenharmony_ci	.error "Fixed section exception vector bad size";	\
12962306a36Sopenharmony_ci	.endif;							\
13062306a36Sopenharmony_ci	.if (start) < sname##_start;				\
13162306a36Sopenharmony_ci	.error "Fixed section underflow";			\
13262306a36Sopenharmony_ci	.abort;							\
13362306a36Sopenharmony_ci	.endif;							\
13462306a36Sopenharmony_ci	. = (start) - sname##_start;				\
13562306a36Sopenharmony_ci	.global name;						\
13662306a36Sopenharmony_ciname:
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci#define FIXED_SECTION_ENTRY_END_LOCATION(sname, name, start, size) \
13962306a36Sopenharmony_ci	.if (start) + (size) > sname##_end;			\
14062306a36Sopenharmony_ci	.error "Fixed section overflow";			\
14162306a36Sopenharmony_ci	.abort;							\
14262306a36Sopenharmony_ci	.endif;							\
14362306a36Sopenharmony_ci	.if (. - name > (start) + (size) - name##_start);	\
14462306a36Sopenharmony_ci	.error "Fixed entry overflow";				\
14562306a36Sopenharmony_ci	.abort;							\
14662306a36Sopenharmony_ci	.endif;							\
14762306a36Sopenharmony_ci	. = ((start) + (size) - sname##_start);			\
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/*
15162306a36Sopenharmony_ci * These macros are used to change symbols in other fixed sections to be
15262306a36Sopenharmony_ci * absolute or related to our current fixed section.
15362306a36Sopenharmony_ci *
15462306a36Sopenharmony_ci * - DEFINE_FIXED_SYMBOL / FIXED_SYMBOL_ABS_ADDR is used to find the
15562306a36Sopenharmony_ci *   absolute address of a symbol within a fixed section, from any section.
15662306a36Sopenharmony_ci *
15762306a36Sopenharmony_ci * - ABS_ADDR is used to find the absolute address of any symbol, from within
15862306a36Sopenharmony_ci *   a fixed section.
15962306a36Sopenharmony_ci */
16062306a36Sopenharmony_ci// define label as being _in_ sname
16162306a36Sopenharmony_ci#define DEFINE_FIXED_SYMBOL(label, sname) \
16262306a36Sopenharmony_ci	label##_absolute = (label - start_ ## sname + sname ## _start)
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci#define FIXED_SYMBOL_ABS_ADDR(label)				\
16562306a36Sopenharmony_ci	(label##_absolute)
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci// find label from _within_ sname
16862306a36Sopenharmony_ci#define ABS_ADDR(label, sname) (label - start_ ## sname + sname ## _start)
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci#endif	/* _ASM_POWERPC_HEAD_64_H */
173