@@ -124,6 +124,20 @@ const unsigned char * const x86_nops[ASM_NOP_MAX+1] =
124
124
#endif
125
125
};
126
126
127
+ /*
128
+ * Nomenclature for variable names to simplify and clarify this code and ease
129
+ * any potential staring at it:
130
+ *
131
+ * @instr: source address of the original instructions in the kernel text as
132
+ * generated by the compiler.
133
+ *
134
+ * @buf: temporary buffer on which the patching operates. This buffer is
135
+ * eventually text-poked into the kernel image.
136
+ *
137
+ * @replacement/@repl: pointer to the opcodes which are replacing @instr, located
138
+ * in the .altinstr_replacement section.
139
+ */
140
+
127
141
/*
128
142
* Fill the buffer with a single effective instruction of size @len.
129
143
*
@@ -133,28 +147,28 @@ const unsigned char * const x86_nops[ASM_NOP_MAX+1] =
133
147
* each single-byte NOPs). If @len to fill out is > ASM_NOP_MAX, pad with INT3 and
134
148
* *jump* over instead of executing long and daft NOPs.
135
149
*/
136
- static void add_nop (u8 * instr , unsigned int len )
150
+ static void add_nop (u8 * buf , unsigned int len )
137
151
{
138
- u8 * target = instr + len ;
152
+ u8 * target = buf + len ;
139
153
140
154
if (!len )
141
155
return ;
142
156
143
157
if (len <= ASM_NOP_MAX ) {
144
- memcpy (instr , x86_nops [len ], len );
158
+ memcpy (buf , x86_nops [len ], len );
145
159
return ;
146
160
}
147
161
148
162
if (len < 128 ) {
149
- __text_gen_insn (instr , JMP8_INSN_OPCODE , instr , target , JMP8_INSN_SIZE );
150
- instr += JMP8_INSN_SIZE ;
163
+ __text_gen_insn (buf , JMP8_INSN_OPCODE , buf , target , JMP8_INSN_SIZE );
164
+ buf += JMP8_INSN_SIZE ;
151
165
} else {
152
- __text_gen_insn (instr , JMP32_INSN_OPCODE , instr , target , JMP32_INSN_SIZE );
153
- instr += JMP32_INSN_SIZE ;
166
+ __text_gen_insn (buf , JMP32_INSN_OPCODE , buf , target , JMP32_INSN_SIZE );
167
+ buf += JMP32_INSN_SIZE ;
154
168
}
155
169
156
- for (;instr < target ; instr ++ )
157
- * instr = INT3_INSN_OPCODE ;
170
+ for (;buf < target ; buf ++ )
171
+ * buf = INT3_INSN_OPCODE ;
158
172
}
159
173
160
174
extern s32 __retpoline_sites [], __retpoline_sites_end [];
@@ -187,12 +201,12 @@ static bool insn_is_nop(struct insn *insn)
187
201
* Find the offset of the first non-NOP instruction starting at @offset
188
202
* but no further than @len.
189
203
*/
190
- static int skip_nops (u8 * instr , int offset , int len )
204
+ static int skip_nops (u8 * buf , int offset , int len )
191
205
{
192
206
struct insn insn ;
193
207
194
208
for (; offset < len ; offset += insn .length ) {
195
- if (insn_decode_kernel (& insn , & instr [offset ]))
209
+ if (insn_decode_kernel (& insn , & buf [offset ]))
196
210
break ;
197
211
198
212
if (!insn_is_nop (& insn ))
@@ -207,7 +221,7 @@ static int skip_nops(u8 *instr, int offset, int len)
207
221
* to the end of the NOP sequence into a single NOP.
208
222
*/
209
223
static bool
210
- __optimize_nops (u8 * instr , size_t len , struct insn * insn , int * next , int * prev , int * target )
224
+ __optimize_nops (const u8 * const instr , u8 * buf , size_t len , struct insn * insn , int * next , int * prev , int * target )
211
225
{
212
226
int i = * next - insn -> length ;
213
227
@@ -222,12 +236,12 @@ __optimize_nops(u8 *instr, size_t len, struct insn *insn, int *next, int *prev,
222
236
if (insn_is_nop (insn )) {
223
237
int nop = i ;
224
238
225
- * next = skip_nops (instr , * next , len );
239
+ * next = skip_nops (buf , * next , len );
226
240
if (* target && * next == * target )
227
241
nop = * prev ;
228
242
229
- add_nop (instr + nop , * next - nop );
230
- DUMP_BYTES (ALT , instr , len , "%px: [%d:%d) optimized NOPs: " , instr , nop , * next );
243
+ add_nop (buf + nop , * next - nop );
244
+ DUMP_BYTES (ALT , buf , len , "%px: [%d:%d) optimized NOPs: " , instr , nop , * next );
231
245
return true;
232
246
}
233
247
@@ -239,32 +253,22 @@ __optimize_nops(u8 *instr, size_t len, struct insn *insn, int *next, int *prev,
239
253
* "noinline" to cause control flow change and thus invalidate I$ and
240
254
* cause refetch after modification.
241
255
*/
242
- static void __init_or_module noinline optimize_nops (u8 * instr , size_t len )
256
+ static void __init_or_module noinline optimize_nops (const u8 * const instr , u8 * buf , size_t len )
243
257
{
244
258
int prev , target = 0 ;
245
259
246
260
for (int next , i = 0 ; i < len ; i = next ) {
247
261
struct insn insn ;
248
262
249
- if (insn_decode_kernel (& insn , & instr [i ]))
263
+ if (insn_decode_kernel (& insn , & buf [i ]))
250
264
return ;
251
265
252
266
next = i + insn .length ;
253
267
254
- __optimize_nops (instr , len , & insn , & next , & prev , & target );
268
+ __optimize_nops (instr , buf , len , & insn , & next , & prev , & target );
255
269
}
256
270
}
257
271
258
- static void __init_or_module noinline optimize_nops_inplace (u8 * instr , size_t len )
259
- {
260
- unsigned long flags ;
261
-
262
- local_irq_save (flags );
263
- optimize_nops (instr , len );
264
- sync_core ();
265
- local_irq_restore (flags );
266
- }
267
-
268
272
/*
269
273
* In this context, "source" is where the instructions are placed in the
270
274
* section .altinstr_replacement, for example during kernel build by the
@@ -335,19 +339,19 @@ bool need_reloc(unsigned long offset, u8 *src, size_t src_len)
335
339
return (target < src || target > src + src_len );
336
340
}
337
341
338
- void apply_relocation (u8 * buf , size_t len , u8 * dest , u8 * src , size_t src_len )
342
+ void apply_relocation (u8 * buf , const u8 * const instr , size_t instrlen , u8 * repl , size_t repl_len )
339
343
{
340
344
int prev , target = 0 ;
341
345
342
- for (int next , i = 0 ; i < len ; i = next ) {
346
+ for (int next , i = 0 ; i < instrlen ; i = next ) {
343
347
struct insn insn ;
344
348
345
349
if (WARN_ON_ONCE (insn_decode_kernel (& insn , & buf [i ])))
346
350
return ;
347
351
348
352
next = i + insn .length ;
349
353
350
- if (__optimize_nops (buf , len , & insn , & next , & prev , & target ))
354
+ if (__optimize_nops (instr , buf , instrlen , & insn , & next , & prev , & target ))
351
355
continue ;
352
356
353
357
switch (insn .opcode .bytes [0 ]) {
@@ -361,18 +365,18 @@ void apply_relocation(u8 *buf, size_t len, u8 *dest, u8 *src, size_t src_len)
361
365
case JMP8_INSN_OPCODE :
362
366
case JMP32_INSN_OPCODE :
363
367
case CALL_INSN_OPCODE :
364
- if (need_reloc (next + insn .immediate .value , src , src_len )) {
368
+ if (need_reloc (next + insn .immediate .value , repl , repl_len )) {
365
369
apply_reloc (insn .immediate .nbytes ,
366
370
buf + i + insn_offset_immediate (& insn ),
367
- src - dest );
371
+ repl - instr );
368
372
}
369
373
370
374
/*
371
375
* Where possible, convert JMP.d32 into JMP.d8.
372
376
*/
373
377
if (insn .opcode .bytes [0 ] == JMP32_INSN_OPCODE ) {
374
378
s32 imm = insn .immediate .value ;
375
- imm += src - dest ;
379
+ imm += repl - instr ;
376
380
imm += JMP32_INSN_SIZE - JMP8_INSN_SIZE ;
377
381
if ((imm >> 31 ) == (imm >> 7 )) {
378
382
buf [i + 0 ] = JMP8_INSN_OPCODE ;
@@ -385,10 +389,10 @@ void apply_relocation(u8 *buf, size_t len, u8 *dest, u8 *src, size_t src_len)
385
389
}
386
390
387
391
if (insn_rip_relative (& insn )) {
388
- if (need_reloc (next + insn .displacement .value , src , src_len )) {
392
+ if (need_reloc (next + insn .displacement .value , repl , repl_len )) {
389
393
apply_reloc (insn .displacement .nbytes ,
390
394
buf + i + insn_offset_displacement (& insn ),
391
- src - dest );
395
+ repl - instr );
392
396
}
393
397
}
394
398
}
@@ -504,7 +508,9 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
504
508
* patch if feature is *NOT* present.
505
509
*/
506
510
if (!boot_cpu_has (a -> cpuid ) == !(a -> flags & ALT_FLAG_NOT )) {
507
- optimize_nops_inplace (instr , a -> instrlen );
511
+ memcpy (insn_buff , instr , a -> instrlen );
512
+ optimize_nops (instr , insn_buff , a -> instrlen );
513
+ text_poke_early (instr , insn_buff , a -> instrlen );
508
514
continue ;
509
515
}
510
516
@@ -526,7 +532,7 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
526
532
for (; insn_buff_sz < a -> instrlen ; insn_buff_sz ++ )
527
533
insn_buff [insn_buff_sz ] = 0x90 ;
528
534
529
- apply_relocation (insn_buff , a -> instrlen , instr , replacement , a -> replacementlen );
535
+ apply_relocation (insn_buff , instr , a -> instrlen , replacement , a -> replacementlen );
530
536
531
537
DUMP_BYTES (ALT , instr , a -> instrlen , "%px: old_insn: " , instr );
532
538
DUMP_BYTES (ALT , replacement , a -> replacementlen , "%px: rpl_insn: " , replacement );
@@ -761,7 +767,7 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end)
761
767
762
768
len = patch_retpoline (addr , & insn , bytes );
763
769
if (len == insn .length ) {
764
- optimize_nops (bytes , len );
770
+ optimize_nops (addr , bytes , len );
765
771
DUMP_BYTES (RETPOLINE , ((u8 * )addr ), len , "%px: orig: " , addr );
766
772
DUMP_BYTES (RETPOLINE , ((u8 * )bytes ), len , "%px: repl: " , addr );
767
773
text_poke_early (addr , bytes , len );
0 commit comments