diff --git a/xen/arch/x86/Rules.mk b/xen/arch/x86/Rules.mk index ac585a37ea..cc301cdc5b 100644 --- a/xen/arch/x86/Rules.mk +++ b/xen/arch/x86/Rules.mk @@ -29,6 +29,10 @@ $(call as-option-add,CFLAGS,CC,"invpcid (%rax)$$(comma)%rax",-DHAVE_AS_INVPCID) $(call as-option-add,CFLAGS,CC,\ ".if ((1 > 0) < 0); .error \"\";.endif",,-DHAVE_AS_NEGATIVE_TRUE) +# Check to see whether the assmbler supports the .nop directive. +$(call as-option-add,CFLAGS,CC,\ + ".L1: .L2: .nops (.L2 - .L1)$$(comma)9",-DHAVE_AS_NOPS_DIRECTIVE) + CFLAGS += -mno-red-zone -fpic -fno-asynchronous-unwind-tables # Xen doesn't use SSE interally. If the compiler supports it, also skip the diff --git a/xen/arch/x86/alternative.c b/xen/arch/x86/alternative.c index 0ef7a8ba1f..ea835d98a3 100644 --- a/xen/arch/x86/alternative.c +++ b/xen/arch/x86/alternative.c @@ -84,6 +84,19 @@ static const unsigned char * const p6_nops[ASM_NOP_MAX+1] init_or_livepatch_cons static const unsigned char * const *ideal_nops init_or_livepatch_data = p6_nops; +#ifdef HAVE_AS_NOPS_DIRECTIVE + +/* Nops in .init.rodata to compare against the runtime ideal nops. */ +asm ( ".pushsection .init.rodata, \"a\", @progbits\n\t" + "toolchain_nops: .nops " __stringify(ASM_NOP_MAX) "\n\t" + ".popsection\n\t"); +extern char toolchain_nops[ASM_NOP_MAX]; +static bool __read_mostly toolchain_nops_are_ideal; + +#else +# define toolchain_nops_are_ideal false +#endif + static void __init arch_init_ideal_nops(void) { switch ( boot_cpu_data.x86_vendor ) @@ -112,6 +125,11 @@ static void __init arch_init_ideal_nops(void) ideal_nops = k8_nops; break; } + +#ifdef HAVE_AS_NOPS_DIRECTIVE + if ( memcmp(ideal_nops[ASM_NOP_MAX], toolchain_nops, ASM_NOP_MAX) == 0 ) + toolchain_nops_are_ideal = true; +#endif } /* Use this to add nops to a buffer, then text_poke the whole buffer. */ @@ -209,7 +227,7 @@ void init_or_livepatch apply_alternatives(struct alt_instr *start, base->priv = 1; /* Nothing useful to do? */ - if ( a->pad_len <= 1 ) + if ( toolchain_nops_are_ideal || a->pad_len <= 1 ) continue; add_nops(buf, a->pad_len); diff --git a/xen/include/asm-x86/alternative-asm.h b/xen/include/asm-x86/alternative-asm.h index 0b6151634a..e6c42d721d 100644 --- a/xen/include/asm-x86/alternative-asm.h +++ b/xen/include/asm-x86/alternative-asm.h @@ -1,6 +1,8 @@ #ifndef _ASM_X86_ALTERNATIVE_ASM_H_ #define _ASM_X86_ALTERNATIVE_ASM_H_ +#include + #ifdef __ASSEMBLY__ /* @@ -19,6 +21,14 @@ .byte 0 /* priv */ .endm +.macro mknops nr_bytes +#ifdef HAVE_AS_NOPS_DIRECTIVE + .nops \nr_bytes, ASM_NOP_MAX +#else + .skip \nr_bytes, 0x90 +#endif +.endm + /* GAS's idea of true is -1, while Clang's idea is 1. */ #ifdef HAVE_AS_NEGATIVE_TRUE # define as_true(x) (-(x)) @@ -29,7 +39,7 @@ #define decl_orig(insn, padding) \ .L\@_orig_s: insn; .L\@_orig_e: \ .L\@_diff = padding; \ - .skip as_true(.L\@_diff > 0) * .L\@_diff, 0x90; \ + mknops (as_true(.L\@_diff > 0) * .L\@_diff); \ .L\@_orig_p: #define orig_len (.L\@_orig_e - .L\@_orig_s) diff --git a/xen/include/asm-x86/alternative.h b/xen/include/asm-x86/alternative.h index 619472efcb..66fe791818 100644 --- a/xen/include/asm-x86/alternative.h +++ b/xen/include/asm-x86/alternative.h @@ -2,7 +2,6 @@ #define __X86_ALTERNATIVE_H__ #include -#include #ifndef __ASSEMBLY__ #include @@ -27,6 +26,14 @@ extern void add_nops(void *insns, unsigned int len); extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end); extern void alternative_instructions(void); +asm ( ".macro mknops nr_bytes\n\t" +#ifdef HAVE_AS_NOPS_DIRECTIVE + ".nops \\nr_bytes, " __stringify(ASM_NOP_MAX) "\n\t" +#else + ".skip \\nr_bytes, 0x90\n\t" +#endif + ".endm\n\t" ); + #define alt_orig_len "(.LXEN%=_orig_e - .LXEN%=_orig_s)" #define alt_pad_len "(.LXEN%=_orig_p - .LXEN%=_orig_e)" #define alt_total_len "(.LXEN%=_orig_p - .LXEN%=_orig_s)" @@ -46,7 +53,7 @@ extern void alternative_instructions(void); #define OLDINSTR(oldinstr, padding) \ ".LXEN%=_orig_s:\n\t" oldinstr "\n .LXEN%=_orig_e:\n\t" \ ".LXEN%=_diff = " padding "\n\t" \ - ".skip "AS_TRUE"(.LXEN%=_diff > 0) * .LXEN%=_diff, 0x90\n\t" \ + "mknops ("AS_TRUE"(.LXEN%=_diff > 0) * .LXEN%=_diff)\n\t" \ ".LXEN%=_orig_p:\n\t" #define OLDINSTR_1(oldinstr, n1) \