29
29
#include <asm/io.h>
30
30
#include <asm/fixmap.h>
31
31
#include <asm/paravirt.h>
32
+ #include <asm/asm-prototypes.h>
32
33
33
34
int __read_mostly alternatives_patched ;
34
35
@@ -113,6 +114,7 @@ static void __init_or_module add_nops(void *insns, unsigned int len)
113
114
}
114
115
}
115
116
117
+ extern s32 __retpoline_sites [], __retpoline_sites_end [];
116
118
extern struct alt_instr __alt_instructions [], __alt_instructions_end [];
117
119
extern s32 __smp_locks [], __smp_locks_end [];
118
120
void text_poke_early (void * addr , const void * opcode , size_t len );
@@ -221,7 +223,7 @@ static __always_inline int optimize_nops_range(u8 *instr, u8 instrlen, int off)
221
223
* "noinline" to cause control flow change and thus invalidate I$ and
222
224
* cause refetch after modification.
223
225
*/
224
- static void __init_or_module noinline optimize_nops (struct alt_instr * a , u8 * instr )
226
+ static void __init_or_module noinline optimize_nops (u8 * instr , size_t len )
225
227
{
226
228
struct insn insn ;
227
229
int i = 0 ;
@@ -239,11 +241,11 @@ static void __init_or_module noinline optimize_nops(struct alt_instr *a, u8 *ins
239
241
* optimized.
240
242
*/
241
243
if (insn .length == 1 && insn .opcode .bytes [0 ] == 0x90 )
242
- i += optimize_nops_range (instr , a -> instrlen , i );
244
+ i += optimize_nops_range (instr , len , i );
243
245
else
244
246
i += insn .length ;
245
247
246
- if (i >= a -> instrlen )
248
+ if (i >= len )
247
249
return ;
248
250
}
249
251
}
@@ -331,10 +333,135 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
331
333
text_poke_early (instr , insn_buff , insn_buff_sz );
332
334
333
335
next :
334
- optimize_nops (a , instr );
336
+ optimize_nops (instr , a -> instrlen );
335
337
}
336
338
}
337
339
340
+ #if defined(CONFIG_RETPOLINE ) && defined(CONFIG_STACK_VALIDATION )
341
+
342
+ /*
343
+ * CALL/JMP *%\reg
344
+ */
345
+ static int emit_indirect (int op , int reg , u8 * bytes )
346
+ {
347
+ int i = 0 ;
348
+ u8 modrm ;
349
+
350
+ switch (op ) {
351
+ case CALL_INSN_OPCODE :
352
+ modrm = 0x10 ; /* Reg = 2; CALL r/m */
353
+ break ;
354
+
355
+ case JMP32_INSN_OPCODE :
356
+ modrm = 0x20 ; /* Reg = 4; JMP r/m */
357
+ break ;
358
+
359
+ default :
360
+ WARN_ON_ONCE (1 );
361
+ return -1 ;
362
+ }
363
+
364
+ if (reg >= 8 ) {
365
+ bytes [i ++ ] = 0x41 ; /* REX.B prefix */
366
+ reg -= 8 ;
367
+ }
368
+
369
+ modrm |= 0xc0 ; /* Mod = 3 */
370
+ modrm += reg ;
371
+
372
+ bytes [i ++ ] = 0xff ; /* opcode */
373
+ bytes [i ++ ] = modrm ;
374
+
375
+ return i ;
376
+ }
377
+
378
+ /*
379
+ * Rewrite the compiler generated retpoline thunk calls.
380
+ *
381
+ * For spectre_v2=off (!X86_FEATURE_RETPOLINE), rewrite them into immediate
382
+ * indirect instructions, avoiding the extra indirection.
383
+ *
384
+ * For example, convert:
385
+ *
386
+ * CALL __x86_indirect_thunk_\reg
387
+ *
388
+ * into:
389
+ *
390
+ * CALL *%\reg
391
+ *
392
+ */
393
+ static int patch_retpoline (void * addr , struct insn * insn , u8 * bytes )
394
+ {
395
+ retpoline_thunk_t * target ;
396
+ int reg , i = 0 ;
397
+
398
+ target = addr + insn -> length + insn -> immediate .value ;
399
+ reg = target - __x86_indirect_thunk_array ;
400
+
401
+ if (WARN_ON_ONCE (reg & ~0xf ))
402
+ return -1 ;
403
+
404
+ /* If anyone ever does: CALL/JMP *%rsp, we're in deep trouble. */
405
+ BUG_ON (reg == 4 );
406
+
407
+ if (cpu_feature_enabled (X86_FEATURE_RETPOLINE ))
408
+ return -1 ;
409
+
410
+ i = emit_indirect (insn -> opcode .bytes [0 ], reg , bytes );
411
+ if (i < 0 )
412
+ return i ;
413
+
414
+ for (; i < insn -> length ;)
415
+ bytes [i ++ ] = BYTES_NOP1 ;
416
+
417
+ return i ;
418
+ }
419
+
420
+ /*
421
+ * Generated by 'objtool --retpoline'.
422
+ */
423
+ void __init_or_module noinline apply_retpolines (s32 * start , s32 * end )
424
+ {
425
+ s32 * s ;
426
+
427
+ for (s = start ; s < end ; s ++ ) {
428
+ void * addr = (void * )s + * s ;
429
+ struct insn insn ;
430
+ int len , ret ;
431
+ u8 bytes [16 ];
432
+ u8 op1 , op2 ;
433
+
434
+ ret = insn_decode_kernel (& insn , addr );
435
+ if (WARN_ON_ONCE (ret < 0 ))
436
+ continue ;
437
+
438
+ op1 = insn .opcode .bytes [0 ];
439
+ op2 = insn .opcode .bytes [1 ];
440
+
441
+ switch (op1 ) {
442
+ case CALL_INSN_OPCODE :
443
+ case JMP32_INSN_OPCODE :
444
+ break ;
445
+
446
+ default :
447
+ WARN_ON_ONCE (1 );
448
+ continue ;
449
+ }
450
+
451
+ len = patch_retpoline (addr , & insn , bytes );
452
+ if (len == insn .length ) {
453
+ optimize_nops (bytes , len );
454
+ text_poke_early (addr , bytes , len );
455
+ }
456
+ }
457
+ }
458
+
459
+ #else /* !RETPOLINES || !CONFIG_STACK_VALIDATION */
460
+
461
+ void __init_or_module noinline apply_retpolines (s32 * start , s32 * end ) { }
462
+
463
+ #endif /* CONFIG_RETPOLINE && CONFIG_STACK_VALIDATION */
464
+
338
465
#ifdef CONFIG_SMP
339
466
static void alternatives_smp_lock (const s32 * start , const s32 * end ,
340
467
u8 * text , u8 * text_end )
@@ -642,6 +769,12 @@ void __init alternative_instructions(void)
642
769
*/
643
770
apply_paravirt (__parainstructions , __parainstructions_end );
644
771
772
+ /*
773
+ * Rewrite the retpolines, must be done before alternatives since
774
+ * those can rewrite the retpoline thunks.
775
+ */
776
+ apply_retpolines (__retpoline_sites , __retpoline_sites_end );
777
+
645
778
/*
646
779
* Then patch alternatives, such that those paravirt calls that are in
647
780
* alternatives can be overwritten by their immediate fragments.
0 commit comments