]> Git Repo - linux.git/blob - arch/s390/include/asm/alternative.h
Linux 6.14-rc3
[linux.git] / arch / s390 / include / asm / alternative.h
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_S390_ALTERNATIVE_H
3 #define _ASM_S390_ALTERNATIVE_H
4
5 /*
6  * Each alternative comes with a 32 bit feature field:
7  *      union {
8  *              u32 feature;
9  *              struct {
10  *                      u32 ctx  : 4;
11  *                      u32 type : 8;
12  *                      u32 data : 20;
13  *              };
14  *      }
15  *
16  * @ctx is a bitfield, where only one bit must be set. Each bit defines
17  * in which context an alternative is supposed to be applied to the
18  * kernel image:
19  *
20  * - from the decompressor before the kernel itself is executed
21  * - from early kernel code from within the kernel
22  *
23  * @type is a number which defines the type and with that the type
24  * specific alternative patching.
25  *
26  * @data is additional type specific information which defines if an
27  * alternative should be applied.
28  */
29
30 #define ALT_CTX_EARLY           1
31 #define ALT_CTX_LATE            2
32 #define ALT_CTX_ALL             (ALT_CTX_EARLY | ALT_CTX_LATE)
33
34 #define ALT_TYPE_FACILITY       0
35 #define ALT_TYPE_SPEC           1
36 #define ALT_TYPE_LOWCORE        2
37
38 #define ALT_DATA_SHIFT          0
39 #define ALT_TYPE_SHIFT          20
40 #define ALT_CTX_SHIFT           28
41
42 #define ALT_FACILITY(facility)          (ALT_CTX_EARLY << ALT_CTX_SHIFT         | \
43                                          ALT_TYPE_FACILITY << ALT_TYPE_SHIFT    | \
44                                          (facility) << ALT_DATA_SHIFT)
45
46 #define ALT_SPEC(facility)              (ALT_CTX_LATE << ALT_CTX_SHIFT          | \
47                                          ALT_TYPE_SPEC << ALT_TYPE_SHIFT        | \
48                                          (facility) << ALT_DATA_SHIFT)
49
50 #define ALT_LOWCORE                     (ALT_CTX_EARLY << ALT_CTX_SHIFT         | \
51                                          ALT_TYPE_LOWCORE << ALT_TYPE_SHIFT)
52
53 #ifndef __ASSEMBLY__
54
55 #include <linux/types.h>
56 #include <linux/stddef.h>
57 #include <linux/stringify.h>
58
59 struct alt_instr {
60         s32 instr_offset;       /* original instruction */
61         s32 repl_offset;        /* offset to replacement instruction */
62         union {
63                 u32 feature;    /* feature required for replacement */
64                 struct {
65                         u32 ctx  : 4;  /* context */
66                         u32 type : 8;  /* type of alternative */
67                         u32 data : 20; /* patching information */
68                 };
69         };
70         u8  instrlen;           /* length of original instruction */
71 } __packed;
72
73 extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
74
75 void __apply_alternatives(struct alt_instr *start, struct alt_instr *end, unsigned int ctx);
76
77 static inline void apply_alternative_instructions(void)
78 {
79         __apply_alternatives(__alt_instructions, __alt_instructions_end, ALT_CTX_LATE);
80 }
81
82 static inline void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
83 {
84         __apply_alternatives(start, end, ALT_CTX_ALL);
85 }
86
87 /*
88  * +---------------------------------+
89  * |661:                             |662:
90  * | oldinstr                        |
91  * +---------------------------------+
92  *
93  * .altinstr_replacement section
94  * +---------------------------------+
95  * |6641:                            |6651:
96  * | alternative instr 1             |
97  * +---------------------------------+
98  * |6642:                            |6652:
99  * | alternative instr 2             |
100  * +---------------------------------+
101  *
102  * .altinstructions section
103  * +---------------------------------+
104  * | alt_instr entries for each      |
105  * | alternative instr               |
106  * +---------------------------------+
107  */
108
109 #define b_altinstr(num)         "664"#num
110 #define e_altinstr(num)         "665"#num
111 #define oldinstr_len            "662b-661b"
112 #define altinstr_len(num)       e_altinstr(num)"b-"b_altinstr(num)"b"
113
114 #define OLDINSTR(oldinstr) \
115         "661:\n\t" oldinstr "\n662:\n"
116
117 #define ALTINSTR_ENTRY(feature, num)                                    \
118         "\t.long 661b - .\n"                    /* old instruction */   \
119         "\t.long " b_altinstr(num)"b - .\n"     /* alt instruction */   \
120         "\t.long " __stringify(feature) "\n"    /* feature         */   \
121         "\t.byte " oldinstr_len "\n"            /* instruction len */   \
122         "\t.org . - (" oldinstr_len ") & 1\n"                           \
123         "\t.org . - (" oldinstr_len ") + (" altinstr_len(num) ")\n"     \
124         "\t.org . - (" altinstr_len(num) ") + (" oldinstr_len ")\n"
125
126 #define ALTINSTR_REPLACEMENT(altinstr, num)     /* replacement */       \
127         b_altinstr(num)":\n\t" altinstr "\n" e_altinstr(num) ":\n"
128
129 /* alternative assembly primitive: */
130 #define ALTERNATIVE(oldinstr, altinstr, feature) \
131         ".pushsection .altinstr_replacement, \"ax\"\n"                  \
132         ALTINSTR_REPLACEMENT(altinstr, 1)                               \
133         ".popsection\n"                                                 \
134         OLDINSTR(oldinstr)                                              \
135         ".pushsection .altinstructions,\"a\"\n"                         \
136         ALTINSTR_ENTRY(feature, 1)                                      \
137         ".popsection\n"
138
139 #define ALTERNATIVE_2(oldinstr, altinstr1, feature1, altinstr2, feature2)\
140         ".pushsection .altinstr_replacement, \"ax\"\n"                  \
141         ALTINSTR_REPLACEMENT(altinstr1, 1)                              \
142         ALTINSTR_REPLACEMENT(altinstr2, 2)                              \
143         ".popsection\n"                                                 \
144         OLDINSTR(oldinstr)                                              \
145         ".pushsection .altinstructions,\"a\"\n"                         \
146         ALTINSTR_ENTRY(feature1, 1)                                     \
147         ALTINSTR_ENTRY(feature2, 2)                                     \
148         ".popsection\n"
149
150 /*
151  * Alternative instructions for different CPU types or capabilities.
152  *
153  * This allows to use optimized instructions even on generic binary
154  * kernels.
155  *
156  * oldinstr is padded with jump and nops at compile time if altinstr is
157  * longer. altinstr is padded with jump and nops at run-time during patching.
158  *
159  * For non barrier like inlines please define new variants
160  * without volatile and memory clobber.
161  */
162 #define alternative(oldinstr, altinstr, feature)                        \
163         asm_inline volatile(ALTERNATIVE(oldinstr, altinstr, feature) : : : "memory")
164
165 #define alternative_2(oldinstr, altinstr1, feature1, altinstr2, feature2) \
166         asm_inline volatile(ALTERNATIVE_2(oldinstr, altinstr1, feature1,   \
167                                    altinstr2, feature2) ::: "memory")
168
169 /* Alternative inline assembly with input. */
170 #define alternative_input(oldinstr, newinstr, feature, input...)        \
171         asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, feature)   \
172                 : : input)
173
174 /* Like alternative_input, but with a single output argument */
175 #define alternative_io(oldinstr, altinstr, feature, output, input...)   \
176         asm_inline volatile(ALTERNATIVE(oldinstr, altinstr, feature)    \
177                 : output : input)
178
179 /* Use this macro if more than one output parameter is needed. */
180 #define ASM_OUTPUT2(a...) a
181
182 /* Use this macro if clobbers are needed without inputs. */
183 #define ASM_NO_INPUT_CLOBBER(clobber...) : clobber
184
185 #else  /* __ASSEMBLY__ */
186
187 /*
188  * Issue one struct alt_instr descriptor entry (need to put it into
189  * the section .altinstructions, see below). This entry contains
190  * enough information for the alternatives patching code to patch an
191  * instruction. See apply_alternatives().
192  */
193 .macro alt_entry orig_start, orig_end, alt_start, alt_end, feature
194         .long   \orig_start - .
195         .long   \alt_start - .
196         .long   \feature
197         .byte   \orig_end - \orig_start
198         .org    . - ( \orig_end - \orig_start ) & 1
199         .org    . - ( \orig_end - \orig_start ) + ( \alt_end - \alt_start )
200         .org    . - ( \alt_end - \alt_start ) + ( \orig_end - \orig_start )
201 .endm
202
203 /*
204  * Define an alternative between two instructions. If @feature is
205  * present, early code in apply_alternatives() replaces @oldinstr with
206  * @newinstr.
207  */
208 .macro ALTERNATIVE oldinstr, newinstr, feature
209         .pushsection .altinstr_replacement,"ax"
210 770:    \newinstr
211 771:    .popsection
212 772:    \oldinstr
213 773:    .pushsection .altinstructions,"a"
214         alt_entry 772b, 773b, 770b, 771b, \feature
215         .popsection
216 .endm
217
218 /*
219  * Define an alternative between two instructions. If @feature is
220  * present, early code in apply_alternatives() replaces @oldinstr with
221  * @newinstr.
222  */
223 .macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2
224         .pushsection .altinstr_replacement,"ax"
225 770:    \newinstr1
226 771:    \newinstr2
227 772:    .popsection
228 773:    \oldinstr
229 774:    .pushsection .altinstructions,"a"
230         alt_entry 773b, 774b, 770b, 771b,\feature1
231         alt_entry 773b, 774b, 771b, 772b,\feature2
232         .popsection
233 .endm
234
235 #endif /* __ASSEMBLY__ */
236
237 #endif /* _ASM_S390_ALTERNATIVE_H */
This page took 0.04915 seconds and 4 git commands to generate.