On Mon, 13 Jan 2003, Mike Uhler wrote: > > If I print the parameters at label `sigill' in emulate_load_store_insn(), I > > get: > > > > pc 0x80346448 addr 0x83d9f81e ins 0x14600012 > > > > And emulate_load_store_insn() gets confused because 0x14600012 is not a > > load/store. 0x14600012 is the branch instruction before the load, not the load > > after the branch instruction! Note that bit 31 of cause (CAUSEF_BD) is not set. > > Some more investigations showed that the branch is indeed not taken. > > > > Apparently if an unaligned access happens right after a branch which is not > > taking, epc points to the branch instruction, and CAUSEF_BD is not set > > (technically speaking, this is not a branch delay, since the branch is not > > taken :-). Is this expected behavior? The CPU is a VR4120A core. > > > > As a workaround, I assume I can just test whether pc points to a branch > > instruction, and increment pc if that's the case? > > Prior to the MIPS32/MIPS64 architecture definition, which requires that EPC > point at the branch and the Cause[BD] bit be set on any exception in the > branch delay slot, there were a few CPUs which interpreted the rules in the > manner that you describe. I don't happen to have a VR4120A manual in front > of me, but the behavior you describe could easily be the case of this differnt > interpretation. Thanks! The following patch (against linux-mips-2.4.x CVS) cures my crash. I don't know on which CPUs this may happen (need #ifdef CONFIG_CPU_VR41XX?), nor whether all branch and jump instructions are affected (I included everything that starts with a `b' or `j'). Index: arch/mips/kernel/unaligned.c =================================================================== RCS file: /home/cvs/linux/arch/mips/kernel/unaligned.c,v retrieving revision 1.15.2.14 diff -u -r1.15.2.14 unaligned.c --- arch/mips/kernel/unaligned.c 6 Jan 2003 22:05:25 -0000 1.15.2.14 +++ arch/mips/kernel/unaligned.c 13 Jan 2003 18:01:26 -0000 @@ -103,6 +103,7 @@ /* * This load never faults. */ +retry: __get_user(insn.word, (unsigned int *)pc); switch (insn.i_format.opcode) { @@ -134,6 +135,26 @@ case lbu_op: case sb_op: goto sigbus; + + /* + * On some CPUs, if an unaligned access happens in a branch delay slot + * and the branch is not taken, EPC points at the branch instruction, + * but the BD bit in the cause register is not set. + */ + case bcond_op: + case j_op: + case jal_op: + case beq_op: + case bne_op: + case blez_op: + case bgtz_op: + case beql_op: + case bnel_op: + case blezl_op: + case bgtzl_op: + case jalx_op: + pc += 4; + goto retry; /* * The remaining opcodes are the ones that are really of interest. Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds