kvmvapic: Add option ROM

This imports and builds the original VAPIC option ROM of qemu-kvm.
Its interaction with QEMU is described in the commit that introduces the
corresponding device model.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:
Jan Kiszka 2012-02-17 18:31:18 +01:00 committed by Avi Kivity
parent d362e757d3
commit 2a2af967b0
4 changed files with 344 additions and 2 deletions

1
.gitignore vendored
View File

@ -75,6 +75,7 @@ pc-bios/vgabios-pq/status
pc-bios/optionrom/linuxboot.bin
pc-bios/optionrom/multiboot.bin
pc-bios/optionrom/multiboot.raw
pc-bios/optionrom/kvmvapic.bin
.stgit-*
cscope.*
tags

View File

@ -253,7 +253,7 @@ pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
mpc8544ds.dtb \
multiboot.bin linuxboot.bin \
multiboot.bin linuxboot.bin kvmvapic.bin \
s390-zipl.rom \
spapr-rtas.bin slof.bin \
palcode-clipper

View File

@ -14,7 +14,7 @@ CFLAGS += -I$(SRC_PATH)
CFLAGS += $(call cc-option, $(CFLAGS), -fno-stack-protector)
QEMU_CFLAGS = $(CFLAGS)
build-all: multiboot.bin linuxboot.bin
build-all: multiboot.bin linuxboot.bin kvmvapic.bin
# suppress auto-removal of intermediate files
.SECONDARY:

View File

@ -0,0 +1,341 @@
#
# Local APIC acceleration for Windows XP and related guests
#
# Copyright 2011 Red Hat, Inc. and/or its affiliates
#
# Author: Avi Kivity <avi@redhat.com>
#
# This work is licensed under the terms of the GNU GPL, version 2, or (at your
# option) any later version. See the COPYING file in the top-level directory.
#
.text 0
.code16
.global _start
_start:
.short 0xaa55
.byte (_end - _start) / 512
# clear vapic area: firmware load using rep insb may cause
# stale tpr/isr/irr data to corrupt the vapic area.
push %es
push %cs
pop %es
xor %ax, %ax
mov $vapic_size/2, %cx
lea vapic, %di
cld
rep stosw
pop %es
mov $vapic_base, %ax
out %ax, $0x7e
lret
.code32
vapic_size = 2*4096
.macro fixup delta=-4
777:
.text 1
.long 777b + \delta - vapic_base
.text 0
.endm
.macro reenable_vtpr
out %al, $0x7e
.endm
.text 1
fixup_start = .
.text 0
.align 16
vapic_base:
.ascii "kvm aPiC"
/* relocation data */
.long vapic_base ; fixup
.long fixup_start ; fixup
.long fixup_end ; fixup
.long vapic ; fixup
.long vapic_size
vcpu_shift:
.long 0
real_tpr:
.long 0
.long up_set_tpr ; fixup
.long up_set_tpr_eax ; fixup
.long up_get_tpr_eax ; fixup
.long up_get_tpr_ecx ; fixup
.long up_get_tpr_edx ; fixup
.long up_get_tpr_ebx ; fixup
.long 0 /* esp. won't work. */
.long up_get_tpr_ebp ; fixup
.long up_get_tpr_esi ; fixup
.long up_get_tpr_edi ; fixup
.long up_get_tpr_stack ; fixup
.long mp_set_tpr ; fixup
.long mp_set_tpr_eax ; fixup
.long mp_get_tpr_eax ; fixup
.long mp_get_tpr_ecx ; fixup
.long mp_get_tpr_edx ; fixup
.long mp_get_tpr_ebx ; fixup
.long 0 /* esp. won't work. */
.long mp_get_tpr_ebp ; fixup
.long mp_get_tpr_esi ; fixup
.long mp_get_tpr_edi ; fixup
.long mp_get_tpr_stack ; fixup
.macro kvm_hypercall
.byte 0x0f, 0x01, 0xc1
.endm
kvm_hypercall_vapic_poll_irq = 1
pcr_cpu = 0x51
.align 64
mp_get_tpr_eax:
pushf
cli
reenable_vtpr
push %ecx
fs/movzbl pcr_cpu, %eax
mov vcpu_shift, %ecx ; fixup
shl %cl, %eax
testb $1, vapic+4(%eax) ; fixup delta=-5
jz mp_get_tpr_bad
movzbl vapic(%eax), %eax ; fixup
mp_get_tpr_out:
pop %ecx
popf
ret
mp_get_tpr_bad:
mov real_tpr, %eax ; fixup
mov (%eax), %eax
jmp mp_get_tpr_out
mp_get_tpr_ebx:
mov %eax, %ebx
call mp_get_tpr_eax
xchg %eax, %ebx
ret
mp_get_tpr_ecx:
mov %eax, %ecx
call mp_get_tpr_eax
xchg %eax, %ecx
ret
mp_get_tpr_edx:
mov %eax, %edx
call mp_get_tpr_eax
xchg %eax, %edx
ret
mp_get_tpr_esi:
mov %eax, %esi
call mp_get_tpr_eax
xchg %eax, %esi
ret
mp_get_tpr_edi:
mov %eax, %edi
call mp_get_tpr_edi
xchg %eax, %edi
ret
mp_get_tpr_ebp:
mov %eax, %ebp
call mp_get_tpr_eax
xchg %eax, %ebp
ret
mp_get_tpr_stack:
call mp_get_tpr_eax
xchg %eax, 4(%esp)
ret
mp_set_tpr_eax:
push %eax
call mp_set_tpr
ret
mp_set_tpr:
pushf
push %eax
push %ecx
push %edx
push %ebx
cli
reenable_vtpr
mp_set_tpr_failed:
fs/movzbl pcr_cpu, %edx
mov vcpu_shift, %ecx ; fixup
shl %cl, %edx
testb $1, vapic+4(%edx) ; fixup delta=-5
jz mp_set_tpr_bad
mov vapic(%edx), %eax ; fixup
mov %eax, %ebx
mov 24(%esp), %bl
/* %ebx = new vapic (%bl = tpr, %bh = isr, %b3 = irr) */
lock cmpxchg %ebx, vapic(%edx) ; fixup
jnz mp_set_tpr_failed
/* compute ppr */
cmp %bh, %bl
jae mp_tpr_is_bigger
mp_isr_is_bigger:
mov %bh, %bl
mp_tpr_is_bigger:
/* %bl = ppr */
mov %bl, %ch /* ch = ppr */
rol $8, %ebx
/* now: %bl = irr, %bh = ppr */
cmp %bh, %bl
ja mp_set_tpr_poll_irq
mp_set_tpr_out:
pop %ebx
pop %edx
pop %ecx
pop %eax
popf
ret $4
mp_set_tpr_poll_irq:
mov $kvm_hypercall_vapic_poll_irq, %eax
kvm_hypercall
jmp mp_set_tpr_out
mp_set_tpr_bad:
mov 24(%esp), %ecx
mov real_tpr, %eax ; fixup
mov %ecx, (%eax)
jmp mp_set_tpr_out
up_get_tpr_eax:
reenable_vtpr
movzbl vapic, %eax ; fixup
ret
up_get_tpr_ebx:
reenable_vtpr
movzbl vapic, %ebx ; fixup
ret
up_get_tpr_ecx:
reenable_vtpr
movzbl vapic, %ecx ; fixup
ret
up_get_tpr_edx:
reenable_vtpr
movzbl vapic, %edx ; fixup
ret
up_get_tpr_esi:
reenable_vtpr
movzbl vapic, %esi ; fixup
ret
up_get_tpr_edi:
reenable_vtpr
movzbl vapic, %edi ; fixup
ret
up_get_tpr_ebp:
reenable_vtpr
movzbl vapic, %ebp ; fixup
ret
up_get_tpr_stack:
reenable_vtpr
movzbl vapic, %eax ; fixup
xchg %eax, 4(%esp)
ret
up_set_tpr_eax:
push %eax
call up_set_tpr
ret
up_set_tpr:
pushf
push %eax
push %ecx
push %ebx
reenable_vtpr
up_set_tpr_failed:
mov vapic, %eax ; fixup
mov %eax, %ebx
mov 20(%esp), %bl
/* %ebx = new vapic (%bl = tpr, %bh = isr, %b3 = irr) */
lock cmpxchg %ebx, vapic ; fixup
jnz up_set_tpr_failed
/* compute ppr */
cmp %bh, %bl
jae up_tpr_is_bigger
up_isr_is_bigger:
mov %bh, %bl
up_tpr_is_bigger:
/* %bl = ppr */
mov %bl, %ch /* ch = ppr */
rol $8, %ebx
/* now: %bl = irr, %bh = ppr */
cmp %bh, %bl
ja up_set_tpr_poll_irq
up_set_tpr_out:
pop %ebx
pop %ecx
pop %eax
popf
ret $4
up_set_tpr_poll_irq:
mov $kvm_hypercall_vapic_poll_irq, %eax
kvm_hypercall
jmp up_set_tpr_out
.text 1
fixup_end = .
.text 0
/*
* vapic format:
* per-vcpu records of size 2^vcpu shift.
* byte 0: tpr (r/w)
* byte 1: highest in-service interrupt (isr) (r/o); bits 3:0 are zero
* byte 2: zero (r/o)
* byte 3: highest pending interrupt (irr) (r/o)
*/
.text 2
.align 128
vapic:
. = . + vapic_size
.byte 0 # reserve space for signature
.align 512, 0
_end: