Xen Test Framework
asm.S
Go to the documentation of this file.
1#include <xtf/asm_macros.h>
2#include <xtf/extable.h>
3#include <arch/segment.h>
4
5 .section .text.user, "ax", @progbits
6
7.macro GEN_ABS_STUB seg load_seg
8
9ENTRY(stub_\seg\‍()_abs) /* exinfo_t stub_\seg_abs(unsigned long addr) */
10#ifdef __i386__
11 /*
12 * Switch segment if necessary. The old segment is preserved on the
13 * stack for the duration of the test.
14 */
15 .if \load_seg
16 .ifeqs "\seg", "none"
17 push %ds
18 push $(GDTE_AVAIL1 << 3 | 3)
19 pop %ds
20 .else
21 push %\seg
22 push $(GDTE_AVAIL1 << 3 | 3)
23 pop %\seg
24 .endif
25 .endif
26#endif
27
28 /* The bottom bit of 'addr' encodes FEP. */
29#ifdef __i386__
30 testb $1, %al
31#else
32 testb $1, %dil
33#endif
34
35 /*
36 * No exception if we don't fault.
37 * Reused by the 64bit case, and careful to not clobber flags.
38 */
39 mov $0, %eax
40
41 jz 1f
42
43 _ASM_XEN_FEP
44 .ifeqs "\seg", "none"
45#ifdef __i386__
461: movb $0, 0xc0000000
47#else
481: movabsb %al, 0x8000000040000000
49#endif
50 .else
51#ifdef __i386__
521: movb $0, %\seg:0xc0000000
53#else
541: movabsb %al, %\seg:0x8000000040000000
55#endif
56 .endif
57
582:
59#ifdef __i386__
60 /* Restore the old segment if necessary. */
61 .if \load_seg
62 .ifeqs "\seg", "none"
63 pop %ds
64 .else
65 pop %\seg
66 .endif
67 .endif
68#endif
69
70 ret
71
72 _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_eax)
73ENDFUNC(stub_\seg\‍()_abs)
74.endm
75
76.macro GEN_REG_STUB seg reg load_seg preserve_reg
77
78ENTRY(stub_\seg\‍()_\reg) /* exinfo_t stub_\seg_\reg(unsigned long addr) */
79
80#ifdef __i386__
81 /*
82 * Switch segment if necessary. The old segment is preserved on the
83 * stack for the duration of the test.
84 */
85 .if \load_seg
86 .ifeqs "\seg", "none"
87 push %ds
88 push $(GDTE_AVAIL1 << 3 | 3)
89 pop %ds
90 .else
91 push %\seg
92 push $(GDTE_AVAIL1 << 3 | 3)
93 pop %\seg
94 .endif
95 .endif
96#endif
97
98 /* Preserve the subject register if necessary. */
99 .if \preserve_reg
100 mov %\reg, %_ASM_CX
101 .endif
102
103 /* Move 'addr' into \reg */
104#ifdef __i386__
105 mov %eax, %\reg
106#else
107 mov %rdi, %\reg
108#endif
109
110 /* The bottom bit of 'addr' encodes FEP. */
111 test $1, %\reg
112 jz 1f
113
114 _ASM_XEN_FEP
115 .ifeqs "\seg", "none"
1161: movb $0, (%\reg)
117 .else
1181: movb $0, %\seg:(%\reg)
119 .endif
120
121 /* No exception if we didn't fault. */
122 xor %eax, %eax
1232:
124 /* Restore the register if necessary. */
125 .if \preserve_reg
126 mov %_ASM_CX, %\reg
127 .endif
128
129#ifdef __i386__
130 /* Restore the old segment if necessary. */
131 .if \load_seg
132 .ifeqs "\seg", "none"
133 pop %ds
134 .else
135 pop %\seg
136 .endif
137 .endif
138#endif
139
140 ret
141
142 _ASM_EXTABLE_HANDLER(1b, 2b, ex_record_fault_eax)
143ENDFUNC(stub_\seg\‍()_\reg)
144.endm
145
146/*
147 * Instantiate `GEN_ABS_STUB foreach segment` and `GEN_REG_STUB foreach
148 * segment, foreach register`, calculaing whether the segment needs loading
149 * (implicit %ds, explicit %{e,d,f,g}s), and whether the register needs
150 * preserving (depends on the calling ABI).
151 */
152.local seg_mask, seg_idx, reg_mask, reg_idx
153#ifdef __i386__
154 seg_mask = 0b1100100
155#else
156 seg_mask = 0
157#endif
158 seg_idx = 6
159
160.irp seg, none, es, cs, ss, ds, fs, gs
161
162 GEN_ABS_STUB \seg, (seg_mask & (1 << seg_idx))
163
164#ifdef __i386__
165 reg_mask = 0b00011111
166 reg_idx = 7
167 .irp reg, eax, ecx, edx, ebx, esp, ebp, esi, edi
168#else
169 reg_mask = 0b0001110000001111
170 reg_idx = 15
171 .irp reg, rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15
172#endif
173
174 GEN_REG_STUB \seg, \reg, (seg_mask & (1 << seg_idx)), (reg_mask & (1 << reg_idx))
175 reg_idx = reg_idx - 1
176
177 .endr
178 seg_idx = seg_idx - 1
179
180.endr
181
182/*
183 * Local variables:
184 * tab-width: 8
185 * indent-tabs-mode: nil
186 * End:
187 */