summaryrefslogtreecommitdiff
path: root/arch/powerpc/include/asm/inst.h
diff options
context:
space:
mode:
authorJordan Niethe <jniethe5@gmail.com>2020-05-15 12:12:55 +1000
committerMichael Ellerman <mpe@ellerman.id.au>2020-05-19 00:10:39 +1000
commit650b55b707fdfa764e9f2b81314d3eb4216fb962 (patch)
tree33027daca271c94467f02d17945afc0517929171 /arch/powerpc/include/asm/inst.h
parent7a8818e0df5c6b53c89c7c928498668a2bbb3de0 (diff)
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 <jniethe5@gmail.com> Reviewed-by: Alistair Popple <alistair@popple.id.au> [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 <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20200506034050.24806-24-jniethe5@gmail.com
Diffstat (limited to 'arch/powerpc/include/asm/inst.h')
-rw-r--r--arch/powerpc/include/asm/inst.h70
1 files changed, 64 insertions, 6 deletions
diff --git a/arch/powerpc/include/asm/inst.h b/arch/powerpc/include/asm/inst.h
index c7ea70e73073..d82e0c99cfa1 100644
--- a/arch/powerpc/include/asm/inst.h
+++ b/arch/powerpc/include/asm/inst.h
@@ -2,29 +2,80 @@
#ifndef _ASM_POWERPC_INST_H
#define _ASM_POWERPC_INST_H
+#include <asm/ppc-opcode.h>
+
/*
* Instruction data type for POWER
*/
struct ppc_inst {
u32 val;
+#ifdef CONFIG_PPC64
+ u32 suffix;
+#endif
} __packed;
-#define ppc_inst(x) ((struct ppc_inst){ .val = x })
-
static inline u32 ppc_inst_val(struct ppc_inst x)
{
return x.val;
}
-static inline int ppc_inst_len(struct ppc_inst x)
+static inline int ppc_inst_primary_opcode(struct ppc_inst x)
{
- return sizeof(struct ppc_inst);
+ return ppc_inst_val(x) >> 26;
}
-static inline int ppc_inst_primary_opcode(struct ppc_inst x)
+#ifdef CONFIG_PPC64
+#define ppc_inst(x) ((struct ppc_inst){ .val = (x), .suffix = 0xff })
+
+#define ppc_inst_prefix(x, y) ((struct ppc_inst){ .val = (x), .suffix = (y) })
+
+static inline u32 ppc_inst_suffix(struct ppc_inst x)
{
- return ppc_inst_val(x) >> 26;
+ return x.suffix;
+}
+
+static inline bool ppc_inst_prefixed(struct ppc_inst x)
+{
+ return (ppc_inst_primary_opcode(x) == 1) && ppc_inst_suffix(x) != 0xff;
+}
+
+static inline struct ppc_inst ppc_inst_swab(struct ppc_inst x)
+{
+ return ppc_inst_prefix(swab32(ppc_inst_val(x)),
+ swab32(ppc_inst_suffix(x)));
+}
+
+static inline struct ppc_inst ppc_inst_read(const struct ppc_inst *ptr)
+{
+ u32 val, suffix;
+
+ val = *(u32 *)ptr;
+ if ((val >> 26) == OP_PREFIX) {
+ suffix = *((u32 *)ptr + 1);
+ return ppc_inst_prefix(val, suffix);
+ } else {
+ return ppc_inst(val);
+ }
+}
+
+static inline bool ppc_inst_equal(struct ppc_inst x, struct ppc_inst y)
+{
+ return *(u64 *)&x == *(u64 *)&y;
+}
+
+#else
+
+#define ppc_inst(x) ((struct ppc_inst){ .val = x })
+
+static inline bool ppc_inst_prefixed(struct ppc_inst x)
+{
+ return false;
+}
+
+static inline u32 ppc_inst_suffix(struct ppc_inst x)
+{
+ return 0;
}
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)
return ppc_inst_val(x) == ppc_inst_val(y);
}
+#endif /* CONFIG_PPC64 */
+
+static inline int ppc_inst_len(struct ppc_inst x)
+{
+ return ppc_inst_prefixed(x) ? 8 : 4;
+}
+
int probe_user_read_inst(struct ppc_inst *inst,
struct ppc_inst __user *nip);