linux/arch/s390/include/asm/alternative-asm.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2#ifndef _ASM_S390_ALTERNATIVE_ASM_H
   3#define _ASM_S390_ALTERNATIVE_ASM_H
   4
   5#ifdef __ASSEMBLY__
   6
   7/*
   8 * Check the length of an instruction sequence. The length may not be larger
   9 * than 254 bytes and it has to be divisible by 2.
  10 */
  11.macro alt_len_check start,end
  12        .if ( \end - \start ) > 254
  13        .error "cpu alternatives does not support instructions blocks > 254 bytes\n"
  14        .endif
  15        .if ( \end - \start ) % 2
  16        .error "cpu alternatives instructions length is odd\n"
  17        .endif
  18.endm
  19
  20/*
  21 * Issue one struct alt_instr descriptor entry (need to put it into
  22 * the section .altinstructions, see below). This entry contains
  23 * enough information for the alternatives patching code to patch an
  24 * instruction. See apply_alternatives().
  25 */
  26.macro alt_entry orig_start, orig_end, alt_start, alt_end, feature
  27        .long   \orig_start - .
  28        .long   \alt_start - .
  29        .word   \feature
  30        .byte   \orig_end - \orig_start
  31        .byte   \alt_end - \alt_start
  32.endm
  33
  34/*
  35 * Fill up @bytes with nops. The macro emits 6-byte nop instructions
  36 * for the bulk of the area, possibly followed by a 4-byte and/or
  37 * a 2-byte nop if the size of the area is not divisible by 6.
  38 */
  39.macro alt_pad_fill bytes
  40        .fill   ( \bytes ) / 6, 6, 0xc0040000
  41        .fill   ( \bytes ) % 6 / 4, 4, 0x47000000
  42        .fill   ( \bytes ) % 6 % 4 / 2, 2, 0x0700
  43.endm
  44
  45/*
  46 * Fill up @bytes with nops. If the number of bytes is larger
  47 * than 6, emit a jg instruction to branch over all nops, then
  48 * fill an area of size (@bytes - 6) with nop instructions.
  49 */
  50.macro alt_pad bytes
  51        .if ( \bytes > 0 )
  52        .if ( \bytes > 6 )
  53        jg      . + \bytes
  54        alt_pad_fill \bytes - 6
  55        .else
  56        alt_pad_fill \bytes
  57        .endif
  58        .endif
  59.endm
  60
  61/*
  62 * Define an alternative between two instructions. If @feature is
  63 * present, early code in apply_alternatives() replaces @oldinstr with
  64 * @newinstr. ".skip" directive takes care of proper instruction padding
  65 * in case @newinstr is longer than @oldinstr.
  66 */
  67.macro ALTERNATIVE oldinstr, newinstr, feature
  68        .pushsection .altinstr_replacement,"ax"
  69770:    \newinstr
  70771:    .popsection
  71772:    \oldinstr
  72773:    alt_len_check 770b, 771b
  73        alt_len_check 772b, 773b
  74        alt_pad ( ( 771b - 770b ) - ( 773b - 772b ) )
  75774:    .pushsection .altinstructions,"a"
  76        alt_entry 772b, 774b, 770b, 771b, \feature
  77        .popsection
  78.endm
  79
  80/*
  81 * Define an alternative between two instructions. If @feature is
  82 * present, early code in apply_alternatives() replaces @oldinstr with
  83 * @newinstr. ".skip" directive takes care of proper instruction padding
  84 * in case @newinstr is longer than @oldinstr.
  85 */
  86.macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2
  87        .pushsection .altinstr_replacement,"ax"
  88770:    \newinstr1
  89771:    \newinstr2
  90772:    .popsection
  91773:    \oldinstr
  92774:    alt_len_check 770b, 771b
  93        alt_len_check 771b, 772b
  94        alt_len_check 773b, 774b
  95        .if ( 771b - 770b > 772b - 771b )
  96        alt_pad ( ( 771b - 770b ) - ( 774b - 773b ) )
  97        .else
  98        alt_pad ( ( 772b - 771b ) - ( 774b - 773b ) )
  99        .endif
 100775:    .pushsection .altinstructions,"a"
 101        alt_entry 773b, 775b, 770b, 771b,\feature1
 102        alt_entry 773b, 775b, 771b, 772b,\feature2
 103        .popsection
 104.endm
 105
 106#endif  /*  __ASSEMBLY__  */
 107
 108#endif /* _ASM_S390_ALTERNATIVE_ASM_H */
 109