@@ -124,6 +124,20 @@ const unsigned char * const x86_nops[ASM_NOP_MAX+1] =
124124#endif
125125};
126126
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+
127141/*
128142 * Fill the buffer with a single effective instruction of size @len.
129143 *
@@ -133,28 +147,28 @@ const unsigned char * const x86_nops[ASM_NOP_MAX+1] =
133147 * each single-byte NOPs). If @len to fill out is > ASM_NOP_MAX, pad with INT3 and
134148 * *jump* over instead of executing long and daft NOPs.
135149 */
136- static void add_nop (u8 * instr , unsigned int len )
150+ static void add_nop (u8 * buf , unsigned int len )
137151{
138- u8 * target = instr + len ;
152+ u8 * target = buf + len ;
139153
140154 if (!len )
141155 return ;
142156
143157 if (len <= ASM_NOP_MAX ) {
144- memcpy (instr , x86_nops [len ], len );
158+ memcpy (buf , x86_nops [len ], len );
145159 return ;
146160 }
147161
148162 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 ;
151165 } 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 ;
154168 }
155169
156- for (;instr < target ; instr ++ )
157- * instr = INT3_INSN_OPCODE ;
170+ for (;buf < target ; buf ++ )
171+ * buf = INT3_INSN_OPCODE ;
158172}
159173
160174extern s32 __retpoline_sites [], __retpoline_sites_end [];
@@ -187,12 +201,12 @@ static bool insn_is_nop(struct insn *insn)
187201 * Find the offset of the first non-NOP instruction starting at @offset
188202 * but no further than @len.
189203 */
190- static int skip_nops (u8 * instr , int offset , int len )
204+ static int skip_nops (u8 * buf , int offset , int len )
191205{
192206 struct insn insn ;
193207
194208 for (; offset < len ; offset += insn .length ) {
195- if (insn_decode_kernel (& insn , & instr [offset ]))
209+ if (insn_decode_kernel (& insn , & buf [offset ]))
196210 break ;
197211
198212 if (!insn_is_nop (& insn ))
@@ -207,7 +221,7 @@ static int skip_nops(u8 *instr, int offset, int len)
207221 * to the end of the NOP sequence into a single NOP.
208222 */
209223static 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 )
211225{
212226 int i = * next - insn -> length ;
213227
@@ -222,12 +236,12 @@ __optimize_nops(u8 *instr, size_t len, struct insn *insn, int *next, int *prev,
222236 if (insn_is_nop (insn )) {
223237 int nop = i ;
224238
225- * next = skip_nops (instr , * next , len );
239+ * next = skip_nops (buf , * next , len );
226240 if (* target && * next == * target )
227241 nop = * prev ;
228242
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 );
231245 return true;
232246 }
233247
@@ -239,32 +253,22 @@ __optimize_nops(u8 *instr, size_t len, struct insn *insn, int *next, int *prev,
239253 * "noinline" to cause control flow change and thus invalidate I$ and
240254 * cause refetch after modification.
241255 */
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 )
243257{
244258 int prev , target = 0 ;
245259
246260 for (int next , i = 0 ; i < len ; i = next ) {
247261 struct insn insn ;
248262
249- if (insn_decode_kernel (& insn , & instr [i ]))
263+ if (insn_decode_kernel (& insn , & buf [i ]))
250264 return ;
251265
252266 next = i + insn .length ;
253267
254- __optimize_nops (instr , len , & insn , & next , & prev , & target );
268+ __optimize_nops (instr , buf , len , & insn , & next , & prev , & target );
255269 }
256270}
257271
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-
268272/*
269273 * In this context, "source" is where the instructions are placed in the
270274 * 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)
335339 return (target < src || target > src + src_len );
336340}
337341
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 )
339343{
340344 int prev , target = 0 ;
341345
342- for (int next , i = 0 ; i < len ; i = next ) {
346+ for (int next , i = 0 ; i < instrlen ; i = next ) {
343347 struct insn insn ;
344348
345349 if (WARN_ON_ONCE (insn_decode_kernel (& insn , & buf [i ])))
346350 return ;
347351
348352 next = i + insn .length ;
349353
350- if (__optimize_nops (buf , len , & insn , & next , & prev , & target ))
354+ if (__optimize_nops (instr , buf , instrlen , & insn , & next , & prev , & target ))
351355 continue ;
352356
353357 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)
361365 case JMP8_INSN_OPCODE :
362366 case JMP32_INSN_OPCODE :
363367 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 )) {
365369 apply_reloc (insn .immediate .nbytes ,
366370 buf + i + insn_offset_immediate (& insn ),
367- src - dest );
371+ repl - instr );
368372 }
369373
370374 /*
371375 * Where possible, convert JMP.d32 into JMP.d8.
372376 */
373377 if (insn .opcode .bytes [0 ] == JMP32_INSN_OPCODE ) {
374378 s32 imm = insn .immediate .value ;
375- imm += src - dest ;
379+ imm += repl - instr ;
376380 imm += JMP32_INSN_SIZE - JMP8_INSN_SIZE ;
377381 if ((imm >> 31 ) == (imm >> 7 )) {
378382 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)
385389 }
386390
387391 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 )) {
389393 apply_reloc (insn .displacement .nbytes ,
390394 buf + i + insn_offset_displacement (& insn ),
391- src - dest );
395+ repl - instr );
392396 }
393397 }
394398 }
@@ -504,7 +508,9 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
504508 * patch if feature is *NOT* present.
505509 */
506510 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 );
508514 continue ;
509515 }
510516
@@ -526,7 +532,7 @@ void __init_or_module noinline apply_alternatives(struct alt_instr *start,
526532 for (; insn_buff_sz < a -> instrlen ; insn_buff_sz ++ )
527533 insn_buff [insn_buff_sz ] = 0x90 ;
528534
529- apply_relocation (insn_buff , a -> instrlen , instr , replacement , a -> replacementlen );
535+ apply_relocation (insn_buff , instr , a -> instrlen , replacement , a -> replacementlen );
530536
531537 DUMP_BYTES (ALT , instr , a -> instrlen , "%px: old_insn: " , instr );
532538 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)
761767
762768 len = patch_retpoline (addr , & insn , bytes );
763769 if (len == insn .length ) {
764- optimize_nops (bytes , len );
770+ optimize_nops (addr , bytes , len );
765771 DUMP_BYTES (RETPOLINE , ((u8 * )addr ), len , "%px: orig: " , addr );
766772 DUMP_BYTES (RETPOLINE , ((u8 * )bytes ), len , "%px: repl: " , addr );
767773 text_poke_early (addr , bytes , len );
0 commit comments