Skip to content

R5900 short loop erratum

frno7 edited this page Feb 6, 2022 · 7 revisions

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:

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.

GAS handles the short loop bug in most cases. However, GAS is unable to adjust machine code having the noreorder directive, as used by the kernel on several occasions.

The short loop bug also affects user space programs, which is why generic MIPS code cannot execute unadjusted on the R5900. The GAS and GCC option -mfix-r5900 must be given for such cases. This option is automatically enabled with a mipsr5900el-unknown-linux-gnu compiler. The -mfix-r5900 option 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.