• Peter Zijlstra's avatar
    x86/alternatives: Add nested alternatives macros · d2a793da
    Peter Zijlstra authored
    Instead of making increasingly complicated ALTERNATIVE_n()
    implementations, use a nested alternative expression.
    
    The only difference between:
    
      ALTERNATIVE_2(oldinst, newinst1, flag1, newinst2, flag2)
    
    and
    
      ALTERNATIVE(ALTERNATIVE(oldinst, newinst1, flag1),
                  newinst2, flag2)
    
    is that the outer alternative can add additional padding when the inner
    alternative is the shorter one, which then results in
    alt_instr::instrlen being inconsistent.
    
    However, this is easily remedied since the alt_instr entries will be
    consecutive and it is trivial to compute the max(alt_instr::instrlen) at
    runtime while patching.
    
    Specifically, after this the ALTERNATIVE_2 macro, after CPP expansion
    (and manual layout), looks like this:
    
      .macro ALTERNATIVE_2 oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2
      740:
      740: \oldinstr ;
      741: .skip -(((744f-743f)-(741b-740b)) > 0) * ((744f-743f)-(741b-740b)),0x90 ;
      742: .pushsection .altinstructions,"a" ;
      	altinstr_entry 740b,743f,\ft_flags1,742b-740b,744f-743f ;
      .popsection ;
      .pushsection .altinstr_replacement,"ax" ;
      743: \newinstr1 ;
      744: .popsection ; ;
      741: .skip -(((744f-743f)-(741b-740b)) > 0) * ((744f-743f)-(741b-740b)),0x90 ;
      742: .pushsection .altinstructions,"a" ;
      altinstr_entry 740b,743f,\ft_flags2,742b-740b,744f-743f ;
      .popsection ;
      .pushsection .altinstr_replacement,"ax" ;
      743: \newinstr2 ;
      744: .popsection ;
      .endm
    
    The only label that is ambiguous is 740, however they all reference the
    same spot, so that doesn't matter.
    
    NOTE: obviously only @oldinstr may be an alternative; making @newinstr
    an alternative would mean patching .altinstr_replacement which very
    likely isn't what is intended, also the labels will be confused in that
    case.
    
      [ bp: Debug an issue where it would match the wrong two insns and
        and consider them nested due to the same signed offsets in the
        .alternative section and use instr_va() to compare the full virtual
        addresses instead.
    
        - Use new labels to denote that the new, nested
        alternatives are being used when staring at preprocessed output.
    
        - Use the %c constraint everywhere instead of %P and document the
          difference for future reference. ]
    Signed-off-by: default avatarPeter Zijlstra <peterz@infradead.org>
    Co-developed-by: default avatarBorislav Petkov (AMD) <bp@alien8.de>
    Signed-off-by: default avatarBorislav Petkov (AMD) <bp@alien8.de>
    Acked-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
    Link: https://lkml.kernel.org/r/20230628104952.GA2439977@hirez.programming.kicks-ass.net
    d2a793da
special.c 4.09 KB