• Cyril Bur's avatar
    powerpc: Don't enable FP/Altivec if not checkpointed · a7771176
    Cyril Bur authored
    Lazy save and restore of FP/Altivec means that a userspace process can
    be sent to userspace with FP or Altivec disabled and loaded only as
    required (by way of an FP/Altivec unavailable exception). Transactional
    Memory complicates this situation as a transaction could be started
    without FP/Altivec being loaded up. This causes the hardware to
    checkpoint incorrect registers. Handling FP/Altivec unavailable
    exceptions while a thread is transactional requires a reclaim and
    recheckpoint to ensure the CPU has correct state for both sets of
    registers.
    
    Lazy save and restore of FP/Altivec cannot be done if a process is
    transactional. If a facility was enabled it must remain enabled whenever
    a thread is transactional.
    
    Commit dc16b553 ("powerpc: Always restore FPU/VEC/VSX if hardware
    transactional memory in use") ensures that the facilities are always
    enabled if a thread is transactional. A bug in the introduced code may
    cause it to inadvertently enable a facility that was (and should remain)
    disabled. The problem with this extraneous enablement is that the
    registers for the erroneously enabled facility have not been correctly
    recheckpointed - the recheckpointing code assumed the facility would
    remain disabled.
    
    Further compounding the issue, the transactional {fp,altivec,vsx}
    unavailable code has been incorrectly using the MSR to enable
    facilities. The presence of the {FP,VEC,VSX} bit in the regs->msr simply
    means if the registers are live on the CPU, not if the kernel should
    load them before returning to userspace. This has worked due to the bug
    mentioned above.
    
    This causes transactional threads which return to their failure handler
    to observe incorrect checkpointed registers. Perhaps an example will
    help illustrate the problem:
    
    A userspace process is running and uses both FP and Altivec registers.
    This process then continues to run for some time without touching
    either sets of registers. The kernel subsequently disables the
    facilities as part of lazy save and restore. The userspace process then
    performs a tbegin and the CPU checkpoints 'junk' FP and Altivec
    registers. The process then performs a floating point instruction
    triggering a fp unavailable exception in the kernel.
    
    The kernel then loads the FP registers - and only the FP registers.
    Since the thread is transactional it must perform a reclaim and
    recheckpoint to ensure both the checkpointed registers and the
    transactional registers are correct. It then (correctly) enables
    MSR[FP] for the process. Later (on exception exist) the kernel also
    (inadvertently) enables MSR[VEC]. The process is then returned to
    userspace.
    
    Since the act of loading the FP registers doomed the transaction we know
    CPU will fail the transaction, restore its checkpointed registers, and
    return the process to its failure handler. The problem is that we're
    now running with Altivec enabled and the 'junk' checkpointed registers
    are restored. The kernel had only recheckpointed FP.
    
    This patch solves this by only activating FP/Altivec if userspace was
    using them when it entered the kernel and not simply if the process is
    transactional.
    
    Fixes: dc16b553 ("powerpc: Always restore FPU/VEC/VSX if hardware
    transactional memory in use")
    Signed-off-by: default avatarCyril Bur <cyrilbur@gmail.com>
    Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
    a7771176
traps.c 55.5 KB