162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#include <asm/core.h>
362306a36Sopenharmony_ci#include <asm/regs.h>
462306a36Sopenharmony_ci#include <asm/asmmacro.h>
562306a36Sopenharmony_ci#include <asm/cacheasm.h>
662306a36Sopenharmony_ci#include <asm/processor.h>
762306a36Sopenharmony_ci	/*
862306a36Sopenharmony_ci	 * RB-Data: RedBoot data/bss
962306a36Sopenharmony_ci	 * P:	    Boot-Parameters
1062306a36Sopenharmony_ci	 * L:	    Kernel-Loader
1162306a36Sopenharmony_ci	 *
1262306a36Sopenharmony_ci	 * The Linux-Kernel image including the loader must be loaded
1362306a36Sopenharmony_ci	 * to a position so that the kernel and the boot parameters
1462306a36Sopenharmony_ci	 * can fit in the space before the load address.
1562306a36Sopenharmony_ci	 *  ______________________________________________________
1662306a36Sopenharmony_ci	 * |_RB-Data_|_P_|__________|_L_|___Linux-Kernel___|______|
1762306a36Sopenharmony_ci	 *                          ^
1862306a36Sopenharmony_ci	 *                          ^ Load address
1962306a36Sopenharmony_ci	 *  ______________________________________________________
2062306a36Sopenharmony_ci	 * |___Linux-Kernel___|_P_|_L_|___________________________|
2162306a36Sopenharmony_ci	 *
2262306a36Sopenharmony_ci	 * The loader copies the parameter to the position that will
2362306a36Sopenharmony_ci	 * be the end of the kernel and itself to the end of the
2462306a36Sopenharmony_ci	 * parameter list.
2562306a36Sopenharmony_ci	 */
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/* Make sure we have enough space for the 'uncompressor' */
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define STACK_SIZE 32768
3062306a36Sopenharmony_ci#define HEAP_SIZE (131072*4)
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	# a2: Parameter list
3362306a36Sopenharmony_ci	# a3: Size of parameter list
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	.section .start, "ax"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	.globl __start
3862306a36Sopenharmony_ci	/* this must be the first byte of the loader! */
3962306a36Sopenharmony_ci__start:
4062306a36Sopenharmony_ci	abi_entry(32)		# we do not intend to return
4162306a36Sopenharmony_ci	_call0	_start
4262306a36Sopenharmony_ci__start_a0:
4362306a36Sopenharmony_ci	.align 4
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	.section .text, "ax"
4662306a36Sopenharmony_ci	.literal_position
4762306a36Sopenharmony_ci	.begin literal_prefix .text
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	/* put literals in here! */
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	.globl _start
5262306a36Sopenharmony_ci_start:
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	/* 'reset' window registers */
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	movi	a4, 1
5762306a36Sopenharmony_ci	wsr	a4, ps
5862306a36Sopenharmony_ci	rsync
5962306a36Sopenharmony_ci#if XCHAL_HAVE_WINDOWED
6062306a36Sopenharmony_ci	rsr	a5, windowbase
6162306a36Sopenharmony_ci	ssl	a5
6262306a36Sopenharmony_ci	sll	a4, a4
6362306a36Sopenharmony_ci	wsr	a4, windowstart
6462306a36Sopenharmony_ci	rsync
6562306a36Sopenharmony_ci#endif
6662306a36Sopenharmony_ci	movi	a4, KERNEL_PS_WOE_MASK
6762306a36Sopenharmony_ci	wsr	a4, ps
6862306a36Sopenharmony_ci	rsync
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ciKABI_C0	mov	abi_saved0, abi_arg0
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/* copy the loader to its address
7362306a36Sopenharmony_ci	 * Note: The loader itself is a very small piece, so we assume we
7462306a36Sopenharmony_ci	 *       don't partially overlap. We also assume (even more important)
7562306a36Sopenharmony_ci	 *	 that the kernel image is out of the way. Usually, when the
7662306a36Sopenharmony_ci	 *	 load address of this image is not at an arbitrary address,
7762306a36Sopenharmony_ci	 *	 but aligned to some 10K's we shouldn't overlap.
7862306a36Sopenharmony_ci	 */
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	/* Note: The assembler cannot relax "addi a0, a0, ..." to an
8162306a36Sopenharmony_ci	   l32r, so we load to a4 first. */
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	# addi	a4, a0, __start - __start_a0
8462306a36Sopenharmony_ci	# mov	a0, a4
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	movi	a4, __start
8762306a36Sopenharmony_ci	movi	a5, __start_a0
8862306a36Sopenharmony_ci	add	a4, a0, a4
8962306a36Sopenharmony_ci	sub	a0, a4, a5
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	movi	a4, __start
9262306a36Sopenharmony_ci	movi	a5, __reloc_end
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	# a0: address where this code has been loaded
9562306a36Sopenharmony_ci	# a4: compiled address of __start
9662306a36Sopenharmony_ci	# a5: compiled end address
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	mov.n	a7, a0
9962306a36Sopenharmony_ci	mov.n	a8, a4
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci1:
10262306a36Sopenharmony_ci	l32i	a10, a7, 0
10362306a36Sopenharmony_ci	l32i	a11, a7, 4
10462306a36Sopenharmony_ci	s32i	a10, a8, 0
10562306a36Sopenharmony_ci	s32i	a11, a8, 4
10662306a36Sopenharmony_ci	l32i	a10, a7, 8
10762306a36Sopenharmony_ci	l32i	a11, a7, 12
10862306a36Sopenharmony_ci	s32i	a10, a8, 8
10962306a36Sopenharmony_ci	s32i	a11, a8, 12
11062306a36Sopenharmony_ci	addi	a8, a8, 16
11162306a36Sopenharmony_ci	addi	a7, a7, 16
11262306a36Sopenharmony_ci	blt	a8, a5, 1b
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/* We have to flush and invalidate the caches here before we jump. */
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#if XCHAL_DCACHE_IS_WRITEBACK
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	___flush_dcache_all a5 a6
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci#endif
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	___invalidate_icache_all a5 a6
12462306a36Sopenharmony_ci	isync
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	movi	a11, _reloc
12762306a36Sopenharmony_ci	jx	a11
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	.globl _reloc
13062306a36Sopenharmony_ci_reloc:
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* RedBoot is now at the end of the memory, so we don't have
13362306a36Sopenharmony_ci	 * to copy the parameter list. Keep the code around; in case
13462306a36Sopenharmony_ci	 * we need it again. */
13562306a36Sopenharmony_ci#if 0
13662306a36Sopenharmony_ci	# a0: load address
13762306a36Sopenharmony_ci	# a2: start address of parameter list
13862306a36Sopenharmony_ci	# a3: length of parameter list
13962306a36Sopenharmony_ci	# a4: __start
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	/* copy the parameter list out of the way */
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	movi	a6, _param_start
14462306a36Sopenharmony_ci	add	a3, a2, a3
14562306a36Sopenharmony_ci2:
14662306a36Sopenharmony_ci	l32i	a8, a2, 0
14762306a36Sopenharmony_ci	s32i	a8, a6, 0
14862306a36Sopenharmony_ci	addi	a2, a2, 4
14962306a36Sopenharmony_ci	addi	a6, a6, 4
15062306a36Sopenharmony_ci	blt	a2, a3, 2b
15162306a36Sopenharmony_ci#endif
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	/* clear BSS section */
15462306a36Sopenharmony_ci	movi	a6, __bss_start
15562306a36Sopenharmony_ci	movi	a7, __bss_end
15662306a36Sopenharmony_ci	movi.n	a5, 0
15762306a36Sopenharmony_ci3:
15862306a36Sopenharmony_ci	s32i	a5, a6, 0
15962306a36Sopenharmony_ci	addi	a6, a6, 4
16062306a36Sopenharmony_ci	blt	a6, a7, 3b
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	movi	a5, -16
16362306a36Sopenharmony_ci	movi	a1, _stack + STACK_SIZE
16462306a36Sopenharmony_ci	and	a1, a1, a5
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/* Uncompress the kernel */
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	# a0: load address
16962306a36Sopenharmony_ci	# a2: boot parameter
17062306a36Sopenharmony_ci	# a4: __start
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	movi	a3, __image_load
17362306a36Sopenharmony_ci	sub	a4, a3, a4
17462306a36Sopenharmony_ci	add	abi_arg2, a0, a4
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	# a1  Stack
17762306a36Sopenharmony_ci	# a8(a4)  Load address of the image
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	movi	abi_arg0, _image_start
18062306a36Sopenharmony_ci	movi	abi_arg4, _image_end
18162306a36Sopenharmony_ci	movi	abi_arg1, 0x1000000
18262306a36Sopenharmony_ci	sub	abi_tmp0, abi_arg4, abi_arg0
18362306a36Sopenharmony_ci	movi	abi_arg3, complen
18462306a36Sopenharmony_ci	s32i	abi_tmp0, abi_arg3, 0
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	movi	a0, 0
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	# abi_arg0 destination
18962306a36Sopenharmony_ci	# abi_arg1 maximum size of destination
19062306a36Sopenharmony_ci	# abi_arg2 source
19162306a36Sopenharmony_ci	# abi_arg3 ptr to length
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	.extern gunzip
19462306a36Sopenharmony_ci	movi	abi_tmp0, gunzip
19562306a36Sopenharmony_ci	beqz	abi_tmp0, 1f
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	abi_callx	abi_tmp0
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	j	2f
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	# abi_arg0 destination start
20362306a36Sopenharmony_ci	# abi_arg1 maximum size of destination
20462306a36Sopenharmony_ci	# abi_arg2 source start
20562306a36Sopenharmony_ci	# abi_arg3 ptr to length
20662306a36Sopenharmony_ci	# abi_arg4 destination end
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci1:
20962306a36Sopenharmony_ci        l32i    abi_tmp0, abi_arg2, 0
21062306a36Sopenharmony_ci        l32i    abi_tmp1, abi_arg2, 4
21162306a36Sopenharmony_ci        s32i    abi_tmp0, abi_arg0, 0
21262306a36Sopenharmony_ci        s32i    abi_tmp1, abi_arg0, 4
21362306a36Sopenharmony_ci        l32i    abi_tmp0, abi_arg2, 8
21462306a36Sopenharmony_ci        l32i    abi_tmp1, abi_arg2, 12
21562306a36Sopenharmony_ci        s32i    abi_tmp0, abi_arg0, 8
21662306a36Sopenharmony_ci        s32i    abi_tmp1, abi_arg0, 12
21762306a36Sopenharmony_ci        addi    abi_arg0, abi_arg0, 16
21862306a36Sopenharmony_ci        addi    abi_arg2, abi_arg2, 16
21962306a36Sopenharmony_ci        blt     abi_arg0, abi_arg4, 1b
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	/* jump to the kernel */
22362306a36Sopenharmony_ci2:
22462306a36Sopenharmony_ci#if XCHAL_DCACHE_IS_WRITEBACK
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	___flush_dcache_all a5 a6
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci#endif
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	___invalidate_icache_all a5 a6
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	isync
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	# a2  Boot parameter list
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ciKABI_C0	mov	abi_arg0, abi_saved0
23762306a36Sopenharmony_ci	movi	a0, _image_start
23862306a36Sopenharmony_ci	jx	a0
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	.align 16
24162306a36Sopenharmony_ci	.data
24262306a36Sopenharmony_ci	.globl avail_ram
24362306a36Sopenharmony_ciavail_ram:
24462306a36Sopenharmony_ci	.long	_heap
24562306a36Sopenharmony_ci	.globl end_avail
24662306a36Sopenharmony_ciend_avail:
24762306a36Sopenharmony_ci	.long	_heap + HEAP_SIZE
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	.comm _stack, STACK_SIZE
25062306a36Sopenharmony_ci	.comm _heap, HEAP_SIZE
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	.globl end_avail
25362306a36Sopenharmony_ci	.comm complen, 4
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	.end	literal_prefix
256