Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c71b7eff authored by Anton Blanchard's avatar Anton Blanchard
Browse files

powerpc: Add ABIv2 support to ppc_function_entry



Skip over the well known global entry point code for ABIv2.

Signed-off-by: default avatarAnton Blanchard <anton@samba.org>
parent 814e4cd9
Loading
Loading
Loading
Loading
+36 −4
Original line number Diff line number Diff line
@@ -42,15 +42,47 @@ void __patch_exception(int exc, unsigned long addr);
} while (0)
#endif

#define OP_RT_RA_MASK	0xffff0000UL
#define LIS_R2		0x3c020000UL
#define ADDIS_R2_R12	0x3c4c0000UL
#define ADDI_R2_R2	0x38420000UL

static inline unsigned long ppc_function_entry(void *func)
{
#ifdef CONFIG_PPC64
#if defined(CONFIG_PPC64)
#if defined(_CALL_ELF) && _CALL_ELF == 2
	u32 *insn = func;

	/*
	 * On PPC64 the function pointer actually points to the function's
	 * descriptor. The first entry in the descriptor is the address
	 * of the function text.
	 * A PPC64 ABIv2 function may have a local and a global entry
	 * point. We need to use the local entry point when patching
	 * functions, so identify and step over the global entry point
	 * sequence.
	 *
	 * The global entry point sequence is always of the form:
	 *
	 * addis r2,r12,XXXX
	 * addi  r2,r2,XXXX
	 *
	 * A linker optimisation may convert the addis to lis:
	 *
	 * lis   r2,XXXX
	 * addi  r2,r2,XXXX
	 */
	if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) ||
	     ((*insn & OP_RT_RA_MASK) == LIS_R2)) &&
	    ((*(insn+1) & OP_RT_RA_MASK) == ADDI_R2_R2))
		return (unsigned long)(insn + 2);
	else
		return (unsigned long)func;
#else
	/*
	 * On PPC64 ABIv1 the function pointer actually points to the
	 * function's descriptor. The first entry in the descriptor is the
	 * address of the function text.
	 */
	return ((func_descr_t *)func)->entry;
#endif
#else
	return (unsigned long)func;
#endif