|
@@ -2,6 +2,7 @@
|
|
|
#define __ASM_ALTERNATIVE_H
|
|
|
|
|
|
#include <asm/cpufeature.h>
|
|
|
+#include <asm/insn.h>
|
|
|
|
|
|
#ifndef __ASSEMBLY__
|
|
|
|
|
@@ -90,34 +91,55 @@ void apply_alternatives(void *start, size_t length);
|
|
|
.endm
|
|
|
|
|
|
/*
|
|
|
- * Begin an alternative code sequence.
|
|
|
+ * Alternative sequences
|
|
|
+ *
|
|
|
+ * The code for the case where the capability is not present will be
|
|
|
+ * assembled and linked as normal. There are no restrictions on this
|
|
|
+ * code.
|
|
|
+ *
|
|
|
+ * The code for the case where the capability is present will be
|
|
|
+ * assembled into a special section to be used for dynamic patching.
|
|
|
+ * Code for that case must:
|
|
|
+ *
|
|
|
+ * 1. Be exactly the same length (in bytes) as the default code
|
|
|
+ * sequence.
|
|
|
*
|
|
|
- * The code that follows this macro will be assembled and linked as
|
|
|
- * normal. There are no restrictions on this code.
|
|
|
+ * 2. Not contain a branch target that is used outside of the
|
|
|
+ * alternative sequence it is defined in (branches into an
|
|
|
+ * alternative sequence are not fixed up).
|
|
|
+ */
|
|
|
+
|
|
|
+/*
|
|
|
+ * Begin an alternative code sequence.
|
|
|
*/
|
|
|
.macro alternative_if_not cap
|
|
|
+ .set .Lasm_alt_mode, 0
|
|
|
.pushsection .altinstructions, "a"
|
|
|
altinstruction_entry 661f, 663f, \cap, 662f-661f, 664f-663f
|
|
|
.popsection
|
|
|
661:
|
|
|
.endm
|
|
|
|
|
|
+.macro alternative_if cap
|
|
|
+ .set .Lasm_alt_mode, 1
|
|
|
+ .pushsection .altinstructions, "a"
|
|
|
+ altinstruction_entry 663f, 661f, \cap, 664f-663f, 662f-661f
|
|
|
+ .popsection
|
|
|
+ .pushsection .altinstr_replacement, "ax"
|
|
|
+ .align 2 /* So GAS knows label 661 is suitably aligned */
|
|
|
+661:
|
|
|
+.endm
|
|
|
+
|
|
|
/*
|
|
|
- * Provide the alternative code sequence.
|
|
|
- *
|
|
|
- * The code that follows this macro is assembled into a special
|
|
|
- * section to be used for dynamic patching. Code that follows this
|
|
|
- * macro must:
|
|
|
- *
|
|
|
- * 1. Be exactly the same length (in bytes) as the default code
|
|
|
- * sequence.
|
|
|
- *
|
|
|
- * 2. Not contain a branch target that is used outside of the
|
|
|
- * alternative sequence it is defined in (branches into an
|
|
|
- * alternative sequence are not fixed up).
|
|
|
+ * Provide the other half of the alternative code sequence.
|
|
|
*/
|
|
|
.macro alternative_else
|
|
|
-662: .pushsection .altinstr_replacement, "ax"
|
|
|
+662:
|
|
|
+ .if .Lasm_alt_mode==0
|
|
|
+ .pushsection .altinstr_replacement, "ax"
|
|
|
+ .else
|
|
|
+ .popsection
|
|
|
+ .endif
|
|
|
663:
|
|
|
.endm
|
|
|
|
|
@@ -125,11 +147,25 @@ void apply_alternatives(void *start, size_t length);
|
|
|
* Complete an alternative code sequence.
|
|
|
*/
|
|
|
.macro alternative_endif
|
|
|
-664: .popsection
|
|
|
+664:
|
|
|
+ .if .Lasm_alt_mode==0
|
|
|
+ .popsection
|
|
|
+ .endif
|
|
|
.org . - (664b-663b) + (662b-661b)
|
|
|
.org . - (662b-661b) + (664b-663b)
|
|
|
.endm
|
|
|
|
|
|
+/*
|
|
|
+ * Provides a trivial alternative or default sequence consisting solely
|
|
|
+ * of NOPs. The number of NOPs is chosen automatically to match the
|
|
|
+ * previous case.
|
|
|
+ */
|
|
|
+.macro alternative_else_nop_endif
|
|
|
+alternative_else
|
|
|
+ nops (662b-661b) / AARCH64_INSN_SIZE
|
|
|
+alternative_endif
|
|
|
+.endm
|
|
|
+
|
|
|
#define _ALTERNATIVE_CFG(insn1, insn2, cap, cfg, ...) \
|
|
|
alternative_insn insn1, insn2, cap, IS_ENABLED(cfg)
|
|
|
|