Rev 5270 | Rev 6934 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 5270 | Rev 6082 | ||
---|---|---|---|
Line 3... | Line 3... | ||
3 | 3 | ||
4 | #include |
4 | #include |
5 | #include |
5 | #include |
6 | #include |
6 | #include |
- | 7 | #include |
|
Line 7... | Line 8... | ||
7 | #include |
8 | #include |
8 | 9 | ||
9 | /* |
10 | /* |
10 | * Alternative inline assembly for SMP. |
11 | * Alternative inline assembly for SMP. |
Line 45... | Line 46... | ||
45 | struct alt_instr { |
46 | struct alt_instr { |
46 | s32 instr_offset; /* original instruction */ |
47 | s32 instr_offset; /* original instruction */ |
47 | s32 repl_offset; /* offset to replacement instruction */ |
48 | s32 repl_offset; /* offset to replacement instruction */ |
48 | u16 cpuid; /* cpuid bit set for replacement */ |
49 | u16 cpuid; /* cpuid bit set for replacement */ |
49 | u8 instrlen; /* length of original instruction */ |
50 | u8 instrlen; /* length of original instruction */ |
50 | u8 replacementlen; /* length of new instruction, <= instrlen */ |
51 | u8 replacementlen; /* length of new instruction */ |
- | 52 | u8 padlen; /* length of build-time padding */ |
|
- | 53 | } __packed; |
|
- | 54 | ||
51 | }; |
55 | /* |
- | 56 | * Debug flag that can be tested to see whether alternative |
|
- | 57 | * instructions were patched in already: |
|
- | 58 | */ |
|
- | 59 | extern int alternatives_patched; |
|
Line 52... | Line 60... | ||
52 | 60 | ||
53 | extern void alternative_instructions(void); |
61 | extern void alternative_instructions(void); |
Line 54... | Line 62... | ||
54 | extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end); |
62 | extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end); |
Line 73... | Line 81... | ||
73 | { |
81 | { |
74 | return 0; |
82 | return 0; |
75 | } |
83 | } |
76 | #endif /* CONFIG_SMP */ |
84 | #endif /* CONFIG_SMP */ |
Line 77... | Line -... | ||
77 | - | ||
78 | #define OLDINSTR(oldinstr) "661:\n\t" oldinstr "\n662:\n" |
- | |
79 | 85 | ||
80 | #define b_replacement(number) "663"#number |
86 | #define b_replacement(num) "664"#num |
Line -... | Line 87... | ||
- | 87 | #define e_replacement(num) "665"#num |
|
81 | #define e_replacement(number) "664"#number |
88 | |
- | 89 | #define alt_end_marker "663" |
|
- | 90 | #define alt_slen "662b-661b" |
|
82 | 91 | #define alt_pad_len alt_end_marker"b-662b" |
|
- | 92 | #define alt_total_slen alt_end_marker"b-661b" |
|
- | 93 | #define alt_rlen(num) e_replacement(num)"f-"b_replacement(num)"f" |
|
- | 94 | ||
- | 95 | #define __OLDINSTR(oldinstr, num) \ |
|
- | 96 | "661:\n\t" oldinstr "\n662:\n" \ |
|
- | 97 | ".skip -(((" alt_rlen(num) ")-(" alt_slen ")) > 0) * " \ |
|
- | 98 | "((" alt_rlen(num) ")-(" alt_slen ")),0x90\n" |
|
- | 99 | ||
- | 100 | #define OLDINSTR(oldinstr, num) \ |
|
- | 101 | __OLDINSTR(oldinstr, num) \ |
|
- | 102 | alt_end_marker ":\n" |
|
- | 103 | ||
- | 104 | /* |
|
- | 105 | * max without conditionals. Idea adapted from: |
|
- | 106 | * http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax |
|
- | 107 | * |
|
- | 108 | * The additional "-" is needed because gas works with s32s. |
|
Line -... | Line 109... | ||
- | 109 | */ |
|
- | 110 | #define alt_max_short(a, b) "((" a ") ^ (((" a ") ^ (" b ")) & -(-((" a ") - (" b ")))))" |
|
- | 111 | ||
- | 112 | /* |
|
- | 113 | * Pad the second replacement alternative with additional NOPs if it is |
|
- | 114 | * additionally longer than the first replacement alternative. |
|
- | 115 | */ |
|
- | 116 | #define OLDINSTR_2(oldinstr, num1, num2) \ |
|
- | 117 | "661:\n\t" oldinstr "\n662:\n" \ |
|
- | 118 | ".skip -((" alt_max_short(alt_rlen(num1), alt_rlen(num2)) " - (" alt_slen ")) > 0) * " \ |
|
83 | #define alt_slen "662b-661b" |
119 | "(" alt_max_short(alt_rlen(num1), alt_rlen(num2)) " - (" alt_slen ")), 0x90\n" \ |
84 | #define alt_rlen(number) e_replacement(number)"f-"b_replacement(number)"f" |
120 | alt_end_marker ":\n" |
85 | 121 | ||
86 | #define ALTINSTR_ENTRY(feature, number) \ |
122 | #define ALTINSTR_ENTRY(feature, num) \ |
87 | " .long 661b - .\n" /* label */ \ |
123 | " .long 661b - .\n" /* label */ \ |
88 | " .long " b_replacement(number)"f - .\n" /* new instruction */ \ |
124 | " .long " b_replacement(num)"f - .\n" /* new instruction */ \ |
89 | " .word " __stringify(feature) "\n" /* feature bit */ \ |
- | |
90 | " .byte " alt_slen "\n" /* source len */ \ |
- | |
91 | " .byte " alt_rlen(number) "\n" /* replacement len */ |
125 | " .word " __stringify(feature) "\n" /* feature bit */ \ |
Line 92... | Line 126... | ||
92 | 126 | " .byte " alt_total_slen "\n" /* source len */ \ |
|
93 | #define DISCARD_ENTRY(number) /* rlen <= slen */ \ |
127 | " .byte " alt_rlen(num) "\n" /* replacement len */ \ |
Line 94... | Line 128... | ||
94 | " .byte 0xff + (" alt_rlen(number) ") - (" alt_slen ")\n" |
128 | " .byte " alt_pad_len "\n" /* pad len */ |
95 | 129 | ||
96 | #define ALTINSTR_REPLACEMENT(newinstr, feature, number) /* replacement */ \ |
130 | #define ALTINSTR_REPLACEMENT(newinstr, feature, num) /* replacement */ \ |
97 | b_replacement(number)":\n\t" newinstr "\n" e_replacement(number) ":\n\t" |
131 | b_replacement(num)":\n\t" newinstr "\n" e_replacement(num) ":\n\t" |
98 | 132 | ||
99 | /* alternative assembly primitive: */ |
133 | /* alternative assembly primitive: */ |
100 | #define ALTERNATIVE(oldinstr, newinstr, feature) \ |
- | |
101 | OLDINSTR(oldinstr) \ |
- | |
102 | ".pushsection .altinstructions,\"a\"\n" \ |
- | |
103 | ALTINSTR_ENTRY(feature, 1) \ |
134 | #define ALTERNATIVE(oldinstr, newinstr, feature) \ |
104 | ".popsection\n" \ |
135 | OLDINSTR(oldinstr, 1) \ |
105 | ".pushsection .discard,\"aw\",@progbits\n" \ |
136 | ".pushsection .altinstructions,\"a\"\n" \ |
Line 106... | Line 137... | ||
106 | DISCARD_ENTRY(1) \ |
137 | ALTINSTR_ENTRY(feature, 1) \ |
107 | ".popsection\n" \ |
138 | ".popsection\n" \ |
108 | ".pushsection .altinstr_replacement, \"ax\"\n" \ |
139 | ".pushsection .altinstr_replacement, \"ax\"\n" \ |
109 | ALTINSTR_REPLACEMENT(newinstr, feature, 1) \ |
140 | ALTINSTR_REPLACEMENT(newinstr, feature, 1) \ |
110 | ".popsection" |
141 | ".popsection" |
111 | 142 | ||
112 | #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\ |
- | |
113 | OLDINSTR(oldinstr) \ |
- | |
114 | ".pushsection .altinstructions,\"a\"\n" \ |
- | |
115 | ALTINSTR_ENTRY(feature1, 1) \ |
- | |
116 | ALTINSTR_ENTRY(feature2, 2) \ |
143 | #define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2)\ |
117 | ".popsection\n" \ |
144 | OLDINSTR_2(oldinstr, 1, 2) \ |
118 | ".pushsection .discard,\"aw\",@progbits\n" \ |
145 | ".pushsection .altinstructions,\"a\"\n" \ |
119 | DISCARD_ENTRY(1) \ |
146 | ALTINSTR_ENTRY(feature1, 1) \ |
Line 143... | Line 170... | ||
143 | * without volatile and memory clobber. |
170 | * without volatile and memory clobber. |
144 | */ |
171 | */ |
145 | #define alternative(oldinstr, newinstr, feature) \ |
172 | #define alternative(oldinstr, newinstr, feature) \ |
146 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory") |
173 | asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory") |
Line -... | Line 174... | ||
- | 174 | ||
- | 175 | #define alternative_2(oldinstr, newinstr1, feature1, newinstr2, feature2) \ |
|
- | 176 | asm volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2) ::: "memory") |
|
147 | 177 | ||
148 | /* |
178 | /* |
149 | * Alternative inline assembly with input. |
179 | * Alternative inline assembly with input. |
150 | * |
180 | * |
151 | * Pecularities: |
181 | * Pecularities: |