]> git.proxmox.com Git - qemu.git/blob - pc-bios/optionrom/kvmvapic.S
kvmvapic: Add option ROM
[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 .text 0
13 .code16
14 .global _start
15 _start:
16 .short 0xaa55
17 .byte (_end - _start) / 512
18 # clear vapic area: firmware load using rep insb may cause
19 # stale tpr/isr/irr data to corrupt the vapic area.
20 push %es
21 push %cs
22 pop %es
23 xor %ax, %ax
24 mov $vapic_size/2, %cx
25 lea vapic, %di
26 cld
27 rep stosw
28 pop %es
29 mov $vapic_base, %ax
30 out %ax, $0x7e
31 lret
32
33 .code32
34 vapic_size = 2*4096
35
36 .macro fixup delta=-4
37 777:
38 .text 1
39 .long 777b + \delta - vapic_base
40 .text 0
41 .endm
42
43 .macro reenable_vtpr
44 out %al, $0x7e
45 .endm
46
47 .text 1
48 fixup_start = .
49 .text 0
50
51 .align 16
52
53 vapic_base:
54 .ascii "kvm aPiC"
55
56 /* relocation data */
57 .long vapic_base ; fixup
58 .long fixup_start ; fixup
59 .long fixup_end ; fixup
60
61 .long vapic ; fixup
62 .long vapic_size
63 vcpu_shift:
64 .long 0
65 real_tpr:
66 .long 0
67 .long up_set_tpr ; fixup
68 .long up_set_tpr_eax ; fixup
69 .long up_get_tpr_eax ; fixup
70 .long up_get_tpr_ecx ; fixup
71 .long up_get_tpr_edx ; fixup
72 .long up_get_tpr_ebx ; fixup
73 .long 0 /* esp. won't work. */
74 .long up_get_tpr_ebp ; fixup
75 .long up_get_tpr_esi ; fixup
76 .long up_get_tpr_edi ; fixup
77 .long up_get_tpr_stack ; fixup
78 .long mp_set_tpr ; fixup
79 .long mp_set_tpr_eax ; fixup
80 .long mp_get_tpr_eax ; fixup
81 .long mp_get_tpr_ecx ; fixup
82 .long mp_get_tpr_edx ; fixup
83 .long mp_get_tpr_ebx ; fixup
84 .long 0 /* esp. won't work. */
85 .long mp_get_tpr_ebp ; fixup
86 .long mp_get_tpr_esi ; fixup
87 .long mp_get_tpr_edi ; fixup
88 .long mp_get_tpr_stack ; fixup
89
90 .macro kvm_hypercall
91 .byte 0x0f, 0x01, 0xc1
92 .endm
93
94 kvm_hypercall_vapic_poll_irq = 1
95
96 pcr_cpu = 0x51
97
98 .align 64
99
100 mp_get_tpr_eax:
101 pushf
102 cli
103 reenable_vtpr
104 push %ecx
105
106 fs/movzbl pcr_cpu, %eax
107
108 mov vcpu_shift, %ecx ; fixup
109 shl %cl, %eax
110 testb $1, vapic+4(%eax) ; fixup delta=-5
111 jz mp_get_tpr_bad
112 movzbl vapic(%eax), %eax ; fixup
113
114 mp_get_tpr_out:
115 pop %ecx
116 popf
117 ret
118
119 mp_get_tpr_bad:
120 mov real_tpr, %eax ; fixup
121 mov (%eax), %eax
122 jmp mp_get_tpr_out
123
124 mp_get_tpr_ebx:
125 mov %eax, %ebx
126 call mp_get_tpr_eax
127 xchg %eax, %ebx
128 ret
129
130 mp_get_tpr_ecx:
131 mov %eax, %ecx
132 call mp_get_tpr_eax
133 xchg %eax, %ecx
134 ret
135
136 mp_get_tpr_edx:
137 mov %eax, %edx
138 call mp_get_tpr_eax
139 xchg %eax, %edx
140 ret
141
142 mp_get_tpr_esi:
143 mov %eax, %esi
144 call mp_get_tpr_eax
145 xchg %eax, %esi
146 ret
147
148 mp_get_tpr_edi:
149 mov %eax, %edi
150 call mp_get_tpr_edi
151 xchg %eax, %edi
152 ret
153
154 mp_get_tpr_ebp:
155 mov %eax, %ebp
156 call mp_get_tpr_eax
157 xchg %eax, %ebp
158 ret
159
160 mp_get_tpr_stack:
161 call mp_get_tpr_eax
162 xchg %eax, 4(%esp)
163 ret
164
165 mp_set_tpr_eax:
166 push %eax
167 call mp_set_tpr
168 ret
169
170 mp_set_tpr:
171 pushf
172 push %eax
173 push %ecx
174 push %edx
175 push %ebx
176 cli
177 reenable_vtpr
178
179 mp_set_tpr_failed:
180 fs/movzbl pcr_cpu, %edx
181
182 mov vcpu_shift, %ecx ; fixup
183 shl %cl, %edx
184
185 testb $1, vapic+4(%edx) ; fixup delta=-5
186 jz mp_set_tpr_bad
187
188 mov vapic(%edx), %eax ; fixup
189
190 mov %eax, %ebx
191 mov 24(%esp), %bl
192
193 /* %ebx = new vapic (%bl = tpr, %bh = isr, %b3 = irr) */
194
195 lock cmpxchg %ebx, vapic(%edx) ; fixup
196 jnz mp_set_tpr_failed
197
198 /* compute ppr */
199 cmp %bh, %bl
200 jae mp_tpr_is_bigger
201 mp_isr_is_bigger:
202 mov %bh, %bl
203 mp_tpr_is_bigger:
204 /* %bl = ppr */
205 mov %bl, %ch /* ch = 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 %ecx
280 push %ebx
281 reenable_vtpr
282
283 up_set_tpr_failed:
284 mov vapic, %eax ; fixup
285
286 mov %eax, %ebx
287 mov 20(%esp), %bl
288
289 /* %ebx = new vapic (%bl = tpr, %bh = isr, %b3 = irr) */
290
291 lock cmpxchg %ebx, vapic ; fixup
292 jnz up_set_tpr_failed
293
294 /* compute ppr */
295 cmp %bh, %bl
296 jae up_tpr_is_bigger
297 up_isr_is_bigger:
298 mov %bh, %bl
299 up_tpr_is_bigger:
300 /* %bl = ppr */
301 mov %bl, %ch /* ch = ppr */
302 rol $8, %ebx
303 /* now: %bl = irr, %bh = ppr */
304 cmp %bh, %bl
305 ja up_set_tpr_poll_irq
306
307 up_set_tpr_out:
308 pop %ebx
309 pop %ecx
310 pop %eax
311 popf
312 ret $4
313
314 up_set_tpr_poll_irq:
315 mov $kvm_hypercall_vapic_poll_irq, %eax
316 kvm_hypercall
317 jmp up_set_tpr_out
318
319 .text 1
320 fixup_end = .
321 .text 0
322
323 /*
324 * vapic format:
325 * per-vcpu records of size 2^vcpu shift.
326 * byte 0: tpr (r/w)
327 * byte 1: highest in-service interrupt (isr) (r/o); bits 3:0 are zero
328 * byte 2: zero (r/o)
329 * byte 3: highest pending interrupt (irr) (r/o)
330 */
331 .text 2
332
333 .align 128
334
335 vapic:
336 . = . + vapic_size
337
338 .byte 0 # reserve space for signature
339 .align 512, 0
340
341 _end: