qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

kvmvapic.S (5233B)


      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 
     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