• Mark Rutland's avatar
    arm64: alternatives: make clean_dcache_range_nopatch() noinstr-safe · 39138093
    Mark Rutland authored
    When patching kernel alternatives, we need to be careful not to execute
    kernel code which is itself subject to patching. In general, if code is
    executed after the instructions in memory have been patched but prior to
    the cache maintenance and barriers completing, it could lead to
    UNPREDICTABLE results.
    
    As our regular cache maintenance routines are patched with alternatives,
    we have a clean_dcache_range_nopatch() function which is *intended* to
    avoid patchable code and therefore supposed to be safe in the middle of
    patching alternatives. Unfortunately, it's not marked as 'noinstr', and
    so can be instrumented with patchable code.
    
    Additionally, it calls read_sanitised_ftr_reg() (which may be
    instrumented with patchable code) to find the sanitized value of
    CTR_EL0.DminLine, and is therefore not safe to call during patching.
    
    Luckily, since commit:
    
      675b0563 ("arm64: cpufeature: expose arm64_ftr_reg struct for CTR_EL0")
    
    ... we can read the sanitised CTR_EL0 value directly, and avoid the call
    to read_sanitised_ftr_reg().
    
    This patch marks clean_dcache_range_nopatch() as noinstr, and has it
    read the sanitized CTR_EL0 value directly, avoiding the issues above.
    
    As a bonus, this is also an optimization. As read_sanitised_ftr_reg()
    performs a binary search to find the CTR_EL0 value, reading the value
    directly avoids this binary search per applied alternative, avoiding
    some unnecessary work.
    Signed-off-by: default avatarMark Rutland <mark.rutland@arm.com>
    Cc: Will Deacon <will@kernel.org>
    Link: https://lore.kernel.org/r/20230616103150.1238132-1-mark.rutland@arm.comSigned-off-by: default avatarCatalin Marinas <catalin.marinas@arm.com>
    39138093
alternative.c 7.63 KB