migration: rename unix.c to socket.c
[qemu.git] / pc-bios / optionrom / kvmvapic.S
1 #
2 # Local APIC acceleration for Windows XP and related guests
3 #
4 # Copyright 2011 Red Hat, Inc. and/or its affiliates
5 #
6 # Author: Avi Kivity <avi@redhat.com>
7 #
8 # This work is licensed under the terms of the GNU GPL, version 2, or (at your
9 # option) any later version.  See the COPYING file in the top-level directory.
10 #
11
12 #include "optionrom.h"
13
14 OPTION_ROM_START
15
16         # clear vapic area: firmware load using rep insb may cause
17         # stale tpr/isr/irr data to corrupt the vapic area.
18         push %es
19         push %cs
20         pop %es
21         xor %ax, %ax
22         mov $vapic_size/2, %cx
23         lea vapic, %di
24         cld
25         rep stosw
26         pop %es
27
28         # announce presence to the hypervisor
29         mov $vapic_base, %ax
30         out %ax, $0x7e
31
32         lret
33
34         .code32
35 vapic_size = 2*4096
36
37 .macro fixup delta=-4
38 777:
39         .text 1
40         .long 777b + \delta  - vapic_base
41         .text 0
42 .endm
43
44 .macro reenable_vtpr
45         out %al, $0x7e
46 .endm
47
48 .text 1
49         fixup_start = .
50 .text 0
51
52 .align 16
53
54 vapic_base:
55         .ascii "kvm aPiC"
56
57         /* relocation data */
58         .long vapic_base        ; fixup
59         .long fixup_start       ; fixup
60         .long fixup_end         ; fixup
61
62         .long vapic             ; fixup
63         .long vapic_size
64 vcpu_shift:
65         .long 0
66 real_tpr:
67         .long 0
68         .long up_set_tpr        ; fixup
69         .long up_set_tpr_eax    ; fixup
70         .long up_get_tpr_eax    ; fixup
71         .long up_get_tpr_ecx    ; fixup
72         .long up_get_tpr_edx    ; fixup
73         .long up_get_tpr_ebx    ; fixup
74         .long 0 /* esp. won't work. */
75         .long up_get_tpr_ebp    ; fixup
76         .long up_get_tpr_esi    ; fixup
77         .long up_get_tpr_edi    ; fixup
78         .long up_get_tpr_stack  ; fixup
79         .long mp_set_tpr        ; fixup
80         .long mp_set_tpr_eax    ; fixup
81         .long mp_get_tpr_eax    ; fixup
82         .long mp_get_tpr_ecx    ; fixup
83         .long mp_get_tpr_edx    ; fixup
84         .long mp_get_tpr_ebx    ; fixup
85         .long 0 /* esp. won't work. */
86         .long mp_get_tpr_ebp    ; fixup
87         .long mp_get_tpr_esi    ; fixup
88         .long mp_get_tpr_edi    ; fixup
89         .long mp_get_tpr_stack  ; fixup
90
91 .macro kvm_hypercall
92         .byte 0x0f, 0x01, 0xc1
93 .endm
94
95 kvm_hypercall_vapic_poll_irq = 1
96
97 pcr_cpu = 0x51
98
99 .align 64
100
101 mp_get_tpr_eax:
102         pushf
103         cli
104         reenable_vtpr
105         push %ecx
106
107         fs/movzbl pcr_cpu, %eax
108
109         mov vcpu_shift, %ecx    ; fixup
110         shl %cl, %eax
111         testb $1, vapic+4(%eax) ; fixup delta=-5
112         jz mp_get_tpr_bad
113         movzbl vapic(%eax), %eax ; fixup
114
115 mp_get_tpr_out:
116         pop %ecx
117         popf
118         ret
119
120 mp_get_tpr_bad:
121         mov real_tpr, %eax      ; fixup
122         mov (%eax), %eax
123         jmp mp_get_tpr_out
124
125 mp_get_tpr_ebx:
126         mov %eax, %ebx
127         call mp_get_tpr_eax
128         xchg %eax, %ebx
129         ret
130
131 mp_get_tpr_ecx:
132         mov %eax, %ecx
133         call mp_get_tpr_eax
134         xchg %eax, %ecx
135         ret
136
137 mp_get_tpr_edx:
138         mov %eax, %edx
139         call mp_get_tpr_eax
140         xchg %eax, %edx
141         ret
142
143 mp_get_tpr_esi:
144         mov %eax, %esi
145         call mp_get_tpr_eax
146         xchg %eax, %esi
147         ret
148
149 mp_get_tpr_edi:
150         mov %eax, %edi
151         call mp_get_tpr_edi
152         xchg %eax, %edi
153         ret
154
155 mp_get_tpr_ebp:
156         mov %eax, %ebp
157         call mp_get_tpr_eax
158         xchg %eax, %ebp
159         ret
160
161 mp_get_tpr_stack:
162         call mp_get_tpr_eax
163         xchg %eax, 4(%esp)
164         ret
165
166 mp_set_tpr_eax:
167         push %eax
168         call mp_set_tpr
169         ret
170
171 mp_set_tpr:
172         pushf
173         push %eax
174         push %ecx
175         push %edx
176         push %ebx
177         cli
178         reenable_vtpr
179
180 mp_set_tpr_failed:
181         fs/movzbl pcr_cpu, %edx
182
183         mov vcpu_shift, %ecx    ; fixup
184         shl %cl, %edx
185
186         testb $1, vapic+4(%edx) ; fixup delta=-5
187         jz mp_set_tpr_bad
188
189         mov vapic(%edx), %eax   ; fixup
190
191         mov %eax, %ebx
192         mov 24(%esp), %bl
193
194         /* %ebx = new vapic (%bl = tpr, %bh = isr, %b3 = irr) */
195
196         lock cmpxchg %ebx, vapic(%edx) ; fixup
197         jnz mp_set_tpr_failed
198
199         /* compute ppr */
200         cmp %bh, %bl
201         jae mp_tpr_is_bigger
202 mp_isr_is_bigger:
203         mov %bh, %bl
204 mp_tpr_is_bigger:
205         /* %bl = ppr */
206         rol $8, %ebx
207         /* now: %bl = irr, %bh = ppr */
208         cmp %bh, %bl
209         ja mp_set_tpr_poll_irq
210
211 mp_set_tpr_out:
212         pop %ebx
213         pop %edx
214         pop %ecx
215         pop %eax
216         popf
217         ret $4
218
219 mp_set_tpr_poll_irq:
220         mov $kvm_hypercall_vapic_poll_irq, %eax
221         kvm_hypercall
222         jmp mp_set_tpr_out
223
224 mp_set_tpr_bad:
225         mov 24(%esp), %ecx
226         mov real_tpr, %eax      ; fixup
227         mov %ecx, (%eax)
228         jmp mp_set_tpr_out
229
230 up_get_tpr_eax:
231         reenable_vtpr
232         movzbl vapic, %eax ; fixup
233         ret
234
235 up_get_tpr_ebx:
236         reenable_vtpr
237         movzbl vapic, %ebx ; fixup
238         ret
239
240 up_get_tpr_ecx:
241         reenable_vtpr
242         movzbl vapic, %ecx ; fixup
243         ret
244
245 up_get_tpr_edx:
246         reenable_vtpr
247         movzbl vapic, %edx ; fixup
248         ret
249
250 up_get_tpr_esi:
251         reenable_vtpr
252         movzbl vapic, %esi ; fixup
253         ret
254
255 up_get_tpr_edi:
256         reenable_vtpr
257         movzbl vapic, %edi ; fixup
258         ret
259
260 up_get_tpr_ebp:
261         reenable_vtpr
262         movzbl vapic, %ebp ; fixup
263         ret
264
265 up_get_tpr_stack:
266         reenable_vtpr
267         movzbl vapic, %eax ; fixup
268         xchg %eax, 4(%esp)
269         ret
270
271 up_set_tpr_eax:
272         push %eax
273         call up_set_tpr
274         ret
275
276 up_set_tpr:
277         pushf
278         push %eax
279         push %ebx
280         reenable_vtpr
281
282 up_set_tpr_failed:
283         mov vapic, %eax ; fixup
284
285         mov %eax, %ebx
286         mov 16(%esp), %bl
287
288         /* %ebx = new vapic (%bl = tpr, %bh = isr, %b3 = irr) */
289
290         lock cmpxchg %ebx, vapic ; fixup
291         jnz up_set_tpr_failed
292
293         /* compute ppr */
294         cmp %bh, %bl
295         jae up_tpr_is_bigger
296 up_isr_is_bigger:
297         mov %bh, %bl
298 up_tpr_is_bigger:
299         /* %bl = ppr */
300         rol $8, %ebx
301         /* now: %bl = irr, %bh = ppr */
302         cmp %bh, %bl
303         ja up_set_tpr_poll_irq
304
305 up_set_tpr_out:
306         pop %ebx
307         pop %eax
308         popf
309         ret $4
310
311 up_set_tpr_poll_irq:
312         mov $kvm_hypercall_vapic_poll_irq, %eax
313         kvm_hypercall
314         jmp up_set_tpr_out
315
316 .text 1
317         fixup_end = .
318 .text 0
319
320 /*
321  * vapic format:
322  *  per-vcpu records of size 2^vcpu shift.
323  *     byte 0: tpr (r/w)
324  *     byte 1: highest in-service interrupt (isr) (r/o); bits 3:0 are zero
325  *     byte 2: zero (r/o)
326  *     byte 3: highest pending interrupt (irr) (r/o)
327  */
328 .text 2
329
330 .align 128
331
332 vapic:
333 . = . + vapic_size
334
335 OPTION_ROM_END