1 #ifndef __ASM_ALTERNATIVE_H 2 #define __ASM_ALTERNATIVE_H 3 4 #ifndef __ASSEMBLY__ 5 6 #include <linux/types.h> 7 #include <linux/stddef.h> 8 #include <linux/stringify.h> 9 10 struct alt_instr { 11 s32 orig_offset; /* offset to original instruction */ 12 s32 alt_offset; /* offset to replacement instruction */ 13 u16 cpufeature; /* cpufeature bit set for replacement */ 14 u8 orig_len; /* size of original instruction(s) */ 15 u8 alt_len; /* size of new instruction(s), <= orig_len */ 16 }; 17 18 void apply_alternatives_all(void); 19 void apply_alternatives(void *start, size_t length); 20 void free_alternatives_memory(void); 21 22 #define ALTINSTR_ENTRY(feature) \ 23 " .word 661b - .\n" /* label */ \ 24 " .word 663f - .\n" /* new instruction */ \ 25 " .hword " __stringify(feature) "\n" /* feature bit */ \ 26 " .byte 662b-661b\n" /* source len */ \ 27 " .byte 664f-663f\n" /* replacement len */ 28 29 /* 30 * alternative assembly primitive: 31 * 32 * If any of these .org directive fail, it means that insn1 and insn2 33 * don't have the same length. This used to be written as 34 * 35 * .if ((664b-663b) != (662b-661b)) 36 * .error "Alternatives instruction length mismatch" 37 * .endif 38 * 39 * but most assemblers die if insn1 or insn2 have a .inst. This should 40 * be fixed in a binutils release posterior to 2.25.51.0.2 (anything 41 * containing commit 4e4d08cf7399b606 or c1baaddf8861). 42 */ 43 #define ALTERNATIVE(oldinstr, newinstr, feature) \ 44 "661:\n\t" \ 45 oldinstr "\n" \ 46 "662:\n" \ 47 ".pushsection .altinstructions,\"a\"\n" \ 48 ALTINSTR_ENTRY(feature) \ 49 ".popsection\n" \ 50 ".pushsection .altinstr_replacement, \"a\"\n" \ 51 "663:\n\t" \ 52 newinstr "\n" \ 53 "664:\n\t" \ 54 ".popsection\n\t" \ 55 ".org . - (664b-663b) + (662b-661b)\n\t" \ 56 ".org . - (662b-661b) + (664b-663b)\n" 57 58 #else 59 60 .macro altinstruction_entry orig_offset alt_offset feature orig_len alt_len 61 .word \orig_offset - . 62 .word \alt_offset - . 63 .hword \feature 64 .byte \orig_len 65 .byte \alt_len 66 .endm 67 68 .macro alternative_insn insn1 insn2 cap 69 661: \insn1 70 662: .pushsection .altinstructions, "a" 71 altinstruction_entry 661b, 663f, \cap, 662b-661b, 664f-663f 72 .popsection 73 .pushsection .altinstr_replacement, "ax" 74 663: \insn2 75 664: .popsection 76 .org . - (664b-663b) + (662b-661b) 77 .org . - (662b-661b) + (664b-663b) 78 .endm 79 80 #endif /* __ASSEMBLY__ */ 81 82 #endif /* __ASM_ALTERNATIVE_H */ 83