/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * linux/arch/unicore32/boot/compressed/head.S
 *
 * Code specific to PKUnity SoC and UniCore ISA
 *
 * Copyright (C) 2001-2010 GUAN Xue-tao
 */
#include <linux/linkage.h>
#include <mach/memory.h>

#define csub	cmpsub
#define cand	cmpand
#define nop8	nop; nop; nop; nop; nop; nop; nop; nop

		.section ".start", #alloc, #execinstr
		.text
start:
		.type	start,#function

		/* Initialize ASR, PRIV mode and INTR off */
		mov	r0, #0xD3
		mov.a	asr, r0

		adr	r0, LC0
		ldm	(r1, r2, r3, r5, r6, r7, r8), [r0]+
		ldw	sp, [r0+], #28
		sub.a	r0, r0, r1		@ calculate the delta offset

		/*
		 * if delta is zero, we are running at the address
		 * we were linked at.
		 */
		beq	not_relocated

		/*
		 * We're running at a different address.  We need to fix
		 * up various pointers:
		 *   r5 - zImage base address (_start)
		 *   r7 - GOT start
		 *   r8 - GOT end
		 */
		add	r5, r5, r0
		add	r7, r7, r0
		add	r8, r8, r0

		/*
		 * we need to fix up pointers into the BSS region.
		 *   r2 - BSS start
		 *   r3 - BSS end
		 *   sp - stack pointer
		 */
		add	r2, r2, r0
		add	r3, r3, r0
		add	sp, sp, r0

		/*
		 * Relocate all entries in the GOT table.
		 * This fixes up the C references.
		 *   r7 - GOT start
		 *   r8 - GOT end
		 */
1001:		ldw	r1, [r7+], #0
		add	r1, r1, r0
		stw.w	r1, [r7]+, #4
		csub.a	r7, r8
		bub	1001b

not_relocated:
		/*
		 * Clear BSS region.
		 *   r2 - BSS start
		 *   r3 - BSS end
		 */
		mov	r0, #0
1002:		stw.w	r0, [r2]+, #4
		csub.a	r2, r3
		bub	1002b

		/*
		 * Turn on the cache.
		 */
                mov     r0, #0
                movc    p0.c5, r0, #28		@ cache invalidate all
                nop8
                movc    p0.c6, r0, #6		@ tlb invalidate all
                nop8

                mov     r0, #0x1c		@ en icache and wb dcache
                movc    p0.c1, r0, #0
                nop8

		/*
		 * Set up some pointers, for starting decompressing.
		 */

		mov	r1, sp			@ malloc space above stack
		add	r2, sp, #0x10000	@ 64k max

		/*
		 * Check to see if we will overwrite ourselves.
		 *   r4 = final kernel address
		 *   r5 = start of this image
		 *   r6 = size of decompressed image
		 *   r2 = end of malloc space (and therefore this image)
		 * We basically want:
		 *   r4 >= r2 -> OK
		 *   r4 + image length <= r5 -> OK
		 */
		ldw	r4, =KERNEL_IMAGE_START
		csub.a	r4, r2
		bea	wont_overwrite
		add	r0, r4, r6
		csub.a	r0, r5
		beb	wont_overwrite

		/*
		 * If overwrite, just print error message
		 */
		b	__error_overwrite

		/*
		 * We're not in danger of overwriting ourselves.
		 * Do this the simple way.
		 */
wont_overwrite:
		/*
		 * decompress_kernel:
		 *   r0: output_start
		 *   r1: free_mem_ptr_p
		 *   r2: free_mem_ptr_end_p
		 */
		mov	r0, r4
		b.l	decompress_kernel	@ C functions

		/*
		 * Clean and flush the cache to maintain consistency.
		 */
		mov	r0, #0
                movc    p0.c5, r0, #14		@ flush dcache
		nop8
                movc    p0.c5, r0, #20		@ icache invalidate all
                nop8

		/*
		 * Turn off the Cache and MMU.
		 */
		mov	r0, #0			@ disable i/d cache and MMU
		movc	p0.c1, r0, #0
                nop8

		mov	r0, #0			@ must be zero
		ldw	r4, =KERNEL_IMAGE_START
		mov	pc, r4			@ call kernel


		.align	2
		.type	LC0, #object
LC0:		.word	LC0			@ r1
		.word	__bss_start		@ r2
		.word	_end			@ r3
		.word	_start			@ r5
		.word	_image_size		@ r6
		.word	_got_start		@ r7
		.word	_got_end		@ r8
		.word	decompress_stack_end	@ sp
		.size	LC0, . - LC0

print_string:
#ifdef CONFIG_DEBUG_OCD
2001:		ldb.w	r1, [r0]+, #1
		csub.a	r1, #0
		bne	2002f
		mov	pc, lr
2002:
		movc	r2, p1.c0, #0
		cand.a	r2, #2
		bne	2002b
		movc	p1.c1, r1, #1
		csub.a	r1, #'\n'
		cmoveq	r1, #'\r'
		beq	2002b
		b	2001b
#else
		mov	pc, lr
#endif

__error_overwrite:
		adr	r0, str_error
		b.l	print_string
2001:		nop8
		b	2001b
str_error:	.asciz	"\nError: Kernel address OVERWRITE\n"
		.align

		.ltorg

		.align	4
		.section ".stack", "aw", %nobits
decompress_stack:	.space	4096
decompress_stack_end:
