diff options
Diffstat (limited to 'arch/x86/xen/xen-asm_64.S')
-rw-r--r-- | arch/x86/xen/xen-asm_64.S | 252 |
1 files changed, 63 insertions, 189 deletions
diff --git a/arch/x86/xen/xen-asm_64.S b/arch/x86/xen/xen-asm_64.S index 05794c566e87..02f496a8dbaa 100644 --- a/arch/x86/xen/xen-asm_64.S +++ b/arch/x86/xen/xen-asm_64.S | |||
@@ -1,174 +1,45 @@ | |||
1 | /* | 1 | /* |
2 | Asm versions of Xen pv-ops, suitable for either direct use or inlining. | 2 | * Asm versions of Xen pv-ops, suitable for either direct use or |
3 | The inline versions are the same as the direct-use versions, with the | 3 | * inlining. The inline versions are the same as the direct-use |
4 | pre- and post-amble chopped off. | 4 | * versions, with the pre- and post-amble chopped off. |
5 | 5 | * | |
6 | This code is encoded for size rather than absolute efficiency, | 6 | * This code is encoded for size rather than absolute efficiency, with |
7 | with a view to being able to inline as much as possible. | 7 | * a view to being able to inline as much as possible. |
8 | 8 | * | |
9 | We only bother with direct forms (ie, vcpu in pda) of the operations | 9 | * We only bother with direct forms (ie, vcpu in pda) of the |
10 | here; the indirect forms are better handled in C, since they're | 10 | * operations here; the indirect forms are better handled in C, since |
11 | generally too large to inline anyway. | 11 | * they're generally too large to inline anyway. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/linkage.h> | ||
15 | |||
16 | #include <asm/asm-offsets.h> | ||
17 | #include <asm/processor-flags.h> | ||
18 | #include <asm/errno.h> | 14 | #include <asm/errno.h> |
15 | #include <asm/percpu.h> | ||
16 | #include <asm/processor-flags.h> | ||
19 | #include <asm/segment.h> | 17 | #include <asm/segment.h> |
20 | 18 | ||
21 | #include <xen/interface/xen.h> | 19 | #include <xen/interface/xen.h> |
22 | 20 | ||
23 | #define RELOC(x, v) .globl x##_reloc; x##_reloc=v | 21 | #include "xen-asm.h" |
24 | #define ENDPATCH(x) .globl x##_end; x##_end=. | ||
25 | |||
26 | /* Pseudo-flag used for virtual NMI, which we don't implement yet */ | ||
27 | #define XEN_EFLAGS_NMI 0x80000000 | ||
28 | |||
29 | #if 1 | ||
30 | /* | ||
31 | x86-64 does not yet support direct access to percpu variables | ||
32 | via a segment override, so we just need to make sure this code | ||
33 | never gets used | ||
34 | */ | ||
35 | #define BUG ud2a | ||
36 | #define PER_CPU_VAR(var, off) 0xdeadbeef | ||
37 | #endif | ||
38 | |||
39 | /* | ||
40 | Enable events. This clears the event mask and tests the pending | ||
41 | event status with one and operation. If there are pending | ||
42 | events, then enter the hypervisor to get them handled. | ||
43 | */ | ||
44 | ENTRY(xen_irq_enable_direct) | ||
45 | BUG | ||
46 | |||
47 | /* Unmask events */ | ||
48 | movb $0, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask) | ||
49 | |||
50 | /* Preempt here doesn't matter because that will deal with | ||
51 | any pending interrupts. The pending check may end up being | ||
52 | run on the wrong CPU, but that doesn't hurt. */ | ||
53 | |||
54 | /* Test for pending */ | ||
55 | testb $0xff, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_pending) | ||
56 | jz 1f | ||
57 | |||
58 | 2: call check_events | ||
59 | 1: | ||
60 | ENDPATCH(xen_irq_enable_direct) | ||
61 | ret | ||
62 | ENDPROC(xen_irq_enable_direct) | ||
63 | RELOC(xen_irq_enable_direct, 2b+1) | ||
64 | |||
65 | /* | ||
66 | Disabling events is simply a matter of making the event mask | ||
67 | non-zero. | ||
68 | */ | ||
69 | ENTRY(xen_irq_disable_direct) | ||
70 | BUG | ||
71 | |||
72 | movb $1, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask) | ||
73 | ENDPATCH(xen_irq_disable_direct) | ||
74 | ret | ||
75 | ENDPROC(xen_irq_disable_direct) | ||
76 | RELOC(xen_irq_disable_direct, 0) | ||
77 | |||
78 | /* | ||
79 | (xen_)save_fl is used to get the current interrupt enable status. | ||
80 | Callers expect the status to be in X86_EFLAGS_IF, and other bits | ||
81 | may be set in the return value. We take advantage of this by | ||
82 | making sure that X86_EFLAGS_IF has the right value (and other bits | ||
83 | in that byte are 0), but other bits in the return value are | ||
84 | undefined. We need to toggle the state of the bit, because | ||
85 | Xen and x86 use opposite senses (mask vs enable). | ||
86 | */ | ||
87 | ENTRY(xen_save_fl_direct) | ||
88 | BUG | ||
89 | |||
90 | testb $0xff, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask) | ||
91 | setz %ah | ||
92 | addb %ah,%ah | ||
93 | ENDPATCH(xen_save_fl_direct) | ||
94 | ret | ||
95 | ENDPROC(xen_save_fl_direct) | ||
96 | RELOC(xen_save_fl_direct, 0) | ||
97 | |||
98 | /* | ||
99 | In principle the caller should be passing us a value return | ||
100 | from xen_save_fl_direct, but for robustness sake we test only | ||
101 | the X86_EFLAGS_IF flag rather than the whole byte. After | ||
102 | setting the interrupt mask state, it checks for unmasked | ||
103 | pending events and enters the hypervisor to get them delivered | ||
104 | if so. | ||
105 | */ | ||
106 | ENTRY(xen_restore_fl_direct) | ||
107 | BUG | ||
108 | |||
109 | testb $X86_EFLAGS_IF>>8, %ah | ||
110 | setz PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_mask) | ||
111 | /* Preempt here doesn't matter because that will deal with | ||
112 | any pending interrupts. The pending check may end up being | ||
113 | run on the wrong CPU, but that doesn't hurt. */ | ||
114 | |||
115 | /* check for unmasked and pending */ | ||
116 | cmpw $0x0001, PER_CPU_VAR(xen_vcpu_info, XEN_vcpu_info_pending) | ||
117 | jz 1f | ||
118 | 2: call check_events | ||
119 | 1: | ||
120 | ENDPATCH(xen_restore_fl_direct) | ||
121 | ret | ||
122 | ENDPROC(xen_restore_fl_direct) | ||
123 | RELOC(xen_restore_fl_direct, 2b+1) | ||
124 | |||
125 | |||
126 | /* | ||
127 | Force an event check by making a hypercall, | ||
128 | but preserve regs before making the call. | ||
129 | */ | ||
130 | check_events: | ||
131 | push %rax | ||
132 | push %rcx | ||
133 | push %rdx | ||
134 | push %rsi | ||
135 | push %rdi | ||
136 | push %r8 | ||
137 | push %r9 | ||
138 | push %r10 | ||
139 | push %r11 | ||
140 | call xen_force_evtchn_callback | ||
141 | pop %r11 | ||
142 | pop %r10 | ||
143 | pop %r9 | ||
144 | pop %r8 | ||
145 | pop %rdi | ||
146 | pop %rsi | ||
147 | pop %rdx | ||
148 | pop %rcx | ||
149 | pop %rax | ||
150 | ret | ||
151 | 22 | ||
152 | ENTRY(xen_adjust_exception_frame) | 23 | ENTRY(xen_adjust_exception_frame) |
153 | mov 8+0(%rsp),%rcx | 24 | mov 8+0(%rsp), %rcx |
154 | mov 8+8(%rsp),%r11 | 25 | mov 8+8(%rsp), %r11 |
155 | ret $16 | 26 | ret $16 |
156 | 27 | ||
157 | hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32 | 28 | hypercall_iret = hypercall_page + __HYPERVISOR_iret * 32 |
158 | /* | 29 | /* |
159 | Xen64 iret frame: | 30 | * Xen64 iret frame: |
160 | 31 | * | |
161 | ss | 32 | * ss |
162 | rsp | 33 | * rsp |
163 | rflags | 34 | * rflags |
164 | cs | 35 | * cs |
165 | rip <-- standard iret frame | 36 | * rip <-- standard iret frame |
166 | 37 | * | |
167 | flags | 38 | * flags |
168 | 39 | * | |
169 | rcx } | 40 | * rcx } |
170 | r11 }<-- pushed by hypercall page | 41 | * r11 }<-- pushed by hypercall page |
171 | rsp -> rax } | 42 | * rsp->rax } |
172 | */ | 43 | */ |
173 | ENTRY(xen_iret) | 44 | ENTRY(xen_iret) |
174 | pushq $0 | 45 | pushq $0 |
@@ -177,8 +48,8 @@ ENDPATCH(xen_iret) | |||
177 | RELOC(xen_iret, 1b+1) | 48 | RELOC(xen_iret, 1b+1) |
178 | 49 | ||
179 | /* | 50 | /* |
180 | sysexit is not used for 64-bit processes, so it's | 51 | * sysexit is not used for 64-bit processes, so it's only ever used to |
181 | only ever used to return to 32-bit compat userspace. | 52 | * return to 32-bit compat userspace. |
182 | */ | 53 | */ |
183 | ENTRY(xen_sysexit) | 54 | ENTRY(xen_sysexit) |
184 | pushq $__USER32_DS | 55 | pushq $__USER32_DS |
@@ -193,13 +64,15 @@ ENDPATCH(xen_sysexit) | |||
193 | RELOC(xen_sysexit, 1b+1) | 64 | RELOC(xen_sysexit, 1b+1) |
194 | 65 | ||
195 | ENTRY(xen_sysret64) | 66 | ENTRY(xen_sysret64) |
196 | /* We're already on the usermode stack at this point, but still | 67 | /* |
197 | with the kernel gs, so we can easily switch back */ | 68 | * We're already on the usermode stack at this point, but |
198 | movq %rsp, %gs:pda_oldrsp | 69 | * still with the kernel gs, so we can easily switch back |
199 | movq %gs:pda_kernelstack,%rsp | 70 | */ |
71 | movq %rsp, PER_CPU_VAR(old_rsp) | ||
72 | movq PER_CPU_VAR(kernel_stack), %rsp | ||
200 | 73 | ||
201 | pushq $__USER_DS | 74 | pushq $__USER_DS |
202 | pushq %gs:pda_oldrsp | 75 | pushq PER_CPU_VAR(old_rsp) |
203 | pushq %r11 | 76 | pushq %r11 |
204 | pushq $__USER_CS | 77 | pushq $__USER_CS |
205 | pushq %rcx | 78 | pushq %rcx |
@@ -210,13 +83,15 @@ ENDPATCH(xen_sysret64) | |||
210 | RELOC(xen_sysret64, 1b+1) | 83 | RELOC(xen_sysret64, 1b+1) |
211 | 84 | ||
212 | ENTRY(xen_sysret32) | 85 | ENTRY(xen_sysret32) |
213 | /* We're already on the usermode stack at this point, but still | 86 | /* |
214 | with the kernel gs, so we can easily switch back */ | 87 | * We're already on the usermode stack at this point, but |
215 | movq %rsp, %gs:pda_oldrsp | 88 | * still with the kernel gs, so we can easily switch back |
216 | movq %gs:pda_kernelstack, %rsp | 89 | */ |
90 | movq %rsp, PER_CPU_VAR(old_rsp) | ||
91 | movq PER_CPU_VAR(kernel_stack), %rsp | ||
217 | 92 | ||
218 | pushq $__USER32_DS | 93 | pushq $__USER32_DS |
219 | pushq %gs:pda_oldrsp | 94 | pushq PER_CPU_VAR(old_rsp) |
220 | pushq %r11 | 95 | pushq %r11 |
221 | pushq $__USER32_CS | 96 | pushq $__USER32_CS |
222 | pushq %rcx | 97 | pushq %rcx |
@@ -227,28 +102,27 @@ ENDPATCH(xen_sysret32) | |||
227 | RELOC(xen_sysret32, 1b+1) | 102 | RELOC(xen_sysret32, 1b+1) |
228 | 103 | ||
229 | /* | 104 | /* |
230 | Xen handles syscall callbacks much like ordinary exceptions, | 105 | * Xen handles syscall callbacks much like ordinary exceptions, which |
231 | which means we have: | 106 | * means we have: |
232 | - kernel gs | 107 | * - kernel gs |
233 | - kernel rsp | 108 | * - kernel rsp |
234 | - an iret-like stack frame on the stack (including rcx and r11): | 109 | * - an iret-like stack frame on the stack (including rcx and r11): |
235 | ss | 110 | * ss |
236 | rsp | 111 | * rsp |
237 | rflags | 112 | * rflags |
238 | cs | 113 | * cs |
239 | rip | 114 | * rip |
240 | r11 | 115 | * r11 |
241 | rsp-> rcx | 116 | * rsp->rcx |
242 | 117 | * | |
243 | In all the entrypoints, we undo all that to make it look | 118 | * In all the entrypoints, we undo all that to make it look like a |
244 | like a CPU-generated syscall/sysenter and jump to the normal | 119 | * CPU-generated syscall/sysenter and jump to the normal entrypoint. |
245 | entrypoint. | ||
246 | */ | 120 | */ |
247 | 121 | ||
248 | .macro undo_xen_syscall | 122 | .macro undo_xen_syscall |
249 | mov 0*8(%rsp),%rcx | 123 | mov 0*8(%rsp), %rcx |
250 | mov 1*8(%rsp),%r11 | 124 | mov 1*8(%rsp), %r11 |
251 | mov 5*8(%rsp),%rsp | 125 | mov 5*8(%rsp), %rsp |
252 | .endm | 126 | .endm |
253 | 127 | ||
254 | /* Normal 64-bit system call target */ | 128 | /* Normal 64-bit system call target */ |
@@ -275,7 +149,7 @@ ENDPROC(xen_sysenter_target) | |||
275 | 149 | ||
276 | ENTRY(xen_syscall32_target) | 150 | ENTRY(xen_syscall32_target) |
277 | ENTRY(xen_sysenter_target) | 151 | ENTRY(xen_sysenter_target) |
278 | lea 16(%rsp), %rsp /* strip %rcx,%r11 */ | 152 | lea 16(%rsp), %rsp /* strip %rcx, %r11 */ |
279 | mov $-ENOSYS, %rax | 153 | mov $-ENOSYS, %rax |
280 | pushq $VGCF_in_syscall | 154 | pushq $VGCF_in_syscall |
281 | jmp hypercall_iret | 155 | jmp hypercall_iret |