]> git.proxmox.com Git - qemu.git/blob - pc-bios/optionrom/kvmvapic.S
qga: Fix compiler warnings (missing format attribute, wrong format strings)
[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