diff options
author | Andi Kleen <ak@suse.de> | 2007-08-10 16:31:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-08-11 18:58:13 -0400 |
commit | ab144f5ec64c42218a555ec1dbde6b60cf2982d6 (patch) | |
tree | e3a4532e1db116e87060c9b18f4cfbf6258fdba3 | |
parent | d3f3c9346979bfa074c64eac5fc3ed5bba4f40ed (diff) |
i386: Make patching more robust, fix paravirt issue
Commit 19d36ccdc34f5ed444f8a6af0cbfdb6790eb1177 "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>
-rw-r--r-- | arch/i386/kernel/alternative.c | 33 | ||||
-rw-r--r-- | arch/i386/kernel/paravirt.c | 52 | ||||
-rw-r--r-- | arch/i386/kernel/vmi.c | 35 | ||||
-rw-r--r-- | arch/i386/xen/enlighten.c | 12 | ||||
-rw-r--r-- | drivers/lguest/lguest.c | 9 | ||||
-rw-r--r-- | include/asm-i386/paravirt.h | 16 |
6 files changed, 90 insertions, 67 deletions
diff --git a/arch/i386/kernel/alternative.c b/arch/i386/kernel/alternative.c index c85598acb8f..27a6b0c9a7c 100644 --- a/arch/i386/kernel/alternative.c +++ b/arch/i386/kernel/alternative.c | |||
@@ -11,6 +11,8 @@ | |||
11 | #include <asm/mce.h> | 11 | #include <asm/mce.h> |
12 | #include <asm/nmi.h> | 12 | #include <asm/nmi.h> |
13 | 13 | ||
14 | #define MAX_PATCH_LEN (255-1) | ||
15 | |||
14 | #ifdef CONFIG_HOTPLUG_CPU | 16 | #ifdef CONFIG_HOTPLUG_CPU |
15 | static int smp_alt_once; | 17 | static int smp_alt_once; |
16 | 18 | ||
@@ -148,7 +150,8 @@ static unsigned char** find_nop_table(void) | |||
148 | 150 | ||
149 | #endif /* CONFIG_X86_64 */ | 151 | #endif /* CONFIG_X86_64 */ |
150 | 152 | ||
151 | static void nop_out(void *insns, unsigned int len) | 153 | /* Use this to add nops to a buffer, then text_poke the whole buffer. */ |
154 | static void add_nops(void *insns, unsigned int len) | ||
152 | { | 155 | { |
153 | unsigned char **noptable = find_nop_table(); | 156 | unsigned char **noptable = find_nop_table(); |
154 | 157 | ||
@@ -156,7 +159,7 @@ static void nop_out(void *insns, unsigned int len) | |||
156 | unsigned int noplen = len; | 159 | unsigned int noplen = len; |
157 | if (noplen > ASM_NOP_MAX) | 160 | if (noplen > ASM_NOP_MAX) |
158 | noplen = ASM_NOP_MAX; | 161 | noplen = ASM_NOP_MAX; |
159 | text_poke(insns, noptable[noplen], noplen); | 162 | memcpy(insns, noptable[noplen], noplen); |
160 | insns += noplen; | 163 | insns += noplen; |
161 | len -= noplen; | 164 | len -= noplen; |
162 | } | 165 | } |
@@ -174,15 +177,15 @@ extern u8 *__smp_locks[], *__smp_locks_end[]; | |||
174 | void apply_alternatives(struct alt_instr *start, struct alt_instr *end) | 177 | void apply_alternatives(struct alt_instr *start, struct alt_instr *end) |
175 | { | 178 | { |
176 | struct alt_instr *a; | 179 | struct alt_instr *a; |
177 | u8 *instr; | 180 | char insnbuf[MAX_PATCH_LEN]; |
178 | int diff; | ||
179 | 181 | ||
180 | DPRINTK("%s: alt table %p -> %p\n", __FUNCTION__, start, end); | 182 | DPRINTK("%s: alt table %p -> %p\n", __FUNCTION__, start, end); |
181 | for (a = start; a < end; a++) { | 183 | for (a = start; a < end; a++) { |
184 | u8 *instr = a->instr; | ||
182 | BUG_ON(a->replacementlen > a->instrlen); | 185 | BUG_ON(a->replacementlen > a->instrlen); |
186 | BUG_ON(a->instrlen > sizeof(insnbuf)); | ||
183 | if (!boot_cpu_has(a->cpuid)) | 187 | if (!boot_cpu_has(a->cpuid)) |
184 | continue; | 188 | continue; |
185 | instr = a->instr; | ||
186 | #ifdef CONFIG_X86_64 | 189 | #ifdef CONFIG_X86_64 |
187 | /* vsyscall code is not mapped yet. resolve it manually. */ | 190 | /* vsyscall code is not mapped yet. resolve it manually. */ |
188 | if (instr >= (u8 *)VSYSCALL_START && instr < (u8*)VSYSCALL_END) { | 191 | if (instr >= (u8 *)VSYSCALL_START && instr < (u8*)VSYSCALL_END) { |
@@ -191,9 +194,10 @@ void apply_alternatives(struct alt_instr *start, struct alt_instr *end) | |||
191 | __FUNCTION__, a->instr, instr); | 194 | __FUNCTION__, a->instr, instr); |
192 | } | 195 | } |
193 | #endif | 196 | #endif |
194 | memcpy(instr, a->replacement, a->replacementlen); | 197 | memcpy(insnbuf, a->replacement, a->replacementlen); |
195 | diff = a->instrlen - a->replacementlen; | 198 | add_nops(insnbuf + a->replacementlen, |
196 | nop_out(instr + a->replacementlen, diff); | 199 | a->instrlen - a->replacementlen); |
200 | text_poke(instr, insnbuf, a->instrlen); | ||
197 | } | 201 | } |
198 | } | 202 | } |
199 | 203 | ||
@@ -215,16 +219,18 @@ static void alternatives_smp_lock(u8 **start, u8 **end, u8 *text, u8 *text_end) | |||
215 | static void alternatives_smp_unlock(u8 **start, u8 **end, u8 *text, u8 *text_end) | 219 | static void alternatives_smp_unlock(u8 **start, u8 **end, u8 *text, u8 *text_end) |
216 | { | 220 | { |
217 | u8 **ptr; | 221 | u8 **ptr; |
222 | char insn[1]; | ||
218 | 223 | ||
219 | if (noreplace_smp) | 224 | if (noreplace_smp) |
220 | return; | 225 | return; |
221 | 226 | ||
227 | add_nops(insn, 1); | ||
222 | for (ptr = start; ptr < end; ptr++) { | 228 | for (ptr = start; ptr < end; ptr++) { |
223 | if (*ptr < text) | 229 | if (*ptr < text) |
224 | continue; | 230 | continue; |
225 | if (*ptr > text_end) | 231 | if (*ptr > text_end) |
226 | continue; | 232 | continue; |
227 | nop_out(*ptr, 1); | 233 | text_poke(*ptr, insn, 1); |
228 | }; | 234 | }; |
229 | } | 235 | } |
230 | 236 | ||
@@ -351,6 +357,7 @@ void apply_paravirt(struct paravirt_patch_site *start, | |||
351 | struct paravirt_patch_site *end) | 357 | struct paravirt_patch_site *end) |
352 | { | 358 | { |
353 | struct paravirt_patch_site *p; | 359 | struct paravirt_patch_site *p; |
360 | char insnbuf[MAX_PATCH_LEN]; | ||
354 | 361 | ||
355 | if (noreplace_paravirt) | 362 | if (noreplace_paravirt) |
356 | return; | 363 | return; |
@@ -358,13 +365,15 @@ void apply_paravirt(struct paravirt_patch_site *start, | |||
358 | for (p = start; p < end; p++) { | 365 | for (p = start; p < end; p++) { |
359 | unsigned int used; | 366 | unsigned int used; |
360 | 367 | ||
361 | used = paravirt_ops.patch(p->instrtype, p->clobbers, p->instr, | 368 | BUG_ON(p->len > MAX_PATCH_LEN); |
362 | p->len); | 369 | used = paravirt_ops.patch(p->instrtype, p->clobbers, insnbuf, |
370 | (unsigned long)p->instr, p->len); | ||
363 | 371 | ||
364 | BUG_ON(used > p->len); | 372 | BUG_ON(used > p->len); |
365 | 373 | ||
366 | /* Pad the rest with nops */ | 374 | /* Pad the rest with nops */ |
367 | nop_out(p->instr + used, p->len - used); | 375 | add_nops(insnbuf + used, p->len - used); |
376 | text_poke(p->instr, insnbuf, p->len); | ||
368 | } | 377 | } |
369 | } | 378 | } |
370 | extern struct paravirt_patch_site __start_parainstructions[], | 379 | extern struct paravirt_patch_site __start_parainstructions[], |
diff --git a/arch/i386/kernel/paravirt.c b/arch/i386/kernel/paravirt.c index ea962c0667d..739cfb207dd 100644 --- a/arch/i386/kernel/paravirt.c +++ b/arch/i386/kernel/paravirt.c | |||
@@ -69,7 +69,8 @@ DEF_NATIVE(read_tsc, "rdtsc"); | |||
69 | 69 | ||
70 | DEF_NATIVE(ud2a, "ud2a"); | 70 | DEF_NATIVE(ud2a, "ud2a"); |
71 | 71 | ||
72 | static unsigned native_patch(u8 type, u16 clobbers, void *insns, unsigned len) | 72 | static unsigned native_patch(u8 type, u16 clobbers, void *ibuf, |
73 | unsigned long addr, unsigned len) | ||
73 | { | 74 | { |
74 | const unsigned char *start, *end; | 75 | const unsigned char *start, *end; |
75 | unsigned ret; | 76 | unsigned ret; |
@@ -90,7 +91,7 @@ static unsigned native_patch(u8 type, u16 clobbers, void *insns, unsigned len) | |||
90 | #undef SITE | 91 | #undef SITE |
91 | 92 | ||
92 | patch_site: | 93 | patch_site: |
93 | ret = paravirt_patch_insns(insns, len, start, end); | 94 | ret = paravirt_patch_insns(ibuf, len, start, end); |
94 | break; | 95 | break; |
95 | 96 | ||
96 | case PARAVIRT_PATCH(make_pgd): | 97 | case PARAVIRT_PATCH(make_pgd): |
@@ -107,7 +108,7 @@ static unsigned native_patch(u8 type, u16 clobbers, void *insns, unsigned len) | |||
107 | break; | 108 | break; |
108 | 109 | ||
109 | default: | 110 | default: |
110 | ret = paravirt_patch_default(type, clobbers, insns, len); | 111 | ret = paravirt_patch_default(type, clobbers, ibuf, addr, len); |
111 | break; | 112 | break; |
112 | } | 113 | } |
113 | 114 | ||
@@ -129,68 +130,67 @@ struct branch { | |||
129 | u32 delta; | 130 | u32 delta; |
130 | } __attribute__((packed)); | 131 | } __attribute__((packed)); |
131 | 132 | ||
132 | unsigned paravirt_patch_call(void *target, u16 tgt_clobbers, | 133 | unsigned paravirt_patch_call(void *insnbuf, |
133 | void *site, u16 site_clobbers, | 134 | const void *target, u16 tgt_clobbers, |
135 | unsigned long addr, u16 site_clobbers, | ||
134 | unsigned len) | 136 | unsigned len) |
135 | { | 137 | { |
136 | unsigned char *call = site; | 138 | struct branch *b = insnbuf; |
137 | unsigned long delta = (unsigned long)target - (unsigned long)(call+5); | 139 | unsigned long delta = (unsigned long)target - (addr+5); |
138 | struct branch b; | ||
139 | 140 | ||
140 | if (tgt_clobbers & ~site_clobbers) | 141 | if (tgt_clobbers & ~site_clobbers) |
141 | return len; /* target would clobber too much for this site */ | 142 | return len; /* target would clobber too much for this site */ |
142 | if (len < 5) | 143 | if (len < 5) |
143 | return len; /* call too long for patch site */ | 144 | return len; /* call too long for patch site */ |
144 | 145 | ||
145 | b.opcode = 0xe8; /* call */ | 146 | b->opcode = 0xe8; /* call */ |
146 | b.delta = delta; | 147 | b->delta = delta; |
147 | BUILD_BUG_ON(sizeof(b) != 5); | 148 | BUILD_BUG_ON(sizeof(*b) != 5); |
148 | text_poke(call, (unsigned char *)&b, 5); | ||
149 | 149 | ||
150 | return 5; | 150 | return 5; |
151 | } | 151 | } |
152 | 152 | ||
153 | unsigned paravirt_patch_jmp(void *target, void *site, unsigned len) | 153 | unsigned paravirt_patch_jmp(const void *target, void *insnbuf, |
154 | unsigned long addr, unsigned len) | ||
154 | { | 155 | { |
155 | unsigned char *jmp = site; | 156 | struct branch *b = insnbuf; |
156 | unsigned long delta = (unsigned long)target - (unsigned long)(jmp+5); | 157 | unsigned long delta = (unsigned long)target - (addr+5); |
157 | struct branch b; | ||
158 | 158 | ||
159 | if (len < 5) | 159 | if (len < 5) |
160 | return len; /* call too long for patch site */ | 160 | return len; /* call too long for patch site */ |
161 | 161 | ||
162 | b.opcode = 0xe9; /* jmp */ | 162 | b->opcode = 0xe9; /* jmp */ |
163 | b.delta = delta; | 163 | b->delta = delta; |
164 | text_poke(jmp, (unsigned char *)&b, 5); | ||
165 | 164 | ||
166 | return 5; | 165 | return 5; |
167 | } | 166 | } |
168 | 167 | ||
169 | unsigned paravirt_patch_default(u8 type, u16 clobbers, void *site, unsigned len) | 168 | unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf, |
169 | unsigned long addr, unsigned len) | ||
170 | { | 170 | { |
171 | void *opfunc = *((void **)¶virt_ops + type); | 171 | void *opfunc = *((void **)¶virt_ops + type); |
172 | unsigned ret; | 172 | unsigned ret; |
173 | 173 | ||
174 | if (opfunc == NULL) | 174 | if (opfunc == NULL) |
175 | /* If there's no function, patch it with a ud2a (BUG) */ | 175 | /* If there's no function, patch it with a ud2a (BUG) */ |
176 | ret = paravirt_patch_insns(site, len, start_ud2a, end_ud2a); | 176 | ret = paravirt_patch_insns(insnbuf, len, start_ud2a, end_ud2a); |
177 | else if (opfunc == paravirt_nop) | 177 | else if (opfunc == paravirt_nop) |
178 | /* If the operation is a nop, then nop the callsite */ | 178 | /* If the operation is a nop, then nop the callsite */ |
179 | ret = paravirt_patch_nop(); | 179 | ret = paravirt_patch_nop(); |
180 | else if (type == PARAVIRT_PATCH(iret) || | 180 | else if (type == PARAVIRT_PATCH(iret) || |
181 | type == PARAVIRT_PATCH(irq_enable_sysexit)) | 181 | type == PARAVIRT_PATCH(irq_enable_sysexit)) |
182 | /* If operation requires a jmp, then jmp */ | 182 | /* If operation requires a jmp, then jmp */ |
183 | ret = paravirt_patch_jmp(opfunc, site, len); | 183 | ret = paravirt_patch_jmp(opfunc, insnbuf, addr, len); |
184 | else | 184 | else |
185 | /* Otherwise call the function; assume target could | 185 | /* Otherwise call the function; assume target could |
186 | clobber any caller-save reg */ | 186 | clobber any caller-save reg */ |
187 | ret = paravirt_patch_call(opfunc, CLBR_ANY, | 187 | ret = paravirt_patch_call(insnbuf, opfunc, CLBR_ANY, |
188 | site, clobbers, len); | 188 | addr, clobbers, len); |
189 | 189 | ||
190 | return ret; | 190 | return ret; |
191 | } | 191 | } |
192 | 192 | ||
193 | unsigned paravirt_patch_insns(void *site, unsigned len, | 193 | unsigned paravirt_patch_insns(void *insnbuf, unsigned len, |
194 | const char *start, const char *end) | 194 | const char *start, const char *end) |
195 | { | 195 | { |
196 | unsigned insn_len = end - start; | 196 | unsigned insn_len = end - start; |
@@ -198,7 +198,7 @@ unsigned paravirt_patch_insns(void *site, unsigned len, | |||
198 | if (insn_len > len || start == NULL) | 198 | if (insn_len > len || start == NULL) |
199 | insn_len = len; | 199 | insn_len = len; |
200 | else | 200 | else |
201 | memcpy(site, start, insn_len); | 201 | memcpy(insnbuf, start, insn_len); |
202 | 202 | ||
203 | return insn_len; | 203 | return insn_len; |
204 | } | 204 | } |
diff --git a/arch/i386/kernel/vmi.c b/arch/i386/kernel/vmi.c index 72042bb7ec9..18673e0f193 100644 --- a/arch/i386/kernel/vmi.c +++ b/arch/i386/kernel/vmi.c | |||
@@ -87,12 +87,14 @@ struct vmi_timer_ops vmi_timer_ops; | |||
87 | #define IRQ_PATCH_INT_MASK 0 | 87 | #define IRQ_PATCH_INT_MASK 0 |
88 | #define IRQ_PATCH_DISABLE 5 | 88 | #define IRQ_PATCH_DISABLE 5 |
89 | 89 | ||
90 | static inline void patch_offset(unsigned char *eip, unsigned char *dest) | 90 | static inline void patch_offset(void *insnbuf, |
91 | unsigned long eip, unsigned long dest) | ||
91 | { | 92 | { |
92 | *(unsigned long *)(eip+1) = dest-eip-5; | 93 | *(unsigned long *)(insnbuf+1) = dest-eip-5; |
93 | } | 94 | } |
94 | 95 | ||
95 | static unsigned patch_internal(int call, unsigned len, void *insns) | 96 | static unsigned patch_internal(int call, unsigned len, void *insnbuf, |
97 | unsigned long eip) | ||
96 | { | 98 | { |
97 | u64 reloc; | 99 | u64 reloc; |
98 | struct vmi_relocation_info *const rel = (struct vmi_relocation_info *)&reloc; | 100 | struct vmi_relocation_info *const rel = (struct vmi_relocation_info *)&reloc; |
@@ -100,14 +102,14 @@ static unsigned patch_internal(int call, unsigned len, void *insns) | |||
100 | switch(rel->type) { | 102 | switch(rel->type) { |
101 | case VMI_RELOCATION_CALL_REL: | 103 | case VMI_RELOCATION_CALL_REL: |
102 | BUG_ON(len < 5); | 104 | BUG_ON(len < 5); |
103 | *(char *)insns = MNEM_CALL; | 105 | *(char *)insnbuf = MNEM_CALL; |
104 | patch_offset(insns, rel->eip); | 106 | patch_offset(insnbuf, eip, (unsigned long)rel->eip); |
105 | return 5; | 107 | return 5; |
106 | 108 | ||
107 | case VMI_RELOCATION_JUMP_REL: | 109 | case VMI_RELOCATION_JUMP_REL: |
108 | BUG_ON(len < 5); | 110 | BUG_ON(len < 5); |
109 | *(char *)insns = MNEM_JMP; | 111 | *(char *)insnbuf = MNEM_JMP; |
110 | patch_offset(insns, rel->eip); | 112 | patch_offset(insnbuf, eip, (unsigned long)rel->eip); |
111 | return 5; | 113 | return 5; |
112 | 114 | ||
113 | case VMI_RELOCATION_NOP: | 115 | case VMI_RELOCATION_NOP: |
@@ -128,21 +130,26 @@ static unsigned patch_internal(int call, unsigned len, void *insns) | |||
128 | * Apply patch if appropriate, return length of new instruction | 130 | * Apply patch if appropriate, return length of new instruction |
129 | * sequence. The callee does nop padding for us. | 131 | * sequence. The callee does nop padding for us. |
130 | */ | 132 | */ |
131 | static unsigned vmi_patch(u8 type, u16 clobbers, void *insns, unsigned len) | 133 | static unsigned vmi_patch(u8 type, u16 clobbers, void *insns, |
134 | unsigned long eip, unsigned len) | ||
132 | { | 135 | { |
133 | switch (type) { | 136 | switch (type) { |
134 | case PARAVIRT_PATCH(irq_disable): | 137 | case PARAVIRT_PATCH(irq_disable): |
135 | return patch_internal(VMI_CALL_DisableInterrupts, len, insns); | 138 | return patch_internal(VMI_CALL_DisableInterrupts, len, |
139 | insns, eip); | ||
136 | case PARAVIRT_PATCH(irq_enable): | 140 | case PARAVIRT_PATCH(irq_enable): |
137 | return patch_internal(VMI_CALL_EnableInterrupts, len, insns); | 141 | return patch_internal(VMI_CALL_EnableInterrupts, len, |
142 | insns, eip); | ||
138 | case PARAVIRT_PATCH(restore_fl): | 143 | case PARAVIRT_PATCH(restore_fl): |
139 | return patch_internal(VMI_CALL_SetInterruptMask, len, insns); | 144 | return patch_internal(VMI_CALL_SetInterruptMask, len, |
145 | insns, eip); | ||
140 | case PARAVIRT_PATCH(save_fl): | 146 | case PARAVIRT_PATCH(save_fl): |
141 | return patch_internal(VMI_CALL_GetInterruptMask, len, insns); | 147 | return patch_internal(VMI_CALL_GetInterruptMask, len, |
148 | insns, eip); | ||
142 | case PARAVIRT_PATCH(iret): | 149 | case PARAVIRT_PATCH(iret): |
143 | return patch_internal(VMI_CALL_IRET, len, insns); | 150 | return patch_internal(VMI_CALL_IRET, len, insns, eip); |
144 | case PARAVIRT_PATCH(irq_enable_sysexit): | 151 | case PARAVIRT_PATCH(irq_enable_sysexit): |
145 | return patch_internal(VMI_CALL_SYSEXIT, len, insns); | 152 | return patch_internal(VMI_CALL_SYSEXIT, len, insns, eip); |
146 | default: | 153 | default: |
147 | break; | 154 | break; |
148 | } | 155 | } |
diff --git a/arch/i386/xen/enlighten.c b/arch/i386/xen/enlighten.c index 9a8c1181c00..f0c37511d8d 100644 --- a/arch/i386/xen/enlighten.c +++ b/arch/i386/xen/enlighten.c | |||
@@ -842,7 +842,8 @@ void __init xen_setup_vcpu_info_placement(void) | |||
842 | } | 842 | } |
843 | } | 843 | } |
844 | 844 | ||
845 | static unsigned xen_patch(u8 type, u16 clobbers, void *insns, unsigned len) | 845 | static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf, |
846 | unsigned long addr, unsigned len) | ||
846 | { | 847 | { |
847 | char *start, *end, *reloc; | 848 | char *start, *end, *reloc; |
848 | unsigned ret; | 849 | unsigned ret; |
@@ -869,7 +870,7 @@ static unsigned xen_patch(u8 type, u16 clobbers, void *insns, unsigned len) | |||
869 | if (start == NULL || (end-start) > len) | 870 | if (start == NULL || (end-start) > len) |
870 | goto default_patch; | 871 | goto default_patch; |
871 | 872 | ||
872 | ret = paravirt_patch_insns(insns, len, start, end); | 873 | ret = paravirt_patch_insns(insnbuf, len, start, end); |
873 | 874 | ||
874 | /* Note: because reloc is assigned from something that | 875 | /* Note: because reloc is assigned from something that |
875 | appears to be an array, gcc assumes it's non-null, | 876 | appears to be an array, gcc assumes it's non-null, |
@@ -877,8 +878,8 @@ static unsigned xen_patch(u8 type, u16 clobbers, void *insns, unsigned len) | |||
877 | end. */ | 878 | end. */ |
878 | if (reloc > start && reloc < end) { | 879 | if (reloc > start && reloc < end) { |
879 | int reloc_off = reloc - start; | 880 | int reloc_off = reloc - start; |
880 | long *relocp = (long *)(insns + reloc_off); | 881 | long *relocp = (long *)(insnbuf + reloc_off); |
881 | long delta = start - (char *)insns; | 882 | long delta = start - (char *)addr; |
882 | 883 | ||
883 | *relocp += delta; | 884 | *relocp += delta; |
884 | } | 885 | } |
@@ -886,7 +887,8 @@ static unsigned xen_patch(u8 type, u16 clobbers, void *insns, unsigned len) | |||
886 | 887 | ||
887 | default_patch: | 888 | default_patch: |
888 | default: | 889 | default: |
889 | ret = paravirt_patch_default(type, clobbers, insns, len); | 890 | ret = paravirt_patch_default(type, clobbers, insnbuf, |
891 | addr, len); | ||
890 | break; | 892 | break; |
891 | } | 893 | } |
892 | 894 | ||
diff --git a/drivers/lguest/lguest.c b/drivers/lguest/lguest.c index 524beea7fb1..6e135ac0834 100644 --- a/drivers/lguest/lguest.c +++ b/drivers/lguest/lguest.c | |||
@@ -936,23 +936,24 @@ static const struct lguest_insns | |||
936 | /* Now our patch routine is fairly simple (based on the native one in | 936 | /* Now our patch routine is fairly simple (based on the native one in |
937 | * paravirt.c). If we have a replacement, we copy it in and return how much of | 937 | * paravirt.c). If we have a replacement, we copy it in and return how much of |
938 | * the available space we used. */ | 938 | * the available space we used. */ |
939 | static unsigned lguest_patch(u8 type, u16 clobber, void *insns, unsigned len) | 939 | static unsigned lguest_patch(u8 type, u16 clobber, void *ibuf, |
940 | unsigned long addr, unsigned len) | ||
940 | { | 941 | { |
941 | unsigned int insn_len; | 942 | unsigned int insn_len; |
942 | 943 | ||
943 | /* Don't do anything special if we don't have a replacement */ | 944 | /* Don't do anything special if we don't have a replacement */ |
944 | if (type >= ARRAY_SIZE(lguest_insns) || !lguest_insns[type].start) | 945 | if (type >= ARRAY_SIZE(lguest_insns) || !lguest_insns[type].start) |
945 | return paravirt_patch_default(type, clobber, insns, len); | 946 | return paravirt_patch_default(type, clobber, ibuf, addr, len); |
946 | 947 | ||
947 | insn_len = lguest_insns[type].end - lguest_insns[type].start; | 948 | insn_len = lguest_insns[type].end - lguest_insns[type].start; |
948 | 949 | ||
949 | /* Similarly if we can't fit replacement (shouldn't happen, but let's | 950 | /* Similarly if we can't fit replacement (shouldn't happen, but let's |
950 | * be thorough). */ | 951 | * be thorough). */ |
951 | if (len < insn_len) | 952 | if (len < insn_len) |
952 | return paravirt_patch_default(type, clobber, insns, len); | 953 | return paravirt_patch_default(type, clobber, ibuf, addr, len); |
953 | 954 | ||
954 | /* Copy in our instructions. */ | 955 | /* Copy in our instructions. */ |
955 | memcpy(insns, lguest_insns[type].start, insn_len); | 956 | memcpy(ibuf, lguest_insns[type].start, insn_len); |
956 | return insn_len; | 957 | return insn_len; |
957 | } | 958 | } |
958 | 959 | ||
diff --git a/include/asm-i386/paravirt.h b/include/asm-i386/paravirt.h index 7df88be2dd9..9fa3fa9e62d 100644 --- a/include/asm-i386/paravirt.h +++ b/include/asm-i386/paravirt.h | |||
@@ -47,7 +47,8 @@ struct paravirt_ops | |||
47 | * The patch function should return the number of bytes of code | 47 | * The patch function should return the number of bytes of code |
48 | * generated, as we nop pad the rest in generic code. | 48 | * generated, as we nop pad the rest in generic code. |
49 | */ | 49 | */ |
50 | unsigned (*patch)(u8 type, u16 clobber, void *firstinsn, unsigned len); | 50 | unsigned (*patch)(u8 type, u16 clobber, void *insnbuf, |
51 | unsigned long addr, unsigned len); | ||
51 | 52 | ||
52 | /* Basic arch-specific setup */ | 53 | /* Basic arch-specific setup */ |
53 | void (*arch_setup)(void); | 54 | void (*arch_setup)(void); |
@@ -253,13 +254,16 @@ extern struct paravirt_ops paravirt_ops; | |||
253 | 254 | ||
254 | unsigned paravirt_patch_nop(void); | 255 | unsigned paravirt_patch_nop(void); |
255 | unsigned paravirt_patch_ignore(unsigned len); | 256 | unsigned paravirt_patch_ignore(unsigned len); |
256 | unsigned paravirt_patch_call(void *target, u16 tgt_clobbers, | 257 | unsigned paravirt_patch_call(void *insnbuf, |
257 | void *site, u16 site_clobbers, | 258 | const void *target, u16 tgt_clobbers, |
259 | unsigned long addr, u16 site_clobbers, | ||
258 | unsigned len); | 260 | unsigned len); |
259 | unsigned paravirt_patch_jmp(void *target, void *site, unsigned len); | 261 | unsigned paravirt_patch_jmp(const void *target, void *insnbuf, |
260 | unsigned paravirt_patch_default(u8 type, u16 clobbers, void *site, unsigned len); | 262 | unsigned long addr, unsigned len); |
263 | unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf, | ||
264 | unsigned long addr, unsigned len); | ||
261 | 265 | ||
262 | unsigned paravirt_patch_insns(void *site, unsigned len, | 266 | unsigned paravirt_patch_insns(void *insnbuf, unsigned len, |
263 | const char *start, const char *end); | 267 | const char *start, const char *end); |
264 | 268 | ||
265 | int paravirt_disable_iospace(void); | 269 | int paravirt_disable_iospace(void); |