diff -Nur binutils-2.20.orig/gas/config/tc-mips.c binutils-2.20/gas/config/tc-mips.c --- binutils-2.20.orig/gas/config/tc-mips.c 2009-09-22 17:41:00.000000000 +0200 +++ binutils-2.20/gas/config/tc-mips.c 2010-03-06 18:44:16.000000000 +0100 @@ -761,6 +761,15 @@ NUM_FIX_VR4120_CLASSES }; +/* ...likewise -mfix-loongson2f-jump. */ +static int mips_fix_loongson2f_jump; + +/* ...likewise -mfix-loongson2f-nop. */ +static int mips_fix_loongson2f_nop; + +/* True if -mfix-loongson2f-nop or -mfix-loongson2f-jump passed */ +static int mips_fix_loongson2f; + /* Given two FIX_VR4120_* values X and Y, bit Y of element X is set if there must be at least one other instruction between an instruction of type X and an instruction of type Y. */ @@ -1918,6 +1927,8 @@ if (nop_insn.insn_mo == NULL && strcmp (name, "nop") == 0) { create_insn (&nop_insn, mips_opcodes + i); + if (mips_fix_loongson2f_nop) + nop_insn.insn_opcode = LOONGSON2F_NOP_INSN; nop_insn.fixed_p = 1; } } @@ -2731,6 +2742,53 @@ return nops; } +static void +macro_build (expressionS *ep, const char *name, const char *fmt, ...); + +static void fix_loongson2f_nop(struct mips_cl_insn *ip) +{ + /* Fix NOP issue: Replace nops by "or at,at,zero" */ + if (strcmp(ip->insn_mo->name, "nop") == 0) + ip->insn_opcode = LOONGSON2F_NOP_INSN; +} + +static void fix_loongson2f_jump(struct mips_cl_insn *ip) +{ + + /* Fix Jump Issue: Eliminate instruction fetch from outside 256M region + * jr target pc &= 'hffff_ffff_cfff_ffff + */ + if (strcmp(ip->insn_mo->name, "j") == 0 + || strcmp(ip->insn_mo->name, "jr") == 0 + || strcmp(ip->insn_mo->name, "jalr") == 0) + { + int sreg; + expressionS ep; + + if (! mips_opts.at) + return; + + sreg = EXTRACT_OPERAND (RS, *ip); + if (sreg == ZERO || sreg == KT0 || sreg == KT1 || sreg == ATREG) + return; + + ep.X_op = O_constant; + ep.X_add_number = 0xcfff0000; + macro_build (&ep, "lui", "t,u", ATREG, BFD_RELOC_HI16); + ep.X_add_number = 0xffff; + macro_build (&ep, "ori", "t,r,i", ATREG, ATREG, BFD_RELOC_LO16); + macro_build (NULL, "and", "d,v,t", sreg, sreg, ATREG); + } +} + +static void fix_loongson2f(struct mips_cl_insn *ip) +{ + if (mips_fix_loongson2f_nop) + fix_loongson2f_nop(ip); + if (mips_fix_loongson2f_jump) + fix_loongson2f_jump(ip); +} + /* Output an instruction. IP is the instruction information. ADDRESS_EXPR is an operand of the instruction to be used with RELOC_TYPE. */ @@ -2744,6 +2802,9 @@ bfd_boolean relaxed_branch = FALSE; segment_info_type *si = seg_info (now_seg); + if (mips_fix_loongson2f) + fix_loongson2f(ip); + /* Mark instruction labels in mips16 mode. */ mips16_mark_labels (); @@ -11220,6 +11281,10 @@ OPTION_MNO_7000_HILO_FIX, OPTION_FIX_24K, OPTION_NO_FIX_24K, + OPTION_FIX_LOONGSON2F_JUMP, + OPTION_NO_FIX_LOONGSON2F_JUMP, + OPTION_FIX_LOONGSON2F_NOP, + OPTION_NO_FIX_LOONGSON2F_NOP, OPTION_FIX_VR4120, OPTION_NO_FIX_VR4120, OPTION_FIX_VR4130, @@ -11308,6 +11373,10 @@ {"mfix7000", no_argument, NULL, OPTION_M7000_HILO_FIX}, {"no-fix-7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX}, {"mno-fix7000", no_argument, NULL, OPTION_MNO_7000_HILO_FIX}, + {"mfix-loongson2f-jump", no_argument, NULL, OPTION_FIX_LOONGSON2F_JUMP}, + {"mno-fix-loongson2f-jump", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_JUMP}, + {"mfix-loongson2f-nop", no_argument, NULL, OPTION_FIX_LOONGSON2F_NOP}, + {"mno-fix-loongson2f-nop", no_argument, NULL, OPTION_NO_FIX_LOONGSON2F_NOP}, {"mfix-vr4120", no_argument, NULL, OPTION_FIX_VR4120}, {"mno-fix-vr4120", no_argument, NULL, OPTION_NO_FIX_VR4120}, {"mfix-vr4130", no_argument, NULL, OPTION_FIX_VR4130}, @@ -11575,6 +11644,22 @@ mips_fix_24k = 0; break; + case OPTION_FIX_LOONGSON2F_JUMP: + mips_fix_loongson2f_jump = 1; + break; + + case OPTION_NO_FIX_LOONGSON2F_JUMP: + mips_fix_loongson2f_jump = 0; + break; + + case OPTION_FIX_LOONGSON2F_NOP: + mips_fix_loongson2f_nop = 1; + break; + + case OPTION_NO_FIX_LOONGSON2F_NOP: + mips_fix_loongson2f_nop = 0; + break; + case OPTION_FIX_VR4120: mips_fix_vr4120 = 1; break; @@ -11789,6 +11874,8 @@ return 0; } + mips_fix_loongson2f = mips_fix_loongson2f_nop || mips_fix_loongson2f_jump; + return 1; } @@ -14794,6 +14881,8 @@ mips_handle_align (fragS *fragp) { char *p; + int bytes, size, excess; + valueT opcode; if (fragp->fr_type != rs_align_code) return; @@ -14801,17 +14890,27 @@ p = fragp->fr_literal + fragp->fr_fix; if (*p) { - int bytes; + opcode = mips16_nop_insn.insn_opcode; + size = 2; + } + else + { + opcode = nop_insn.insn_opcode; + size = 4; + } - bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix; - if (bytes & 1) - { - *p++ = 0; - fragp->fr_fix++; - } - md_number_to_chars (p, mips16_nop_insn.insn_opcode, 2); - fragp->fr_var = 2; + bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix; + excess = bytes % size; + if (excess != 0) + { + /* If we're not inserting a whole number of instructions, pad the + end of the fixed part of the frag with zeros */ + memset (p, 0, excess); + p += excess; + fragp->fr_fix += excess; } + md_number_to_chars (p, opcode, size); + fragp->fr_var = size; } static void @@ -15523,6 +15622,8 @@ -mmt generate MT instructions\n\ -mno-mt do not generate MT instructions\n")); fprintf (stream, _("\ +-mfix-loongson2f-jump work around Loongson2F JUMP instructions\ +-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-24k insert a nop after ERET and DERET instructions\n\ diff -Nur binutils-2.20.orig/gas/config/tc-mips.h binutils-2.20/gas/config/tc-mips.h --- binutils-2.20.orig/gas/config/tc-mips.h 2009-09-02 09:24:20.000000000 +0200 +++ binutils-2.20/gas/config/tc-mips.h 2010-03-06 18:44:16.000000000 +0100 @@ -59,7 +59,7 @@ extern void mips_handle_align (struct frag *); #define HANDLE_ALIGN(fragp) mips_handle_align (fragp) -#define MAX_MEM_FOR_RS_ALIGN_CODE (1 + 2) +#define MAX_MEM_FOR_RS_ALIGN_CODE (3 + 4) struct insn_label_list; struct mips_segment_info { diff -Nur binutils-2.20.orig/gas/doc/c-mips.texi binutils-2.20/gas/doc/c-mips.texi --- binutils-2.20.orig/gas/doc/c-mips.texi 2009-09-28 12:23:57.000000000 +0200 +++ binutils-2.20/gas/doc/c-mips.texi 2010-03-06 18:44:16.000000000 +0100 @@ -172,6 +172,19 @@ Cause nops to be inserted if the read of the destination register of an mfhi or mflo instruction occurs in the following two instructions. +@item -mfix-loongson2f-jump +@itemx -mno-fix-loongson2f-jump +Eliminate instruction fetch from outside 256M region to work around the +Loongson2F @samp{jump} instructions. Without it, under extreme cases, kernel +may crash. The issue has been solved in latest processor batches, but this fix +has no side effect to them. + +@item -mfix-loongson2f-nop +@itemx -mno-fix-loongson2f-nop +Replace nops by @code{or at,at,zero} to work around the Loongson2F @samp{nop} +errata. Without it, under extreme cases, cpu might deadlock. The issue has been +solved in latest loongson2f batches, but this fix has no side effect to them. + @item -mfix-vr4120 @itemx -no-mfix-vr4120 Insert nops to work around certain VR4120 errata. This option is diff -Nur binutils-2.20.orig/gas/testsuite/gas/mips/loongson-2f-2.d binutils-2.20/gas/testsuite/gas/mips/loongson-2f-2.d --- binutils-2.20.orig/gas/testsuite/gas/mips/loongson-2f-2.d 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.20/gas/testsuite/gas/mips/loongson-2f-2.d 2010-03-06 18:44:16.000000000 +0100 @@ -0,0 +1,18 @@ +#as: -mfix-loongson2f-nop +#objdump: -M reg-names=numeric -dr +#name: ST Microelectronics Loongson-2F workarounds of nop issue + +.*: file format .* + + +Disassembly of section .text: + +00000000 : + 0: 00200825 move \$1,\$1 + 4: 00200825 move \$1,\$1 + 8: 00200825 move \$1,\$1 + c: 00200825 move \$1,\$1 + 10: 00200825 move \$1,\$1 + 14: 00200825 move \$1,\$1 + 18: 00200825 move \$1,\$1 + 1c: 00200825 move \$1,\$1 diff -Nur binutils-2.20.orig/gas/testsuite/gas/mips/loongson-2f-2.s binutils-2.20/gas/testsuite/gas/mips/loongson-2f-2.s --- binutils-2.20.orig/gas/testsuite/gas/mips/loongson-2f-2.s 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.20/gas/testsuite/gas/mips/loongson-2f-2.s 2010-03-06 18:44:16.000000000 +0100 @@ -0,0 +1,10 @@ +# Test the work around of the NOP issue of loongson2F + .text + .set noreorder + + .align 5 # Test _implicit_ nops +loongson2f_nop_insn: + nop # Test _explicit_ nops + +# align section end to 16-byte boundary for easier testing on multiple targets + .p2align 4 diff -Nur binutils-2.20.orig/gas/testsuite/gas/mips/loongson-2f-3.d binutils-2.20/gas/testsuite/gas/mips/loongson-2f-3.d --- binutils-2.20.orig/gas/testsuite/gas/mips/loongson-2f-3.d 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.20/gas/testsuite/gas/mips/loongson-2f-3.d 2010-03-06 18:44:16.000000000 +0100 @@ -0,0 +1,35 @@ +#as: -mfix-loongson2f-jump +#objdump: -M reg-names=numeric -dr +#name: ST Microelectronics Loongson-2F workarounds of Jump Instruction issue + +.*: file format .* + + +Disassembly of section .text: + +00000000 <.text>: + 0: 3c01cfff lui \$1,0xcfff + 4: 3421ffff ori \$1,\$1,0xffff + 8: 03c1f024 and \$30,\$30,\$1 + c: 03c00008 jr \$30 + 10: 00000000 nop + + 14: 3c01cfff lui \$1,0xcfff + 18: 3421ffff ori \$1,\$1,0xffff + 1c: 03e1f824 and \$31,\$31,\$1 + 20: 03e00008 jr \$31 + 24: 00000000 nop + + 28: 3c01cfff lui \$1,0xcfff + 2c: 3421ffff ori \$1,\$1,0xffff + 30: 03c1f024 and \$30,\$30,\$1 + 34: 03c0f809 jalr \$30 + 38: 00000000 nop + + 3c: 00200008 jr \$1 + 40: 00000000 nop + + 44: 08000000 j 0x0 + 44: R_MIPS_26 external_label + 48: 00000000 nop + 4c: 00000000 nop diff -Nur binutils-2.20.orig/gas/testsuite/gas/mips/loongson-2f-3.s binutils-2.20/gas/testsuite/gas/mips/loongson-2f-3.s --- binutils-2.20.orig/gas/testsuite/gas/mips/loongson-2f-3.s 1970-01-01 01:00:00.000000000 +0100 +++ binutils-2.20/gas/testsuite/gas/mips/loongson-2f-3.s 2010-03-06 18:44:16.000000000 +0100 @@ -0,0 +1,23 @@ +# Test the work around of the Jump instruction Issue of Loongson2F + .text + .set noreorder + + j $30 # j with register + nop + + jr $31 # jr + nop + + jalr $30 # jalr + nop + + .set noat + jr $1 # jr with at register and .set annotation + nop + .set at + + j external_label # j with label + nop + +# align section end to 16-byte boundary for easier testing on multiple targets + .p2align 4 diff -Nur binutils-2.20.orig/gas/testsuite/gas/mips/mips.exp binutils-2.20/gas/testsuite/gas/mips/mips.exp --- binutils-2.20.orig/gas/testsuite/gas/mips/mips.exp 2009-09-22 17:41:03.000000000 +0200 +++ binutils-2.20/gas/testsuite/gas/mips/mips.exp 2010-03-06 18:44:16.000000000 +0100 @@ -789,6 +789,8 @@ run_dump_test "loongson-2e" run_dump_test "loongson-2f" + run_dump_test "loongson-2f-2" + run_dump_test "loongson-2f-3" run_dump_test_arches "octeon" [mips_arch_list_matching octeon] run_list_test_arches "octeon-ill" "" \ diff -Nur binutils-2.20.orig/include/opcode/mips.h binutils-2.20/include/opcode/mips.h --- binutils-2.20.orig/include/opcode/mips.h 2009-09-02 09:21:40.000000000 +0200 +++ binutils-2.20/include/opcode/mips.h 2010-03-06 18:44:16.000000000 +0100 @@ -1106,4 +1106,8 @@ extern const struct mips_opcode mips16_opcodes[]; extern const int bfd_mips16_num_opcodes; +/* Replace the original nops by "or at,at,zero", + Used to implement -mfix-loongson2f */ +#define LOONGSON2F_NOP_INSN 0x00200825 + #endif /* _MIPS_H_ */