aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@codesourcery.com>2014-11-17 11:10:32 -0500
committerRalf Baechle <ralf@linux-mips.org>2014-11-19 12:22:09 -0500
commit935c2dbec4d6d3163ee8e7409996904a734ad89a (patch)
treee786a6f69c5c5f2f03ac85e5466906a6524fec18 /arch
parent99436f7d69045800ffd1d66912f85d37150c7e2b (diff)
MIPS: jump_label.c: Handle the microMIPS J instruction encoding
Implement the microMIPS encoding of the J instruction for the purpose of the static keys feature, fixing a crash early on in bootstrap as the kernel is unhappy seeing the ISA bit set in jump table entries. Make sure the ISA bit correctly reflects the instruction encoding chosen for the kernel, 0 for the standard MIPS and 1 for the microMIPS encoding. Also make sure the instruction to patch is a 32-bit NOP in the microMIPS mode as by default the 16-bit short encoding is assumed Signed-off-by: Maciej W. Rozycki <macro@codesourcery.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/8516/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/mips/include/asm/jump_label.h8
-rw-r--r--arch/mips/kernel/jump_label.c40
2 files changed, 38 insertions, 10 deletions
diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h
index e194f957ca8c..fdbff44e5482 100644
--- a/arch/mips/include/asm/jump_label.h
+++ b/arch/mips/include/asm/jump_label.h
@@ -20,9 +20,15 @@
20#define WORD_INSN ".word" 20#define WORD_INSN ".word"
21#endif 21#endif
22 22
23#ifdef CONFIG_CPU_MICROMIPS
24#define NOP_INSN "nop32"
25#else
26#define NOP_INSN "nop"
27#endif
28
23static __always_inline bool arch_static_branch(struct static_key *key) 29static __always_inline bool arch_static_branch(struct static_key *key)
24{ 30{
25 asm_volatile_goto("1:\tnop\n\t" 31 asm_volatile_goto("1:\t" NOP_INSN "\n\t"
26 "nop\n\t" 32 "nop\n\t"
27 ".pushsection __jump_table, \"aw\"\n\t" 33 ".pushsection __jump_table, \"aw\"\n\t"
28 WORD_INSN " 1b, %l[l_yes], %0\n\t" 34 WORD_INSN " 1b, %l[l_yes], %0\n\t"
diff --git a/arch/mips/kernel/jump_label.c b/arch/mips/kernel/jump_label.c
index f65a843e883b..dda800e9e731 100644
--- a/arch/mips/kernel/jump_label.c
+++ b/arch/mips/kernel/jump_label.c
@@ -18,31 +18,53 @@
18 18
19#ifdef HAVE_JUMP_LABEL 19#ifdef HAVE_JUMP_LABEL
20 20
21#define J_RANGE_MASK ((1ul << 28) - 1) 21/*
22 * Define parameters for the standard MIPS and the microMIPS jump
23 * instruction encoding respectively:
24 *
25 * - the ISA bit of the target, either 0 or 1 respectively,
26 *
27 * - the amount the jump target address is shifted right to fit in the
28 * immediate field of the machine instruction, either 2 or 1,
29 *
30 * - the mask determining the size of the jump region relative to the
31 * delay-slot instruction, either 256MB or 128MB,
32 *
33 * - the jump target alignment, either 4 or 2 bytes.
34 */
35#define J_ISA_BIT IS_ENABLED(CONFIG_CPU_MICROMIPS)
36#define J_RANGE_SHIFT (2 - J_ISA_BIT)
37#define J_RANGE_MASK ((1ul << (26 + J_RANGE_SHIFT)) - 1)
38#define J_ALIGN_MASK ((1ul << J_RANGE_SHIFT) - 1)
22 39
23void arch_jump_label_transform(struct jump_entry *e, 40void arch_jump_label_transform(struct jump_entry *e,
24 enum jump_label_type type) 41 enum jump_label_type type)
25{ 42{
43 union mips_instruction *insn_p;
26 union mips_instruction insn; 44 union mips_instruction insn;
27 union mips_instruction *insn_p =
28 (union mips_instruction *)(unsigned long)e->code;
29 45
30 /* Jump only works within a 256MB aligned region of its delay slot. */ 46 insn_p = (union mips_instruction *)msk_isa16_mode(e->code);
47
48 /* Jump only works within an aligned region its delay slot is in. */
31 BUG_ON((e->target & ~J_RANGE_MASK) != ((e->code + 4) & ~J_RANGE_MASK)); 49 BUG_ON((e->target & ~J_RANGE_MASK) != ((e->code + 4) & ~J_RANGE_MASK));
32 50
33 /* Target must have 4 byte alignment. */ 51 /* Target must have the right alignment and ISA must be preserved. */
34 BUG_ON((e->target & 3) != 0); 52 BUG_ON((e->target & J_ALIGN_MASK) != J_ISA_BIT);
35 53
36 if (type == JUMP_LABEL_ENABLE) { 54 if (type == JUMP_LABEL_ENABLE) {
37 insn.j_format.opcode = j_op; 55 insn.j_format.opcode = J_ISA_BIT ? mm_j32_op : j_op;
38 insn.j_format.target = (e->target & J_RANGE_MASK) >> 2; 56 insn.j_format.target = e->target >> J_RANGE_SHIFT;
39 } else { 57 } else {
40 insn.word = 0; /* nop */ 58 insn.word = 0; /* nop */
41 } 59 }
42 60
43 get_online_cpus(); 61 get_online_cpus();
44 mutex_lock(&text_mutex); 62 mutex_lock(&text_mutex);
45 *insn_p = insn; 63 if (IS_ENABLED(CONFIG_CPU_MICROMIPS)) {
64 insn_p->halfword[0] = insn.word >> 16;
65 insn_p->halfword[1] = insn.word;
66 } else
67 *insn_p = insn;
46 68
47 flush_icache_range((unsigned long)insn_p, 69 flush_icache_range((unsigned long)insn_p,
48 (unsigned long)insn_p + sizeof(*insn_p)); 70 (unsigned long)insn_p + sizeof(*insn_p));