Fix 32-bit overflow in parallels image support
[qemu-kvm/fedora.git] / kvm / bios / vapic.S
blobcf2a474d5dfe43e2984d75aa48d2669026c30086
1         .text
2         .code32
3         .align 4096
5 vapic_size = 2*4096
7 .macro fixup delta=-4
8 777:
9         .pushsection .fixup, "a"
10         .long 777b + \delta  - vapic_base
11         .popsection
12 .endm
14 .macro reenable_vtpr
15         out %al, $0x7e
16 .endm
18 vapic_base:
19         .ascii "kvm aPiC"
21         /* relocation data */
22         .long vapic_base        ; fixup
23         .long fixup_start       ; fixup
24         .long fixup_end         ; fixup
26         .long vapic             ; fixup
27         .long vapic_size
28 vcpu_shift:
29         .long 0
30 real_tpr:
31         .long 0
32         .long up_set_tpr        ; fixup
33         .long up_set_tpr_eax    ; fixup
34         .long up_get_tpr_eax    ; fixup
35         .long up_get_tpr_ecx    ; fixup
36         .long up_get_tpr_edx    ; fixup
37         .long up_get_tpr_ebx    ; fixup
38         .long 0 /* esp. won't work. */
39         .long up_get_tpr_ebp    ; fixup
40         .long up_get_tpr_esi    ; fixup
41         .long up_get_tpr_edi    ; fixup
42         .long up_get_tpr_stack  ; fixup
43         .long mp_set_tpr        ; fixup
44         .long mp_set_tpr_eax    ; fixup
45         .long mp_get_tpr_eax    ; fixup
46         .long mp_get_tpr_ecx    ; fixup
47         .long mp_get_tpr_edx    ; fixup
48         .long mp_get_tpr_ebx    ; fixup
49         .long 0 /* esp. won't work. */
50         .long mp_get_tpr_ebp    ; fixup
51         .long mp_get_tpr_esi    ; fixup
52         .long mp_get_tpr_edi    ; fixup
53         .long mp_get_tpr_stack  ; fixup
55 .macro kvm_hypercall
56         .byte 0x0f, 0x01, 0xc1
57 .endm
59 kvm_hypercall_vapic_poll_irq = 1
61 pcr_cpu = 0x51
63 .align 64
65 mp_get_tpr_eax:
66         pushf
67         cli
68         reenable_vtpr
69         push %ecx
71         fs/movzbl pcr_cpu, %eax
73         mov vcpu_shift, %ecx    ; fixup
74         shl %cl, %eax
75         testb $1, vapic+4(%eax) ; fixup delta=-5
76         jz mp_get_tpr_bad
77         movzbl vapic(%eax), %eax ; fixup
79 mp_get_tpr_out:
80         pop %ecx
81         popf
82         ret
84 mp_get_tpr_bad:
85         mov real_tpr, %eax      ; fixup
86         mov (%eax), %eax
87         jmp mp_get_tpr_out
89 mp_get_tpr_ebx:
90         mov %eax, %ebx
91         call mp_get_tpr_eax
92         xchg %eax, %ebx
93         ret
95 mp_get_tpr_ecx:
96         mov %eax, %ecx
97         call mp_get_tpr_eax
98         xchg %eax, %ecx
99         ret
101 mp_get_tpr_edx:
102         mov %eax, %edx
103         call mp_get_tpr_eax
104         xchg %eax, %edx
105         ret
107 mp_get_tpr_esi:
108         mov %eax, %esi
109         call mp_get_tpr_eax
110         xchg %eax, %esi
111         ret
113 mp_get_tpr_edi:
114         mov %eax, %edi
115         call mp_get_tpr_edi
116         xchg %eax, %edi
117         ret
119 mp_get_tpr_ebp:
120         mov %eax, %ebp
121         call mp_get_tpr_eax
122         xchg %eax, %ebp
123         ret
125 mp_get_tpr_stack:
126         call mp_get_tpr_eax
127         xchg %eax, 4(%esp)
128         ret
130 mp_set_tpr_eax:
131         push %eax
132         call mp_set_tpr
133         ret
135 mp_set_tpr:
136         pushf
137         push %eax
138         push %ecx
139         push %edx
140         push %ebx
141         cli
142         reenable_vtpr
144 mp_set_tpr_failed:
145         fs/movzbl pcr_cpu, %edx
147         mov vcpu_shift, %ecx    ; fixup
148         shl %cl, %edx
150         testb $1, vapic+4(%edx) ; fixup delta=-5
151         jz mp_set_tpr_bad
153         mov vapic(%edx), %eax   ; fixup
155         mov %eax, %ebx
156         mov 24(%esp), %bl
158         /* %ebx = new vapic (%bl = tpr, %bh = isr, %b3 = irr) */
160         lock cmpxchg %ebx, vapic(%edx) ; fixup
161         jnz mp_set_tpr_failed
163         /* compute ppr */
164         cmp %bh, %bl
165         jae mp_tpr_is_bigger
166 mp_isr_is_bigger:
167         mov %bh, %bl
168 mp_tpr_is_bigger:
169         /* %bl = ppr */
170         mov %bl, %ch   /* ch = ppr */
171         rol $8, %ebx
172         /* now: %bl = irr, %bh = ppr */
173         cmp %bh, %bl
174         ja mp_set_tpr_poll_irq
176 mp_set_tpr_out:
177         pop %ebx
178         pop %edx
179         pop %ecx
180         pop %eax
181         popf
182         ret $4
184 mp_set_tpr_poll_irq:
185         mov $kvm_hypercall_vapic_poll_irq, %eax
186         kvm_hypercall
187         jmp mp_set_tpr_out
189 mp_set_tpr_bad:
190         mov 24(%esp), %ecx
191         mov real_tpr, %eax      ; fixup
192         mov %ecx, (%eax)
193         jmp mp_set_tpr_out
195 up_get_tpr_eax:
196         reenable_vtpr
197         movzbl vapic, %eax ; fixup
198         ret
200 up_get_tpr_ebx:
201         reenable_vtpr
202         movzbl vapic, %ebx ; fixup
203         ret
205 up_get_tpr_ecx:
206         reenable_vtpr
207         movzbl vapic, %ecx ; fixup
208         ret
210 up_get_tpr_edx:
211         reenable_vtpr
212         movzbl vapic, %edx ; fixup
213         ret
215 up_get_tpr_esi:
216         reenable_vtpr
217         movzbl vapic, %esi ; fixup
218         ret
220 up_get_tpr_edi:
221         reenable_vtpr
222         movzbl vapic, %edi ; fixup
223         ret
225 up_get_tpr_ebp:
226         reenable_vtpr
227         movzbl vapic, %ebp ; fixup
228         ret
230 up_get_tpr_stack:
231         reenable_vtpr
232         movzbl vapic, %eax ; fixup
233         xchg %eax, 4(%esp)
234         ret
236 up_set_tpr_eax:
237         push %eax
238         call up_set_tpr
239         ret
241 up_set_tpr:
242         pushf
243         push %eax
244         push %ecx
245         push %ebx
246         reenable_vtpr
248 up_set_tpr_failed:
249         mov vapic, %eax ; fixup
251         mov %eax, %ebx
252         mov 20(%esp), %bl
254         /* %ebx = new vapic (%bl = tpr, %bh = isr, %b3 = irr) */
256         lock cmpxchg %ebx, vapic ; fixup
257         jnz up_set_tpr_failed
259         /* compute ppr */
260         cmp %bh, %bl
261         jae up_tpr_is_bigger
262 up_isr_is_bigger:
263         mov %bh, %bl
264 up_tpr_is_bigger:
265         /* %bl = ppr */
266         mov %bl, %ch   /* ch = ppr */
267         rol $8, %ebx
268         /* now: %bl = irr, %bh = ppr */
269         cmp %bh, %bl
270         ja up_set_tpr_poll_irq
272 up_set_tpr_out:
273         pop %ebx
274         pop %ecx
275         pop %eax
276         popf
277         ret $4
279 up_set_tpr_poll_irq:
280         mov $kvm_hypercall_vapic_poll_irq, %eax
281         kvm_hypercall
282         jmp up_set_tpr_out
284 .align 4096
286  * vapic format:
287  *  per-vcpu records of size 2^vcpu shift.
288  *     byte 0: tpr (r/w)
289  *     byte 1: highest in-service interrupt (isr) (r/o); bits 3:0 are zero
290  *     byte 2: zero (r/o)
291  *     byte 3: highest pending interrupt (irr) (r/o)
292  */
293 vapic:
294 . = . + vapic_size