summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gnu/usr.bin/binutils/gas/config/tc-mips.c80
-rw-r--r--gnu/usr.bin/binutils/gas/doc/c-mips.texi8
-rw-r--r--gnu/usr.bin/binutils/include/opcode/mips.h4
-rw-r--r--gnu/usr.bin/binutils/opcodes/mips-opc.c4
4 files changed, 94 insertions, 2 deletions
diff --git a/gnu/usr.bin/binutils/gas/config/tc-mips.c b/gnu/usr.bin/binutils/gas/config/tc-mips.c
index 7b6cee85df4..d7800823ea5 100644
--- a/gnu/usr.bin/binutils/gas/config/tc-mips.c
+++ b/gnu/usr.bin/binutils/gas/config/tc-mips.c
@@ -630,6 +630,8 @@ static int mips_fix_vr4120;
efficient expansion. */
static int mips_relax_branch;
+
+static int mips_fix_loongson2f_btb;
/* The expansion of many macros depends on the type of symbol that
they refer to. For example, when generating position-dependent code,
@@ -867,6 +869,7 @@ static void mips_no_prev_insn (int);
static void mips16_macro_build
(expressionS *, const char *, const char *, va_list);
static void load_register (int, expressionS *, int);
+static void macro_build (expressionS *, const char *, const char *, ...);
static void macro_start (void);
static void macro_end (void);
static void macro (struct mips_cl_insn * ip);
@@ -2968,6 +2971,41 @@ macro_end (void)
}
}
+/* Fix jump through register issue on loongson2f processor for kernel code:
+ force a BTB clear before the jump to prevent it from being incorrectly
+ prefetched by the branch prediction engine. */
+
+static void
+macro_build_jrpatch (expressionS *ep, unsigned int sreg)
+{
+ if (!mips_fix_loongson2f_btb)
+ return;
+
+ if (sreg == ZERO || sreg == KT0 || sreg == KT1 || sreg == AT)
+ return;
+
+ if (mips_opts.noat)
+ {
+ as_warn (_("unable to apply loongson2f BTB workaround when .set noat"));
+ return;
+ }
+
+ /* li $at, COP_0_BTB_CLEAR | COP_0_RAS_DISABLE */
+ ep->X_op = O_constant;
+ ep->X_add_number = 3;
+ macro_build (ep, "ori", "t,r,i", AT, ZERO, BFD_RELOC_LO16);
+
+ /* dmtc0 $at, COP_0_DIAG */
+ macro_build (NULL, "dmtc0", "t,G", AT, 22);
+
+ /* Hide these two instructions to avoid getting a ``macro expanded into
+ multiple instructions'' warning. */
+ if (mips_relax.sequence != 2)
+ mips_macro_warning.sizes[0] -= 2 * 4;
+ if (mips_relax.sequence != 1)
+ mips_macro_warning.sizes[1] -= 2 * 4;
+}
+
/* Build an instruction created by a macro expansion. This is passed
a pointer to the count of instructions created so far, an
expression, the name of the instruction to build, an operand format
@@ -3336,6 +3374,7 @@ macro_build_jalr (expressionS *ep)
frag_grow (8);
f = frag_more (0);
}
+ macro_build_jrpatch (ep, PIC_CALL_REG);
macro_build (NULL, "jalr", "d,s", RA, PIC_CALL_REG);
if (HAVE_NEWABI)
fix_new_exp (frag_now, f - frag_now->fr_literal,
@@ -5509,6 +5548,26 @@ macro (struct mips_cl_insn *ip)
break;
+ case M_JR_S:
+ macro_build_jrpatch (&expr1, sreg);
+ macro_build (NULL, "jr", "s", sreg);
+ return; /* didn't modify $at */
+
+ case M_J_S:
+ macro_build_jrpatch (&expr1, sreg);
+ macro_build (NULL, "j", "s", sreg);
+ return; /* didn't modify $at */
+
+ case M_JALR_S:
+ macro_build_jrpatch (&expr1, sreg);
+ macro_build (NULL, "jalr", "s", sreg);
+ return; /* didn't modify $at */
+
+ case M_JALR_DS:
+ macro_build_jrpatch (&expr1, sreg);
+ macro_build (NULL, "jalr", "d,s", dreg, sreg);
+ return; /* didn't modify $at */
+
case M_J_A:
/* The j instruction may not be used in PIC code, since it
requires an absolute address. We convert it to a b
@@ -5528,12 +5587,16 @@ macro (struct mips_cl_insn *ip)
case M_JAL_2:
if (mips_pic == NO_PIC
|| mips_pic == EMBEDDED_PIC)
- macro_build (NULL, "jalr", "d,s", dreg, sreg);
+ {
+ macro_build_jrpatch (&expr1, sreg);
+ macro_build (NULL, "jalr", "d,s", dreg, sreg);
+ }
else if (mips_pic == SVR4_PIC)
{
if (sreg != PIC_CALL_REG)
as_warn (_("MIPS PIC call to register other than $25"));
+ macro_build_jrpatch (&expr1, sreg);
macro_build (NULL, "jalr", "d,s", dreg, sreg);
if (! HAVE_NEWABI)
{
@@ -10258,9 +10321,13 @@ struct option md_longopts[] =
#define OPTION_NO_FIX_VR4120 (OPTION_FIX_BASE + 3)
{"mfix-vr4120", no_argument, NULL, OPTION_FIX_VR4120},
{"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120},
+#define OPTION_FIX_LOONGSON2F_BTB (OPTION_FIX_BASE + 4)
+#define OPTION_NO_FIX_LOONGSON2F_BTB (OPTION_FIX_BASE + 5)
+ {"mfix-loongson2f-btb", no_argument, NULL, OPTION_FIX_LOONGSON2F_BTB},
+ {"mno-fix-loongson2f-btb", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_BTB},
/* Miscellaneous options. */
-#define OPTION_MISC_BASE (OPTION_FIX_BASE + 4)
+#define OPTION_MISC_BASE (OPTION_FIX_BASE + 6)
#define OPTION_MEMBEDDED_PIC (OPTION_MISC_BASE + 0)
{"membedded-pic", no_argument, NULL, OPTION_MEMBEDDED_PIC},
#define OPTION_TRAP (OPTION_MISC_BASE + 1)
@@ -10507,6 +10574,14 @@ md_parse_option (int c, char *arg)
mips_fix_vr4120 = 0;
break;
+ case OPTION_FIX_LOONGSON2F_BTB:
+ mips_fix_loongson2f_btb = 1;
+ break;
+
+ case OPTION_NO_FIX_LOONGSON2F_BTB:
+ mips_fix_loongson2f_btb = 0;
+ break;
+
case OPTION_RELAX_BRANCH:
mips_relax_branch = 1;
break;
@@ -14374,6 +14449,7 @@ MIPS options:\n\
-no-mips16 do not generate mips16 instructions\n"));
fprintf (stream, _("\
-mfix-vr4120 work around certain VR4120 errata\n\
+-mfix-loongson2f-btb work around Loongson2F BTB errata\n\
-mgp32 use 32-bit GPRs, regardless of the chosen ISA\n\
-mfp32 use 32-bit FPRs, regardless of the chosen ISA\n\
-O0 remove unneeded NOPs, do not swap branches\n\
diff --git a/gnu/usr.bin/binutils/gas/doc/c-mips.texi b/gnu/usr.bin/binutils/gas/doc/c-mips.texi
index 1375230a673..f5a427ce2dc 100644
--- a/gnu/usr.bin/binutils/gas/doc/c-mips.texi
+++ b/gnu/usr.bin/binutils/gas/doc/c-mips.texi
@@ -128,6 +128,14 @@ Insert nops to work around certain VR4120 errata. This option is
intended to be used on GCC-generated code: it is not designed to catch
all problems in hand-written assembler code.
+@item -mfix-loongson2f-btb
+@itemx -mno-fix-loongson2f-btb
+Clear the Branch Target Buffer before any jump through a register. This
+option is intended to be used on kernel code for the Loongson 2F processor
+only; userland code compiled with this option will fault, and kernel code
+compiled with this option run on another processor than Loongson 2F will
+yield unpredictable results.
+
@item -m4010
@itemx -no-m4010
Generate code for the LSI @sc{r4010} chip. This tells the assembler to
diff --git a/gnu/usr.bin/binutils/include/opcode/mips.h b/gnu/usr.bin/binutils/include/opcode/mips.h
index 5c3ddfcd7b5..f5a1c549186 100644
--- a/gnu/usr.bin/binutils/include/opcode/mips.h
+++ b/gnu/usr.bin/binutils/include/opcode/mips.h
@@ -582,7 +582,11 @@ enum
M_DSUB_I,
M_DSUBU_I,
M_DSUBU_I_2,
+ M_JR_S,
+ M_J_S,
M_J_A,
+ M_JALR_S,
+ M_JALR_DS,
M_JAL_1,
M_JAL_2,
M_JAL_A,
diff --git a/gnu/usr.bin/binutils/opcodes/mips-opc.c b/gnu/usr.bin/binutils/opcodes/mips-opc.c
index 9a80e53d43d..d16b804c2be 100644
--- a/gnu/usr.bin/binutils/opcodes/mips-opc.c
+++ b/gnu/usr.bin/binutils/opcodes/mips-opc.c
@@ -612,8 +612,10 @@ const struct mips_opcode mips_builtin_opcodes[] =
{"flushid", "", 0xbc030000, 0xffffffff, 0, L1 },
{"hibernate","", 0x42000023, 0xffffffff, 0, V1 },
{"ins", "t,r,+A,+B", 0x7c000004, 0xfc00003f, WR_t|RD_s, I33 },
+{"jr", "s", 0, (int) M_JR_S, INSN_MACRO, I1 },
{"jr", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, I1 },
{"jr.hb", "s", 0x00000408, 0xfc1fffff, UBD|RD_s, I33 },
+{"j", "s", 0, (int) M_J_S, INSN_MACRO, I1 },
{"j", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, I1 }, /* jr */
/* SVR4 PIC code requires special handling for j, so it must be a
macro. */
@@ -622,7 +624,9 @@ const struct mips_opcode mips_builtin_opcodes[] =
assembler, but will never match user input (because the line above
will match first). */
{"j", "a", 0x08000000, 0xfc000000, UBD, I1 },
+{"jalr", "s", 0, (int) M_JALR_S, INSN_MACRO, I1 },
{"jalr", "s", 0x0000f809, 0xfc1fffff, UBD|RD_s|WR_d, I1 },
+{"jalr", "d,s", 0, (int) M_JALR_DS, INSN_MACRO, I1 },
{"jalr", "d,s", 0x00000009, 0xfc1f07ff, UBD|RD_s|WR_d, I1 },
{"jalr.hb", "s", 0x0000fc09, 0xfc1fffff, UBD|RD_s|WR_d, I33 },
{"jalr.hb", "d,s", 0x00000409, 0xfc1f07ff, UBD|RD_s|WR_d, I33 },