Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/include/asm/alternative.h
Line
Count
Source (jump to first uncovered line)
1
#ifndef __X86_ALTERNATIVE_H__
2
#define __X86_ALTERNATIVE_H__
3
4
#include <asm/nops.h>
5
6
#ifdef __ASSEMBLY__
7
.macro altinstruction_entry orig alt feature orig_len alt_len
8
        .long \orig - .
9
        .long \alt - .
10
        .word \feature
11
        .byte \orig_len
12
        .byte \alt_len
13
.endm
14
#else
15
#include <xen/stringify.h>
16
#include <xen/types.h>
17
18
struct alt_instr {
19
    s32 instr_offset;       /* original instruction */
20
    s32 repl_offset;        /* offset to replacement instruction */
21
    u16 cpuid;              /* cpuid bit set for replacement */
22
    u8  instrlen;           /* length of original instruction */
23
    u8  replacementlen;     /* length of new instruction, <= instrlen */
24
};
25
26
#define __ALT_PTR(a,f)      ((u8 *)((void *)&(a)->f + (a)->f))
27
#define ALT_ORIG_PTR(a)     __ALT_PTR(a, instr_offset)
28
#define ALT_REPL_PTR(a)     __ALT_PTR(a, repl_offset)
29
30
extern void add_nops(void *insns, unsigned int len);
31
/* Similar to alternative_instructions except it can be run with IRQs enabled. */
32
extern void apply_alternatives(const struct alt_instr *start,
33
                               const struct alt_instr *end);
34
extern void alternative_instructions(void);
35
36
#define OLDINSTR(oldinstr)      "661:\n\t" oldinstr "\n662:\n"
37
38
#define b_replacement(number)   "663"#number
39
#define e_replacement(number)   "664"#number
40
41
#define alt_slen "662b-661b"
42
#define alt_rlen(number) e_replacement(number)"f-"b_replacement(number)"f"
43
44
#define ALTINSTR_ENTRY(feature, number)                                       \
45
        " .long 661b - .\n"                             /* label           */ \
46
        " .long " b_replacement(number)"f - .\n"        /* new instruction */ \
47
        " .word " __stringify(feature) "\n"             /* feature bit     */ \
48
        " .byte " alt_slen "\n"                         /* source len      */ \
49
        " .byte " alt_rlen(number) "\n"                 /* replacement len */
50
51
#define DISCARD_ENTRY(number)                           /* rlen <= slen */    \
52
        " .byte 0xff + (" alt_rlen(number) ") - (" alt_slen ")\n"
53
54
#define ALTINSTR_REPLACEMENT(newinstr, feature, number) /* replacement */     \
55
        b_replacement(number)":\n\t" newinstr "\n" e_replacement(number) ":\n\t"
56
57
#define ALTERNATIVE_N(newinstr, feature, number)  \
58
  ".pushsection .altinstructions,\"a\"\n"   \
59
  ALTINSTR_ENTRY(feature, number)     \
60
  ".section .discard,\"a\",@progbits\n"   \
61
  DISCARD_ENTRY(number)       \
62
  ".section .altinstr_replacement, \"ax\"\n"  \
63
  ALTINSTR_REPLACEMENT(newinstr, feature, number) \
64
  ".popsection\n"
65
66
/* alternative assembly primitive: */
67
#define ALTERNATIVE(oldinstr, newinstr, feature)        \
68
  OLDINSTR(oldinstr)              \
69
  ALTERNATIVE_N(newinstr, feature, 1)
70
71
#define ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2) \
72
  ALTERNATIVE(oldinstr, newinstr1, feature1)        \
73
  ALTERNATIVE_N(newinstr2, feature2, 2)
74
75
#define ALTERNATIVE_3(oldinstr, newinstr1, feature1, newinstr2, feature2, \
76
          newinstr3, feature3)          \
77
  ALTERNATIVE_2(oldinstr, newinstr1, feature1, newinstr2, feature2) \
78
  ALTERNATIVE_N(newinstr3, feature3, 3)
79
80
/*
81
 * Alternative instructions for different CPU types or capabilities.
82
 *
83
 * This allows to use optimized instructions even on generic binary
84
 * kernels.
85
 *
86
 * length of oldinstr must be longer or equal the length of newinstr
87
 * It can be padded with nops as needed.
88
 *
89
 * For non barrier like inlines please define new variants
90
 * without volatile and memory clobber.
91
 */
92
#define alternative(oldinstr, newinstr, feature)                        \
93
200M
        asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory")
94
95
/*
96
 * Alternative inline assembly with input.
97
 *
98
 * Pecularities:
99
 * No memory clobber here.
100
 * Argument numbers start with 1.
101
 * Best is to use constraints that are fixed size (like (%1) ... "r")
102
 * If you use variable sized constraints like "m" or "g" in the
103
 * replacement make sure to pad to the worst case length.
104
 */
105
#define alternative_input(oldinstr, newinstr, feature, input...)  \
106
0
  asm volatile (ALTERNATIVE(oldinstr, newinstr, feature)    \
107
0
          : : input)
108
109
/* Like alternative_input, but with a single output argument */
110
#define alternative_io(oldinstr, newinstr, feature, output, input...) \
111
277
  asm volatile (ALTERNATIVE(oldinstr, newinstr, feature)    \
112
277
          : output : input)
113
114
/*
115
 * This is similar to alternative_io. But it has two features and
116
 * respective instructions.
117
 *
118
 * If CPU has feature2, newinstr2 is used.
119
 * Otherwise, if CPU has feature1, newinstr1 is used.
120
 * Otherwise, oldinstr is used.
121
 */
122
#define alternative_io_2(oldinstr, newinstr1, feature1, newinstr2,  \
123
       feature2, output, input...)      \
124
  asm volatile(ALTERNATIVE_2(oldinstr, newinstr1, feature1, \
125
           newinstr2, feature2)     \
126
         : output : input)
127
128
/*
129
 * This is similar to alternative_io. But it has three features and
130
 * respective instructions.
131
 *
132
 * If CPU has feature3, newinstr3 is used.
133
 * Otherwise, if CPU has feature2, newinstr2 is used.
134
 * Otherwise, if CPU has feature1, newinstr1 is used.
135
 * Otherwise, oldinstr is used.
136
 */
137
#define alternative_io_3(oldinstr, newinstr1, feature1, newinstr2,  \
138
       feature2, newinstr3, feature3, output,   \
139
       input...)          \
140
  asm volatile(ALTERNATIVE_3(oldinstr, newinstr1, feature1, \
141
           newinstr2, feature2, newinstr3,  \
142
           feature3)        \
143
         : output : input)
144
145
/* Use this macro(s) if you need more than one output parameter. */
146
#define ASM_OUTPUT2(a...) a
147
148
#endif  /*  __ASSEMBLY__  */
149
150
#endif /* __X86_ALTERNATIVE_H__ */