i386: Make patching more robust, fix paravirt issue
Commit 19d36ccdc3
"x86: Fix alternatives
and kprobes to remap write-protected kernel text" uses code which is
being patched for patching.
In particular, paravirt_ops does patching in two stages: first it
calls paravirt_ops.patch, then it fills any remaining instructions
with nop_out(). nop_out calls text_poke() which calls
lookup_address() which calls pgd_val() (aka paravirt_ops.pgd_val):
that call site is one of the places we patch.
If we always do patching as one single call to text_poke(), we only
need make sure we're not patching the memcpy in text_poke itself.
This means the prototype to paravirt_ops.patch needs to change, to
marshal the new code into a buffer rather than patching in place as it
does now. It also means all patching goes through text_poke(), which
is known to be safe (apply_alternatives is also changed to make a
single patch).
AK: fix compilation on x86-64 (bad rusty!)
AK: fix boot on x86-64 (sigh)
AK: merged with other patches
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
committed by
Linus Torvalds
parent
d3f3c93469
commit
ab144f5ec6
@ -936,23 +936,24 @@ static const struct lguest_insns
|
||||
/* Now our patch routine is fairly simple (based on the native one in
|
||||
* paravirt.c). If we have a replacement, we copy it in and return how much of
|
||||
* the available space we used. */
|
||||
static unsigned lguest_patch(u8 type, u16 clobber, void *insns, unsigned len)
|
||||
static unsigned lguest_patch(u8 type, u16 clobber, void *ibuf,
|
||||
unsigned long addr, unsigned len)
|
||||
{
|
||||
unsigned int insn_len;
|
||||
|
||||
/* Don't do anything special if we don't have a replacement */
|
||||
if (type >= ARRAY_SIZE(lguest_insns) || !lguest_insns[type].start)
|
||||
return paravirt_patch_default(type, clobber, insns, len);
|
||||
return paravirt_patch_default(type, clobber, ibuf, addr, len);
|
||||
|
||||
insn_len = lguest_insns[type].end - lguest_insns[type].start;
|
||||
|
||||
/* Similarly if we can't fit replacement (shouldn't happen, but let's
|
||||
* be thorough). */
|
||||
if (len < insn_len)
|
||||
return paravirt_patch_default(type, clobber, insns, len);
|
||||
return paravirt_patch_default(type, clobber, ibuf, addr, len);
|
||||
|
||||
/* Copy in our instructions. */
|
||||
memcpy(insns, lguest_insns[type].start, insn_len);
|
||||
memcpy(ibuf, lguest_insns[type].start, insn_len);
|
||||
return insn_len;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user