summaryrefslogtreecommitdiff
path: root/xen/include/asm-x86/alternative-asm.h
blob: e6c42d721d2bc3d2379faf97fab2123cdad07faa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#ifndef _ASM_X86_ALTERNATIVE_ASM_H_
#define _ASM_X86_ALTERNATIVE_ASM_H_

#include <asm/nops.h>

#ifdef __ASSEMBLY__

/*
 * Issue one struct alt_instr descriptor entry (need to put it into
 * the section .altinstructions, see below). This entry contains
 * enough information for the alternatives patching code to patch an
 * instruction. See apply_alternatives().
 */
.macro altinstruction_entry orig repl feature orig_len repl_len pad_len
    .long \orig - .
    .long \repl - .
    .word \feature
    .byte \orig_len
    .byte \repl_len
    .byte \pad_len
    .byte 0 /* priv */
.endm

.macro mknops nr_bytes
#ifdef HAVE_AS_NOPS_DIRECTIVE
    .nops \nr_bytes, ASM_NOP_MAX
#else
    .skip \nr_bytes, 0x90
#endif
.endm

/* GAS's idea of true is -1, while Clang's idea is 1. */
#ifdef HAVE_AS_NEGATIVE_TRUE
# define as_true(x) (-(x))
#else
# define as_true(x) (x)
#endif

#define decl_orig(insn, padding)                  \
 .L\@_orig_s: insn; .L\@_orig_e:                  \
 .L\@_diff = padding;                             \
 mknops (as_true(.L\@_diff > 0) * .L\@_diff);     \
 .L\@_orig_p:

#define orig_len               (.L\@_orig_e       -     .L\@_orig_s)
#define pad_len                (.L\@_orig_p       -     .L\@_orig_e)
#define total_len              (.L\@_orig_p       -     .L\@_orig_s)

#define decl_repl(insn, nr)     .L\@_repl_s\()nr: insn; .L\@_repl_e\()nr:
#define repl_len(nr)           (.L\@_repl_e\()nr  -     .L\@_repl_s\()nr)

#define as_max(a, b)           ((a) ^ (((a) ^ (b)) & -as_true((a) < (b))))

.macro ALTERNATIVE oldinstr, newinstr, feature
    decl_orig(\oldinstr, repl_len(1) - orig_len)

    .pushsection .altinstructions, "a", @progbits
    altinstruction_entry .L\@_orig_s, .L\@_repl_s1, \feature, \
        orig_len, repl_len(1), pad_len

    .section .discard, "a", @progbits
    /*
     * Assembler-time checks:
     *   - total_len <= 255
     *   - \newinstr <= total_len
     */
    .byte total_len
    .byte 0xff + repl_len(1) - total_len

    .section .altinstr_replacement, "ax", @progbits

    decl_repl(\newinstr, 1)

    .popsection
.endm

.macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2
    decl_orig(\oldinstr, as_max(repl_len(1), repl_len(2)) - orig_len)

    .pushsection .altinstructions, "a", @progbits

    altinstruction_entry .L\@_orig_s, .L\@_repl_s1, \feature1, \
        orig_len, repl_len(1), pad_len
    altinstruction_entry .L\@_orig_s, .L\@_repl_s2, \feature2, \
        orig_len, repl_len(2), pad_len

    .section .discard, "a", @progbits
    /*
     * Assembler-time checks:
     *   - total_len <= 255
     *   - \newinstr* <= total_len
     */
    .byte total_len
    .byte 0xff + repl_len(1) - total_len
    .byte 0xff + repl_len(2) - total_len

    .section .altinstr_replacement, "ax", @progbits

    decl_repl(\newinstr1, 1)
    decl_repl(\newinstr2, 2)

    .popsection
.endm

#undef as_max
#undef repl_len
#undef decl_repl
#undef total_len
#undef pad_len
#undef orig_len
#undef decl_orig
#undef as_true

#endif /* __ASSEMBLY__ */
#endif /* _ASM_X86_ALTERNATIVE_ASM_H_ */

/*
 * Local variables:
 * mode: C
 * c-file-style: "BSD"
 * c-basic-offset: 4
 * tab-width: 4
 * indent-tabs-mode: nil
 * End:
 */