• Paul Burton's avatar
    MIPS: Workaround GCC __builtin_unreachable reordering bug · 9b77cd9a
    Paul Burton authored
    BugLink: https://bugs.launchpad.net/bugs/1836668
    
    [ Upstream commit 906d441f ]
    
    Some versions of GCC for the MIPS architecture suffer from a bug which
    can lead to instructions from beyond an unreachable statement being
    incorrectly reordered into earlier branch delay slots if the unreachable
    statement is the only content of a case in a switch statement. This can
    lead to seemingly random behaviour, such as invalid memory accesses from
    incorrectly reordered loads or stores, and link failures on microMIPS
    builds.
    
    See this potential GCC fix for details:
    
        https://gcc.gnu.org/ml/gcc-patches/2015-09/msg00360.html
    
    Runtime problems resulting from this bug were initially observed using a
    maltasmvp_defconfig v4.4 kernel built using GCC 4.9.2 (from a Codescape
    SDK 2015.06-05 toolchain), with the result being an address exception
    taken after log messages about the L1 caches (during probe of the L2
    cache):
    
        Initmem setup node 0 [mem 0x0000000080000000-0x000000009fffffff]
        VPE topology {2,2} total 4
        Primary instruction cache 64kB, VIPT, 4-way, linesize 32 bytes.
        Primary data cache 64kB, 4-way, PIPT, no aliases, linesize 32 bytes
        <AdEL exception here>
    
    This is early enough that the kernel exception vectors are not in use,
    so any further output depends upon the bootloader. This is reproducible
    in QEMU where no further output occurs - ie. the system hangs here.
    Given the nature of the bug it may potentially be hit with differing
    symptoms. The bug is known to affect GCC versions as recent as 7.3, and
    it is unclear whether GCC 8 fixed it or just happens not to encounter
    the bug in the testcase found at the link above due to differing
    optimizations.
    
    This bug can be worked around by placing a volatile asm statement, which
    GCC is prevented from reordering past, prior to the
    __builtin_unreachable call.
    
    That was actually done already for other reasons by commit 173a3efd
    ("bug.h: work around GCC PR82365 in BUG()"), but creates problems for
    microMIPS builds due to the lack of a .insn directive. The microMIPS ISA
    allows for interlinking with regular MIPS32 code by repurposing bit 0 of
    the program counter as an ISA mode bit. To switch modes one changes the
    value of this bit in the PC. However typical branch instructions encode
    their offsets as multiples of 2-byte instruction halfwords, which means
    they cannot change ISA mode - this must be done using either an indirect
    branch (a jump-register in MIPS terminology) or a dedicated jalx
    instruction. In order to ensure that regular branches don't attempt to
    target code in a different ISA which they can't actually switch to, the
    linker will check that branch targets are code in the same ISA as the
    branch.
    
    Unfortunately our empty asm volatile statements don't qualify as code,
    and the link for microMIPS builds fails with errors such as:
    
        arch/mips/mm/dma-default.s:3265: Error: branch to a symbol in another ISA mode
        arch/mips/mm/dma-default.s:5027: Error: branch to a symbol in another ISA mode
    
    Resolve this by adding a .insn directive within the asm statement which
    declares that what comes next is code. This may or may not be true,
    since we don't really know what comes next, but as this code is in an
    unreachable path anyway that doesn't matter since we won't execute it.
    
    We do this in asm/compiler.h & select CONFIG_HAVE_ARCH_COMPILER_H in
    order to have this included by linux/compiler_types.h after
    linux/compiler-gcc.h. This will result in asm/compiler.h being included
    in all C compilations via the -include linux/compiler_types.h argument
    in c_flags, which should be harmless.
    Signed-off-by: default avatarPaul Burton <paul.burton@mips.com>
    Fixes: 173a3efd ("bug.h: work around GCC PR82365 in BUG()")
    Patchwork: https://patchwork.linux-mips.org/patch/20270/
    Cc: James Hogan <jhogan@kernel.org>
    Cc: Ralf Baechle <ralf@linux-mips.org>
    Cc: Arnd Bergmann <arnd@arndb.de>
    Cc: linux-mips@linux-mips.org
    Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
    Signed-off-by: default avatarKhalid Elmously <khalid.elmously@canonical.com>
    Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
    9b77cd9a
Kconfig 74.8 KB