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:
parent
d362e757d3
commit
2a2af967b0
1
.gitignore
vendored
1
.gitignore
vendored
@ -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
|
||||
|
2
Makefile
2
Makefile
@ -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
|
||||
|
@ -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:
|
||||
|
341
pc-bios/optionrom/kvmvapic.S
Normal file
341
pc-bios/optionrom/kvmvapic.S
Normal 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:
|
Loading…
Reference in New Issue
Block a user