Commit 935c2dbe authored by Maciej W. Rozycki's avatar Maciej W. Rozycki Committed by Ralf Baechle

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: default avatarMaciej W. Rozycki <macro@codesourcery.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/8516/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 99436f7d
...@@ -20,9 +20,15 @@ ...@@ -20,9 +20,15 @@
#define WORD_INSN ".word" #define WORD_INSN ".word"
#endif #endif
#ifdef CONFIG_CPU_MICROMIPS
#define NOP_INSN "nop32"
#else
#define NOP_INSN "nop"
#endif
static __always_inline bool arch_static_branch(struct static_key *key) static __always_inline bool arch_static_branch(struct static_key *key)
{ {
asm_volatile_goto("1:\tnop\n\t" asm_volatile_goto("1:\t" NOP_INSN "\n\t"
"nop\n\t" "nop\n\t"
".pushsection __jump_table, \"aw\"\n\t" ".pushsection __jump_table, \"aw\"\n\t"
WORD_INSN " 1b, %l[l_yes], %0\n\t" WORD_INSN " 1b, %l[l_yes], %0\n\t"
......
...@@ -18,31 +18,53 @@ ...@@ -18,31 +18,53 @@
#ifdef HAVE_JUMP_LABEL #ifdef HAVE_JUMP_LABEL
#define J_RANGE_MASK ((1ul << 28) - 1) /*
* Define parameters for the standard MIPS and the microMIPS jump
* instruction encoding respectively:
*
* - the ISA bit of the target, either 0 or 1 respectively,
*
* - the amount the jump target address is shifted right to fit in the
* immediate field of the machine instruction, either 2 or 1,
*
* - the mask determining the size of the jump region relative to the
* delay-slot instruction, either 256MB or 128MB,
*
* - the jump target alignment, either 4 or 2 bytes.
*/
#define J_ISA_BIT IS_ENABLED(CONFIG_CPU_MICROMIPS)
#define J_RANGE_SHIFT (2 - J_ISA_BIT)
#define J_RANGE_MASK ((1ul << (26 + J_RANGE_SHIFT)) - 1)
#define J_ALIGN_MASK ((1ul << J_RANGE_SHIFT) - 1)
void arch_jump_label_transform(struct jump_entry *e, void arch_jump_label_transform(struct jump_entry *e,
enum jump_label_type type) enum jump_label_type type)
{ {
union mips_instruction *insn_p;
union mips_instruction insn; union mips_instruction insn;
union mips_instruction *insn_p =
(union mips_instruction *)(unsigned long)e->code;
/* Jump only works within a 256MB aligned region of its delay slot. */ insn_p = (union mips_instruction *)msk_isa16_mode(e->code);
/* Jump only works within an aligned region its delay slot is in. */
BUG_ON((e->target & ~J_RANGE_MASK) != ((e->code + 4) & ~J_RANGE_MASK)); BUG_ON((e->target & ~J_RANGE_MASK) != ((e->code + 4) & ~J_RANGE_MASK));
/* Target must have 4 byte alignment. */ /* Target must have the right alignment and ISA must be preserved. */
BUG_ON((e->target & 3) != 0); BUG_ON((e->target & J_ALIGN_MASK) != J_ISA_BIT);
if (type == JUMP_LABEL_ENABLE) { if (type == JUMP_LABEL_ENABLE) {
insn.j_format.opcode = j_op; insn.j_format.opcode = J_ISA_BIT ? mm_j32_op : j_op;
insn.j_format.target = (e->target & J_RANGE_MASK) >> 2; insn.j_format.target = e->target >> J_RANGE_SHIFT;
} else { } else {
insn.word = 0; /* nop */ insn.word = 0; /* nop */
} }
get_online_cpus(); get_online_cpus();
mutex_lock(&text_mutex); mutex_lock(&text_mutex);
*insn_p = insn; if (IS_ENABLED(CONFIG_CPU_MICROMIPS)) {
insn_p->halfword[0] = insn.word >> 16;
insn_p->halfword[1] = insn.word;
} else
*insn_p = insn;
flush_icache_range((unsigned long)insn_p, flush_icache_range((unsigned long)insn_p,
(unsigned long)insn_p + sizeof(*insn_p)); (unsigned long)insn_p + sizeof(*insn_p));
......
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