Skip to content

Commit 60bc276

Browse files
jgross1bp3tk0v
authored andcommitted
x86/paravirt: Switch mixed paravirt/alternative calls to alternatives
Instead of stacking alternative and paravirt patching, use the new ALT_FLAG_CALL flag to switch those mixed calls to pure alternative handling. Eliminate the need to be careful regarding the sequence of alternative and paravirt patching. [ bp: Touch up commit message. ] Signed-off-by: Juergen Gross <jgross@suse.com> Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20231210062138.2417-5-jgross@suse.com
1 parent da0fe6e commit 60bc276

6 files changed

Lines changed: 44 additions & 51 deletions

File tree

arch/x86/include/asm/alternative.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ struct alt_instr {
8989
u8 replacementlen; /* length of new instruction */
9090
} __packed;
9191

92+
extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
93+
9294
/*
9395
* Debug flag that can be tested to see whether alternative
9496
* instructions were patched in already:
@@ -104,11 +106,10 @@ extern void apply_fineibt(s32 *start_retpoline, s32 *end_retpoine,
104106
s32 *start_cfi, s32 *end_cfi);
105107

106108
struct module;
107-
struct paravirt_patch_site;
108109

109110
struct callthunk_sites {
110111
s32 *call_start, *call_end;
111-
struct paravirt_patch_site *pv_start, *pv_end;
112+
struct alt_instr *alt_start, *alt_end;
112113
};
113114

114115
#ifdef CONFIG_CALL_THUNKS

arch/x86/include/asm/paravirt.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -738,20 +738,20 @@ void native_pv_lock_init(void) __init;
738738

739739
#ifdef CONFIG_X86_64
740740
#ifdef CONFIG_PARAVIRT_XXL
741+
#ifdef CONFIG_DEBUG_ENTRY
741742

742743
#define PARA_PATCH(off) ((off) / 8)
743744
#define PARA_SITE(ptype, ops) _PVSITE(ptype, ops)
744745
#define PARA_INDIRECT(addr) *addr(%rip)
745746

746-
#ifdef CONFIG_DEBUG_ENTRY
747747
.macro PARA_IRQ_save_fl
748-
PARA_SITE(PARA_PATCH(PV_IRQ_save_fl),
749-
ANNOTATE_RETPOLINE_SAFE;
750-
call PARA_INDIRECT(pv_ops+PV_IRQ_save_fl);)
748+
ANNOTATE_RETPOLINE_SAFE;
749+
call PARA_INDIRECT(pv_ops+PV_IRQ_save_fl);
751750
.endm
752751

753-
#define SAVE_FLAGS ALTERNATIVE "PARA_IRQ_save_fl;", "pushf; pop %rax;", \
754-
ALT_NOT_XEN
752+
#define SAVE_FLAGS ALTERNATIVE_2 "PARA_IRQ_save_fl;", \
753+
"ALT_CALL_INSTR;", ALT_CALL_ALWAYS, \
754+
"pushf; pop %rax;", ALT_NOT_XEN
755755
#endif
756756
#endif /* CONFIG_PARAVIRT_XXL */
757757
#endif /* CONFIG_X86_64 */

arch/x86/include/asm/paravirt_types.h

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -276,15 +276,11 @@ extern struct paravirt_patch_template pv_ops;
276276
#define NATIVE_LABEL(a,x,b) "\n\t.globl " a #x "_" #b "\n" a #x "_" #b ":\n\t"
277277

278278
unsigned int paravirt_patch(u8 type, void *insn_buff, unsigned long addr, unsigned int len);
279+
#define paravirt_ptr(op) [paravirt_opptr] "m" (pv_ops.op)
279280

280281
int paravirt_disable_iospace(void);
281282

282-
/*
283-
* This generates an indirect call based on the operation type number.
284-
* The type number, computed in PARAVIRT_PATCH, is derived from the
285-
* offset into the paravirt_patch_template structure, and can therefore be
286-
* freely converted back into a structure offset.
287-
*/
283+
/* This generates an indirect call based on the operation type number. */
288284
#define PARAVIRT_CALL \
289285
ANNOTATE_RETPOLINE_SAFE \
290286
"call *%[paravirt_opptr];"
@@ -317,12 +313,6 @@ int paravirt_disable_iospace(void);
317313
* However, x86_64 also has to clobber all caller saved registers, which
318314
* unfortunately, are quite a bit (r8 - r11)
319315
*
320-
* The call instruction itself is marked by placing its start address
321-
* and size into the .parainstructions section, so that
322-
* apply_paravirt() in arch/i386/kernel/alternative.c can do the
323-
* appropriate patching under the control of the backend pv_init_ops
324-
* implementation.
325-
*
326316
* Unfortunately there's no way to get gcc to generate the args setup
327317
* for the call, and then allow the call itself to be generated by an
328318
* inline asm. Because of this, we must do the complete arg setup and
@@ -421,14 +411,27 @@ int paravirt_disable_iospace(void);
421411
__mask & __eax; \
422412
})
423413

424-
414+
/*
415+
* Use alternative patching for paravirt calls:
416+
* - For replacing an indirect call with a direct one, use the "normal"
417+
* ALTERNATIVE() macro with the indirect call as the initial code sequence,
418+
* which will be replaced with the related direct call by using the
419+
* ALT_FLAG_DIRECT_CALL special case and the "always on" feature.
420+
* - In case the replacement is either a direct call or a short code sequence
421+
* depending on a feature bit, the ALTERNATIVE_2() macro is being used.
422+
* The indirect call is the initial code sequence again, while the special
423+
* code sequence is selected with the specified feature bit. In case the
424+
* feature is not active, the direct call is used as above via the
425+
* ALT_FLAG_DIRECT_CALL special case and the "always on" feature.
426+
*/
425427
#define ____PVOP_CALL(ret, op, call_clbr, extra_clbr, ...) \
426428
({ \
427429
PVOP_CALL_ARGS; \
428430
PVOP_TEST_NULL(op); \
429-
asm volatile(paravirt_alt(PARAVIRT_CALL) \
431+
asm volatile(ALTERNATIVE(PARAVIRT_CALL, ALT_CALL_INSTR, \
432+
ALT_CALL_ALWAYS) \
430433
: call_clbr, ASM_CALL_CONSTRAINT \
431-
: paravirt_type(op), \
434+
: paravirt_ptr(op), \
432435
##__VA_ARGS__ \
433436
: "memory", "cc" extra_clbr); \
434437
ret; \
@@ -439,10 +442,11 @@ int paravirt_disable_iospace(void);
439442
({ \
440443
PVOP_CALL_ARGS; \
441444
PVOP_TEST_NULL(op); \
442-
asm volatile(ALTERNATIVE(paravirt_alt(PARAVIRT_CALL), \
443-
alt, cond) \
445+
asm volatile(ALTERNATIVE_2(PARAVIRT_CALL, \
446+
ALT_CALL_INSTR, ALT_CALL_ALWAYS, \
447+
alt, cond) \
444448
: call_clbr, ASM_CALL_CONSTRAINT \
445-
: paravirt_type(op), \
449+
: paravirt_ptr(op), \
446450
##__VA_ARGS__ \
447451
: "memory", "cc" extra_clbr); \
448452
ret; \

arch/x86/kernel/alternative.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,6 @@ extern s32 __retpoline_sites[], __retpoline_sites_end[];
160160
extern s32 __return_sites[], __return_sites_end[];
161161
extern s32 __cfi_sites[], __cfi_sites_end[];
162162
extern s32 __ibt_endbr_seal[], __ibt_endbr_seal_end[];
163-
extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
164163
extern s32 __smp_locks[], __smp_locks_end[];
165164
void text_poke_early(void *addr, const void *opcode, size_t len);
166165

arch/x86/kernel/callthunks.c

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -233,22 +233,21 @@ patch_call_sites(s32 *start, s32 *end, const struct core_text *ct)
233233
}
234234

235235
static __init_or_module void
236-
patch_paravirt_call_sites(struct paravirt_patch_site *start,
237-
struct paravirt_patch_site *end,
238-
const struct core_text *ct)
236+
patch_alt_call_sites(struct alt_instr *start, struct alt_instr *end,
237+
const struct core_text *ct)
239238
{
240-
struct paravirt_patch_site *p;
239+
struct alt_instr *a;
241240

242-
for (p = start; p < end; p++)
243-
patch_call((void *)&p->instr_offset + p->instr_offset, ct);
241+
for (a = start; a < end; a++)
242+
patch_call((void *)&a->instr_offset + a->instr_offset, ct);
244243
}
245244

246245
static __init_or_module void
247246
callthunks_setup(struct callthunk_sites *cs, const struct core_text *ct)
248247
{
249248
prdbg("Patching call sites %s\n", ct->name);
250249
patch_call_sites(cs->call_start, cs->call_end, ct);
251-
patch_paravirt_call_sites(cs->pv_start, cs->pv_end, ct);
250+
patch_alt_call_sites(cs->alt_start, cs->alt_end, ct);
252251
prdbg("Patching call sites done%s\n", ct->name);
253252
}
254253

@@ -257,8 +256,8 @@ void __init callthunks_patch_builtin_calls(void)
257256
struct callthunk_sites cs = {
258257
.call_start = __call_sites,
259258
.call_end = __call_sites_end,
260-
.pv_start = __parainstructions,
261-
.pv_end = __parainstructions_end
259+
.alt_start = __alt_instructions,
260+
.alt_end = __alt_instructions_end
262261
};
263262

264263
if (!cpu_feature_enabled(X86_FEATURE_CALL_DEPTH))

arch/x86/kernel/module.c

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ int module_finalize(const Elf_Ehdr *hdr,
276276
struct module *me)
277277
{
278278
const Elf_Shdr *s, *alt = NULL, *locks = NULL,
279-
*para = NULL, *orc = NULL, *orc_ip = NULL,
279+
*orc = NULL, *orc_ip = NULL,
280280
*retpolines = NULL, *returns = NULL, *ibt_endbr = NULL,
281281
*calls = NULL, *cfi = NULL;
282282
char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
@@ -286,8 +286,6 @@ int module_finalize(const Elf_Ehdr *hdr,
286286
alt = s;
287287
if (!strcmp(".smp_locks", secstrings + s->sh_name))
288288
locks = s;
289-
if (!strcmp(".parainstructions", secstrings + s->sh_name))
290-
para = s;
291289
if (!strcmp(".orc_unwind", secstrings + s->sh_name))
292290
orc = s;
293291
if (!strcmp(".orc_unwind_ip", secstrings + s->sh_name))
@@ -304,14 +302,6 @@ int module_finalize(const Elf_Ehdr *hdr,
304302
ibt_endbr = s;
305303
}
306304

307-
/*
308-
* See alternative_instructions() for the ordering rules between the
309-
* various patching types.
310-
*/
311-
if (para) {
312-
void *pseg = (void *)para->sh_addr;
313-
apply_paravirt(pseg, pseg + para->sh_size);
314-
}
315305
if (retpolines || cfi) {
316306
void *rseg = NULL, *cseg = NULL;
317307
unsigned int rsize = 0, csize = 0;
@@ -341,17 +331,17 @@ int module_finalize(const Elf_Ehdr *hdr,
341331
void *aseg = (void *)alt->sh_addr;
342332
apply_alternatives(aseg, aseg + alt->sh_size);
343333
}
344-
if (calls || para) {
334+
if (calls || alt) {
345335
struct callthunk_sites cs = {};
346336

347337
if (calls) {
348338
cs.call_start = (void *)calls->sh_addr;
349339
cs.call_end = (void *)calls->sh_addr + calls->sh_size;
350340
}
351341

352-
if (para) {
353-
cs.pv_start = (void *)para->sh_addr;
354-
cs.pv_end = (void *)para->sh_addr + para->sh_size;
342+
if (alt) {
343+
cs.alt_start = (void *)alt->sh_addr;
344+
cs.alt_end = (void *)alt->sh_addr + alt->sh_size;
355345
}
356346

357347
callthunks_patch_module_calls(&cs, me);

0 commit comments

Comments
 (0)