actions-thumb.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * arch/arm/probes/kprobes/actions-thumb.c
  4. *
  5. * Copyright (C) 2011 Jon Medhurst <[email protected]>.
  6. */
  7. #include <linux/types.h>
  8. #include <linux/kernel.h>
  9. #include <linux/ptrace.h>
  10. #include <linux/kprobes.h>
  11. #include "../decode-thumb.h"
  12. #include "core.h"
  13. #include "checkers.h"
  14. /* These emulation encodings are functionally equivalent... */
  15. #define t32_emulate_rd8rn16rm0ra12_noflags \
  16. t32_emulate_rdlo12rdhi8rn16rm0_noflags
  17. /* t32 thumb actions */
  18. static void __kprobes
  19. t32_simulate_table_branch(probes_opcode_t insn,
  20. struct arch_probes_insn *asi, struct pt_regs *regs)
  21. {
  22. unsigned long pc = regs->ARM_pc;
  23. int rn = (insn >> 16) & 0xf;
  24. int rm = insn & 0xf;
  25. unsigned long rnv = (rn == 15) ? pc : regs->uregs[rn];
  26. unsigned long rmv = regs->uregs[rm];
  27. unsigned int halfwords;
  28. if (insn & 0x10) /* TBH */
  29. halfwords = ((u16 *)rnv)[rmv];
  30. else /* TBB */
  31. halfwords = ((u8 *)rnv)[rmv];
  32. regs->ARM_pc = pc + 2 * halfwords;
  33. }
  34. static void __kprobes
  35. t32_simulate_mrs(probes_opcode_t insn,
  36. struct arch_probes_insn *asi, struct pt_regs *regs)
  37. {
  38. int rd = (insn >> 8) & 0xf;
  39. unsigned long mask = 0xf8ff03df; /* Mask out execution state */
  40. regs->uregs[rd] = regs->ARM_cpsr & mask;
  41. }
  42. static void __kprobes
  43. t32_simulate_cond_branch(probes_opcode_t insn,
  44. struct arch_probes_insn *asi, struct pt_regs *regs)
  45. {
  46. unsigned long pc = regs->ARM_pc;
  47. long offset = insn & 0x7ff; /* imm11 */
  48. offset += (insn & 0x003f0000) >> 5; /* imm6 */
  49. offset += (insn & 0x00002000) << 4; /* J1 */
  50. offset += (insn & 0x00000800) << 7; /* J2 */
  51. offset -= (insn & 0x04000000) >> 7; /* Apply sign bit */
  52. regs->ARM_pc = pc + (offset * 2);
  53. }
  54. static enum probes_insn __kprobes
  55. t32_decode_cond_branch(probes_opcode_t insn, struct arch_probes_insn *asi,
  56. const struct decode_header *d)
  57. {
  58. int cc = (insn >> 22) & 0xf;
  59. asi->insn_check_cc = probes_condition_checks[cc];
  60. asi->insn_handler = t32_simulate_cond_branch;
  61. return INSN_GOOD_NO_SLOT;
  62. }
  63. static void __kprobes
  64. t32_simulate_branch(probes_opcode_t insn,
  65. struct arch_probes_insn *asi, struct pt_regs *regs)
  66. {
  67. unsigned long pc = regs->ARM_pc;
  68. long offset = insn & 0x7ff; /* imm11 */
  69. offset += (insn & 0x03ff0000) >> 5; /* imm10 */
  70. offset += (insn & 0x00002000) << 9; /* J1 */
  71. offset += (insn & 0x00000800) << 10; /* J2 */
  72. if (insn & 0x04000000)
  73. offset -= 0x00800000; /* Apply sign bit */
  74. else
  75. offset ^= 0x00600000; /* Invert J1 and J2 */
  76. if (insn & (1 << 14)) {
  77. /* BL or BLX */
  78. regs->ARM_lr = regs->ARM_pc | 1;
  79. if (!(insn & (1 << 12))) {
  80. /* BLX so switch to ARM mode */
  81. regs->ARM_cpsr &= ~PSR_T_BIT;
  82. pc &= ~3;
  83. }
  84. }
  85. regs->ARM_pc = pc + (offset * 2);
  86. }
  87. static void __kprobes
  88. t32_simulate_ldr_literal(probes_opcode_t insn,
  89. struct arch_probes_insn *asi, struct pt_regs *regs)
  90. {
  91. unsigned long addr = regs->ARM_pc & ~3;
  92. int rt = (insn >> 12) & 0xf;
  93. unsigned long rtv;
  94. long offset = insn & 0xfff;
  95. if (insn & 0x00800000)
  96. addr += offset;
  97. else
  98. addr -= offset;
  99. if (insn & 0x00400000) {
  100. /* LDR */
  101. rtv = *(unsigned long *)addr;
  102. if (rt == 15) {
  103. bx_write_pc(rtv, regs);
  104. return;
  105. }
  106. } else if (insn & 0x00200000) {
  107. /* LDRH */
  108. if (insn & 0x01000000)
  109. rtv = *(s16 *)addr;
  110. else
  111. rtv = *(u16 *)addr;
  112. } else {
  113. /* LDRB */
  114. if (insn & 0x01000000)
  115. rtv = *(s8 *)addr;
  116. else
  117. rtv = *(u8 *)addr;
  118. }
  119. regs->uregs[rt] = rtv;
  120. }
  121. static enum probes_insn __kprobes
  122. t32_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
  123. const struct decode_header *d)
  124. {
  125. enum probes_insn ret = kprobe_decode_ldmstm(insn, asi, d);
  126. /* Fixup modified instruction to have halfwords in correct order...*/
  127. insn = __mem_to_opcode_arm(asi->insn[0]);
  128. ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn >> 16);
  129. ((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0xffff);
  130. return ret;
  131. }
  132. static void __kprobes
  133. t32_emulate_ldrdstrd(probes_opcode_t insn,
  134. struct arch_probes_insn *asi, struct pt_regs *regs)
  135. {
  136. unsigned long pc = regs->ARM_pc & ~3;
  137. int rt1 = (insn >> 12) & 0xf;
  138. int rt2 = (insn >> 8) & 0xf;
  139. int rn = (insn >> 16) & 0xf;
  140. register unsigned long rt1v asm("r0") = regs->uregs[rt1];
  141. register unsigned long rt2v asm("r1") = regs->uregs[rt2];
  142. register unsigned long rnv asm("r2") = (rn == 15) ? pc
  143. : regs->uregs[rn];
  144. __asm__ __volatile__ (
  145. "blx %[fn]"
  146. : "=r" (rt1v), "=r" (rt2v), "=r" (rnv)
  147. : "0" (rt1v), "1" (rt2v), "2" (rnv), [fn] "r" (asi->insn_fn)
  148. : "lr", "memory", "cc"
  149. );
  150. if (rn != 15)
  151. regs->uregs[rn] = rnv; /* Writeback base register */
  152. regs->uregs[rt1] = rt1v;
  153. regs->uregs[rt2] = rt2v;
  154. }
  155. static void __kprobes
  156. t32_emulate_ldrstr(probes_opcode_t insn,
  157. struct arch_probes_insn *asi, struct pt_regs *regs)
  158. {
  159. int rt = (insn >> 12) & 0xf;
  160. int rn = (insn >> 16) & 0xf;
  161. int rm = insn & 0xf;
  162. register unsigned long rtv asm("r0") = regs->uregs[rt];
  163. register unsigned long rnv asm("r2") = regs->uregs[rn];
  164. register unsigned long rmv asm("r3") = regs->uregs[rm];
  165. __asm__ __volatile__ (
  166. "blx %[fn]"
  167. : "=r" (rtv), "=r" (rnv)
  168. : "0" (rtv), "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
  169. : "lr", "memory", "cc"
  170. );
  171. regs->uregs[rn] = rnv; /* Writeback base register */
  172. if (rt == 15) /* Can't be true for a STR as they aren't allowed */
  173. bx_write_pc(rtv, regs);
  174. else
  175. regs->uregs[rt] = rtv;
  176. }
  177. static void __kprobes
  178. t32_emulate_rd8rn16rm0_rwflags(probes_opcode_t insn,
  179. struct arch_probes_insn *asi, struct pt_regs *regs)
  180. {
  181. int rd = (insn >> 8) & 0xf;
  182. int rn = (insn >> 16) & 0xf;
  183. int rm = insn & 0xf;
  184. register unsigned long rdv asm("r1") = regs->uregs[rd];
  185. register unsigned long rnv asm("r2") = regs->uregs[rn];
  186. register unsigned long rmv asm("r3") = regs->uregs[rm];
  187. unsigned long cpsr = regs->ARM_cpsr;
  188. __asm__ __volatile__ (
  189. "msr cpsr_fs, %[cpsr] \n\t"
  190. "blx %[fn] \n\t"
  191. "mrs %[cpsr], cpsr \n\t"
  192. : "=r" (rdv), [cpsr] "=r" (cpsr)
  193. : "0" (rdv), "r" (rnv), "r" (rmv),
  194. "1" (cpsr), [fn] "r" (asi->insn_fn)
  195. : "lr", "memory", "cc"
  196. );
  197. regs->uregs[rd] = rdv;
  198. regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
  199. }
  200. static void __kprobes
  201. t32_emulate_rd8pc16_noflags(probes_opcode_t insn,
  202. struct arch_probes_insn *asi, struct pt_regs *regs)
  203. {
  204. unsigned long pc = regs->ARM_pc;
  205. int rd = (insn >> 8) & 0xf;
  206. register unsigned long rdv asm("r1") = regs->uregs[rd];
  207. register unsigned long rnv asm("r2") = pc & ~3;
  208. __asm__ __volatile__ (
  209. "blx %[fn]"
  210. : "=r" (rdv)
  211. : "0" (rdv), "r" (rnv), [fn] "r" (asi->insn_fn)
  212. : "lr", "memory", "cc"
  213. );
  214. regs->uregs[rd] = rdv;
  215. }
  216. static void __kprobes
  217. t32_emulate_rd8rn16_noflags(probes_opcode_t insn,
  218. struct arch_probes_insn *asi, struct pt_regs *regs)
  219. {
  220. int rd = (insn >> 8) & 0xf;
  221. int rn = (insn >> 16) & 0xf;
  222. register unsigned long rdv asm("r1") = regs->uregs[rd];
  223. register unsigned long rnv asm("r2") = regs->uregs[rn];
  224. __asm__ __volatile__ (
  225. "blx %[fn]"
  226. : "=r" (rdv)
  227. : "0" (rdv), "r" (rnv), [fn] "r" (asi->insn_fn)
  228. : "lr", "memory", "cc"
  229. );
  230. regs->uregs[rd] = rdv;
  231. }
  232. static void __kprobes
  233. t32_emulate_rdlo12rdhi8rn16rm0_noflags(probes_opcode_t insn,
  234. struct arch_probes_insn *asi,
  235. struct pt_regs *regs)
  236. {
  237. int rdlo = (insn >> 12) & 0xf;
  238. int rdhi = (insn >> 8) & 0xf;
  239. int rn = (insn >> 16) & 0xf;
  240. int rm = insn & 0xf;
  241. register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
  242. register unsigned long rdhiv asm("r1") = regs->uregs[rdhi];
  243. register unsigned long rnv asm("r2") = regs->uregs[rn];
  244. register unsigned long rmv asm("r3") = regs->uregs[rm];
  245. __asm__ __volatile__ (
  246. "blx %[fn]"
  247. : "=r" (rdlov), "=r" (rdhiv)
  248. : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv),
  249. [fn] "r" (asi->insn_fn)
  250. : "lr", "memory", "cc"
  251. );
  252. regs->uregs[rdlo] = rdlov;
  253. regs->uregs[rdhi] = rdhiv;
  254. }
  255. /* t16 thumb actions */
  256. static void __kprobes
  257. t16_simulate_bxblx(probes_opcode_t insn,
  258. struct arch_probes_insn *asi, struct pt_regs *regs)
  259. {
  260. unsigned long pc = regs->ARM_pc + 2;
  261. int rm = (insn >> 3) & 0xf;
  262. unsigned long rmv = (rm == 15) ? pc : regs->uregs[rm];
  263. if (insn & (1 << 7)) /* BLX ? */
  264. regs->ARM_lr = regs->ARM_pc | 1;
  265. bx_write_pc(rmv, regs);
  266. }
  267. static void __kprobes
  268. t16_simulate_ldr_literal(probes_opcode_t insn,
  269. struct arch_probes_insn *asi, struct pt_regs *regs)
  270. {
  271. unsigned long *base = (unsigned long *)((regs->ARM_pc + 2) & ~3);
  272. long index = insn & 0xff;
  273. int rt = (insn >> 8) & 0x7;
  274. regs->uregs[rt] = base[index];
  275. }
  276. static void __kprobes
  277. t16_simulate_ldrstr_sp_relative(probes_opcode_t insn,
  278. struct arch_probes_insn *asi, struct pt_regs *regs)
  279. {
  280. unsigned long* base = (unsigned long *)regs->ARM_sp;
  281. long index = insn & 0xff;
  282. int rt = (insn >> 8) & 0x7;
  283. if (insn & 0x800) /* LDR */
  284. regs->uregs[rt] = base[index];
  285. else /* STR */
  286. base[index] = regs->uregs[rt];
  287. }
  288. static void __kprobes
  289. t16_simulate_reladr(probes_opcode_t insn,
  290. struct arch_probes_insn *asi, struct pt_regs *regs)
  291. {
  292. unsigned long base = (insn & 0x800) ? regs->ARM_sp
  293. : ((regs->ARM_pc + 2) & ~3);
  294. long offset = insn & 0xff;
  295. int rt = (insn >> 8) & 0x7;
  296. regs->uregs[rt] = base + offset * 4;
  297. }
  298. static void __kprobes
  299. t16_simulate_add_sp_imm(probes_opcode_t insn,
  300. struct arch_probes_insn *asi, struct pt_regs *regs)
  301. {
  302. long imm = insn & 0x7f;
  303. if (insn & 0x80) /* SUB */
  304. regs->ARM_sp -= imm * 4;
  305. else /* ADD */
  306. regs->ARM_sp += imm * 4;
  307. }
  308. static void __kprobes
  309. t16_simulate_cbz(probes_opcode_t insn,
  310. struct arch_probes_insn *asi, struct pt_regs *regs)
  311. {
  312. int rn = insn & 0x7;
  313. probes_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn;
  314. if (nonzero & 0x800) {
  315. long i = insn & 0x200;
  316. long imm5 = insn & 0xf8;
  317. unsigned long pc = regs->ARM_pc + 2;
  318. regs->ARM_pc = pc + (i >> 3) + (imm5 >> 2);
  319. }
  320. }
  321. static void __kprobes
  322. t16_simulate_it(probes_opcode_t insn,
  323. struct arch_probes_insn *asi, struct pt_regs *regs)
  324. {
  325. /*
  326. * The 8 IT state bits are split into two parts in CPSR:
  327. * ITSTATE<1:0> are in CPSR<26:25>
  328. * ITSTATE<7:2> are in CPSR<15:10>
  329. * The new IT state is in the lower byte of insn.
  330. */
  331. unsigned long cpsr = regs->ARM_cpsr;
  332. cpsr &= ~PSR_IT_MASK;
  333. cpsr |= (insn & 0xfc) << 8;
  334. cpsr |= (insn & 0x03) << 25;
  335. regs->ARM_cpsr = cpsr;
  336. }
  337. static void __kprobes
  338. t16_singlestep_it(probes_opcode_t insn,
  339. struct arch_probes_insn *asi, struct pt_regs *regs)
  340. {
  341. regs->ARM_pc += 2;
  342. t16_simulate_it(insn, asi, regs);
  343. }
  344. static enum probes_insn __kprobes
  345. t16_decode_it(probes_opcode_t insn, struct arch_probes_insn *asi,
  346. const struct decode_header *d)
  347. {
  348. asi->insn_singlestep = t16_singlestep_it;
  349. return INSN_GOOD_NO_SLOT;
  350. }
  351. static void __kprobes
  352. t16_simulate_cond_branch(probes_opcode_t insn,
  353. struct arch_probes_insn *asi, struct pt_regs *regs)
  354. {
  355. unsigned long pc = regs->ARM_pc + 2;
  356. long offset = insn & 0x7f;
  357. offset -= insn & 0x80; /* Apply sign bit */
  358. regs->ARM_pc = pc + (offset * 2);
  359. }
  360. static enum probes_insn __kprobes
  361. t16_decode_cond_branch(probes_opcode_t insn, struct arch_probes_insn *asi,
  362. const struct decode_header *d)
  363. {
  364. int cc = (insn >> 8) & 0xf;
  365. asi->insn_check_cc = probes_condition_checks[cc];
  366. asi->insn_handler = t16_simulate_cond_branch;
  367. return INSN_GOOD_NO_SLOT;
  368. }
  369. static void __kprobes
  370. t16_simulate_branch(probes_opcode_t insn,
  371. struct arch_probes_insn *asi, struct pt_regs *regs)
  372. {
  373. unsigned long pc = regs->ARM_pc + 2;
  374. long offset = insn & 0x3ff;
  375. offset -= insn & 0x400; /* Apply sign bit */
  376. regs->ARM_pc = pc + (offset * 2);
  377. }
  378. static unsigned long __kprobes
  379. t16_emulate_loregs(probes_opcode_t insn,
  380. struct arch_probes_insn *asi, struct pt_regs *regs)
  381. {
  382. unsigned long oldcpsr = regs->ARM_cpsr;
  383. unsigned long newcpsr;
  384. __asm__ __volatile__ (
  385. "msr cpsr_fs, %[oldcpsr] \n\t"
  386. "mov r11, r7 \n\t"
  387. "ldmia %[regs], {r0-r7} \n\t"
  388. "blx %[fn] \n\t"
  389. "stmia %[regs], {r0-r7} \n\t"
  390. "mov r7, r11 \n\t"
  391. "mrs %[newcpsr], cpsr \n\t"
  392. : [newcpsr] "=r" (newcpsr)
  393. : [oldcpsr] "r" (oldcpsr), [regs] "r" (regs),
  394. [fn] "r" (asi->insn_fn)
  395. : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r11",
  396. "lr", "memory", "cc"
  397. );
  398. return (oldcpsr & ~APSR_MASK) | (newcpsr & APSR_MASK);
  399. }
  400. static void __kprobes
  401. t16_emulate_loregs_rwflags(probes_opcode_t insn,
  402. struct arch_probes_insn *asi, struct pt_regs *regs)
  403. {
  404. regs->ARM_cpsr = t16_emulate_loregs(insn, asi, regs);
  405. }
  406. static void __kprobes
  407. t16_emulate_loregs_noitrwflags(probes_opcode_t insn,
  408. struct arch_probes_insn *asi, struct pt_regs *regs)
  409. {
  410. unsigned long cpsr = t16_emulate_loregs(insn, asi, regs);
  411. if (!in_it_block(cpsr))
  412. regs->ARM_cpsr = cpsr;
  413. }
  414. static void __kprobes
  415. t16_emulate_hiregs(probes_opcode_t insn,
  416. struct arch_probes_insn *asi, struct pt_regs *regs)
  417. {
  418. unsigned long pc = regs->ARM_pc + 2;
  419. int rdn = (insn & 0x7) | ((insn & 0x80) >> 4);
  420. int rm = (insn >> 3) & 0xf;
  421. register unsigned long rdnv asm("r1");
  422. register unsigned long rmv asm("r0");
  423. unsigned long cpsr = regs->ARM_cpsr;
  424. rdnv = (rdn == 15) ? pc : regs->uregs[rdn];
  425. rmv = (rm == 15) ? pc : regs->uregs[rm];
  426. __asm__ __volatile__ (
  427. "msr cpsr_fs, %[cpsr] \n\t"
  428. "blx %[fn] \n\t"
  429. "mrs %[cpsr], cpsr \n\t"
  430. : "=r" (rdnv), [cpsr] "=r" (cpsr)
  431. : "0" (rdnv), "r" (rmv), "1" (cpsr), [fn] "r" (asi->insn_fn)
  432. : "lr", "memory", "cc"
  433. );
  434. if (rdn == 15)
  435. rdnv &= ~1;
  436. regs->uregs[rdn] = rdnv;
  437. regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
  438. }
  439. static enum probes_insn __kprobes
  440. t16_decode_hiregs(probes_opcode_t insn, struct arch_probes_insn *asi,
  441. const struct decode_header *d)
  442. {
  443. insn &= ~0x00ff;
  444. insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */
  445. ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn);
  446. asi->insn_handler = t16_emulate_hiregs;
  447. return INSN_GOOD;
  448. }
  449. static void __kprobes
  450. t16_emulate_push(probes_opcode_t insn,
  451. struct arch_probes_insn *asi, struct pt_regs *regs)
  452. {
  453. __asm__ __volatile__ (
  454. "mov r11, r7 \n\t"
  455. "ldr r9, [%[regs], #13*4] \n\t"
  456. "ldr r8, [%[regs], #14*4] \n\t"
  457. "ldmia %[regs], {r0-r7} \n\t"
  458. "blx %[fn] \n\t"
  459. "str r9, [%[regs], #13*4] \n\t"
  460. "mov r7, r11 \n\t"
  461. :
  462. : [regs] "r" (regs), [fn] "r" (asi->insn_fn)
  463. : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r8", "r9", "r11",
  464. "lr", "memory", "cc"
  465. );
  466. }
  467. static enum probes_insn __kprobes
  468. t16_decode_push(probes_opcode_t insn, struct arch_probes_insn *asi,
  469. const struct decode_header *d)
  470. {
  471. /*
  472. * To simulate a PUSH we use a Thumb-2 "STMDB R9!, {registers}"
  473. * and call it with R9=SP and LR in the register list represented
  474. * by R8.
  475. */
  476. /* 1st half STMDB R9!,{} */
  477. ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe929);
  478. /* 2nd half (register list) */
  479. ((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
  480. asi->insn_handler = t16_emulate_push;
  481. return INSN_GOOD;
  482. }
  483. static void __kprobes
  484. t16_emulate_pop_nopc(probes_opcode_t insn,
  485. struct arch_probes_insn *asi, struct pt_regs *regs)
  486. {
  487. __asm__ __volatile__ (
  488. "mov r11, r7 \n\t"
  489. "ldr r9, [%[regs], #13*4] \n\t"
  490. "ldmia %[regs], {r0-r7} \n\t"
  491. "blx %[fn] \n\t"
  492. "stmia %[regs], {r0-r7} \n\t"
  493. "str r9, [%[regs], #13*4] \n\t"
  494. "mov r7, r11 \n\t"
  495. :
  496. : [regs] "r" (regs), [fn] "r" (asi->insn_fn)
  497. : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r9", "r11",
  498. "lr", "memory", "cc"
  499. );
  500. }
  501. static void __kprobes
  502. t16_emulate_pop_pc(probes_opcode_t insn,
  503. struct arch_probes_insn *asi, struct pt_regs *regs)
  504. {
  505. register unsigned long pc asm("r8");
  506. __asm__ __volatile__ (
  507. "mov r11, r7 \n\t"
  508. "ldr r9, [%[regs], #13*4] \n\t"
  509. "ldmia %[regs], {r0-r7} \n\t"
  510. "blx %[fn] \n\t"
  511. "stmia %[regs], {r0-r7} \n\t"
  512. "str r9, [%[regs], #13*4] \n\t"
  513. "mov r7, r11 \n\t"
  514. : "=r" (pc)
  515. : [regs] "r" (regs), [fn] "r" (asi->insn_fn)
  516. : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r9", "r11",
  517. "lr", "memory", "cc"
  518. );
  519. bx_write_pc(pc, regs);
  520. }
  521. static enum probes_insn __kprobes
  522. t16_decode_pop(probes_opcode_t insn, struct arch_probes_insn *asi,
  523. const struct decode_header *d)
  524. {
  525. /*
  526. * To simulate a POP we use a Thumb-2 "LDMDB R9!, {registers}"
  527. * and call it with R9=SP and PC in the register list represented
  528. * by R8.
  529. */
  530. /* 1st half LDMIA R9!,{} */
  531. ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe8b9);
  532. /* 2nd half (register list) */
  533. ((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
  534. asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc
  535. : t16_emulate_pop_nopc;
  536. return INSN_GOOD;
  537. }
  538. const union decode_action kprobes_t16_actions[NUM_PROBES_T16_ACTIONS] = {
  539. [PROBES_T16_ADD_SP] = {.handler = t16_simulate_add_sp_imm},
  540. [PROBES_T16_CBZ] = {.handler = t16_simulate_cbz},
  541. [PROBES_T16_SIGN_EXTEND] = {.handler = t16_emulate_loregs_rwflags},
  542. [PROBES_T16_PUSH] = {.decoder = t16_decode_push},
  543. [PROBES_T16_POP] = {.decoder = t16_decode_pop},
  544. [PROBES_T16_SEV] = {.handler = probes_emulate_none},
  545. [PROBES_T16_WFE] = {.handler = probes_simulate_nop},
  546. [PROBES_T16_IT] = {.decoder = t16_decode_it},
  547. [PROBES_T16_CMP] = {.handler = t16_emulate_loregs_rwflags},
  548. [PROBES_T16_ADDSUB] = {.handler = t16_emulate_loregs_noitrwflags},
  549. [PROBES_T16_LOGICAL] = {.handler = t16_emulate_loregs_noitrwflags},
  550. [PROBES_T16_LDR_LIT] = {.handler = t16_simulate_ldr_literal},
  551. [PROBES_T16_BLX] = {.handler = t16_simulate_bxblx},
  552. [PROBES_T16_HIREGOPS] = {.decoder = t16_decode_hiregs},
  553. [PROBES_T16_LDRHSTRH] = {.handler = t16_emulate_loregs_rwflags},
  554. [PROBES_T16_LDRSTR] = {.handler = t16_simulate_ldrstr_sp_relative},
  555. [PROBES_T16_ADR] = {.handler = t16_simulate_reladr},
  556. [PROBES_T16_LDMSTM] = {.handler = t16_emulate_loregs_rwflags},
  557. [PROBES_T16_BRANCH_COND] = {.decoder = t16_decode_cond_branch},
  558. [PROBES_T16_BRANCH] = {.handler = t16_simulate_branch},
  559. };
  560. const union decode_action kprobes_t32_actions[NUM_PROBES_T32_ACTIONS] = {
  561. [PROBES_T32_LDMSTM] = {.decoder = t32_decode_ldmstm},
  562. [PROBES_T32_LDRDSTRD] = {.handler = t32_emulate_ldrdstrd},
  563. [PROBES_T32_TABLE_BRANCH] = {.handler = t32_simulate_table_branch},
  564. [PROBES_T32_TST] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
  565. [PROBES_T32_MOV] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
  566. [PROBES_T32_ADDSUB] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
  567. [PROBES_T32_LOGICAL] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
  568. [PROBES_T32_CMP] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
  569. [PROBES_T32_ADDWSUBW_PC] = {.handler = t32_emulate_rd8pc16_noflags,},
  570. [PROBES_T32_ADDWSUBW] = {.handler = t32_emulate_rd8rn16_noflags},
  571. [PROBES_T32_MOVW] = {.handler = t32_emulate_rd8rn16_noflags},
  572. [PROBES_T32_SAT] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
  573. [PROBES_T32_BITFIELD] = {.handler = t32_emulate_rd8rn16_noflags},
  574. [PROBES_T32_SEV] = {.handler = probes_emulate_none},
  575. [PROBES_T32_WFE] = {.handler = probes_simulate_nop},
  576. [PROBES_T32_MRS] = {.handler = t32_simulate_mrs},
  577. [PROBES_T32_BRANCH_COND] = {.decoder = t32_decode_cond_branch},
  578. [PROBES_T32_BRANCH] = {.handler = t32_simulate_branch},
  579. [PROBES_T32_PLDI] = {.handler = probes_simulate_nop},
  580. [PROBES_T32_LDR_LIT] = {.handler = t32_simulate_ldr_literal},
  581. [PROBES_T32_LDRSTR] = {.handler = t32_emulate_ldrstr},
  582. [PROBES_T32_SIGN_EXTEND] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
  583. [PROBES_T32_MEDIA] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
  584. [PROBES_T32_REVERSE] = {.handler = t32_emulate_rd8rn16_noflags},
  585. [PROBES_T32_MUL_ADD] = {.handler = t32_emulate_rd8rn16rm0_rwflags},
  586. [PROBES_T32_MUL_ADD2] = {.handler = t32_emulate_rd8rn16rm0ra12_noflags},
  587. [PROBES_T32_MUL_ADD_LONG] = {
  588. .handler = t32_emulate_rdlo12rdhi8rn16rm0_noflags},
  589. };
  590. const struct decode_checker *kprobes_t32_checkers[] = {t32_stack_checker, NULL};
  591. const struct decode_checker *kprobes_t16_checkers[] = {t16_stack_checker, NULL};