qemu/pc-bios/optionrom/kvmvapic.S
<<
>>
Prefs
   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