Skip to content

Commit 650b55b

Browse files
iamjpnmpe
authored andcommitted
powerpc: Add prefixed instructions to instruction data type
For powerpc64, redefine the ppc_inst type so both word and prefixed instructions can be represented. On powerpc32 the type will remain the same. Update places which had assumed instructions to be 4 bytes long. Signed-off-by: Jordan Niethe <[email protected]> Reviewed-by: Alistair Popple <[email protected]> [mpe: Rework the get_user_inst() macros to be parameterised, and don't assign to the dest if an error occurred. Use CONFIG_PPC64 not __powerpc64__ in a few places. Address other comments from Christophe. Fix some sparse complaints.] Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 7a8818e commit 650b55b

File tree

14 files changed

+175
-17
lines changed

14 files changed

+175
-17
lines changed

arch/powerpc/include/asm/inst.h

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,80 @@
22
#ifndef _ASM_POWERPC_INST_H
33
#define _ASM_POWERPC_INST_H
44

5+
#include <asm/ppc-opcode.h>
6+
57
/*
68
* Instruction data type for POWER
79
*/
810

911
struct ppc_inst {
1012
u32 val;
13+
#ifdef CONFIG_PPC64
14+
u32 suffix;
15+
#endif
1116
} __packed;
1217

13-
#define ppc_inst(x) ((struct ppc_inst){ .val = x })
14-
1518
static inline u32 ppc_inst_val(struct ppc_inst x)
1619
{
1720
return x.val;
1821
}
1922

20-
static inline int ppc_inst_len(struct ppc_inst x)
23+
static inline int ppc_inst_primary_opcode(struct ppc_inst x)
2124
{
22-
return sizeof(struct ppc_inst);
25+
return ppc_inst_val(x) >> 26;
2326
}
2427

25-
static inline int ppc_inst_primary_opcode(struct ppc_inst x)
28+
#ifdef CONFIG_PPC64
29+
#define ppc_inst(x) ((struct ppc_inst){ .val = (x), .suffix = 0xff })
30+
31+
#define ppc_inst_prefix(x, y) ((struct ppc_inst){ .val = (x), .suffix = (y) })
32+
33+
static inline u32 ppc_inst_suffix(struct ppc_inst x)
2634
{
27-
return ppc_inst_val(x) >> 26;
35+
return x.suffix;
36+
}
37+
38+
static inline bool ppc_inst_prefixed(struct ppc_inst x)
39+
{
40+
return (ppc_inst_primary_opcode(x) == 1) && ppc_inst_suffix(x) != 0xff;
41+
}
42+
43+
static inline struct ppc_inst ppc_inst_swab(struct ppc_inst x)
44+
{
45+
return ppc_inst_prefix(swab32(ppc_inst_val(x)),
46+
swab32(ppc_inst_suffix(x)));
47+
}
48+
49+
static inline struct ppc_inst ppc_inst_read(const struct ppc_inst *ptr)
50+
{
51+
u32 val, suffix;
52+
53+
val = *(u32 *)ptr;
54+
if ((val >> 26) == OP_PREFIX) {
55+
suffix = *((u32 *)ptr + 1);
56+
return ppc_inst_prefix(val, suffix);
57+
} else {
58+
return ppc_inst(val);
59+
}
60+
}
61+
62+
static inline bool ppc_inst_equal(struct ppc_inst x, struct ppc_inst y)
63+
{
64+
return *(u64 *)&x == *(u64 *)&y;
65+
}
66+
67+
#else
68+
69+
#define ppc_inst(x) ((struct ppc_inst){ .val = x })
70+
71+
static inline bool ppc_inst_prefixed(struct ppc_inst x)
72+
{
73+
return false;
74+
}
75+
76+
static inline u32 ppc_inst_suffix(struct ppc_inst x)
77+
{
78+
return 0;
2879
}
2980

3081
static inline struct ppc_inst ppc_inst_swab(struct ppc_inst x)
@@ -42,6 +93,13 @@ static inline bool ppc_inst_equal(struct ppc_inst x, struct ppc_inst y)
4293
return ppc_inst_val(x) == ppc_inst_val(y);
4394
}
4495

96+
#endif /* CONFIG_PPC64 */
97+
98+
static inline int ppc_inst_len(struct ppc_inst x)
99+
{
100+
return ppc_inst_prefixed(x) ? 8 : 4;
101+
}
102+
45103
int probe_user_read_inst(struct ppc_inst *inst,
46104
struct ppc_inst __user *nip);
47105

arch/powerpc/include/asm/kprobes.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ extern kprobe_opcode_t optprobe_template_ret[];
4343
extern kprobe_opcode_t optprobe_template_end[];
4444

4545
/* Fixed instruction size for powerpc */
46-
#define MAX_INSN_SIZE 1
46+
#define MAX_INSN_SIZE 2
4747
#define MAX_OPTIMIZED_LENGTH sizeof(kprobe_opcode_t) /* 4 bytes */
4848
#define MAX_OPTINSN_SIZE (optprobe_template_end - optprobe_template_entry)
4949
#define RELATIVEJUMP_SIZE sizeof(kprobe_opcode_t) /* 4 bytes */

arch/powerpc/include/asm/ppc-opcode.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@
158158
/* VMX Vector Store Instructions */
159159
#define OP_31_XOP_STVX 231
160160

161+
/* Prefixed Instructions */
162+
#define OP_PREFIX 1
163+
161164
#define OP_31 31
162165
#define OP_LWZ 32
163166
#define OP_STFS 52

arch/powerpc/include/asm/uaccess.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,40 @@ static inline int __access_ok(unsigned long addr, unsigned long size,
105105
#define __put_user_inatomic(x, ptr) \
106106
__put_user_nosleep((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
107107

108+
#ifdef CONFIG_PPC64
109+
110+
#define ___get_user_instr(gu_op, dest, ptr) \
111+
({ \
112+
long __gui_ret = 0; \
113+
unsigned long __gui_ptr = (unsigned long)ptr; \
114+
struct ppc_inst __gui_inst; \
115+
unsigned int __prefix, __suffix; \
116+
__gui_ret = gu_op(__prefix, (unsigned int __user *)__gui_ptr); \
117+
if (__gui_ret == 0) { \
118+
if ((__prefix >> 26) == OP_PREFIX) { \
119+
__gui_ret = gu_op(__suffix, \
120+
(unsigned int __user *)__gui_ptr + 1); \
121+
__gui_inst = ppc_inst_prefix(__prefix, \
122+
__suffix); \
123+
} else { \
124+
__gui_inst = ppc_inst(__prefix); \
125+
} \
126+
if (__gui_ret == 0) \
127+
(dest) = __gui_inst; \
128+
} \
129+
__gui_ret; \
130+
})
131+
132+
#define get_user_instr(x, ptr) \
133+
___get_user_instr(get_user, x, ptr)
134+
135+
#define __get_user_instr(x, ptr) \
136+
___get_user_instr(__get_user, x, ptr)
137+
138+
#define __get_user_instr_inatomic(x, ptr) \
139+
___get_user_instr(__get_user_inatomic, x, ptr)
140+
141+
#else /* !CONFIG_PPC64 */
108142
#define get_user_instr(x, ptr) \
109143
get_user((x).val, (u32 __user *)(ptr))
110144

@@ -114,6 +148,8 @@ static inline int __access_ok(unsigned long addr, unsigned long size,
114148
#define __get_user_instr_inatomic(x, ptr) \
115149
__get_user_nosleep((x).val, (u32 __user *)(ptr), sizeof(u32))
116150

151+
#endif /* CONFIG_PPC64 */
152+
117153
extern long __put_user_bad(void);
118154

119155
/*

arch/powerpc/include/asm/uprobes.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
typedef ppc_opcode_t uprobe_opcode_t;
1717

18-
#define MAX_UINSN_BYTES 4
18+
#define MAX_UINSN_BYTES 8
1919
#define UPROBE_XOL_SLOT_BYTES (MAX_UINSN_BYTES)
2020

2121
/* The following alias is needed for reference from arch-agnostic code */

arch/powerpc/kernel/crash_dump.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ static void __init create_trampoline(unsigned long addr)
4646
* two instructions it doesn't require any registers.
4747
*/
4848
patch_instruction(p, ppc_inst(PPC_INST_NOP));
49-
patch_branch(++p, addr + PHYSICAL_START, 0);
49+
patch_branch((void *)p + 4, addr + PHYSICAL_START, 0);
5050
}
5151

5252
void __init setup_kdump_trampoline(void)

arch/powerpc/kernel/optprobes.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ void patch_imm64_load_insns(unsigned long val, int reg, kprobe_opcode_t *addr)
198198

199199
int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *p)
200200
{
201-
struct ppc_inst branch_op_callback, branch_emulate_step;
201+
struct ppc_inst branch_op_callback, branch_emulate_step, temp;
202202
kprobe_opcode_t *op_callback_addr, *emulate_step_addr, *buff;
203203
long b_offset;
204204
unsigned long nip, size;
@@ -282,7 +282,9 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *p)
282282
/*
283283
* 3. load instruction to be emulated into relevant register, and
284284
*/
285-
patch_imm32_load_insns(*p->ainsn.insn, buff + TMPL_INSN_IDX);
285+
temp = ppc_inst_read((struct ppc_inst *)p->ainsn.insn);
286+
patch_imm64_load_insns(ppc_inst_val(temp) | ((u64)ppc_inst_suffix(temp) << 32),
287+
4, buff + TMPL_INSN_IDX);
286288

287289
/*
288290
* 4. branch back from trampoline

arch/powerpc/kernel/optprobes_head.S

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ optprobe_template_insn:
9494
/* 2, Pass instruction to be emulated in r4 */
9595
nop
9696
nop
97+
nop
98+
nop
99+
nop
97100

98101
.global optprobe_template_call_emulate
99102
optprobe_template_call_emulate:

arch/powerpc/lib/code-patching.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,18 @@ static int __patch_instruction(struct ppc_inst *exec_addr, struct ppc_inst instr
2424
{
2525
int err = 0;
2626

27-
__put_user_asm(ppc_inst_val(instr), patch_addr, err, "stw");
27+
if (!ppc_inst_prefixed(instr)) {
28+
__put_user_asm(ppc_inst_val(instr), patch_addr, err, "stw");
29+
} else {
30+
#ifdef CONFIG_CPU_LITTLE_ENDIAN
31+
__put_user_asm((u64)ppc_inst_suffix(instr) << 32 |
32+
ppc_inst_val(instr), patch_addr, err, "std");
33+
#else
34+
__put_user_asm((u64)ppc_inst_val(instr) << 32 |
35+
ppc_inst_suffix(instr), patch_addr, err, "std");
36+
#endif
37+
}
38+
2839
if (err)
2940
return err;
3041

arch/powerpc/lib/feature-fixups.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,13 @@ static int patch_feature_section(unsigned long value, struct fixup_entry *fcur)
8484
src = alt_start;
8585
dest = start;
8686

87-
for (; src < alt_end; src++, dest++) {
87+
for (; src < alt_end; src = (void *)src + ppc_inst_len(ppc_inst_read(src)),
88+
(dest = (void *)dest + ppc_inst_len(ppc_inst_read(dest)))) {
8889
if (patch_alt_instruction(src, dest, alt_start, alt_end))
8990
return 1;
9091
}
9192

92-
for (; dest < end; dest++)
93+
for (; dest < end; dest = (void *)dest + ppc_inst_len(ppc_inst(PPC_INST_NOP)))
9394
raw_patch_instruction(dest, ppc_inst(PPC_INST_NOP));
9495

9596
return 0;

0 commit comments

Comments
 (0)