R5900 short loop erratum - frno7/linux GitHub Wiki
The R5900 short loop erratum is a hardware bug of the R5900 processor of the PlayStation 2 that under certain conditions causes program loops to execute only once or twice, leading to undefined behaviour, including data corruption or crashes.
The GNU assembler (GAS) has the following note about it (source):
On the R5900 short loops need to be fixed by inserting a NOP in the branch delay slot.
The short loop bug under certain conditions causes loops to execute only once or twice. We must ensure that the assembler never generates loops that satisfy all of the following conditions:
- a loop consists of less than or equal to six instructions (including the branch delay slot);
- a loop contains only one conditional branch instruction at the end of the loop;
- a loop does not contain any other branch or jump instructions;
- a branch delay slot of the loop is not NOP (EE 2.9 or later).
We need to do this because of a hardware bug in the R5900 chip.
[!CAUTION] GAS and LLVM automatically handle the short loop bug in most cases. However, GAS and LLVM are unable to adjust machine code having the
noreorderdirective, as used by the Linux kernel on several occasions. Moreover, neither GAS nor the LLVM assembler warn about failing to handle the short loop bug.
[!CAUTION] The short loop bug affects user space programs, which is why generic MIPS code cannot execute unadjusted on the R5900. The GAS, GCC and LLVM option
-mfix-r5900must be given for such cases. This option is automatically enabled with amipsr5900eltarget compiler such asmipsr5900el-unknown-linux-gnu. The-mfix-r5900option is safe and compatible with all MIPS I, II and III hardware.
Verifying programs and libraries
The r5900check tool can analyse ELF machine code to find problematic short loops. Let’s look at an example by analysing Busybox:
% linux/tools/r5900check/r5900check initramfs/ps2/sbin/busybox
erratum shortloop path initramfs/ps2/sbin/busybox
code 00403058 -3 00021040
code 0040305c -2 0047302b
code 00403060 -1 00602021
code 00403064 0 14c0fffc
code 00403068 1 2463ffff
Column 2 is the address, column 3 is the offset relative to the jump instruction (with the actual jump at the zero offset), and column 4 the machine code. We can easily disassemble this piece with objdump by printing the relevant addresses,
% mipsr5900el-unknown-linux-gnu-objdump -d --start-address=0x403058 --stop-address=0x40306c initramfs/ps2/sbin/busybox
403058: 00021040 sll v0,v0,0x1
40305c: 0047302b sltu a2,v0,a3
403060: 00602021 move a0,v1
403064: 14c0fffc bnez a2,0x403058
403068: 2463ffff addiu v1,v1,-1
and find that we have this backwards branching BNEZ (branch on not equal zero) instruction. Now let’s review the conditions for the R5900 short loop erratum: as we can see, the loop only has five instructions, it has only one conditional branch (BNEZ), with no other branches or jumps, and no NOP in the branch delay slot (it’s ADDIU). Danger! The next step would be to find out why Busybox has this piece of problematic code.