diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2018-03-19 13:07:31 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2018-03-28 02:38:27 -0400 |
commit | fba9eb7946251d6e420df3bdf7bc45195be7be9a (patch) | |
tree | 4ff0b8e1cf0b14b6bee38ff5cb8c6d43a4446e13 | |
parent | d424986f1d6b16079b3231db0314923f4f8deed1 (diff) |
s390: add assembler macros for CPU alternatives
Add a header with macros usable in assembler files to emit alternative
code sequences. It works analog to the alternatives for inline assmeblies
in C files, with the same restrictions and capabilities.
The syntax is
ALTERNATIVE "<default instructions sequence>", \
"<alternative instructions sequence>", \
"<features-bit>"
and
ALTERNATIVE_2 "<default instructions sequence>", \
"<alternative instructions sqeuence #1>", \
"<feature-bit #1>",
"<alternative instructions sqeuence #2>", \
"<feature-bit #2>"
Reviewed-by: Vasily Gorbik <gor@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/include/asm/alternative-asm.h | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/arch/s390/include/asm/alternative-asm.h b/arch/s390/include/asm/alternative-asm.h new file mode 100644 index 000000000000..955d620db23e --- /dev/null +++ b/arch/s390/include/asm/alternative-asm.h | |||
@@ -0,0 +1,108 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | #ifndef _ASM_S390_ALTERNATIVE_ASM_H | ||
3 | #define _ASM_S390_ALTERNATIVE_ASM_H | ||
4 | |||
5 | #ifdef __ASSEMBLY__ | ||
6 | |||
7 | /* | ||
8 | * Check the length of an instruction sequence. The length may not be larger | ||
9 | * than 254 bytes and it has to be divisible by 2. | ||
10 | */ | ||
11 | .macro alt_len_check start,end | ||
12 | .if ( \end - \start ) > 254 | ||
13 | .error "cpu alternatives does not support instructions blocks > 254 bytes\n" | ||
14 | .endif | ||
15 | .if ( \end - \start ) % 2 | ||
16 | .error "cpu alternatives instructions length is odd\n" | ||
17 | .endif | ||
18 | .endm | ||
19 | |||
20 | /* | ||
21 | * Issue one struct alt_instr descriptor entry (need to put it into | ||
22 | * the section .altinstructions, see below). This entry contains | ||
23 | * enough information for the alternatives patching code to patch an | ||
24 | * instruction. See apply_alternatives(). | ||
25 | */ | ||
26 | .macro alt_entry orig_start, orig_end, alt_start, alt_end, feature | ||
27 | .long \orig_start - . | ||
28 | .long \alt_start - . | ||
29 | .word \feature | ||
30 | .byte \orig_end - \orig_start | ||
31 | .byte \alt_end - \alt_start | ||
32 | .endm | ||
33 | |||
34 | /* | ||
35 | * Fill up @bytes with nops. The macro emits 6-byte nop instructions | ||
36 | * for the bulk of the area, possibly followed by a 4-byte and/or | ||
37 | * a 2-byte nop if the size of the area is not divisible by 6. | ||
38 | */ | ||
39 | .macro alt_pad_fill bytes | ||
40 | .fill ( \bytes ) / 6, 6, 0xc0040000 | ||
41 | .fill ( \bytes ) % 6 / 4, 4, 0x47000000 | ||
42 | .fill ( \bytes ) % 6 % 4 / 2, 2, 0x0700 | ||
43 | .endm | ||
44 | |||
45 | /* | ||
46 | * Fill up @bytes with nops. If the number of bytes is larger | ||
47 | * than 6, emit a jg instruction to branch over all nops, then | ||
48 | * fill an area of size (@bytes - 6) with nop instructions. | ||
49 | */ | ||
50 | .macro alt_pad bytes | ||
51 | .if ( \bytes > 0 ) | ||
52 | .if ( \bytes > 6 ) | ||
53 | jg . + \bytes | ||
54 | alt_pad_fill \bytes - 6 | ||
55 | .else | ||
56 | alt_pad_fill \bytes | ||
57 | .endif | ||
58 | .endif | ||
59 | .endm | ||
60 | |||
61 | /* | ||
62 | * Define an alternative between two instructions. If @feature is | ||
63 | * present, early code in apply_alternatives() replaces @oldinstr with | ||
64 | * @newinstr. ".skip" directive takes care of proper instruction padding | ||
65 | * in case @newinstr is longer than @oldinstr. | ||
66 | */ | ||
67 | .macro ALTERNATIVE oldinstr, newinstr, feature | ||
68 | .pushsection .altinstr_replacement,"ax" | ||
69 | 770: \newinstr | ||
70 | 771: .popsection | ||
71 | 772: \oldinstr | ||
72 | 773: alt_len_check 770b, 771b | ||
73 | alt_len_check 772b, 773b | ||
74 | alt_pad ( ( 771b - 770b ) - ( 773b - 772b ) ) | ||
75 | 774: .pushsection .altinstructions,"a" | ||
76 | alt_entry 772b, 774b, 770b, 771b, \feature | ||
77 | .popsection | ||
78 | .endm | ||
79 | |||
80 | /* | ||
81 | * Define an alternative between two instructions. If @feature is | ||
82 | * present, early code in apply_alternatives() replaces @oldinstr with | ||
83 | * @newinstr. ".skip" directive takes care of proper instruction padding | ||
84 | * in case @newinstr is longer than @oldinstr. | ||
85 | */ | ||
86 | .macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2 | ||
87 | .pushsection .altinstr_replacement,"ax" | ||
88 | 770: \newinstr1 | ||
89 | 771: \newinstr2 | ||
90 | 772: .popsection | ||
91 | 773: \oldinstr | ||
92 | 774: alt_len_check 770b, 771b | ||
93 | alt_len_check 771b, 772b | ||
94 | alt_len_check 773b, 774b | ||
95 | .if ( 771b - 770b > 772b - 771b ) | ||
96 | alt_pad ( ( 771b - 770b ) - ( 774b - 773b ) ) | ||
97 | .else | ||
98 | alt_pad ( ( 772b - 771b ) - ( 774b - 773b ) ) | ||
99 | .endif | ||
100 | 775: .pushsection .altinstructions,"a" | ||
101 | alt_entry 773b, 775b, 770b, 771b,\feature1 | ||
102 | alt_entry 773b, 775b, 771b, 772b,\feature2 | ||
103 | .popsection | ||
104 | .endm | ||
105 | |||
106 | #endif /* __ASSEMBLY__ */ | ||
107 | |||
108 | #endif /* _ASM_S390_ALTERNATIVE_ASM_H */ | ||