1aaddd3eaSMichael Ellerman /* 2aaddd3eaSMichael Ellerman * Copyright 2008 Michael Ellerman, IBM Corporation. 3aaddd3eaSMichael Ellerman * 4aaddd3eaSMichael Ellerman * This program is free software; you can redistribute it and/or 5aaddd3eaSMichael Ellerman * modify it under the terms of the GNU General Public License 6aaddd3eaSMichael Ellerman * as published by the Free Software Foundation; either version 7aaddd3eaSMichael Ellerman * 2 of the License, or (at your option) any later version. 8aaddd3eaSMichael Ellerman */ 9aaddd3eaSMichael Ellerman 10aaddd3eaSMichael Ellerman #include <linux/kernel.h> 11aaddd3eaSMichael Ellerman #include <asm/code-patching.h> 12aaddd3eaSMichael Ellerman 13aaddd3eaSMichael Ellerman 14e7a57273SMichael Ellerman void patch_instruction(unsigned int *addr, unsigned int instr) 15aaddd3eaSMichael Ellerman { 16e7a57273SMichael Ellerman *addr = instr; 17e7a57273SMichael Ellerman asm ("dcbst 0, %0; sync; icbi 0,%0; sync; isync" : : "r" (addr)); 18aaddd3eaSMichael Ellerman } 19aaddd3eaSMichael Ellerman 20e7a57273SMichael Ellerman void patch_branch(unsigned int *addr, unsigned long target, int flags) 21e7a57273SMichael Ellerman { 22e7a57273SMichael Ellerman patch_instruction(addr, create_branch(addr, target, flags)); 23e7a57273SMichael Ellerman } 24e7a57273SMichael Ellerman 25e7a57273SMichael Ellerman unsigned int create_branch(const unsigned int *addr, 26e7a57273SMichael Ellerman unsigned long target, int flags) 27aaddd3eaSMichael Ellerman { 28aaddd3eaSMichael Ellerman unsigned int instruction; 29*053a858eSMichael Ellerman long offset; 30aaddd3eaSMichael Ellerman 31*053a858eSMichael Ellerman offset = target; 32aaddd3eaSMichael Ellerman if (! (flags & BRANCH_ABSOLUTE)) 33*053a858eSMichael Ellerman offset = offset - (unsigned long)addr; 34*053a858eSMichael Ellerman 35*053a858eSMichael Ellerman /* Check we can represent the target in the instruction format */ 36*053a858eSMichael Ellerman if (offset < -0x2000000 || offset > 0x1fffffc || offset & 0x3) 37*053a858eSMichael Ellerman return 0; 38aaddd3eaSMichael Ellerman 39aaddd3eaSMichael Ellerman /* Mask out the flags and target, so they don't step on each other. */ 40*053a858eSMichael Ellerman instruction = 0x48000000 | (flags & 0x3) | (offset & 0x03FFFFFC); 41aaddd3eaSMichael Ellerman 42e7a57273SMichael Ellerman return instruction; 43aaddd3eaSMichael Ellerman } 44