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