Commit 98775936 authored by Russell King's avatar Russell King

Merge tag 'for_russell/arm-be-probes' of...

Merge tag 'for_russell/arm-be-probes' of git://git.linaro.org/people/taras.kondratiuk/linux into devel-stable

It is reworked initial Ben's series for big endian support [1].
Dropped patches that are not directly related to probes and rebased
series on top of Dave Long's ARM uprobes series. Current set of
patches is enough to have functional BE kprobes and uprobes.

One ARM kprobe test fails on Cortex-A15 boards (TC2 and Keystone2 EVM),
while it passes on Pandaboard. The issue is not related to this series
and already present since v3.13-rc7.

v1..v2: Rebased series on top of Dave Long's ARM uprobes series.
        Now this series fixes both BE kprobes and BE uprobes.

Tested on Pandaboard ES and TI Keystone2 EVM.

pull req v1: http://www.spinics.net/lists/arm-kernel/msg300227.html
[1] http://www.spinics.net/lists/arm-kernel/msg285210.html
parents 566b60c0 41b5368f
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <asm/opcodes.h>
#include "kprobes.h" #include "kprobes.h"
...@@ -153,7 +154,8 @@ kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi, ...@@ -153,7 +154,8 @@ kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
if (handler) { if (handler) {
/* We can emulate the instruction in (possibly) modified form */ /* We can emulate the instruction in (possibly) modified form */
asi->insn[0] = (insn & 0xfff00000) | (rn << 16) | reglist; asi->insn[0] = __opcode_to_mem_arm((insn & 0xfff00000) |
(rn << 16) | reglist);
asi->insn_handler = handler; asi->insn_handler = handler;
return INSN_GOOD; return INSN_GOOD;
} }
......
This diff is collapsed.
This diff is collapsed.
...@@ -113,7 +113,7 @@ ...@@ -113,7 +113,7 @@
* @ start of inline data... * @ start of inline data...
* .ascii "mov r0, r7" @ text title for test case * .ascii "mov r0, r7" @ text title for test case
* .byte 0 * .byte 0
* .align 2 * .align 2, 0
* *
* @ TEST_ARG_REG * @ TEST_ARG_REG
* .byte ARG_TYPE_REG * .byte ARG_TYPE_REG
...@@ -1333,7 +1333,8 @@ static void test_case_failed(const char *message) ...@@ -1333,7 +1333,8 @@ static void test_case_failed(const char *message)
static unsigned long next_instruction(unsigned long pc) static unsigned long next_instruction(unsigned long pc)
{ {
#ifdef CONFIG_THUMB2_KERNEL #ifdef CONFIG_THUMB2_KERNEL
if ((pc & 1) && !is_wide_instruction(*(u16 *)(pc - 1))) if ((pc & 1) &&
!is_wide_instruction(__mem_to_opcode_thumb16(*(u16 *)(pc - 1))))
return pc + 2; return pc + 2;
else else
#endif #endif
...@@ -1378,13 +1379,13 @@ static uintptr_t __used kprobes_test_case_start(const char *title, void *stack) ...@@ -1378,13 +1379,13 @@ static uintptr_t __used kprobes_test_case_start(const char *title, void *stack)
if (test_case_is_thumb) { if (test_case_is_thumb) {
u16 *p = (u16 *)(test_code & ~1); u16 *p = (u16 *)(test_code & ~1);
current_instruction = p[0]; current_instruction = __mem_to_opcode_thumb16(p[0]);
if (is_wide_instruction(current_instruction)) { if (is_wide_instruction(current_instruction)) {
current_instruction <<= 16; u16 instr2 = __mem_to_opcode_thumb16(p[1]);
current_instruction |= p[1]; current_instruction = __opcode_thumb32_compose(current_instruction, instr2);
} }
} else { } else {
current_instruction = *(u32 *)test_code; current_instruction = __mem_to_opcode_arm(*(u32 *)test_code);
} }
if (current_title[0] == '.') if (current_title[0] == '.')
......
...@@ -115,7 +115,7 @@ struct test_arg_end { ...@@ -115,7 +115,7 @@ struct test_arg_end {
/* multiple strings to be concatenated. */ \ /* multiple strings to be concatenated. */ \
".ascii "#title" \n\t" \ ".ascii "#title" \n\t" \
".byte 0 \n\t" \ ".byte 0 \n\t" \
".align 2 \n\t" ".align 2, 0 \n\t"
#define TEST_ARG_REG(reg, val) \ #define TEST_ARG_REG(reg, val) \
".byte "__stringify(ARG_TYPE_REG)" \n\t" \ ".byte "__stringify(ARG_TYPE_REG)" \n\t" \
......
...@@ -149,9 +149,9 @@ t32_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi, ...@@ -149,9 +149,9 @@ t32_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
enum probes_insn ret = kprobe_decode_ldmstm(insn, asi, d); enum probes_insn ret = kprobe_decode_ldmstm(insn, asi, d);
/* Fixup modified instruction to have halfwords in correct order...*/ /* Fixup modified instruction to have halfwords in correct order...*/
insn = asi->insn[0]; insn = __mem_to_opcode_arm(asi->insn[0]);
((u16 *)asi->insn)[0] = insn >> 16; ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn >> 16);
((u16 *)asi->insn)[1] = insn & 0xffff; ((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0xffff);
return ret; return ret;
} }
...@@ -516,7 +516,7 @@ t16_decode_hiregs(probes_opcode_t insn, struct arch_probes_insn *asi, ...@@ -516,7 +516,7 @@ t16_decode_hiregs(probes_opcode_t insn, struct arch_probes_insn *asi,
{ {
insn &= ~0x00ff; insn &= ~0x00ff;
insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */ insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */
((u16 *)asi->insn)[0] = insn; ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(insn);
asi->insn_handler = t16_emulate_hiregs; asi->insn_handler = t16_emulate_hiregs;
return INSN_GOOD; return INSN_GOOD;
} }
...@@ -547,8 +547,10 @@ t16_decode_push(probes_opcode_t insn, struct arch_probes_insn *asi, ...@@ -547,8 +547,10 @@ t16_decode_push(probes_opcode_t insn, struct arch_probes_insn *asi,
* and call it with R9=SP and LR in the register list represented * and call it with R9=SP and LR in the register list represented
* by R8. * by R8.
*/ */
((u16 *)asi->insn)[0] = 0xe929; /* 1st half STMDB R9!,{} */ /* 1st half STMDB R9!,{} */
((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */ ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe929);
/* 2nd half (register list) */
((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
asi->insn_handler = t16_emulate_push; asi->insn_handler = t16_emulate_push;
return INSN_GOOD; return INSN_GOOD;
} }
...@@ -600,8 +602,10 @@ t16_decode_pop(probes_opcode_t insn, struct arch_probes_insn *asi, ...@@ -600,8 +602,10 @@ t16_decode_pop(probes_opcode_t insn, struct arch_probes_insn *asi,
* and call it with R9=SP and PC in the register list represented * and call it with R9=SP and PC in the register list represented
* by R8. * by R8.
*/ */
((u16 *)asi->insn)[0] = 0xe8b9; /* 1st half LDMIA R9!,{} */ /* 1st half LDMIA R9!,{} */
((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */ ((u16 *)asi->insn)[0] = __opcode_to_mem_thumb16(0xe8b9);
/* 2nd half (register list) */
((u16 *)asi->insn)[1] = __opcode_to_mem_thumb16(insn & 0x1ff);
asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc
: t16_emulate_pop_nopc; : t16_emulate_pop_nopc;
return INSN_GOOD; return INSN_GOOD;
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/stop_machine.h> #include <linux/stop_machine.h>
#include <linux/stringify.h> #include <linux/stringify.h>
#include <asm/traps.h> #include <asm/traps.h>
#include <asm/opcodes.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/bug.h> #include <linux/bug.h>
...@@ -67,10 +68,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) ...@@ -67,10 +68,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
#ifdef CONFIG_THUMB2_KERNEL #ifdef CONFIG_THUMB2_KERNEL
thumb = true; thumb = true;
addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */ addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */
insn = ((u16 *)addr)[0]; insn = __mem_to_opcode_thumb16(((u16 *)addr)[0]);
if (is_wide_instruction(insn)) { if (is_wide_instruction(insn)) {
insn <<= 16; u16 inst2 = __mem_to_opcode_thumb16(((u16 *)addr)[1]);
insn |= ((u16 *)addr)[1]; insn = __opcode_thumb32_compose(insn, inst2);
decode_insn = thumb32_probes_decode_insn; decode_insn = thumb32_probes_decode_insn;
actions = kprobes_t32_actions; actions = kprobes_t32_actions;
} else { } else {
...@@ -81,7 +82,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) ...@@ -81,7 +82,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
thumb = false; thumb = false;
if (addr & 0x3) if (addr & 0x3)
return -EINVAL; return -EINVAL;
insn = *p->addr; insn = __mem_to_opcode_arm(*p->addr);
decode_insn = arm_probes_decode_insn; decode_insn = arm_probes_decode_insn;
actions = kprobes_arm_actions; actions = kprobes_arm_actions;
#endif #endif
......
...@@ -202,13 +202,14 @@ prepare_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi, ...@@ -202,13 +202,14 @@ prepare_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
#ifdef CONFIG_THUMB2_KERNEL #ifdef CONFIG_THUMB2_KERNEL
if (thumb) { if (thumb) {
u16 *thumb_insn = (u16 *)asi->insn; u16 *thumb_insn = (u16 *)asi->insn;
thumb_insn[1] = 0x4770; /* Thumb bx lr */ /* Thumb bx lr */
thumb_insn[2] = 0x4770; /* Thumb bx lr */ thumb_insn[1] = __opcode_to_mem_thumb16(0x4770);
thumb_insn[2] = __opcode_to_mem_thumb16(0x4770);
return insn; return insn;
} }
asi->insn[1] = 0xe12fff1e; /* ARM bx lr */ asi->insn[1] = __opcode_to_mem_arm(0xe12fff1e); /* ARM bx lr */
#else #else
asi->insn[1] = 0xe1a0f00e; /* mov pc, lr */ asi->insn[1] = __opcode_to_mem_arm(0xe1a0f00e); /* mov pc, lr */
#endif #endif
/* Make an ARM instruction unconditional */ /* Make an ARM instruction unconditional */
if (insn < 0xe0000000) if (insn < 0xe0000000)
...@@ -228,12 +229,12 @@ set_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi, ...@@ -228,12 +229,12 @@ set_emulated_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
if (thumb) { if (thumb) {
u16 *ip = (u16 *)asi->insn; u16 *ip = (u16 *)asi->insn;
if (is_wide_instruction(insn)) if (is_wide_instruction(insn))
*ip++ = insn >> 16; *ip++ = __opcode_to_mem_thumb16(insn >> 16);
*ip++ = insn; *ip++ = __opcode_to_mem_thumb16(insn);
return; return;
} }
#endif #endif
asi->insn[0] = insn; asi->insn[0] = __opcode_to_mem_arm(insn);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment