/*
 * MIPS Relocation
 *
 * Copyright (c) 2017 Imagination Technologies Ltd.
 *
 * SPDX-License-Identifier:	GPL-2.0+
 *
 * Relocation data, found in the .rel section, is generated by the mips-relocs
 * tool & contains a record of all locations in the U-Boot binary that need to
 * be fixed up during relocation.
 *
 * The data is a sequence of unsigned integers, which are of somewhat arbitrary
 * size. This is achieved by encoding integers as a sequence of bytes, each of
 * which contains 7 bits of data with the most significant bit indicating
 * whether any further bytes need to be read. The least significant bits of the
 * integer are found in the first byte - ie. it somewhat resembles little
 * endian.
 *
 * Each pair of two integers represents a relocation that must be applied. The
 * first integer represents the type of relocation as a standard ELF relocation
 * type (ie. R_MIPS_*). The second integer represents the offset at which to
 * apply the relocation, relative to the previous relocation or for the first
 * relocation the start of the relocated .text section.
 *
 * The end of the relocation data is indicated when type R_MIPS_NONE (0) is
 * read, at which point no further integers should be read. That is, the
 * terminating R_MIPS_NONE reloc includes no offset.
 */

#include <common.h>
#include <asm/relocs.h>
#include <asm/sections.h>

/**
 * read_uint() - Read an unsigned integer from the buffer
 * @buf: pointer to a pointer to the reloc buffer
 *
 * Read one whole unsigned integer from the relocation data pointed to by @buf,
 * advancing @buf past the bytes encoding the integer.
 *
 * Returns: the integer read from @buf
 */
static unsigned long read_uint(uint8_t **buf)
{
	unsigned long val = 0;
	unsigned int shift = 0;
	uint8_t new;

	do {
		new = *(*buf)++;
		val |= (new & 0x7f) << shift;
		shift += 7;
	} while (new & 0x80);

	return val;
}

/**
 * apply_reloc() - Apply a single relocation
 * @type: the type of reloc (R_MIPS_*)
 * @addr: the address that the reloc should be applied to
 * @off: the relocation offset, ie. number of bytes we're moving U-Boot by
 *
 * Apply a single relocation of type @type at @addr. This function is
 * intentionally simple, and does the bare minimum needed to fixup the
 * relocated U-Boot - in particular, it does not check for overflows.
 */
static void apply_reloc(unsigned int type, void *addr, long off)
{
	uint32_t u32;

	switch (type) {
	case R_MIPS_26:
		u32 = *(uint32_t *)addr;
		u32 = (u32 & GENMASK(31, 26)) |
		      ((u32 + (off >> 2)) & GENMASK(25, 0));
		*(uint32_t *)addr = u32;
		break;

	case R_MIPS_32:
		*(uint32_t *)addr += off;
		break;

	case R_MIPS_64:
		*(uint64_t *)addr += off;
		break;

	case R_MIPS_HI16:
		*(uint32_t *)addr += off >> 16;
		break;

	default:
		panic("Unhandled reloc type %u\n", type);
	}
}

/**
 * relocate_code() - Relocate U-Boot, generally from flash to DDR
 * @start_addr_sp: new stack pointer
 * @new_gd: pointer to relocated global data
 * @relocaddr: the address to relocate to
 *
 * Relocate U-Boot from its current location (generally in flash) to a new one
 * (generally in DDR). This function will copy the U-Boot binary & apply
 * relocations as necessary, then jump to board_init_r in the new build of
 * U-Boot. As such, this function does not return.
 */
void relocate_code(ulong start_addr_sp, gd_t *new_gd, ulong relocaddr)
{
	unsigned long addr, length, bss_len;
	uint8_t *buf, *bss_start;
	unsigned int type;
	long off;

	/*
	 * Ensure that we're relocating by an offset which is a multiple of
	 * 64KiB, ie. doesn't change the least significant 16 bits of any
	 * addresses. This allows us to discard R_MIPS_LO16 relocs, saving
	 * space in the U-Boot binary & complexity in handling them.
	 */
	off = relocaddr - (unsigned long)__text_start;
	if (off & 0xffff)
		panic("Mis-aligned relocation\n");

	/* Copy U-Boot to RAM */
	length = __image_copy_end - __text_start;
	memcpy((void *)relocaddr, __text_start, length);

	/* Now apply relocations to the copy in RAM */
	buf = __rel_start;
	addr = relocaddr;
	while (true) {
		type = read_uint(&buf);
		if (type == R_MIPS_NONE)
			break;

		addr += read_uint(&buf) << 2;
		apply_reloc(type, (void *)addr, off);
	}

	/* Ensure the icache is coherent */
	flush_cache(relocaddr, length);

	/* Clear the .bss section */
	bss_start = (uint8_t *)((unsigned long)__bss_start + off);
	bss_len = (unsigned long)&__bss_end - (unsigned long)__bss_start;
	memset(bss_start, 0, bss_len);

	/* Jump to the relocated U-Boot */
	asm volatile(
		       "move	$29, %0\n"
		"	move	$4, %1\n"
		"	move	$5, %2\n"
		"	move	$31, $0\n"
		"	jr	%3"
		: /* no outputs */
		: "r"(start_addr_sp),
		  "r"(new_gd),
		  "r"(relocaddr),
		  "r"((unsigned long)board_init_r + off));

	/* Since we jumped to the new U-Boot above, we won't get here */
	unreachable();
}
