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 14OPTION_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 35vapic_size = 2*4096 36 37.macro fixup delta=-4 38777: 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 54vapic_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 64vcpu_shift: 65 .long 0 66real_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 95kvm_hypercall_vapic_poll_irq = 1 96 97pcr_cpu = 0x51 98 99.align 64 100 101mp_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 115mp_get_tpr_out: 116 pop %ecx 117 popf 118 ret 119 120mp_get_tpr_bad: 121 mov real_tpr, %eax ; fixup 122 mov (%eax), %eax 123 jmp mp_get_tpr_out 124 125mp_get_tpr_ebx: 126 mov %eax, %ebx 127 call mp_get_tpr_eax 128 xchg %eax, %ebx 129 ret 130 131mp_get_tpr_ecx: 132 mov %eax, %ecx 133 call mp_get_tpr_eax 134 xchg %eax, %ecx 135 ret 136 137mp_get_tpr_edx: 138 mov %eax, %edx 139 call mp_get_tpr_eax 140 xchg %eax, %edx 141 ret 142 143mp_get_tpr_esi: 144 mov %eax, %esi 145 call mp_get_tpr_eax 146 xchg %eax, %esi 147 ret 148 149mp_get_tpr_edi: 150 mov %eax, %edi 151 call mp_get_tpr_edi 152 xchg %eax, %edi 153 ret 154 155mp_get_tpr_ebp: 156 mov %eax, %ebp 157 call mp_get_tpr_eax 158 xchg %eax, %ebp 159 ret 160 161mp_get_tpr_stack: 162 call mp_get_tpr_eax 163 xchg %eax, 4(%esp) 164 ret 165 166mp_set_tpr_eax: 167 push %eax 168 call mp_set_tpr 169 ret 170 171mp_set_tpr: 172 pushf 173 push %eax 174 push %ecx 175 push %edx 176 push %ebx 177 cli 178 reenable_vtpr 179 180mp_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 202mp_isr_is_bigger: 203 mov %bh, %bl 204mp_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 211mp_set_tpr_out: 212 pop %ebx 213 pop %edx 214 pop %ecx 215 pop %eax 216 popf 217 ret $4 218 219mp_set_tpr_poll_irq: 220 mov $kvm_hypercall_vapic_poll_irq, %eax 221 kvm_hypercall 222 jmp mp_set_tpr_out 223 224mp_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 230up_get_tpr_eax: 231 reenable_vtpr 232 movzbl vapic, %eax ; fixup 233 ret 234 235up_get_tpr_ebx: 236 reenable_vtpr 237 movzbl vapic, %ebx ; fixup 238 ret 239 240up_get_tpr_ecx: 241 reenable_vtpr 242 movzbl vapic, %ecx ; fixup 243 ret 244 245up_get_tpr_edx: 246 reenable_vtpr 247 movzbl vapic, %edx ; fixup 248 ret 249 250up_get_tpr_esi: 251 reenable_vtpr 252 movzbl vapic, %esi ; fixup 253 ret 254 255up_get_tpr_edi: 256 reenable_vtpr 257 movzbl vapic, %edi ; fixup 258 ret 259 260up_get_tpr_ebp: 261 reenable_vtpr 262 movzbl vapic, %ebp ; fixup 263 ret 264 265up_get_tpr_stack: 266 reenable_vtpr 267 movzbl vapic, %eax ; fixup 268 xchg %eax, 4(%esp) 269 ret 270 271up_set_tpr_eax: 272 push %eax 273 call up_set_tpr 274 ret 275 276up_set_tpr: 277 pushf 278 push %eax 279 push %ebx 280 reenable_vtpr 281 282up_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 296up_isr_is_bigger: 297 mov %bh, %bl 298up_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 305up_set_tpr_out: 306 pop %ebx 307 pop %eax 308 popf 309 ret $4 310 311up_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 332vapic: 333. = . + vapic_size 334 335OPTION_ROM_END 336