2 * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
4 * Modifications for ppc64:
5 * Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com>
7 * Copyright 2008 Michael Ellerman, IBM Corporation.
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
15 #include <linux/kernel.h>
16 #include <asm/cputable.h>
17 #include <asm/code-patching.h>
29 static unsigned int *calc_addr(struct fixup_entry *fcur, long offset)
32 * We store the offset to the code as a negative offset from
33 * the start of the alt_entry, to support the VDSO. This
34 * routine converts that back into an actual address.
36 return (unsigned int *)((unsigned long)fcur + offset);
39 static int patch_alt_instruction(unsigned int *src, unsigned int *dest,
40 unsigned int *alt_start, unsigned int *alt_end)
46 if (instr_is_relative_branch(*src)) {
47 unsigned int *target = (unsigned int *)branch_target(src);
49 /* Branch within the section doesn't need translating */
50 if (target < alt_start || target >= alt_end) {
51 instr = translate_branch(dest, src);
57 patch_instruction(dest, instr);
62 static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
64 unsigned int *start, *end, *alt_start, *alt_end, *src, *dest;
66 start = calc_addr(fcur, fcur->start_off);
67 end = calc_addr(fcur, fcur->end_off);
68 alt_start = calc_addr(fcur, fcur->alt_start_off);
69 alt_end = calc_addr(fcur, fcur->alt_end_off);
71 if ((alt_end - alt_start) > (end - start))
74 if ((value & fcur->mask) == fcur->value)
80 for (; src < alt_end; src++, dest++) {
81 if (patch_alt_instruction(src, dest, alt_start, alt_end))
85 for (; dest < end; dest++)
86 patch_instruction(dest, PPC_NOP_INSTR);
91 void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
93 struct fixup_entry *fcur, *fend;
98 for (; fcur < fend; fcur++) {
99 if (patch_feature_section(value, fcur)) {
101 printk("Unable to patch feature section at %p - %p" \
103 calc_addr(fcur, fcur->start_off),
104 calc_addr(fcur, fcur->end_off),
105 calc_addr(fcur, fcur->alt_start_off),
106 calc_addr(fcur, fcur->alt_end_off));