Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/s390/include/asm/alternative.h
26493 views
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_FEATURE 1
36
#define ALT_TYPE_SPEC 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_FEATURE(feature) (ALT_CTX_EARLY << ALT_CTX_SHIFT | \
47
ALT_TYPE_FEATURE << ALT_TYPE_SHIFT | \
48
(feature) << ALT_DATA_SHIFT)
49
50
#define ALT_SPEC(facility) (ALT_CTX_LATE << ALT_CTX_SHIFT | \
51
ALT_TYPE_SPEC << ALT_TYPE_SHIFT | \
52
(facility) << ALT_DATA_SHIFT)
53
54
#ifndef __ASSEMBLER__
55
56
#include <linux/types.h>
57
#include <linux/stddef.h>
58
#include <linux/stringify.h>
59
60
struct alt_instr {
61
s32 instr_offset; /* original instruction */
62
s32 repl_offset; /* offset to replacement instruction */
63
union {
64
u32 feature; /* feature required for replacement */
65
struct {
66
u32 ctx : 4; /* context */
67
u32 type : 8; /* type of alternative */
68
u32 data : 20; /* patching information */
69
};
70
};
71
u8 instrlen; /* length of original instruction */
72
} __packed;
73
74
extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
75
76
void __apply_alternatives(struct alt_instr *start, struct alt_instr *end, unsigned int ctx);
77
78
static inline void apply_alternative_instructions(void)
79
{
80
__apply_alternatives(__alt_instructions, __alt_instructions_end, ALT_CTX_LATE);
81
}
82
83
static inline void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
84
{
85
__apply_alternatives(start, end, ALT_CTX_ALL);
86
}
87
88
/*
89
* +---------------------------------+
90
* |661: |662:
91
* | oldinstr |
92
* +---------------------------------+
93
*
94
* .altinstr_replacement section
95
* +---------------------------------+
96
* |6641: |6651:
97
* | alternative instr 1 |
98
* +---------------------------------+
99
* |6642: |6652:
100
* | alternative instr 2 |
101
* +---------------------------------+
102
*
103
* .altinstructions section
104
* +---------------------------------+
105
* | alt_instr entries for each |
106
* | alternative instr |
107
* +---------------------------------+
108
*/
109
110
#define b_altinstr(num) "664"#num
111
#define e_altinstr(num) "665"#num
112
#define oldinstr_len "662b-661b"
113
#define altinstr_len(num) e_altinstr(num)"b-"b_altinstr(num)"b"
114
115
#define OLDINSTR(oldinstr) \
116
"661:\n\t" oldinstr "\n662:\n"
117
118
#define ALTINSTR_ENTRY(feature, num) \
119
"\t.long 661b - .\n" /* old instruction */ \
120
"\t.long " b_altinstr(num)"b - .\n" /* alt instruction */ \
121
"\t.long " __stringify(feature) "\n" /* feature */ \
122
"\t.byte " oldinstr_len "\n" /* instruction len */ \
123
"\t.org . - (" oldinstr_len ") & 1\n" \
124
"\t.org . - (" oldinstr_len ") + (" altinstr_len(num) ")\n" \
125
"\t.org . - (" altinstr_len(num) ") + (" oldinstr_len ")\n"
126
127
#define ALTINSTR_REPLACEMENT(altinstr, num) /* replacement */ \
128
b_altinstr(num)":\n\t" altinstr "\n" e_altinstr(num) ":\n"
129
130
/* alternative assembly primitive: */
131
#define ALTERNATIVE(oldinstr, altinstr, feature) \
132
".pushsection .altinstr_replacement, \"ax\"\n" \
133
ALTINSTR_REPLACEMENT(altinstr, 1) \
134
".popsection\n" \
135
OLDINSTR(oldinstr) \
136
".pushsection .altinstructions,\"a\"\n" \
137
ALTINSTR_ENTRY(feature, 1) \
138
".popsection\n"
139
140
#define ALTERNATIVE_2(oldinstr, altinstr1, feature1, altinstr2, feature2)\
141
".pushsection .altinstr_replacement, \"ax\"\n" \
142
ALTINSTR_REPLACEMENT(altinstr1, 1) \
143
ALTINSTR_REPLACEMENT(altinstr2, 2) \
144
".popsection\n" \
145
OLDINSTR(oldinstr) \
146
".pushsection .altinstructions,\"a\"\n" \
147
ALTINSTR_ENTRY(feature1, 1) \
148
ALTINSTR_ENTRY(feature2, 2) \
149
".popsection\n"
150
151
/*
152
* Alternative instructions for different CPU types or capabilities.
153
*
154
* This allows to use optimized instructions even on generic binary
155
* kernels.
156
*
157
* oldinstr is padded with jump and nops at compile time if altinstr is
158
* longer. altinstr is padded with jump and nops at run-time during patching.
159
*
160
* For non barrier like inlines please define new variants
161
* without volatile and memory clobber.
162
*/
163
#define alternative(oldinstr, altinstr, feature) \
164
asm_inline volatile(ALTERNATIVE(oldinstr, altinstr, feature) : : : "memory")
165
166
#define alternative_2(oldinstr, altinstr1, feature1, altinstr2, feature2) \
167
asm_inline volatile(ALTERNATIVE_2(oldinstr, altinstr1, feature1, \
168
altinstr2, feature2) ::: "memory")
169
170
/* Alternative inline assembly with input. */
171
#define alternative_input(oldinstr, newinstr, feature, input...) \
172
asm_inline volatile (ALTERNATIVE(oldinstr, newinstr, feature) \
173
: : input)
174
175
/* Like alternative_input, but with a single output argument */
176
#define alternative_io(oldinstr, altinstr, feature, output, input...) \
177
asm_inline volatile(ALTERNATIVE(oldinstr, altinstr, feature) \
178
: output : input)
179
180
/* Use this macro if more than one output parameter is needed. */
181
#define ASM_OUTPUT2(a...) a
182
183
/* Use this macro if clobbers are needed without inputs. */
184
#define ASM_NO_INPUT_CLOBBER(clobber...) : clobber
185
186
#else /* __ASSEMBLER__ */
187
188
/*
189
* Issue one struct alt_instr descriptor entry (need to put it into
190
* the section .altinstructions, see below). This entry contains
191
* enough information for the alternatives patching code to patch an
192
* instruction. See apply_alternatives().
193
*/
194
.macro alt_entry orig_start, orig_end, alt_start, alt_end, feature
195
.long \orig_start - .
196
.long \alt_start - .
197
.long \feature
198
.byte \orig_end - \orig_start
199
.org . - ( \orig_end - \orig_start ) & 1
200
.org . - ( \orig_end - \orig_start ) + ( \alt_end - \alt_start )
201
.org . - ( \alt_end - \alt_start ) + ( \orig_end - \orig_start )
202
.endm
203
204
/*
205
* Define an alternative between two instructions. If @feature is
206
* present, early code in apply_alternatives() replaces @oldinstr with
207
* @newinstr.
208
*/
209
.macro ALTERNATIVE oldinstr, newinstr, feature
210
.pushsection .altinstr_replacement,"ax"
211
770: \newinstr
212
771: .popsection
213
772: \oldinstr
214
773: .pushsection .altinstructions,"a"
215
alt_entry 772b, 773b, 770b, 771b, \feature
216
.popsection
217
.endm
218
219
/*
220
* Define an alternative between two instructions. If @feature is
221
* present, early code in apply_alternatives() replaces @oldinstr with
222
* @newinstr.
223
*/
224
.macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2
225
.pushsection .altinstr_replacement,"ax"
226
770: \newinstr1
227
771: \newinstr2
228
772: .popsection
229
773: \oldinstr
230
774: .pushsection .altinstructions,"a"
231
alt_entry 773b, 774b, 770b, 771b,\feature1
232
alt_entry 773b, 774b, 771b, 772b,\feature2
233
.popsection
234
.endm
235
236
#endif /* __ASSEMBLER__ */
237
238
#endif /* _ASM_S390_ALTERNATIVE_H */
239
240