1aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman#ifndef _ASM_POWERPC_CODE_PATCHING_H 2aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman#define _ASM_POWERPC_CODE_PATCHING_H 3aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman 4aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman/* 5aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman * Copyright 2008, Michael Ellerman, IBM Corporation. 6aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman * 7aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman * This program is free software; you can redistribute it and/or 8aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman * modify it under the terms of the GNU General Public License 9aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman * as published by the Free Software Foundation; either version 10aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman * 2 of the License, or (at your option) any later version. 11aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman */ 12aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman 1307630a37beefe8e4401c602f04e3e5bcbba50b31Michael Ellerman#include <asm/types.h> 1416c57b3620d77e0bc981da5ef32beae730512684Kumar Gala#include <asm/ppc-opcode.h> 15b7bcda631e87eb3466d0baa9885650ba7d7ed89dMichael Ellerman 16aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman/* Flags for create_branch: 17aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman * "b" == create_branch(addr, target, 0); 18aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman * "ba" == create_branch(addr, target, BRANCH_ABSOLUTE); 19aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman * "bl" == create_branch(addr, target, BRANCH_SET_LINK); 20aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman * "bla" == create_branch(addr, target, BRANCH_ABSOLUTE | BRANCH_SET_LINK); 21aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman */ 22aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman#define BRANCH_SET_LINK 0x1 23aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman#define BRANCH_ABSOLUTE 0x2 24aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman 25e7a57273c6407bb6903fbaddec8c2119bf318617Michael Ellermanunsigned int create_branch(const unsigned int *addr, 26e7a57273c6407bb6903fbaddec8c2119bf318617Michael Ellerman unsigned long target, int flags); 27411781a290b0d0a31fd73826b3ee110f1e3cc3b6Michael Ellermanunsigned int create_cond_branch(const unsigned int *addr, 28411781a290b0d0a31fd73826b3ee110f1e3cc3b6Michael Ellerman unsigned long target, int flags); 29b6e3796834faefe4b6e9a2aedfe12665cd51fbc5Steven Rostedtint patch_branch(unsigned int *addr, unsigned long target, int flags); 30b6e3796834faefe4b6e9a2aedfe12665cd51fbc5Steven Rostedtint patch_instruction(unsigned int *addr, unsigned int instr); 31aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman 32411781a290b0d0a31fd73826b3ee110f1e3cc3b6Michael Ellermanint instr_is_relative_branch(unsigned int instr); 33411781a290b0d0a31fd73826b3ee110f1e3cc3b6Michael Ellermanint instr_is_branch_to_addr(const unsigned int *instr, unsigned long addr); 34411781a290b0d0a31fd73826b3ee110f1e3cc3b6Michael Ellermanunsigned long branch_target(const unsigned int *instr); 35411781a290b0d0a31fd73826b3ee110f1e3cc3b6Michael Ellermanunsigned int translate_branch(const unsigned int *dest, 36411781a290b0d0a31fd73826b3ee110f1e3cc3b6Michael Ellerman const unsigned int *src); 371e8341ae0c0e117f0626cd6cf6732a0a9c8723f2Kevin Hao#ifdef CONFIG_PPC_BOOK3E_64 381e8341ae0c0e117f0626cd6cf6732a0a9c8723f2Kevin Haovoid __patch_exception(int exc, unsigned long addr); 391e8341ae0c0e117f0626cd6cf6732a0a9c8723f2Kevin Hao#define patch_exception(exc, name) do { \ 401e8341ae0c0e117f0626cd6cf6732a0a9c8723f2Kevin Hao extern unsigned int name; \ 411e8341ae0c0e117f0626cd6cf6732a0a9c8723f2Kevin Hao __patch_exception((exc), (unsigned long)&name); \ 421e8341ae0c0e117f0626cd6cf6732a0a9c8723f2Kevin Hao} while (0) 431e8341ae0c0e117f0626cd6cf6732a0a9c8723f2Kevin Hao#endif 44411781a290b0d0a31fd73826b3ee110f1e3cc3b6Michael Ellerman 45c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard#define OP_RT_RA_MASK 0xffff0000UL 46c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard#define LIS_R2 0x3c020000UL 47c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard#define ADDIS_R2_R12 0x3c4c0000UL 48c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard#define ADDI_R2_R2 0x38420000UL 49c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard 5007630a37beefe8e4401c602f04e3e5bcbba50b31Michael Ellermanstatic inline unsigned long ppc_function_entry(void *func) 5107630a37beefe8e4401c602f04e3e5bcbba50b31Michael Ellerman{ 52c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard#if defined(CONFIG_PPC64) 53c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard#if defined(_CALL_ELF) && _CALL_ELF == 2 54c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard u32 *insn = func; 55c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard 56c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard /* 57c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * A PPC64 ABIv2 function may have a local and a global entry 58c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * point. We need to use the local entry point when patching 59c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * functions, so identify and step over the global entry point 60c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * sequence. 61c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * 62c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * The global entry point sequence is always of the form: 63c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * 64c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * addis r2,r12,XXXX 65c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * addi r2,r2,XXXX 66c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * 67c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * A linker optimisation may convert the addis to lis: 68c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * 69c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * lis r2,XXXX 70c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * addi r2,r2,XXXX 71c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard */ 72c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) || 73c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard ((*insn & OP_RT_RA_MASK) == LIS_R2)) && 74c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard ((*(insn+1) & OP_RT_RA_MASK) == ADDI_R2_R2)) 75c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard return (unsigned long)(insn + 2); 76c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard else 77c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard return (unsigned long)func; 78c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard#else 7907630a37beefe8e4401c602f04e3e5bcbba50b31Michael Ellerman /* 80c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * On PPC64 ABIv1 the function pointer actually points to the 81c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * function's descriptor. The first entry in the descriptor is the 82c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard * address of the function text. 8307630a37beefe8e4401c602f04e3e5bcbba50b31Michael Ellerman */ 8407630a37beefe8e4401c602f04e3e5bcbba50b31Michael Ellerman return ((func_descr_t *)func)->entry; 85c71b7eff426fa7d8fd33e0964a7f79a3b41faff9Anton Blanchard#endif 8607630a37beefe8e4401c602f04e3e5bcbba50b31Michael Ellerman#else 8707630a37beefe8e4401c602f04e3e5bcbba50b31Michael Ellerman return (unsigned long)func; 8807630a37beefe8e4401c602f04e3e5bcbba50b31Michael Ellerman#endif 8907630a37beefe8e4401c602f04e3e5bcbba50b31Michael Ellerman} 9007630a37beefe8e4401c602f04e3e5bcbba50b31Michael Ellerman 91d997c00c5a9b61474f7ff5f27ed64173bb007987Michael Ellermanstatic inline unsigned long ppc_global_function_entry(void *func) 92d997c00c5a9b61474f7ff5f27ed64173bb007987Michael Ellerman{ 93d997c00c5a9b61474f7ff5f27ed64173bb007987Michael Ellerman#if defined(CONFIG_PPC64) && defined(_CALL_ELF) && _CALL_ELF == 2 94d997c00c5a9b61474f7ff5f27ed64173bb007987Michael Ellerman /* PPC64 ABIv2 the global entry point is at the address */ 95d997c00c5a9b61474f7ff5f27ed64173bb007987Michael Ellerman return (unsigned long)func; 96d997c00c5a9b61474f7ff5f27ed64173bb007987Michael Ellerman#else 97d997c00c5a9b61474f7ff5f27ed64173bb007987Michael Ellerman /* All other cases there is no change vs ppc_function_entry() */ 98d997c00c5a9b61474f7ff5f27ed64173bb007987Michael Ellerman return ppc_function_entry(func); 99d997c00c5a9b61474f7ff5f27ed64173bb007987Michael Ellerman#endif 100d997c00c5a9b61474f7ff5f27ed64173bb007987Michael Ellerman} 101d997c00c5a9b61474f7ff5f27ed64173bb007987Michael Ellerman 102aaddd3eacaeaef3503035750b3f21ac2bfe97cbfMichael Ellerman#endif /* _ASM_POWERPC_CODE_PATCHING_H */ 103