aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/kprobes.c
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2011-01-05 06:47:17 -0500
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2011-01-05 06:47:23 -0500
commitfc0a1fea6b81095b6c0e01ec3407d04c8341974c (patch)
treeda864df5bdb576401afb9531f171ee31d268ddbb /arch/s390/kernel/kprobes.c
parent35f2aaa79a2d484c8449f34461464a1e84e36e2b (diff)
[S390] kprobes: single step cleanup
The saved interrupt mask and the saved control registers are only relevant while single stepping is set up. A secondary kprobe while kprobe single stepping is active may not occur. That makes is safe to remove the save and restore of kprobe_saved_imask / kprobe_save_ctl from save_previous_kprobe and restore_previous_kprobe. Move all single step related code to two functions, enable_singlestep and disable_singlestep. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/kprobes.c')
-rw-r--r--arch/s390/kernel/kprobes.c77
1 files changed, 36 insertions, 41 deletions
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index b8e51759b6e4..91c611f84ff7 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -198,51 +198,58 @@ void __kprobes arch_remove_kprobe(struct kprobe *p)
198 } 198 }
199} 199}
200 200
201static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) 201static void __kprobes enable_singlestep(struct kprobe_ctlblk *kcb,
202 struct pt_regs *regs,
203 unsigned long ip)
202{ 204{
203 per_cr_bits kprobe_per_regs[1]; 205 per_cr_bits kprobe_per_regs[1];
204 206
205 memset(kprobe_per_regs, 0, sizeof(per_cr_bits));
206 regs->psw.addr = (unsigned long)p->ainsn.insn | PSW_ADDR_AMODE;
207
208 /* Set up the per control reg info, will pass to lctl */ 207 /* Set up the per control reg info, will pass to lctl */
208 memset(kprobe_per_regs, 0, sizeof(per_cr_bits));
209 kprobe_per_regs[0].em_instruction_fetch = 1; 209 kprobe_per_regs[0].em_instruction_fetch = 1;
210 kprobe_per_regs[0].starting_addr = (unsigned long)p->ainsn.insn; 210 kprobe_per_regs[0].starting_addr = ip;
211 kprobe_per_regs[0].ending_addr = (unsigned long)p->ainsn.insn + 1; 211 kprobe_per_regs[0].ending_addr = ip;
212 212
213 /* Set the PER control regs, turns on single step for this address */ 213 /* Save control regs and psw mask */
214 __ctl_store(kcb->kprobe_saved_ctl, 9, 11);
215 kcb->kprobe_saved_imask = regs->psw.mask &
216 (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT);
217
218 /* Set PER control regs, turns on single step for the given address */
214 __ctl_load(kprobe_per_regs, 9, 11); 219 __ctl_load(kprobe_per_regs, 9, 11);
215 regs->psw.mask |= PSW_MASK_PER; 220 regs->psw.mask |= PSW_MASK_PER;
216 regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT); 221 regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT);
222 regs->psw.addr = ip | PSW_ADDR_AMODE;
217} 223}
218 224
225static void __kprobes disable_singlestep(struct kprobe_ctlblk *kcb,
226 struct pt_regs *regs,
227 unsigned long ip)
228{
229 /* Restore control regs and psw mask, set new psw address */
230 __ctl_load(kcb->kprobe_saved_ctl, 9, 11);
231 regs->psw.mask &= ~PSW_MASK_PER;
232 regs->psw.mask |= kcb->kprobe_saved_imask;
233 regs->psw.addr = ip | PSW_ADDR_AMODE;
234}
235
236
219static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) 237static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
220{ 238{
221 kcb->prev_kprobe.kp = kprobe_running(); 239 kcb->prev_kprobe.kp = kprobe_running();
222 kcb->prev_kprobe.status = kcb->kprobe_status; 240 kcb->prev_kprobe.status = kcb->kprobe_status;
223 kcb->prev_kprobe.kprobe_saved_imask = kcb->kprobe_saved_imask;
224 memcpy(kcb->prev_kprobe.kprobe_saved_ctl, kcb->kprobe_saved_ctl,
225 sizeof(kcb->kprobe_saved_ctl));
226} 241}
227 242
228static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) 243static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
229{ 244{
230 __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; 245 __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
231 kcb->kprobe_status = kcb->prev_kprobe.status; 246 kcb->kprobe_status = kcb->prev_kprobe.status;
232 kcb->kprobe_saved_imask = kcb->prev_kprobe.kprobe_saved_imask;
233 memcpy(kcb->kprobe_saved_ctl, kcb->prev_kprobe.kprobe_saved_ctl,
234 sizeof(kcb->kprobe_saved_ctl));
235} 247}
236 248
237static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, 249static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
238 struct kprobe_ctlblk *kcb) 250 struct kprobe_ctlblk *kcb)
239{ 251{
240 __get_cpu_var(current_kprobe) = p; 252 __get_cpu_var(current_kprobe) = p;
241 /* Save the interrupt and per flags */
242 kcb->kprobe_saved_imask = regs->psw.mask &
243 (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT);
244 /* Save the control regs that govern PER */
245 __ctl_store(kcb->kprobe_saved_ctl, 9, 11);
246} 253}
247 254
248void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, 255void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
@@ -282,7 +289,8 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
282 save_previous_kprobe(kcb); 289 save_previous_kprobe(kcb);
283 set_current_kprobe(p, regs, kcb); 290 set_current_kprobe(p, regs, kcb);
284 kprobes_inc_nmissed_count(p); 291 kprobes_inc_nmissed_count(p);
285 prepare_singlestep(p, regs); 292 enable_singlestep(kcb, regs,
293 (unsigned long) p->ainsn.insn);
286 kcb->kprobe_status = KPROBE_REENTER; 294 kcb->kprobe_status = KPROBE_REENTER;
287 return 1; 295 return 1;
288 } else { 296 } else {
@@ -311,7 +319,7 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
311 return 1; 319 return 1;
312 320
313ss_probe: 321ss_probe:
314 prepare_singlestep(p, regs); 322 enable_singlestep(kcb, regs, (unsigned long) p->ainsn.insn);
315 kcb->kprobe_status = KPROBE_HIT_SS; 323 kcb->kprobe_status = KPROBE_HIT_SS;
316 return 1; 324 return 1;
317 325
@@ -433,31 +441,20 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,
433static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) 441static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
434{ 442{
435 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); 443 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
436 444 unsigned long ip = regs->psw.addr & PSW_ADDR_INSN;
437 regs->psw.addr &= PSW_ADDR_INSN;
438 445
439 if (p->ainsn.fixup & FIXUP_PSW_NORMAL) 446 if (p->ainsn.fixup & FIXUP_PSW_NORMAL)
440 regs->psw.addr = (unsigned long)p->addr + 447 ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn;
441 ((unsigned long)regs->psw.addr -
442 (unsigned long)p->ainsn.insn);
443 448
444 if (p->ainsn.fixup & FIXUP_BRANCH_NOT_TAKEN) 449 if (p->ainsn.fixup & FIXUP_BRANCH_NOT_TAKEN)
445 if ((unsigned long)regs->psw.addr - 450 if (ip - (unsigned long) p->ainsn.insn == p->ainsn.ilen)
446 (unsigned long)p->ainsn.insn == p->ainsn.ilen) 451 ip = (unsigned long) p->addr + p->ainsn.ilen;
447 regs->psw.addr = (unsigned long)p->addr + p->ainsn.ilen;
448 452
449 if (p->ainsn.fixup & FIXUP_RETURN_REGISTER) 453 if (p->ainsn.fixup & FIXUP_RETURN_REGISTER)
450 regs->gprs[p->ainsn.reg] = ((unsigned long)p->addr + 454 regs->gprs[p->ainsn.reg] += (unsigned long) p->addr -
451 (regs->gprs[p->ainsn.reg] - 455 (unsigned long) p->ainsn.insn;
452 (unsigned long)p->ainsn.insn))
453 | PSW_ADDR_AMODE;
454 456
455 regs->psw.addr |= PSW_ADDR_AMODE; 457 disable_singlestep(kcb, regs, ip);
456 /* turn off PER mode */
457 regs->psw.mask &= ~PSW_MASK_PER;
458 /* Restore the original per control regs */
459 __ctl_load(kcb->kprobe_saved_ctl, 9, 11);
460 regs->psw.mask |= kcb->kprobe_saved_imask;
461} 458}
462 459
463static int __kprobes post_kprobe_handler(struct pt_regs *regs) 460static int __kprobes post_kprobe_handler(struct pt_regs *regs)
@@ -515,9 +512,7 @@ static int __kprobes kprobe_trap_handler(struct pt_regs *regs, int trapnr)
515 * and allow the page fault handler to continue as a 512 * and allow the page fault handler to continue as a
516 * normal page fault. 513 * normal page fault.
517 */ 514 */
518 regs->psw.addr = (unsigned long)cur->addr | PSW_ADDR_AMODE; 515 disable_singlestep(kcb, regs, (unsigned long) cur->addr);
519 regs->psw.mask &= ~PSW_MASK_PER;
520 regs->psw.mask |= kcb->kprobe_saved_imask;
521 if (kcb->kprobe_status == KPROBE_REENTER) 516 if (kcb->kprobe_status == KPROBE_REENTER)
522 restore_previous_kprobe(kcb); 517 restore_previous_kprobe(kcb);
523 else { 518 else {