Module Name:    src
Committed By:   bouyer
Date:           Sat Aug 27 13:19:39 UTC 2011

Modified Files:
        src/external/gpl3/binutils/dist/gas/config: tc-mips.c
        src/external/gpl3/binutils/dist/gas/doc: c-mips.texi
        src/external/gpl3/binutils/dist/include/opcode: mips.h
        src/external/gpl3/binutils/dist/opcodes: mips-opc.c

Log Message:
Add a fix-loongson2f-btb option to gas, from OpenBSD.
This works around a bug in the branch prediction logic of the
CPU which can cause a hard hang. The existing fix-loongson2f-jump
works around the same bug, but by 'fixing' the jump target to be within the
same 256MB region as the kernel. This will (silently) cause a jump
to the wrong address if the jump is intentionally to some other
region (e.g. a call to pmon).
fix-loongson2f-btb instead works around the issue by adding an explicit flush
of the branch target buffer (via a write to a cop0 register) before every
jump register instruction.


To generate a diff of this commit:
cvs rdiff -u -r1.5 -r1.6 src/external/gpl3/binutils/dist/gas/config/tc-mips.c
cvs rdiff -u -r1.3 -r1.4 src/external/gpl3/binutils/dist/gas/doc/c-mips.texi
cvs rdiff -u -r1.3 -r1.4 \
    src/external/gpl3/binutils/dist/include/opcode/mips.h
cvs rdiff -u -r1.5 -r1.6 src/external/gpl3/binutils/dist/opcodes/mips-opc.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/external/gpl3/binutils/dist/gas/config/tc-mips.c
diff -u src/external/gpl3/binutils/dist/gas/config/tc-mips.c:1.5 src/external/gpl3/binutils/dist/gas/config/tc-mips.c:1.6
--- src/external/gpl3/binutils/dist/gas/config/tc-mips.c:1.5	Thu Aug 18 06:32:35 2011
+++ src/external/gpl3/binutils/dist/gas/config/tc-mips.c	Sat Aug 27 13:19:39 2011
@@ -778,6 +778,8 @@
    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,
@@ -1051,6 +1053,7 @@
 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);
@@ -3584,6 +3587,41 @@
       r[i] = (bfd_reloc_code_real_type) va_arg (*args, int);
 }
 
+/* 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.at)
+    {
+      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
@@ -3985,6 +4023,7 @@
       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,
@@ -6167,6 +6206,26 @@
       /* AT is not used, just return */
       return;
 
+    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
@@ -6185,12 +6244,16 @@
       /* Fall through.  */
     case M_JAL_2:
       if (mips_pic == NO_PIC)
-	macro_build (NULL, "jalr", "d,s", dreg, sreg);
+	{
+	  macro_build_jrpatch (&expr1, sreg);
+	  macro_build (NULL, "jalr", "d,s", dreg, sreg);
+	}
       else
 	{
 	  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 (mips_pic == SVR4_PIC && !HAVE_NEWABI)
 	    {
@@ -11324,9 +11387,14 @@
 #define OPTION_NO_FIX_LOONGSON2F_NOP (OPTION_FIX_BASE + 9)
   {"mfix-loongson2f-nop", no_argument, NULL, OPTION_FIX_LOONGSON2F_NOP},
   {"mno-fix-loongson2f-nop", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_NOP},
+#define	OPTION_FIX_LOONGSON2F_BTB (OPTION_FIX_BASE + 10)
+#define OPTION_NO_FIX_LOONGSON2F_BTB (OPTION_FIX_BASE + 11)
+  {"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 + 10)
+#define OPTION_MISC_BASE (OPTION_FIX_BASE + 12)
 #define OPTION_TRAP (OPTION_MISC_BASE + 0)
   {"trap", no_argument, NULL, OPTION_TRAP},
   {"no-break", no_argument, NULL, OPTION_TRAP},
@@ -11645,6 +11713,14 @@
       mips_fix_vr4130 = 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;
@@ -15590,6 +15666,7 @@
 -mfix-loongson2f-nop	work around Loongson2F NOP errata\n\
 -mfix-vr4120		work around certain VR4120 errata\n\
 -mfix-vr4130		work around VR4130 mflo/mfhi 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\
 -msym32			assume all symbols have 32-bit values\n\

Index: src/external/gpl3/binutils/dist/gas/doc/c-mips.texi
diff -u src/external/gpl3/binutils/dist/gas/doc/c-mips.texi:1.3 src/external/gpl3/binutils/dist/gas/doc/c-mips.texi:1.4
--- src/external/gpl3/binutils/dist/gas/doc/c-mips.texi:1.3	Thu Apr 14 07:49:48 2011
+++ src/external/gpl3/binutils/dist/gas/doc/c-mips.texi	Sat Aug 27 13:19:39 2011
@@ -182,6 +182,14 @@
 @itemx -no-mfix-vr4130
 Insert nops to work around the VR4130 @samp{mflo}/@samp{mfhi} errata.
 
+@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

Index: src/external/gpl3/binutils/dist/include/opcode/mips.h
diff -u src/external/gpl3/binutils/dist/include/opcode/mips.h:1.3 src/external/gpl3/binutils/dist/include/opcode/mips.h:1.4
--- src/external/gpl3/binutils/dist/include/opcode/mips.h:1.3	Tue Aug  2 16:11:17 2011
+++ src/external/gpl3/binutils/dist/include/opcode/mips.h	Sat Aug 27 13:19:39 2011
@@ -762,7 +762,11 @@
   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,

Index: src/external/gpl3/binutils/dist/opcodes/mips-opc.c
diff -u src/external/gpl3/binutils/dist/opcodes/mips-opc.c:1.5 src/external/gpl3/binutils/dist/opcodes/mips-opc.c:1.6
--- src/external/gpl3/binutils/dist/opcodes/mips-opc.c:1.5	Thu Apr 14 08:05:00 2011
+++ src/external/gpl3/binutils/dist/opcodes/mips-opc.c	Sat Aug 27 13:19:39 2011
@@ -712,10 +712,12 @@
 {"floor.w.s", "D,S",	0x4600000f, 0xffff003f, WR_D|RD_S|FP_S,		0,		I2	},
 {"hibernate","",        0x42000023, 0xffffffff,	0, 			0,		V1	},
 {"ins",     "t,r,+A,+B", 0x7c000004, 0xfc00003f, WR_t|RD_s,    		0,		I33	},
+{"jr",      "s",	0,        (int) M_JR_S, INSN_MACRO,		0,		I1	},
 {"jr",      "s",	0x00000008, 0xfc1fffff,	UBD|RD_s,		0,		I1	},
 /* jr.hb is officially MIPS{32,64}R2, but it works on R1 as jr with
    the same hazard barrier effect.  */
 {"jr.hb",   "s",	0x00000408, 0xfc1fffff,	UBD|RD_s,		0,		I32	},
+{"j",       "s",	0,         (int) M_J_S, INSN_MACRO,		0,		I1	},
 {"j",       "s",	0x00000008, 0xfc1fffff,	UBD|RD_s,		0,		I1	}, /* jr */
 /* SVR4 PIC code requires special handling for j, so it must be a
    macro.  */
@@ -724,7 +726,9 @@
    assembler, but will never match user input (because the line above
    will match first).  */
 {"j",       "a",	0x08000000, 0xfc000000,	UBD,			0,		I1	},
+{"jalr",    "s",	0,      (int) M_JALR_S, INSN_MACRO,             0,		I1	},
 {"jalr",    "s",	0x0000f809, 0xfc1fffff,	UBD|RD_s|WR_d,		0,		I1	},
+{"jalr",    "d,s",	0,     (int) M_JALR_DS, INSN_MACRO,		0,		I1	},
 {"jalr",    "d,s",	0x00000009, 0xfc1f07ff,	UBD|RD_s|WR_d,		0,		I1	},
 /* jalr.hb is officially MIPS{32,64}R2, but it works on R1 as jalr
    with the same hazard barrier effect.  */

Reply via email to