actions-common.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * arch/arm/probes/kprobes/actions-common.c
  4. *
  5. * Copyright (C) 2011 Jon Medhurst <[email protected]>.
  6. *
  7. * Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is
  8. * Copyright (C) 2006, 2007 Motorola Inc.
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/kprobes.h>
  12. #include <asm/opcodes.h>
  13. #include "core.h"
  14. static void __kprobes simulate_ldm1stm1(probes_opcode_t insn,
  15. struct arch_probes_insn *asi,
  16. struct pt_regs *regs)
  17. {
  18. int rn = (insn >> 16) & 0xf;
  19. int lbit = insn & (1 << 20);
  20. int wbit = insn & (1 << 21);
  21. int ubit = insn & (1 << 23);
  22. int pbit = insn & (1 << 24);
  23. long *addr = (long *)regs->uregs[rn];
  24. int reg_bit_vector;
  25. int reg_count;
  26. reg_count = 0;
  27. reg_bit_vector = insn & 0xffff;
  28. while (reg_bit_vector) {
  29. reg_bit_vector &= (reg_bit_vector - 1);
  30. ++reg_count;
  31. }
  32. if (!ubit)
  33. addr -= reg_count;
  34. addr += (!pbit == !ubit);
  35. reg_bit_vector = insn & 0xffff;
  36. while (reg_bit_vector) {
  37. int reg = __ffs(reg_bit_vector);
  38. reg_bit_vector &= (reg_bit_vector - 1);
  39. if (lbit)
  40. regs->uregs[reg] = *addr++;
  41. else
  42. *addr++ = regs->uregs[reg];
  43. }
  44. if (wbit) {
  45. if (!ubit)
  46. addr -= reg_count;
  47. addr -= (!pbit == !ubit);
  48. regs->uregs[rn] = (long)addr;
  49. }
  50. }
  51. static void __kprobes simulate_stm1_pc(probes_opcode_t insn,
  52. struct arch_probes_insn *asi,
  53. struct pt_regs *regs)
  54. {
  55. unsigned long addr = regs->ARM_pc - 4;
  56. regs->ARM_pc = (long)addr + str_pc_offset;
  57. simulate_ldm1stm1(insn, asi, regs);
  58. regs->ARM_pc = (long)addr + 4;
  59. }
  60. static void __kprobes simulate_ldm1_pc(probes_opcode_t insn,
  61. struct arch_probes_insn *asi,
  62. struct pt_regs *regs)
  63. {
  64. simulate_ldm1stm1(insn, asi, regs);
  65. load_write_pc(regs->ARM_pc, regs);
  66. }
  67. static void __kprobes
  68. emulate_generic_r0_12_noflags(probes_opcode_t insn,
  69. struct arch_probes_insn *asi, struct pt_regs *regs)
  70. {
  71. register void *rregs asm("r1") = regs;
  72. register void *rfn asm("lr") = asi->insn_fn;
  73. __asm__ __volatile__ (
  74. ARM( "stmdb sp!, {%[regs], r11} \n\t" )
  75. THUMB( "stmdb sp!, {%[regs], r7} \n\t" )
  76. "ldmia %[regs], {r0-r12} \n\t"
  77. #if __LINUX_ARM_ARCH__ >= 6
  78. "blx %[fn] \n\t"
  79. #else
  80. "str %[fn], [sp, #-4]! \n\t"
  81. "adr lr, 1f \n\t"
  82. "ldr pc, [sp], #4 \n\t"
  83. "1: \n\t"
  84. #endif
  85. "ldr lr, [sp], #4 \n\t" /* lr = regs */
  86. "stmia lr, {r0-r12} \n\t"
  87. ARM( "ldr r11, [sp], #4 \n\t" )
  88. THUMB( "ldr r7, [sp], #4 \n\t" )
  89. : [regs] "=r" (rregs), [fn] "=r" (rfn)
  90. : "0" (rregs), "1" (rfn)
  91. : "r0", "r2", "r3", "r4", "r5", "r6", ARM("r7") THUMB("r11"),
  92. "r8", "r9", "r10", "r12", "memory", "cc"
  93. );
  94. }
  95. static void __kprobes
  96. emulate_generic_r2_14_noflags(probes_opcode_t insn,
  97. struct arch_probes_insn *asi, struct pt_regs *regs)
  98. {
  99. emulate_generic_r0_12_noflags(insn, asi,
  100. (struct pt_regs *)(regs->uregs+2));
  101. }
  102. static void __kprobes
  103. emulate_ldm_r3_15(probes_opcode_t insn,
  104. struct arch_probes_insn *asi, struct pt_regs *regs)
  105. {
  106. emulate_generic_r0_12_noflags(insn, asi,
  107. (struct pt_regs *)(regs->uregs+3));
  108. load_write_pc(regs->ARM_pc, regs);
  109. }
  110. enum probes_insn __kprobes
  111. kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
  112. const struct decode_header *h)
  113. {
  114. probes_insn_handler_t *handler = 0;
  115. unsigned reglist = insn & 0xffff;
  116. int is_ldm = insn & 0x100000;
  117. int rn = (insn >> 16) & 0xf;
  118. if (rn <= 12 && (reglist & 0xe000) == 0) {
  119. /* Instruction only uses registers in the range R0..R12 */
  120. handler = emulate_generic_r0_12_noflags;
  121. } else if (rn >= 2 && (reglist & 0x8003) == 0) {
  122. /* Instruction only uses registers in the range R2..R14 */
  123. rn -= 2;
  124. reglist >>= 2;
  125. handler = emulate_generic_r2_14_noflags;
  126. } else if (rn >= 3 && (reglist & 0x0007) == 0) {
  127. /* Instruction only uses registers in the range R3..R15 */
  128. if (is_ldm && (reglist & 0x8000)) {
  129. rn -= 3;
  130. reglist >>= 3;
  131. handler = emulate_ldm_r3_15;
  132. }
  133. }
  134. if (handler) {
  135. /* We can emulate the instruction in (possibly) modified form */
  136. asi->insn[0] = __opcode_to_mem_arm((insn & 0xfff00000) |
  137. (rn << 16) | reglist);
  138. asi->insn_handler = handler;
  139. return INSN_GOOD;
  140. }
  141. /* Fallback to slower simulation... */
  142. if (reglist & 0x8000)
  143. handler = is_ldm ? simulate_ldm1_pc : simulate_stm1_pc;
  144. else
  145. handler = simulate_ldm1stm1;
  146. asi->insn_handler = handler;
  147. return INSN_GOOD_NO_SLOT;
  148. }