[PATCH 10/11] powerpc: Add helper functions for synthesising instructions at runtime

Michael Ellerman michael at ellerman.id.au
Mon Oct 17 21:48:47 EST 2005


There's a few places already, and soon will be more, where we synthesise
branch instructions at runtime. Rather than doing it by hand in each case,
it would make sense to have one implementation.

Signed-off-by: Michael Ellerman <michael at ellerman.id.au>
---

 include/asm-powerpc/system.h |   52 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 52 insertions(+)

Index: kexec/include/asm-powerpc/system.h
===================================================================
--- kexec.orig/include/asm-powerpc/system.h
+++ kexec/include/asm-powerpc/system.h
@@ -356,5 +356,57 @@ extern void reloc_got2(unsigned long);
 
 #define PTRRELOC(x)	((typeof(x)) add_reloc_offset((unsigned long)(x)))
 
+typedef enum {
+	BRANCH_RELATIVE,
+	BRANCH_RELATIVE_LINK,
+	BRANCH_ABSOLUTE,
+	BRANCH_ABSOLUTE_LINK
+} branch_t;
+
+static inline void create_instruction(unsigned long addr, unsigned int instr)
+{
+	unsigned int *p;
+	p  = (unsigned int *)addr;
+	*p = instr;
+	asm ("dcbst 0, %0; sync; icbi 0,%0; isync" : : "r" (p));
+}
+
+static inline void create_branch(unsigned long addr, unsigned long target,
+		branch_t type)
+{
+	unsigned int instruction;
+
+	instruction = 0x48000000;	/* Basic branch opcode */
+
+	if (BRANCH_ABSOLUTE == type || BRANCH_ABSOLUTE_LINK == type)
+		instruction |= 0x02;	/* set AA (absolute address) */
+	else
+		target = target - addr;
+
+	if (BRANCH_RELATIVE_LINK == type || BRANCH_ABSOLUTE_LINK == type)
+		instruction |= 0x01;	/* set LK (set link register) */
+
+	instruction |= target & 0x03FFFFFC;
+
+	create_instruction(addr, instruction);
+}
+
+static inline void create_function_call(unsigned long addr, void * func)
+{
+	unsigned long func_addr;
+
+#ifdef CONFIG_PPC64
+	/*
+	 * 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.
+	 */
+	func_addr = *(unsigned long *)func;
+#else
+	func_addr = (unsigned long)func;
+#endif
+	create_branch(addr, func_addr, BRANCH_RELATIVE_LINK);
+}
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_SYSTEM_H */



More information about the Linuxppc64-dev mailing list