|
|
1.1 root 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 <[email protected]>
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.