qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v3 5/9] kvmvapic: Add option ROM


From: Jan Kiszka
Subject: [Qemu-devel] [PATCH v3 5/9] kvmvapic: Add option ROM
Date: Tue, 14 Feb 2012 16:13:11 +0100

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 <address@hidden>
---
 .gitignore                   |    1 +
 Makefile                     |    2 +-
 pc-bios/optionrom/Makefile   |    2 +-
 pc-bios/optionrom/kvmvapic.S |  341 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 344 insertions(+), 2 deletions(-)
 create mode 100644 pc-bios/optionrom/kvmvapic.S

diff --git a/.gitignore b/.gitignore
index f5aab2c..d3b78c3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/Makefile b/Makefile
index 47acf3d..c2ef135 100644
--- a/Makefile
+++ b/Makefile
@@ -255,7 +255,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
diff --git a/pc-bios/optionrom/Makefile b/pc-bios/optionrom/Makefile
index 2caf7e6..f6b4027 100644
--- a/pc-bios/optionrom/Makefile
+++ b/pc-bios/optionrom/Makefile
@@ -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:
diff --git a/pc-bios/optionrom/kvmvapic.S b/pc-bios/optionrom/kvmvapic.S
new file mode 100644
index 0000000..e1d8f18
--- /dev/null
+++ b/pc-bios/optionrom/kvmvapic.S
@@ -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 <address@hidden>
+#
+# 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:
-- 
1.7.3.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]