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 14*e7a57273SMichael Ellerman void patch_instruction(unsigned int *addr, unsigned int instr) 15aaddd3eaSMichael Ellerman { 16*e7a57273SMichael Ellerman *addr = instr; 17*e7a57273SMichael Ellerman asm ("dcbst 0, %0; sync; icbi 0,%0; sync; isync" : : "r" (addr)); 18aaddd3eaSMichael Ellerman } 19aaddd3eaSMichael Ellerman 20*e7a57273SMichael Ellerman void patch_branch(unsigned int *addr, unsigned long target, int flags) 21*e7a57273SMichael Ellerman { 22*e7a57273SMichael Ellerman patch_instruction(addr, create_branch(addr, target, flags)); 23*e7a57273SMichael Ellerman } 24*e7a57273SMichael Ellerman 25*e7a57273SMichael Ellerman unsigned int create_branch(const unsigned int *addr, 26*e7a57273SMichael Ellerman unsigned long target, int flags) 27aaddd3eaSMichael Ellerman { 28aaddd3eaSMichael Ellerman unsigned int instruction; 29aaddd3eaSMichael Ellerman 30aaddd3eaSMichael Ellerman if (! (flags & BRANCH_ABSOLUTE)) 31*e7a57273SMichael Ellerman target = target - (unsigned long)addr; 32aaddd3eaSMichael Ellerman 33aaddd3eaSMichael Ellerman /* Mask out the flags and target, so they don't step on each other. */ 34aaddd3eaSMichael Ellerman instruction = 0x48000000 | (flags & 0x3) | (target & 0x03FFFFFC); 35aaddd3eaSMichael Ellerman 36*e7a57273SMichael Ellerman return instruction; 37aaddd3eaSMichael Ellerman } 38