Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 101724
b: refs/heads/master
c: 9b1a735
h: refs/heads/master
v: v3
  • Loading branch information
Michael Ellerman authored and Paul Mackerras committed Jul 1, 2008
1 parent 92f025a commit 61d07a7
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 15 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: fac23fe4be23259a8eaa9bad822f5b14dd07d15c
refs/heads/master: 9b1a735de64cc975c31a1642ec55e082ddbdfeaf
79 changes: 65 additions & 14 deletions trunk/arch/powerpc/lib/feature-fixups.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,66 @@ struct fixup_entry {
long alt_end_off;
};

static void patch_feature_section(unsigned long value, struct fixup_entry *fcur)
static unsigned int *calc_addr(struct fixup_entry *fcur, long offset)
{
unsigned int *pstart, *pend, *p;
/*
* We store the offset to the code as a negative offset from
* the start of the alt_entry, to support the VDSO. This
* routine converts that back into an actual address.
*/
return (unsigned int *)((unsigned long)fcur + offset);
}

static int patch_alt_instruction(unsigned int *src, unsigned int *dest,
unsigned int *alt_start, unsigned int *alt_end)
{
unsigned int instr;

instr = *src;

if (instr_is_relative_branch(*src)) {
unsigned int *target = (unsigned int *)branch_target(src);

/* Branch within the section doesn't need translating */
if (target < alt_start || target >= alt_end) {
instr = translate_branch(dest, src);
if (!instr)
return 1;
}
}

patch_instruction(dest, instr);

return 0;
}

static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
{
unsigned int *start, *end, *alt_start, *alt_end, *src, *dest;

start = calc_addr(fcur, fcur->start_off);
end = calc_addr(fcur, fcur->end_off);
alt_start = calc_addr(fcur, fcur->alt_start_off);
alt_end = calc_addr(fcur, fcur->alt_end_off);

if ((alt_end - alt_start) > (end - start))
return 1;

if ((value & fcur->mask) == fcur->value)
return;
return 0;

pstart = ((unsigned int *)fcur) + (fcur->start_off / 4);
pend = ((unsigned int *)fcur) + (fcur->end_off / 4);
src = alt_start;
dest = start;

for (p = pstart; p < pend; p++) {
*p = PPC_NOP_INSTR;
asm volatile ("dcbst 0, %0" : : "r" (p));
for (; src < alt_end; src++, dest++) {
if (patch_alt_instruction(src, dest, alt_start, alt_end))
return 1;
}
asm volatile ("sync" : : : "memory");
for (p = pstart; p < pend; p++)
asm volatile ("icbi 0,%0" : : "r" (p));
asm volatile ("sync; isync" : : : "memory");

for (; dest < end; dest++)
patch_instruction(dest, PPC_NOP_INSTR);

return 0;
}

void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
Expand All @@ -53,6 +95,15 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end)
fcur = fixup_start;
fend = fixup_end;

for (; fcur < fend; fcur++)
patch_feature_section(value, fcur);
for (; fcur < fend; fcur++) {
if (patch_feature_section(value, fcur)) {
__WARN();
printk("Unable to patch feature section at %p - %p" \
" with %p - %p\n",
calc_addr(fcur, fcur->start_off),
calc_addr(fcur, fcur->end_off),
calc_addr(fcur, fcur->alt_start_off),
calc_addr(fcur, fcur->alt_end_off));
}
}
}

0 comments on commit 61d07a7

Please sign in to comment.