This is the delta between the qemu and qemu-kvm v0.15.1 versions

Signed-off-by: Bruce Rogers <brogers@suse.com>
This commit is contained in:
Bruce Rogers
2018-02-09 11:12:05 -07:00
parent 82b2b32a32
commit 36f5bc4fdb
169 changed files with 32009 additions and 187 deletions

2
.gitignore vendored
View File

@@ -65,6 +65,8 @@ pc-bios/vgabios-pq/status
pc-bios/optionrom/linuxboot.bin pc-bios/optionrom/linuxboot.bin
pc-bios/optionrom/multiboot.bin pc-bios/optionrom/multiboot.bin
pc-bios/optionrom/multiboot.raw pc-bios/optionrom/multiboot.raw
pc-bios/optionrom/extboot.bin
pc-bios/optionrom/vapic.bin
.stgit-* .stgit-*
cscope.* cscope.*
tags tags

2
.gitmodules vendored
View File

@@ -1,6 +1,6 @@
[submodule "roms/vgabios"] [submodule "roms/vgabios"]
path = roms/vgabios path = roms/vgabios
url = git://git.qemu.org/vgabios.git/ url = git://git.kernel.org/pub/scm/virt/kvm/vgabios.git/
[submodule "roms/seabios"] [submodule "roms/seabios"]
path = roms/seabios path = roms/seabios
url = git://git.qemu.org/seabios.git/ url = git://git.qemu.org/seabios.git/

View File

@@ -246,6 +246,8 @@ mpc8544ds.dtb \
multiboot.bin linuxboot.bin \ multiboot.bin linuxboot.bin \
s390-zipl.rom \ s390-zipl.rom \
spapr-rtas.bin slof.bin spapr-rtas.bin slof.bin
BLOBS += extboot.bin
BLOBS += vapic.bin
else else
BLOBS= BLOBS=
endif endif
@@ -272,7 +274,12 @@ endif
ifneq ($(BLOBS),) ifneq ($(BLOBS),)
$(INSTALL_DIR) "$(DESTDIR)$(datadir)" $(INSTALL_DIR) "$(DESTDIR)$(datadir)"
set -e; for x in $(BLOBS); do \ set -e; for x in $(BLOBS); do \
if [ -f $(SRC_PATH)/pc-bios/$$x ];then \
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \ $(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
fi \
; if [ -f pc-bios/optionrom/$$x ];then \
$(INSTALL_DATA) pc-bios/optionrom/$$x "$(DESTDIR)$(datadir)"; \
fi \
done done
endif endif
$(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps" $(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
@@ -393,6 +400,7 @@ tarbin:
$(datadir)/pxe-pcnet.rom \ $(datadir)/pxe-pcnet.rom \
$(datadir)/pxe-rtl8139.rom \ $(datadir)/pxe-rtl8139.rom \
$(datadir)/pxe-virtio.rom \ $(datadir)/pxe-virtio.rom \
$(datadir)/extboot.bin \
$(docdir)/qemu-doc.html \ $(docdir)/qemu-doc.html \
$(docdir)/qemu-tech.html \ $(docdir)/qemu-tech.html \
$(mandir)/man1/qemu.1 \ $(mandir)/man1/qemu.1 \

View File

@@ -17,6 +17,7 @@ block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o async.
block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.o block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.o
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
block-obj-$(CONFIG_POSIX) += compatfd.o
block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o
block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o
@@ -145,7 +146,7 @@ common-obj-y += $(addprefix ui/, $(ui-obj-y))
common-obj-$(CONFIG_VNC) += $(addprefix ui/, $(vnc-obj-y)) common-obj-$(CONFIG_VNC) += $(addprefix ui/, $(vnc-obj-y))
common-obj-y += iov.o acl.o common-obj-y += iov.o acl.o
common-obj-$(CONFIG_POSIX) += compatfd.o #common-obj-$(CONFIG_POSIX) += compatfd.o
common-obj-y += notify.o event_notifier.o common-obj-y += notify.o event_notifier.o
common-obj-y += qemu-timer.o qemu-timer-common.o common-obj-y += qemu-timer.o qemu-timer-common.o
@@ -170,11 +171,11 @@ user-obj-y += cutils.o cache-utils.o
# libhw # libhw
hw-obj-y = hw-obj-y =
hw-obj-y += vl.o loader.o hw-obj-y += loader.o
hw-obj-$(CONFIG_VIRTIO) += virtio-console.o hw-obj-$(CONFIG_VIRTIO) += virtio-console.o
hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o hw-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
hw-obj-y += fw_cfg.o hw-obj-y += fw_cfg.o
hw-obj-$(CONFIG_PCI) += pci.o pci_bridge.o hw-obj-$(CONFIG_PCI) += pci_bridge.o
hw-obj-$(CONFIG_PCI) += msix.o msi.o hw-obj-$(CONFIG_PCI) += msix.o msi.o
hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o
@@ -191,14 +192,16 @@ hw-obj-$(CONFIG_EMPTY_SLOT) += empty_slot.o
hw-obj-$(CONFIG_SERIAL) += serial.o hw-obj-$(CONFIG_SERIAL) += serial.o
hw-obj-$(CONFIG_PARALLEL) += parallel.o hw-obj-$(CONFIG_PARALLEL) += parallel.o
hw-obj-$(CONFIG_I8254) += i8254.o # Moved back to Makefile.target due to #include qemu-kvm.h:
hw-obj-$(CONFIG_PCSPK) += pcspk.o #hw-obj-$(CONFIG_I8254) += i8254.o
#hw-obj-$(CONFIG_PCSPK) += pcspk.o
hw-obj-$(CONFIG_PCKBD) += pckbd.o hw-obj-$(CONFIG_PCKBD) += pckbd.o
hw-obj-$(CONFIG_USB_UHCI) += usb-uhci.o hw-obj-$(CONFIG_USB_UHCI) += usb-uhci.o
hw-obj-$(CONFIG_USB_OHCI) += usb-ohci.o hw-obj-$(CONFIG_USB_OHCI) += usb-ohci.o
hw-obj-$(CONFIG_USB_EHCI) += usb-ehci.o hw-obj-$(CONFIG_USB_EHCI) += usb-ehci.o
hw-obj-$(CONFIG_FDC) += fdc.o hw-obj-$(CONFIG_FDC) += fdc.o
hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o # needs fixes for cpu hotplug, so moved to Makefile.target:
# hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o
hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o
hw-obj-$(CONFIG_DMA) += dma.o hw-obj-$(CONFIG_DMA) += dma.o
hw-obj-$(CONFIG_HPET) += hpet.o hw-obj-$(CONFIG_HPET) += hpet.o

View File

@@ -71,14 +71,19 @@ all: $(PROGS) stap
######################################################### #########################################################
# cpu emulator library # cpu emulator library
libobj-y = exec.o translate-all.o cpu-exec.o translate.o libobj-y = exec.o cpu-exec.o
libobj-y += tcg/tcg.o libobj-$(CONFIG_NO_CPU_EMULATION) += fake-exec.o
libobj-$(CONFIG_CPU_EMULATION) += translate-all.o translate.o
libobj-$(CONFIG_CPU_EMULATION) += tcg/tcg.o
libobj-y += fpu/softfloat.o libobj-y += fpu/softfloat.o
libobj-y += op_helper.o helper.o libobj-y += op_helper.o helper.o
ifeq ($(TARGET_BASE_ARCH), i386) ifeq ($(TARGET_BASE_ARCH), i386)
libobj-y += cpuid.o libobj-y += cpuid.o
endif endif
libobj-$(CONFIG_NEED_MMU) += mmu.o libobj-$(CONFIG_NEED_MMU) += mmu.o
libobj-$(CONFIG_KVM) += kvm-tpr-opt.o
libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
libobj-y += disas.o libobj-y += disas.o
@@ -187,10 +192,11 @@ endif #CONFIG_BSD_USER
# System emulator target # System emulator target
ifdef CONFIG_SOFTMMU ifdef CONFIG_SOFTMMU
obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o vl.o balloon.o
# virtio has to be here due to weird dependency between PCI and virtio-net. # virtio has to be here due to weird dependency between PCI and virtio-net.
# need to fix this properly # need to fix this properly
obj-$(CONFIG_NO_PCI) += pci-stub.o obj-$(CONFIG_NO_PCI) += pci-stub.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
obj-y += vhost_net.o obj-y += vhost_net.o
obj-$(CONFIG_VHOST_NET) += vhost.o obj-$(CONFIG_VHOST_NET) += vhost.o
@@ -227,10 +233,24 @@ obj-i386-y += mc146818rtc.o i8259.o pc.o
obj-i386-y += cirrus_vga.o sga.o apic.o ioapic.o piix_pci.o obj-i386-y += cirrus_vga.o sga.o apic.o ioapic.o piix_pci.o
obj-i386-y += vmport.o obj-i386-y += vmport.o
obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
obj-i386-y += extboot.o
obj-i386-y += debugcon.o multiboot.o obj-i386-y += debugcon.o multiboot.o
obj-i386-y += pc_piix.o obj-i386-y += pc_piix.o
obj-i386-$(CONFIG_KVM) += kvmclock.o obj-i386-$(CONFIG_KVM) += kvmclock.o
obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
obj-i386-y += testdev.o
obj-i386-y += acpi.o acpi_piix4.o
obj-i386-y += pcspk.o i8254.o
obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
obj-i386-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o
# Hardware support
obj-ia64-y += ide.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
obj-ia64-y += fdc.o mc146818rtc.o serial.o i8259.o ipf.o
obj-ia64-y += cirrus_vga.o parallel.o acpi.o piix_pci.o
obj-ia64-y += usb-uhci.o
obj-ia64-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o
# shared objects # shared objects
obj-ppc-y = ppc.o obj-ppc-y = ppc.o
@@ -286,6 +306,8 @@ obj-lm32-y += milkymist-vgafb.o
obj-lm32-y += framebuffer.o obj-lm32-y += framebuffer.o
obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
obj-mips-y += pcspk.o i8254.o
obj-mips-y += acpi.o acpi_piix4.o
obj-mips-y += mips_addr.o mips_timer.o mips_int.o obj-mips-y += mips_addr.o mips_timer.o mips_int.o
obj-mips-y += vga.o i8259.o obj-mips-y += vga.o i8259.o
obj-mips-y += g364fb.o jazz_led.o obj-mips-y += g364fb.o jazz_led.o
@@ -372,6 +394,11 @@ obj-s390x-y = s390-virtio-bus.o s390-virtio.o
obj-alpha-y = i8259.o mc146818rtc.o obj-alpha-y = i8259.o mc146818rtc.o
obj-alpha-y += vga.o cirrus_vga.o obj-alpha-y += vga.o cirrus_vga.o
ifeq ($(TARGET_ARCH), ia64)
firmware.o: firmware.c
$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
endif
main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
monitor.o: hmp-commands.h qmp-commands.h monitor.o: hmp-commands.h qmp-commands.h

View File

@@ -17,6 +17,8 @@
#include "hw/qdev.h" #include "hw/qdev.h"
#include "block_int.h" #include "block_int.h"
DriveInfo *extboot_drive = NULL;
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives); static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
static const char *const if_name[IF_COUNT] = { static const char *const if_name[IF_COUNT] = {
@@ -236,6 +238,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
int on_read_error, on_write_error; int on_read_error, on_write_error;
const char *devaddr; const char *devaddr;
DriveInfo *dinfo; DriveInfo *dinfo;
int is_extboot = 0;
int snapshot = 0; int snapshot = 0;
int ret; int ret;
@@ -363,6 +366,12 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
} }
} }
is_extboot = qemu_opt_get_bool(opts, "boot", 0);
if (is_extboot && extboot_drive) {
fprintf(stderr, "qemu: two bootable drives specified\n");
return NULL;
}
on_write_error = BLOCK_ERR_STOP_ENOSPC; on_write_error = BLOCK_ERR_STOP_ENOSPC;
if ((buf = qemu_opt_get(opts, "werror")) != NULL) { if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) { if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO && type != IF_NONE) {
@@ -468,6 +477,10 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
strncpy(dinfo->serial, serial, sizeof(dinfo->serial) - 1); strncpy(dinfo->serial, serial, sizeof(dinfo->serial) - 1);
QTAILQ_INSERT_TAIL(&drives, dinfo, next); QTAILQ_INSERT_TAIL(&drives, dinfo, next);
if (is_extboot) {
extboot_drive = dinfo;
}
bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error); bdrv_set_on_error(dinfo->bdrv, on_read_error, on_write_error);
switch(type) { switch(type) {

View File

@@ -66,4 +66,6 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data); int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data); int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data);
extern DriveInfo *extboot_drive;
#endif #endif

View File

@@ -34,7 +34,28 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
asm volatile ("isync" : : : "memory"); asm volatile ("isync" : : : "memory");
} }
/*
* Is this correct for PPC?
*/
static inline void dma_flush_range(unsigned long start, unsigned long stop)
{
}
#elif defined(__ia64__)
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
while (start < stop) {
asm volatile ("fc %0" :: "r"(start));
start += 32;
}
asm volatile (";;sync.i;;srlz.i;;");
}
#define dma_flush_range(start, end) flush_icache_range(start, end)
#define qemu_cache_utils_init(envp) do { (void) (envp); } while (0)
#else #else
static inline void dma_flush_range(unsigned long start, unsigned long stop)
{
}
#define qemu_cache_utils_init(envp) do { (void) (envp); } while (0) #define qemu_cache_utils_init(envp) do { (void) (envp); } while (0)
#endif #endif

79
configure vendored
View File

@@ -93,7 +93,17 @@ audio_pt_int=""
audio_win_int="" audio_win_int=""
cc_i386=i386-pc-linux-gnu-gcc cc_i386=i386-pc-linux-gnu-gcc
target_list="" target_list="x86_64-softmmu"
kvm_version() {
local fname="$(dirname "$0")/KVM_VERSION"
if test -f "$fname"; then
cat "$fname"
else
echo "qemu-kvm-devel"
fi
}
# Default value for a variable defining feature "foo". # Default value for a variable defining feature "foo".
# * foo="no" feature will only be used if --enable-foo arg is given # * foo="no" feature will only be used if --enable-foo arg is given
@@ -163,11 +173,14 @@ darwin_user="no"
bsd_user="no" bsd_user="no"
guest_base="" guest_base=""
uname_release="" uname_release=""
io_thread="no" io_thread="yes"
mixemu="no" mixemu="no"
kvm_cap_pit="yes"
kvm_cap_device_assignment="yes"
aix="no" aix="no"
blobs="yes" blobs="yes"
pkgversion="" pkgversion=" ($(kvm_version))"
cpu_emulation="yes"
check_utests="no" check_utests="no"
user_pie="no" user_pie="no"
zero_malloc="" zero_malloc=""
@@ -465,6 +478,13 @@ Haiku)
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
audio_possible_drivers="$audio_possible_drivers fmod" audio_possible_drivers="$audio_possible_drivers fmod"
fi fi
if [ "$cpu" = "ia64" ] ; then
xen="no"
target_list="ia64-softmmu"
cpu_emulation="no"
gdbstub="no"
slirp="no"
fi
;; ;;
esac esac
@@ -641,6 +661,14 @@ for opt do
;; ;;
--enable-kvm) kvm="yes" --enable-kvm) kvm="yes"
;; ;;
--disable-kvm-pit) kvm_cap_pit="no"
;;
--enable-kvm-pit) kvm_cap_pit="yes"
;;
--disable-kvm-device-assignment) kvm_cap_device_assignment="no"
;;
--enable-kvm-device-assignment) kvm_cap_device_assignment="yes"
;;
--disable-spice) spice="no" --disable-spice) spice="no"
;; ;;
--enable-spice) spice="yes" --enable-spice) spice="yes"
@@ -730,6 +758,8 @@ for opt do
;; ;;
--enable-docs) docs="yes" --enable-docs) docs="yes"
;; ;;
--disable-cpu-emulation) cpu_emulation="no"
;;
--disable-vhost-net) vhost_net="no" --disable-vhost-net) vhost_net="no"
;; ;;
--enable-vhost-net) vhost_net="yes" --enable-vhost-net) vhost_net="yes"
@@ -989,6 +1019,10 @@ echo " --enable-bluez enable bluez stack connectivity"
echo " --disable-slirp disable SLIRP userspace network connectivity" echo " --disable-slirp disable SLIRP userspace network connectivity"
echo " --disable-kvm disable KVM acceleration support" echo " --disable-kvm disable KVM acceleration support"
echo " --enable-kvm enable KVM acceleration support" echo " --enable-kvm enable KVM acceleration support"
echo " --disable-kvm-pit disable KVM pit support"
echo " --enable-kvm-pit enable KVM pit support"
echo " --disable-kvm-device-assignment disable KVM device assignment support"
echo " --enable-kvm-device-assignment enable KVM device assignment support"
echo " --disable-nptl disable usermode NPTL support" echo " --disable-nptl disable usermode NPTL support"
echo " --enable-nptl enable usermode NPTL support" echo " --enable-nptl enable usermode NPTL support"
echo " --enable-system enable all system emulation targets" echo " --enable-system enable all system emulation targets"
@@ -1021,6 +1055,7 @@ echo " --disable-attr disables attr and xattr support"
echo " --enable-attr enable attr and xattr support" echo " --enable-attr enable attr and xattr support"
echo " --enable-io-thread enable IO thread" echo " --enable-io-thread enable IO thread"
echo " --disable-blobs disable installing provided firmware blobs" echo " --disable-blobs disable installing provided firmware blobs"
echo " --disable-cpu-emulation disables use of qemu cpu emulation code"
echo " --enable-docs enable documentation build" echo " --enable-docs enable documentation build"
echo " --disable-docs disable documentation build" echo " --disable-docs disable documentation build"
echo " --disable-vhost-net disable vhost-net acceleration support" echo " --disable-vhost-net disable vhost-net acceleration support"
@@ -1853,6 +1888,27 @@ if test "$guest_agent" != "no" ; then
fi fi
fi fi
##########################################
# libpci header probe for kvm_cap_device_assignment
if test $kvm_cap_device_assignment = "yes" ; then
cat > $TMPC << EOF
#include <pci/header.h>
#ifndef PCI_VENDOR_ID
#error NO LIBPCI HEADER
#endif
int main(void) { return 0; }
EOF
if compile_prog "" "" ; then
kvm_cap_device_assignment=yes
else
echo
echo "Error: libpci header check failed"
echo "Disable KVM Device Assignment capability."
echo
kvm_cap_device_assignment=no
fi
fi
########################################## ##########################################
# pthread probe # pthread probe
PTHREADLIBS_LIST="-pthread -lpthread -lpthreadGC2" PTHREADLIBS_LIST="-pthread -lpthread -lpthreadGC2"
@@ -2687,6 +2743,7 @@ if test -n "$sparc_cpu"; then
echo "Target Sparc Arch $sparc_cpu" echo "Target Sparc Arch $sparc_cpu"
fi fi
echo "xen support $xen" echo "xen support $xen"
echo "CPU emulation $cpu_emulation"
echo "brlapi support $brlapi" echo "brlapi support $brlapi"
echo "bluez support $bluez" echo "bluez support $bluez"
echo "Documentation $docs" echo "Documentation $docs"
@@ -2701,6 +2758,8 @@ echo "Linux AIO support $linux_aio"
echo "ATTR/XATTR support $attr" echo "ATTR/XATTR support $attr"
echo "Install blobs $blobs" echo "Install blobs $blobs"
echo "KVM support $kvm" echo "KVM support $kvm"
echo "KVM PIT support $kvm_cap_pit"
echo "KVM device assig. $kvm_cap_device_assignment"
echo "fdt support $fdt" echo "fdt support $fdt"
echo "preadv support $preadv" echo "preadv support $preadv"
echo "fdatasync $fdatasync" echo "fdatasync $fdatasync"
@@ -2992,6 +3051,11 @@ fi
if test "$fdatasync" = "yes" ; then if test "$fdatasync" = "yes" ; then
echo "CONFIG_FDATASYNC=y" >> $config_host_mak echo "CONFIG_FDATASYNC=y" >> $config_host_mak
fi fi
if test $cpu_emulation = "yes"; then
echo "CONFIG_CPU_EMULATION=y" >> $config_host_mak
else
echo "CONFIG_NO_CPU_EMULATION=y" >> $config_host_mak
fi
if test "$madvise" = "yes" ; then if test "$madvise" = "yes" ; then
echo "CONFIG_MADVISE=y" >> $config_host_mak echo "CONFIG_MADVISE=y" >> $config_host_mak
fi fi
@@ -3199,6 +3263,9 @@ case "$target_arch2" in
target_phys_bits=64 target_phys_bits=64
target_long_alignment=8 target_long_alignment=8
;; ;;
ia64)
target_phys_bits=64
;;
alpha) alpha)
target_phys_bits=64 target_phys_bits=64
target_long_alignment=8 target_long_alignment=8
@@ -3361,6 +3428,12 @@ case "$target_arch2" in
if test $vhost_net = "yes" ; then if test $vhost_net = "yes" ; then
echo "CONFIG_VHOST_NET=y" >> $config_target_mak echo "CONFIG_VHOST_NET=y" >> $config_target_mak
fi fi
if test $kvm_cap_pit = "yes" ; then
echo "CONFIG_KVM_PIT=y" >> $config_target_mak
fi
if test $kvm_cap_device_assignment = "yes" ; then
echo "CONFIG_KVM_DEVICE_ASSIGNMENT=y" >> $config_target_mak
fi
fi fi
esac esac
if test "$target_bigendian" = "yes" ; then if test "$target_bigendian" = "yes" ; then

View File

@@ -19,7 +19,9 @@
#include "config.h" #include "config.h"
#include "cpu.h" #include "cpu.h"
#include "disas.h" #include "disas.h"
#if !defined(TARGET_IA64)
#include "tcg.h" #include "tcg.h"
#endif
#include "qemu-barrier.h" #include "qemu-barrier.h"
int tb_invalidated_flag; int tb_invalidated_flag;
@@ -222,6 +224,7 @@ int cpu_exec(CPUState *env)
#elif defined(TARGET_SH4) #elif defined(TARGET_SH4)
#elif defined(TARGET_CRIS) #elif defined(TARGET_CRIS)
#elif defined(TARGET_S390X) #elif defined(TARGET_S390X)
#elif defined(TARGET_IA64)
/* XXXXX */ /* XXXXX */
#else #else
#error unsupported target CPU #error unsupported target CPU
@@ -613,6 +616,7 @@ int cpu_exec(CPUState *env)
#elif defined(TARGET_MICROBLAZE) #elif defined(TARGET_MICROBLAZE)
#elif defined(TARGET_MIPS) #elif defined(TARGET_MIPS)
#elif defined(TARGET_SH4) #elif defined(TARGET_SH4)
#elif defined(TARGET_IA64)
#elif defined(TARGET_ALPHA) #elif defined(TARGET_ALPHA)
#elif defined(TARGET_CRIS) #elif defined(TARGET_CRIS)
#elif defined(TARGET_S390X) #elif defined(TARGET_S390X)

5
cpus.c
View File

@@ -688,6 +688,11 @@ void qemu_main_loop_start(void)
qemu_cond_broadcast(&qemu_system_cond); qemu_cond_broadcast(&qemu_system_cond);
} }
bool qemu_system_is_ready(void)
{
return qemu_system_ready;
}
void run_on_cpu(CPUState *env, void (*func)(void *data), void *data) void run_on_cpu(CPUState *env, void (*func)(void *data), void *data)
{ {
struct qemu_work_item wi; struct qemu_work_item wi;

1
cpus.h
View File

@@ -7,6 +7,7 @@ void qemu_main_loop_start(void);
void resume_all_vcpus(void); void resume_all_vcpus(void);
void pause_all_vcpus(void); void pause_all_vcpus(void);
void cpu_stop_current(void); void cpu_stop_current(void);
bool qemu_system_is_ready(void);
void cpu_synchronize_all_states(void); void cpu_synchronize_all_states(void);
void cpu_synchronize_all_post_reset(void); void cpu_synchronize_all_post_reset(void);

21
exec.c
View File

@@ -26,7 +26,12 @@
#include "qemu-common.h" #include "qemu-common.h"
#include "cpu.h" #include "cpu.h"
#include "cache-utils.h"
#if !defined(TARGET_IA64)
#include "tcg.h" #include "tcg.h"
#endif
#include "hw/hw.h" #include "hw/hw.h"
#include "hw/qdev.h" #include "hw/qdev.h"
#include "osdep.h" #include "osdep.h"
@@ -461,6 +466,9 @@ static uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE]
static void code_gen_alloc(unsigned long tb_size) static void code_gen_alloc(unsigned long tb_size)
{ {
if (kvm_enabled())
return;
#ifdef USE_STATIC_CODE_GEN_BUFFER #ifdef USE_STATIC_CODE_GEN_BUFFER
code_gen_buffer = static_code_gen_buffer; code_gen_buffer = static_code_gen_buffer;
code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE; code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
@@ -3910,6 +3918,11 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
cpu_physical_memory_set_dirty_flags( cpu_physical_memory_set_dirty_flags(
addr1, (0xff & ~CODE_DIRTY_FLAG)); addr1, (0xff & ~CODE_DIRTY_FLAG));
} }
/* qemu doesn't execute guest code directly, but kvm does
therefore flush instruction caches */
if (kvm_enabled())
flush_icache_range((unsigned long)ptr,
((unsigned long)ptr)+l);
qemu_put_ram_ptr(ptr); qemu_put_ram_ptr(ptr);
} }
} else { } else {
@@ -4103,6 +4116,8 @@ void *cpu_physical_memory_map(target_phys_addr_t addr,
void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len, void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
int is_write, target_phys_addr_t access_len) int is_write, target_phys_addr_t access_len)
{ {
unsigned long flush_len = (unsigned long)access_len;
if (buffer != bounce.buffer) { if (buffer != bounce.buffer) {
if (is_write) { if (is_write) {
ram_addr_t addr1 = qemu_ram_addr_from_host_nofail(buffer); ram_addr_t addr1 = qemu_ram_addr_from_host_nofail(buffer);
@@ -4120,7 +4135,9 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
} }
addr1 += l; addr1 += l;
access_len -= l; access_len -= l;
} }
dma_flush_range((unsigned long)buffer,
(unsigned long)buffer + flush_len);
} }
if (xen_enabled()) { if (xen_enabled()) {
xen_invalidate_map_cache_entry(buffer); xen_invalidate_map_cache_entry(buffer);
@@ -4723,7 +4740,9 @@ void dump_exec_info(FILE *f, fprintf_function cpu_fprintf)
cpu_fprintf(f, "TB flush count %d\n", tb_flush_count); cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count); cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count); cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
#ifdef CONFIG_PROFILER
tcg_dump_info(f, cpu_fprintf); tcg_dump_info(f, cpu_fprintf);
#endif
} }
#define MMUSUFFIX _cmmu #define MMUSUFFIX _cmmu

View File

@@ -1213,6 +1213,19 @@ STEXI
@item block_passwd @var{device} @var{password} @item block_passwd @var{device} @var{password}
@findex block_passwd @findex block_passwd
Set the encrypted device @var{device} password to @var{password} Set the encrypted device @var{device} password to @var{password}
ETEXI
{
.name = "cpu_set",
.args_type = "cpu:i,state:s",
.params = "cpu [online|offline]",
.help = "change cpu state",
.mhandler.cmd = do_cpu_set_nr,
},
STEXI
@item cpu_set @var{cpu} [online|offline]
Set CPU @var{cpu} online or offline.
ETEXI ETEXI
{ {

View File

@@ -36,13 +36,19 @@
#define ACPI_DBG_IO_ADDR 0xb044 #define ACPI_DBG_IO_ADDR 0xb044
#define GPE_BASE 0xafe0 #define GPE_BASE 0xafe0
#define PROC_BASE 0xaf00
#define GPE_LEN 4 #define GPE_LEN 4
#define PCI_BASE 0xae00 #define PCI_BASE 0xae00
#define PCI_EJ_BASE 0xae08 #define PCI_EJ_BASE 0xae08
#define PCI_RMV_BASE 0xae0c #define PCI_RMV_BASE 0xae0c
#define PIIX4_CPU_HOTPLUG_STATUS 4
#define PIIX4_PCI_HOTPLUG_STATUS 2 #define PIIX4_PCI_HOTPLUG_STATUS 2
struct gpe_regs {
uint8_t cpus_sts[32];
};
struct pci_status { struct pci_status {
uint32_t up; uint32_t up;
uint32_t down; uint32_t down;
@@ -68,6 +74,7 @@ typedef struct PIIX4PMState {
/* for pci hotplug */ /* for pci hotplug */
ACPIGPE gpe; ACPIGPE gpe;
struct gpe_regs gpe_cpu;
struct pci_status pci0_status; struct pci_status pci0_status;
uint32_t pci0_hotplug_enable; uint32_t pci0_hotplug_enable;
} PIIX4PMState; } PIIX4PMState;
@@ -216,10 +223,9 @@ static int vmstate_acpi_post_load(void *opaque, int version_id)
{ \ { \
.name = (stringify(_field)), \ .name = (stringify(_field)), \
.version_id = 0, \ .version_id = 0, \
.num = GPE_LEN, \
.info = &vmstate_info_uint16, \ .info = &vmstate_info_uint16, \
.size = sizeof(uint16_t), \ .size = sizeof(uint16_t), \
.flags = VMS_ARRAY | VMS_POINTER, \ .flags = VMS_SINGLE | VMS_POINTER, \
.offset = vmstate_offset_pointer(_state, _field, uint8_t), \ .offset = vmstate_offset_pointer(_state, _field, uint8_t), \
} }
@@ -326,11 +332,16 @@ static void piix4_pm_machine_ready(Notifier *n, void *opaque)
} }
static PIIX4PMState *global_piix4_pm_state; /* cpu hotadd */
static int piix4_pm_initfn(PCIDevice *dev) static int piix4_pm_initfn(PCIDevice *dev)
{ {
PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, dev); PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, dev);
uint8_t *pci_conf; uint8_t *pci_conf;
/* for cpu hotadd */
global_piix4_pm_state = s;
pci_conf = s->dev.config; pci_conf = s->dev.config;
pci_conf[0x06] = 0x80; pci_conf[0x06] = 0x80;
pci_conf[0x07] = 0x02; pci_conf[0x07] = 0x02;
@@ -339,6 +350,13 @@ static int piix4_pm_initfn(PCIDevice *dev)
pci_conf[0x40] = 0x01; /* PM io base read only bit */ pci_conf[0x40] = 0x01; /* PM io base read only bit */
#if defined(TARGET_IA64)
pci_conf[0x40] = 0x41; /* PM io base read only bit */
pci_conf[0x41] = 0x1f;
pm_write_config(s, 0x80, 0x01, 1); /*Set default pm_io_base 0x1f40*/
s->pmcntrl = SCI_EN;
#endif
/* APM */ /* APM */
apm_init(&s->apm, apm_ctrl_changed, s); apm_init(&s->apm, apm_ctrl_changed, s);
@@ -422,7 +440,16 @@ device_init(piix4_pm_register);
static uint32_t gpe_readb(void *opaque, uint32_t addr) static uint32_t gpe_readb(void *opaque, uint32_t addr)
{ {
PIIX4PMState *s = opaque; PIIX4PMState *s = opaque;
uint32_t val = acpi_gpe_ioport_readb(&s->gpe, addr); uint32_t val = 0;
struct gpe_regs *g = &s->gpe_cpu;
switch (addr) {
case PROC_BASE ... PROC_BASE+31:
val = g->cpus_sts[addr - PROC_BASE];
break;
default:
val = acpi_gpe_ioport_readb(&s->gpe, addr);
}
PIIX4_DPRINTF("gpe read %x == %x\n", addr, val); PIIX4_DPRINTF("gpe read %x == %x\n", addr, val);
return val; return val;
@@ -510,17 +537,28 @@ static void pcirmv_write(void *opaque, uint32_t addr, uint32_t val)
return; return;
} }
extern const char *global_cpu_model;
static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev,
PCIHotplugState state); PCIHotplugState state);
static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s) static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
{ {
struct pci_status *pci0_status = &s->pci0_status; struct pci_status *pci0_status = &s->pci0_status;
int i = 0, cpus = smp_cpus;
while (cpus > 0) {
s->gpe_cpu.cpus_sts[i++] = (cpus < 8) ? (1 << cpus) - 1 : 0xff;
cpus -= 8;
}
register_ioport_write(GPE_BASE, GPE_LEN, 1, gpe_writeb, s); register_ioport_write(GPE_BASE, GPE_LEN, 1, gpe_writeb, s);
register_ioport_read(GPE_BASE, GPE_LEN, 1, gpe_readb, s); register_ioport_read(GPE_BASE, GPE_LEN, 1, gpe_readb, s);
acpi_gpe_blk(&s->gpe, GPE_BASE); acpi_gpe_blk(&s->gpe, GPE_BASE);
register_ioport_write(PROC_BASE, 32, 1, gpe_writeb, s);
register_ioport_read(PROC_BASE, 32, 1, gpe_readb, s);
register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status); register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, pci0_status);
register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, pci0_status); register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, pci0_status);
@@ -533,6 +571,48 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev); pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
} }
#if defined(TARGET_I386)
static void enable_processor(PIIX4PMState *s, int cpu)
{
struct gpe_regs *g = &s->gpe_cpu;
ACPIGPE *gpe = &s->gpe;
*gpe->sts = *gpe->sts | PIIX4_CPU_HOTPLUG_STATUS;
g->cpus_sts[cpu/8] |= (1 << (cpu%8));
}
static void disable_processor(PIIX4PMState *s, int cpu)
{
struct gpe_regs *g = &s->gpe_cpu;
ACPIGPE *gpe = &s->gpe;
*gpe->sts = *gpe->sts | PIIX4_CPU_HOTPLUG_STATUS;
g->cpus_sts[cpu/8] &= ~(1 << (cpu%8));
}
void qemu_system_cpu_hot_add(int cpu, int state)
{
CPUState *env;
PIIX4PMState *s = global_piix4_pm_state;
if (state && !qemu_get_cpu(cpu)) {
env = pc_new_cpu(global_cpu_model);
if (!env) {
fprintf(stderr, "cpu %d creation failed\n", cpu);
return;
}
env->cpuid_apic_id = cpu;
}
if (state)
enable_processor(s, cpu);
else
disable_processor(s, cpu);
pm_update_sci(s);
}
#endif
static void enable_device(PIIX4PMState *s, int slot) static void enable_device(PIIX4PMState *s, int slot)
{ {
s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS; s->gpe.sts[0] |= PIIX4_PCI_HOTPLUG_STATUS;

120
hw/apic.c
View File

@@ -23,6 +23,7 @@
#include "host-utils.h" #include "host-utils.h"
#include "sysbus.h" #include "sysbus.h"
#include "trace.h" #include "trace.h"
#include "kvm.h"
/* APIC Local Vector Table */ /* APIC Local Vector Table */
#define APIC_LVT_TIMER 0 #define APIC_LVT_TIMER 0
@@ -302,8 +303,11 @@ void cpu_set_apic_base(DeviceState *d, uint64_t val)
if (!s) if (!s)
return; return;
s->apicbase = (val & 0xfffff000) | if (kvm_enabled() && kvm_irqchip_in_kernel())
(s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE)); s->apicbase = val;
else
s->apicbase = (val & 0xfffff000) |
(s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
/* if disabled, cannot be enabled again */ /* if disabled, cannot be enabled again */
if (!(val & MSR_IA32_APICBASE_ENABLE)) { if (!(val & MSR_IA32_APICBASE_ENABLE)) {
s->apicbase &= ~MSR_IA32_APICBASE_ENABLE; s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
@@ -418,6 +422,11 @@ int apic_get_irq_delivered(void)
return apic_irq_delivered; return apic_irq_delivered;
} }
void apic_set_irq_delivered(void)
{
apic_irq_delivered = 1;
}
static void apic_set_irq(APICState *s, int vector_num, int trigger_mode) static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
{ {
apic_irq_delivered += !get_bit(s->irr, vector_num); apic_irq_delivered += !get_bit(s->irr, vector_num);
@@ -889,6 +898,113 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
} }
} }
#ifdef KVM_CAP_IRQCHIP
static inline uint32_t kapic_reg(struct kvm_lapic_state *kapic, int reg_id)
{
return *((uint32_t *) (kapic->regs + (reg_id << 4)));
}
static inline void kapic_set_reg(struct kvm_lapic_state *kapic,
int reg_id, uint32_t val)
{
*((uint32_t *) (kapic->regs + (reg_id << 4))) = val;
}
static void kvm_kernel_lapic_save_to_user(APICState *s)
{
struct kvm_lapic_state apic;
struct kvm_lapic_state *kapic = &apic;
int i, v;
kvm_get_lapic(s->cpu_env, kapic);
s->id = kapic_reg(kapic, 0x2) >> 24;
s->tpr = kapic_reg(kapic, 0x8);
s->arb_id = kapic_reg(kapic, 0x9);
s->log_dest = kapic_reg(kapic, 0xd) >> 24;
s->dest_mode = kapic_reg(kapic, 0xe) >> 28;
s->spurious_vec = kapic_reg(kapic, 0xf);
for (i = 0; i < 8; i++) {
s->isr[i] = kapic_reg(kapic, 0x10 + i);
s->tmr[i] = kapic_reg(kapic, 0x18 + i);
s->irr[i] = kapic_reg(kapic, 0x20 + i);
}
s->esr = kapic_reg(kapic, 0x28);
s->icr[0] = kapic_reg(kapic, 0x30);
s->icr[1] = kapic_reg(kapic, 0x31);
for (i = 0; i < APIC_LVT_NB; i++)
s->lvt[i] = kapic_reg(kapic, 0x32 + i);
s->initial_count = kapic_reg(kapic, 0x38);
s->divide_conf = kapic_reg(kapic, 0x3e);
v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
s->count_shift = (v + 1) & 7;
s->initial_count_load_time = qemu_get_clock_ns(vm_clock);
apic_timer_update(s, s->initial_count_load_time);
}
static void kvm_kernel_lapic_load_from_user(APICState *s)
{
struct kvm_lapic_state apic;
struct kvm_lapic_state *klapic = &apic;
int i;
memset(klapic, 0, sizeof apic);
kapic_set_reg(klapic, 0x2, s->id << 24);
kapic_set_reg(klapic, 0x8, s->tpr);
kapic_set_reg(klapic, 0xd, s->log_dest << 24);
kapic_set_reg(klapic, 0xe, s->dest_mode << 28 | 0x0fffffff);
kapic_set_reg(klapic, 0xf, s->spurious_vec);
for (i = 0; i < 8; i++) {
kapic_set_reg(klapic, 0x10 + i, s->isr[i]);
kapic_set_reg(klapic, 0x18 + i, s->tmr[i]);
kapic_set_reg(klapic, 0x20 + i, s->irr[i]);
}
kapic_set_reg(klapic, 0x28, s->esr);
kapic_set_reg(klapic, 0x30, s->icr[0]);
kapic_set_reg(klapic, 0x31, s->icr[1]);
for (i = 0; i < APIC_LVT_NB; i++)
kapic_set_reg(klapic, 0x32 + i, s->lvt[i]);
kapic_set_reg(klapic, 0x38, s->initial_count);
kapic_set_reg(klapic, 0x3e, s->divide_conf);
kvm_set_lapic(s->cpu_env, klapic);
}
#endif
void kvm_load_lapic(CPUState *env)
{
#ifdef KVM_CAP_IRQCHIP
APICState *s = DO_UPCAST(APICState, busdev.qdev, env->apic_state);
if (!s) {
return;
}
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_lapic_load_from_user(s);
}
#endif
}
void kvm_save_lapic(CPUState *env)
{
#ifdef KVM_CAP_IRQCHIP
APICState *s = DO_UPCAST(APICState, busdev.qdev, env->apic_state);
if (!s) {
return;
}
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_lapic_save_to_user(s);
}
#endif
}
/* This function is only used for old state version 1 and 2 */ /* This function is only used for old state version 1 and 2 */
static int apic_load_old(QEMUFile *f, void *opaque, int version_id) static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
{ {

View File

@@ -13,6 +13,7 @@ void apic_deliver_pic_intr(DeviceState *s, int level);
int apic_get_interrupt(DeviceState *s); int apic_get_interrupt(DeviceState *s);
void apic_reset_irq_delivered(void); void apic_reset_irq_delivered(void);
int apic_get_irq_delivered(void); int apic_get_irq_delivered(void);
void apic_set_irq_delivered(void);
void cpu_set_apic_base(DeviceState *s, uint64_t val); void cpu_set_apic_base(DeviceState *s, uint64_t val);
uint64_t cpu_get_apic_base(DeviceState *s); uint64_t cpu_get_apic_base(DeviceState *s);
void cpu_set_apic_tpr(DeviceState *s, uint8_t val); void cpu_set_apic_tpr(DeviceState *s, uint8_t val);

View File

@@ -2497,6 +2497,7 @@ static void map_linear_vram(CirrusVGAState *s)
if (!s->vga.map_addr) if (!s->vga.map_addr)
return; return;
#ifndef TARGET_IA64
s->vga.lfb_vram_mapped = 0; s->vga.lfb_vram_mapped = 0;
if (!(s->cirrus_srcptr != s->cirrus_srcptr_end) if (!(s->cirrus_srcptr != s->cirrus_srcptr_end)
@@ -2519,6 +2520,7 @@ static void map_linear_vram(CirrusVGAState *s)
cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000, cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
s->vga.vga_io_memory); s->vga.vga_io_memory);
} }
#endif
vga_dirty_log_start(&s->vga); vga_dirty_log_start(&s->vga);
} }

1909
hw/device-assignment.c Normal file

File diff suppressed because it is too large Load Diff

120
hw/device-assignment.h Normal file
View File

@@ -0,0 +1,120 @@
/*
* Copyright (c) 2007, Neocleus Corporation.
* Copyright (c) 2007, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*
* Data structures for storing PCI state
*
* Adapted to kvm by Qumranet
*
* Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com)
* Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com)
* Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com)
* Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com)
*/
#ifndef __DEVICE_ASSIGNMENT_H__
#define __DEVICE_ASSIGNMENT_H__
#include <sys/mman.h>
#include "qemu-common.h"
#include "qemu-queue.h"
#include "pci.h"
/* From include/linux/pci.h in the kernel sources */
#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
typedef struct PCIHostDevice {
int seg;
int bus;
int dev;
int func;
} PCIHostDevice;
typedef struct {
int type; /* Memory or port I/O */
int valid;
uint32_t base_addr;
uint32_t size; /* size of the region */
int resource_fd;
} PCIRegion;
typedef struct {
uint8_t bus, dev, func; /* Bus inside domain, device and function */
int irq; /* IRQ number */
uint16_t region_number; /* number of active regions */
/* Port I/O or MMIO Regions */
PCIRegion regions[PCI_NUM_REGIONS - 1];
int config_fd;
} PCIDevRegions;
typedef struct {
pcibus_t e_physbase;
ram_addr_t memory_index;
union {
void *r_virtbase; /* mmapped access address for memory regions */
uint32_t r_baseport; /* the base guest port for I/O regions */
} u;
int num; /* our index within v_addrs[] */
pcibus_t e_size; /* emulated size of region in bytes */
pcibus_t r_size; /* real size of region in bytes */
PCIRegion *region;
} AssignedDevRegion;
#define ASSIGNED_DEVICE_USE_IOMMU_BIT 0
#define ASSIGNED_DEVICE_PREFER_MSI_BIT 1
#define ASSIGNED_DEVICE_USE_IOMMU_MASK (1 << ASSIGNED_DEVICE_USE_IOMMU_BIT)
#define ASSIGNED_DEVICE_PREFER_MSI_MASK (1 << ASSIGNED_DEVICE_PREFER_MSI_BIT)
typedef struct AssignedDevice {
PCIDevice dev;
PCIHostDevice host;
uint32_t features;
int intpin;
uint8_t debug_flags;
AssignedDevRegion v_addrs[PCI_NUM_REGIONS - 1];
PCIDevRegions real_device;
int run;
int girq;
unsigned int h_segnr;
unsigned char h_busnr;
unsigned int h_devfn;
int irq_requested_type;
int bound;
struct {
#define ASSIGNED_DEVICE_CAP_MSI (1 << 0)
#define ASSIGNED_DEVICE_CAP_MSIX (1 << 1)
uint32_t available;
#define ASSIGNED_DEVICE_MSI_ENABLED (1 << 0)
#define ASSIGNED_DEVICE_MSIX_ENABLED (1 << 1)
#define ASSIGNED_DEVICE_MSIX_MASKED (1 << 2)
uint32_t state;
} cap;
int irq_entries_nr;
struct kvm_irq_routing_entry *entry;
void *msix_table_page;
target_phys_addr_t msix_table_addr;
int mmio_index;
uint32_t emulate_cmd_mask;
char *configfd_name;
int32_t bootindex;
QLIST_ENTRY(AssignedDevice) next;
} AssignedDevice;
void assigned_dev_update_irqs(void);
#endif /* __DEVICE_ASSIGNMENT_H__ */

123
hw/extboot.c Normal file
View File

@@ -0,0 +1,123 @@
/*
* Extended boot option ROM support.
*
* Copyright IBM, Corp. 2007
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2. See
* the COPYING file in the top-level directory.
*
*/
#include "hw.h"
#include "pc.h"
#include "isa.h"
#include "block.h"
/* Extended Boot ROM suport */
union extboot_cmd
{
uint16_t type;
struct {
uint16_t type;
uint16_t cylinders;
uint16_t heads;
uint16_t sectors;
uint64_t nb_sectors;
} query_geometry;
struct {
uint16_t type;
uint16_t nb_sectors;
uint16_t segment;
uint16_t offset;
uint64_t sector;
} xfer;
};
static void get_translated_chs(BlockDriverState *bs, int *c, int *h, int *s)
{
bdrv_get_geometry_hint(bs, c, h, s);
if (*c <= 1024) {
*c >>= 0;
*h <<= 0;
} else if (*c <= 2048) {
*c >>= 1;
*h <<= 1;
} else if (*c <= 4096) {
*c >>= 2;
*h <<= 2;
} else if (*c <= 8192) {
*c >>= 3;
*h <<= 3;
} else {
*c >>= 4;
*h <<= 4;
}
/* what is the correct algorithm for this?? */
if (*h == 256) {
*h = 255;
*c = *c + 1;
}
}
static void extboot_write_cmd(void *opaque, uint32_t addr, uint32_t value)
{
union extboot_cmd cmd;
BlockDriverState *bs = opaque;
int cylinders, heads, sectors, err;
uint64_t nb_sectors;
target_phys_addr_t pa = 0;
int blen = 0;
void *buf = NULL;
cpu_physical_memory_read((value & 0xFFFF) << 4, (uint8_t *)&cmd,
sizeof(cmd));
if (cmd.type == 0x01 || cmd.type == 0x02) {
pa = cmd.xfer.segment * 16 + cmd.xfer.offset;
blen = cmd.xfer.nb_sectors * 512;
buf = qemu_memalign(512, blen);
}
switch (cmd.type) {
case 0x00:
get_translated_chs(bs, &cylinders, &heads, &sectors);
bdrv_get_geometry(bs, &nb_sectors);
cmd.query_geometry.cylinders = cylinders;
cmd.query_geometry.heads = heads;
cmd.query_geometry.sectors = sectors;
cmd.query_geometry.nb_sectors = nb_sectors;
break;
case 0x01:
err = bdrv_read(bs, cmd.xfer.sector, buf, cmd.xfer.nb_sectors);
if (err)
printf("Read failed\n");
cpu_physical_memory_write(pa, buf, blen);
break;
case 0x02:
cpu_physical_memory_read(pa, buf, blen);
err = bdrv_write(bs, cmd.xfer.sector, buf, cmd.xfer.nb_sectors);
if (err)
printf("Write failed\n");
break;
}
cpu_physical_memory_write((value & 0xFFFF) << 4, (uint8_t *)&cmd,
sizeof(cmd));
if (buf)
qemu_free(buf);
}
void extboot_init(BlockDriverState *bs)
{
register_ioport_write(0x405, 1, 2, extboot_write_cmd, bs);
}

View File

@@ -236,6 +236,11 @@ static int hpet_post_load(void *opaque, int version_id)
if (s->timer[0].config & HPET_TN_FSB_CAP) { if (s->timer[0].config & HPET_TN_FSB_CAP) {
s->flags |= 1 << HPET_MSI_SUPPORT; s->flags |= 1 << HPET_MSI_SUPPORT;
} }
if (hpet_in_legacy_mode(s)) {
hpet_pit_disable();
}
return 0; return 0;
} }

115
hw/i8254-kvm.c Normal file
View File

@@ -0,0 +1,115 @@
/*
* QEMU 8253/8254 interval timer emulation
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "hw.h"
#include "pc.h"
#include "isa.h"
#include "qemu-timer.h"
#include "i8254.h"
#include "qemu-kvm.h"
extern VMStateDescription vmstate_pit;
static void kvm_pit_pre_save(void *opaque)
{
PITState *s = (void *)opaque;
struct kvm_pit_state2 pit2;
struct kvm_pit_channel_state *c;
struct PITChannelState *sc;
int i;
if (kvm_has_pit_state2()) {
kvm_get_pit2(kvm_state, &pit2);
s->flags = pit2.flags;
} else {
/* pit2 is superset of pit struct so just cast it and use it */
kvm_get_pit(kvm_state, (struct kvm_pit_state *)&pit2);
}
for (i = 0; i < 3; i++) {
c = &pit2.channels[i];
sc = &s->channels[i];
sc->count = c->count;
sc->latched_count = c->latched_count;
sc->count_latched = c->count_latched;
sc->status_latched = c->status_latched;
sc->status = c->status;
sc->read_state = c->read_state;
sc->write_state = c->write_state;
sc->write_latch = c->write_latch;
sc->rw_mode = c->rw_mode;
sc->mode = c->mode;
sc->bcd = c->bcd;
sc->gate = c->gate;
sc->count_load_time = c->count_load_time;
}
}
static int kvm_pit_post_load(void *opaque, int version_id)
{
PITState *s = opaque;
struct kvm_pit_state2 pit2;
struct kvm_pit_channel_state *c;
struct PITChannelState *sc;
int i;
pit2.flags = s->flags;
for (i = 0; i < 3; i++) {
c = &pit2.channels[i];
sc = &s->channels[i];
c->count = sc->count;
c->latched_count = sc->latched_count;
c->count_latched = sc->count_latched;
c->status_latched = sc->status_latched;
c->status = sc->status;
c->read_state = sc->read_state;
c->write_state = sc->write_state;
c->write_latch = sc->write_latch;
c->rw_mode = sc->rw_mode;
c->mode = sc->mode;
c->bcd = sc->bcd;
c->gate = sc->gate;
c->count_load_time = sc->count_load_time;
}
if (kvm_has_pit_state2()) {
kvm_set_pit2(kvm_state, &pit2);
} else {
kvm_set_pit(kvm_state, (struct kvm_pit_state *)&pit2);
}
return 0;
}
static void dummy_timer(void *opaque)
{
}
void kvm_pit_init(PITState *pit)
{
PITChannelState *s;
s = &pit->channels[0];
s->irq_timer = qemu_new_timer_ns(vm_clock, dummy_timer, s);
vmstate_pit.pre_save = kvm_pit_pre_save;
vmstate_pit.post_load = kvm_pit_post_load;
return;
}

View File

@@ -25,41 +25,11 @@
#include "pc.h" #include "pc.h"
#include "isa.h" #include "isa.h"
#include "qemu-timer.h" #include "qemu-timer.h"
#include "kvm.h"
#include "i8254.h"
//#define DEBUG_PIT //#define DEBUG_PIT
#define RW_STATE_LSB 1
#define RW_STATE_MSB 2
#define RW_STATE_WORD0 3
#define RW_STATE_WORD1 4
typedef struct PITChannelState {
int count; /* can be 65536 */
uint16_t latched_count;
uint8_t count_latched;
uint8_t status_latched;
uint8_t status;
uint8_t read_state;
uint8_t write_state;
uint8_t write_latch;
uint8_t rw_mode;
uint8_t mode;
uint8_t bcd; /* not supported */
uint8_t gate; /* timer start */
int64_t count_load_time;
/* irq handling */
int64_t next_transition_time;
QEMUTimer *irq_timer;
qemu_irq irq;
} PITChannelState;
typedef struct PITState {
ISADevice dev;
uint32_t irq;
uint32_t iobase;
PITChannelState channels[3];
} PITState;
static PITState pit_state; static PITState pit_state;
static void pit_irq_timer_update(PITChannelState *s, int64_t current_time); static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
@@ -236,13 +206,18 @@ int pit_get_mode(ISADevice *dev, int channel)
return s->mode; return s->mode;
} }
static inline void pit_load_count(PITChannelState *s, int val) static inline void pit_load_count(PITState *s, int val, int chan)
{ {
if (val == 0) if (val == 0)
val = 0x10000; val = 0x10000;
s->count_load_time = qemu_get_clock_ns(vm_clock); s->channels[chan].count_load_time = qemu_get_clock_ns(vm_clock);
s->count = val; s->channels[chan].count = val;
pit_irq_timer_update(s, s->count_load_time); #ifdef TARGET_I386
if (chan == 0 && pit_state.flags & PIT_FLAGS_HPET_LEGACY) {
return;
}
#endif
pit_irq_timer_update(&s->channels[chan], s->channels[chan].count_load_time);
} }
/* if already latched, do not latch again */ /* if already latched, do not latch again */
@@ -302,17 +277,17 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
switch(s->write_state) { switch(s->write_state) {
default: default:
case RW_STATE_LSB: case RW_STATE_LSB:
pit_load_count(s, val); pit_load_count(pit, val, addr);
break; break;
case RW_STATE_MSB: case RW_STATE_MSB:
pit_load_count(s, val << 8); pit_load_count(pit, val << 8, addr);
break; break;
case RW_STATE_WORD0: case RW_STATE_WORD0:
s->write_latch = val; s->write_latch = val;
s->write_state = RW_STATE_WORD1; s->write_state = RW_STATE_WORD1;
break; break;
case RW_STATE_WORD1: case RW_STATE_WORD1:
pit_load_count(s, s->write_latch | (val << 8)); pit_load_count(pit, s->write_latch | (val << 8), addr);
s->write_state = RW_STATE_WORD0; s->write_state = RW_STATE_WORD0;
break; break;
} }
@@ -372,6 +347,11 @@ static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
return ret; return ret;
} }
/* global counters for time-drift fix */
int64_t timer_acks=0, timer_interrupts=0, timer_ints_to_push=0;
extern int time_drift_fix;
static void pit_irq_timer_update(PITChannelState *s, int64_t current_time) static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
{ {
int64_t expire_time; int64_t expire_time;
@@ -382,16 +362,35 @@ static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
expire_time = pit_get_next_transition_time(s, current_time); expire_time = pit_get_next_transition_time(s, current_time);
irq_level = pit_get_out1(s, current_time); irq_level = pit_get_out1(s, current_time);
qemu_set_irq(s->irq, irq_level); qemu_set_irq(s->irq, irq_level);
if (time_drift_fix && irq_level==1) {
/* FIXME: fine tune timer_max_fix (max fix per tick).
* Should it be 1 (double time), 2 , 4, 10 ?
* Currently setting it to 5% of PIT-ticks-per-second (per PIT-tick)
*/
const long pit_ticks_per_sec = (s->count>0) ? (PIT_FREQ/s->count) : 0;
const long timer_max_fix = pit_ticks_per_sec/20;
const long delta = timer_interrupts - timer_acks;
const long max_delta = pit_ticks_per_sec * 60; /* one minute */
if ((delta > max_delta) && (pit_ticks_per_sec > 0)) {
printf("time drift is too long, %ld seconds were lost\n", delta/pit_ticks_per_sec);
timer_acks = timer_interrupts;
timer_ints_to_push = 0;
} else if (delta > 0) {
timer_ints_to_push = MIN(delta, timer_max_fix);
}
timer_interrupts++;
}
#ifdef DEBUG_PIT #ifdef DEBUG_PIT
printf("irq_level=%d next_delay=%f\n", printf("irq_level=%d next_delay=%f\n",
irq_level, irq_level,
(double)(expire_time - current_time) / get_ticks_per_sec()); (double)(expire_time - current_time) / get_ticks_per_sec());
#endif #endif
s->next_transition_time = expire_time; s->next_transition_time = expire_time;
if (expire_time != -1) if (expire_time != -1) {
qemu_mod_timer(s->irq_timer, expire_time); qemu_mod_timer(s->irq_timer, expire_time);
else } else {
qemu_del_timer(s->irq_timer); qemu_del_timer(s->irq_timer);
}
} }
static void pit_irq_timer(void *opaque) static void pit_irq_timer(void *opaque)
@@ -431,9 +430,10 @@ static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
PITChannelState *s; PITChannelState *s;
int i; int i;
if (version_id != 1) if (version_id != PIT_SAVEVM_VERSION)
return -EINVAL; return -EINVAL;
pit->flags = qemu_get_be32(f);
for(i = 0; i < 3; i++) { for(i = 0; i < 3; i++) {
s = &pit->channels[i]; s = &pit->channels[i];
s->count=qemu_get_be32(f); s->count=qemu_get_be32(f);
@@ -454,16 +454,18 @@ static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
qemu_get_timer(f, s->irq_timer); qemu_get_timer(f, s->irq_timer);
} }
} }
return 0; return 0;
} }
static const VMStateDescription vmstate_pit = { VMStateDescription vmstate_pit = {
.name = "i8254", .name = "i8254",
.version_id = 2, .version_id = 2,
.minimum_version_id = 2, .minimum_version_id = 2,
.minimum_version_id_old = 1, .minimum_version_id_old = 1,
.load_state_old = pit_load_old, .load_state_old = pit_load_old,
.fields = (VMStateField []) { .fields = (VMStateField []) {
VMSTATE_UINT32(flags, PITState),
VMSTATE_STRUCT_ARRAY(channels, PITState, 3, 2, vmstate_pit_channel, PITChannelState), VMSTATE_STRUCT_ARRAY(channels, PITState, 3, 2, vmstate_pit_channel, PITChannelState),
VMSTATE_TIMER(channels[0].irq_timer, PITState), VMSTATE_TIMER(channels[0].irq_timer, PITState),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
@@ -476,20 +478,40 @@ static void pit_reset(DeviceState *dev)
PITChannelState *s; PITChannelState *s;
int i; int i;
#ifdef TARGET_I386
pit->flags &= ~PIT_FLAGS_HPET_LEGACY;
#endif
for(i = 0;i < 3; i++) { for(i = 0;i < 3; i++) {
s = &pit->channels[i]; s = &pit->channels[i];
s->mode = 3; s->mode = 3;
s->gate = (i != 2); s->gate = (i != 2);
pit_load_count(s, 0); pit_load_count(pit, 0, i);
}
if (vmstate_pit.post_load) {
vmstate_pit.post_load(pit, 2);
} }
} }
#ifdef TARGET_I386
/* When HPET is operating in legacy mode, i8254 timer0 is disabled */ /* When HPET is operating in legacy mode, i8254 timer0 is disabled */
void hpet_pit_disable(void) {
PITChannelState *s; void hpet_pit_disable(void)
s = &pit_state.channels[0]; {
if (s->irq_timer) PITChannelState *s = &pit_state.channels[0];
qemu_del_timer(s->irq_timer);
if (kvm_enabled() && kvm_pit_in_kernel()) {
if (kvm_has_pit_state2()) {
kvm_hpet_disable_kpit();
} else {
fprintf(stderr, "%s: kvm does not support pit_state2!\n", __FUNCTION__);
exit(1);
}
} else {
pit_state.flags |= PIT_FLAGS_HPET_LEGACY;
if (s->irq_timer) {
qemu_del_timer(s->irq_timer);
}
}
} }
/* When HPET is reset or leaving legacy mode, it must reenable i8254 /* When HPET is reset or leaving legacy mode, it must reenable i8254
@@ -499,18 +521,33 @@ void hpet_pit_disable(void) {
void hpet_pit_enable(void) void hpet_pit_enable(void)
{ {
PITState *pit = &pit_state; PITState *pit = &pit_state;
PITChannelState *s; PITChannelState *s = &pit->channels[0];
s = &pit->channels[0];
s->mode = 3; if (kvm_enabled() && kvm_pit_in_kernel()) {
s->gate = 1; if (kvm_has_pit_state2()) {
pit_load_count(s, 0); kvm_hpet_enable_kpit();
} else {
fprintf(stderr, "%s: kvm does not support pit_state2!\n", __FUNCTION__);
exit(1);
}
} else {
pit_state.flags &= ~PIT_FLAGS_HPET_LEGACY;
pit_load_count(pit, s->count, 0);
}
} }
#endif
static int pit_initfn(ISADevice *dev) static int pit_initfn(ISADevice *dev)
{ {
PITState *pit = DO_UPCAST(PITState, dev, dev); PITState *pit = DO_UPCAST(PITState, dev, dev);
PITChannelState *s; PITChannelState *s;
#ifdef CONFIG_KVM_PIT
if (kvm_enabled() && kvm_pit_in_kernel())
kvm_pit_init(pit);
else {
#endif
s = &pit->channels[0]; s = &pit->channels[0];
/* the timer 0 is connected to an IRQ */ /* the timer 0 is connected to an IRQ */
s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s); s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s);
@@ -520,6 +557,9 @@ static int pit_initfn(ISADevice *dev)
register_ioport_read(pit->iobase, 3, 1, pit_ioport_read, pit); register_ioport_read(pit->iobase, 3, 1, pit_ioport_read, pit);
isa_init_ioport(dev, pit->iobase); isa_init_ioport(dev, pit->iobase);
#ifdef CONFIG_KVM_PIT
}
#endif
qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2); qdev_set_legacy_instance_id(&dev->qdev, pit->iobase, 2);
return 0; return 0;

75
hw/i8254.h Normal file
View File

@@ -0,0 +1,75 @@
/*
* QEMU 8253/8254 interval timer emulation
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef QEMU_I8254_H
#define QEMU_I8254_H
#define PIT_SAVEVM_NAME "i8254"
#define PIT_SAVEVM_VERSION 2
#define RW_STATE_LSB 1
#define RW_STATE_MSB 2
#define RW_STATE_WORD0 3
#define RW_STATE_WORD1 4
#define PIT_FLAGS_HPET_LEGACY 1
typedef struct PITChannelState {
int count; /* can be 65536 */
uint16_t latched_count;
uint8_t count_latched;
uint8_t status_latched;
uint8_t status;
uint8_t read_state;
uint8_t write_state;
uint8_t write_latch;
uint8_t rw_mode;
uint8_t mode;
uint8_t bcd; /* not supported */
uint8_t gate; /* timer start */
int64_t count_load_time;
/* irq handling */
int64_t next_transition_time;
QEMUTimer *irq_timer;
qemu_irq irq;
} PITChannelState;
struct PITState {
ISADevice dev;
uint32_t irq;
uint32_t iobase;
PITChannelState channels[3];
uint32_t flags;
};
void pit_save(QEMUFile *f, void *opaque);
int pit_load(QEMUFile *f, void *opaque, int version_id);
typedef struct PITState PITState;
/* i8254-kvm.c */
void kvm_pit_init(PITState *pit);
#endif

View File

@@ -27,6 +27,8 @@
#include "monitor.h" #include "monitor.h"
#include "qemu-timer.h" #include "qemu-timer.h"
#include "kvm.h"
/* debug PIC */ /* debug PIC */
//#define DEBUG_PIC //#define DEBUG_PIC
@@ -223,6 +225,9 @@ static inline void pic_intack(PicState *s, int irq)
s->irr &= ~(1 << irq); s->irr &= ~(1 << irq);
} }
extern int time_drift_fix;
extern int64_t timer_acks, timer_ints_to_push;
int pic_read_irq(PicState2 *s) int pic_read_irq(PicState2 *s)
{ {
int irq, irq2, intno; int irq, irq2, intno;
@@ -230,6 +235,17 @@ int pic_read_irq(PicState2 *s)
irq = pic_get_irq(&s->pics[0]); irq = pic_get_irq(&s->pics[0]);
if (irq >= 0) { if (irq >= 0) {
pic_intack(&s->pics[0], irq); pic_intack(&s->pics[0], irq);
#ifdef TARGET_I386
if (time_drift_fix && irq == 0) {
timer_acks++;
if (timer_ints_to_push > 0) {
timer_ints_to_push--;
/* simulate an edge irq0, like the one generated by i8254 */
pic_set_irq1(&s->pics[0], 0, 0);
pic_set_irq1(&s->pics[0], 0, 1);
}
}
#endif
if (irq == 2) { if (irq == 2) {
irq2 = pic_get_irq(&s->pics[1]); irq2 = pic_get_irq(&s->pics[1]);
if (irq2 >= 0) { if (irq2 >= 0) {
@@ -262,6 +278,8 @@ int pic_read_irq(PicState2 *s)
return intno; return intno;
} }
static int kvm_kernel_pic_load_from_user(PicState *s);
static void pic_reset(void *opaque) static void pic_reset(void *opaque)
{ {
PicState *s = opaque; PicState *s = opaque;
@@ -282,6 +300,10 @@ static void pic_reset(void *opaque)
s->init4 = 0; s->init4 = 0;
s->single_mode = 0; s->single_mode = 0;
/* Note: ELCR is not reset */ /* Note: ELCR is not reset */
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_pic_load_from_user(s);
}
} }
static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val) static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
@@ -448,9 +470,32 @@ static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
return s->elcr; return s->elcr;
} }
static void kvm_kernel_pic_save_to_user(PicState *s);
static void pic_pre_save(void *opaque)
{
PicState *s = opaque;
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_pic_save_to_user(s);
}
}
static int pic_post_load(void *opaque, int version_id)
{
PicState *s = opaque;
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_pic_load_from_user(s);
}
return 0;
}
static const VMStateDescription vmstate_pic = { static const VMStateDescription vmstate_pic = {
.name = "i8259", .name = "i8259",
.version_id = 1, .version_id = 1,
.pre_save = pic_pre_save,
.post_load = pic_post_load,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1, .minimum_version_id_old = 1,
.fields = (VMStateField []) { .fields = (VMStateField []) {
@@ -537,3 +582,103 @@ qemu_irq *i8259_init(qemu_irq parent_irq)
isa_pic = s; isa_pic = s;
return qemu_allocate_irqs(i8259_set_irq, s, 16); return qemu_allocate_irqs(i8259_set_irq, s, 16);
} }
static void kvm_kernel_pic_save_to_user(PicState *s)
{
#ifdef KVM_CAP_IRQCHIP
struct kvm_irqchip chip;
struct kvm_pic_state *kpic;
chip.chip_id = (&s->pics_state->pics[0] == s) ?
KVM_IRQCHIP_PIC_MASTER :
KVM_IRQCHIP_PIC_SLAVE;
kvm_get_irqchip(kvm_state, &chip);
kpic = &chip.chip.pic;
s->last_irr = kpic->last_irr;
s->irr = kpic->irr;
s->imr = kpic->imr;
s->isr = kpic->isr;
s->priority_add = kpic->priority_add;
s->irq_base = kpic->irq_base;
s->read_reg_select = kpic->read_reg_select;
s->poll = kpic->poll;
s->special_mask = kpic->special_mask;
s->init_state = kpic->init_state;
s->auto_eoi = kpic->auto_eoi;
s->rotate_on_auto_eoi = kpic->rotate_on_auto_eoi;
s->special_fully_nested_mode = kpic->special_fully_nested_mode;
s->init4 = kpic->init4;
s->elcr = kpic->elcr;
s->elcr_mask = kpic->elcr_mask;
#endif
}
static int kvm_kernel_pic_load_from_user(PicState *s)
{
#ifdef KVM_CAP_IRQCHIP
struct kvm_irqchip chip;
struct kvm_pic_state *kpic;
chip.chip_id = (&s->pics_state->pics[0] == s) ?
KVM_IRQCHIP_PIC_MASTER :
KVM_IRQCHIP_PIC_SLAVE;
kpic = &chip.chip.pic;
kpic->last_irr = s->last_irr;
kpic->irr = s->irr;
kpic->imr = s->imr;
kpic->isr = s->isr;
kpic->priority_add = s->priority_add;
kpic->irq_base = s->irq_base;
kpic->read_reg_select = s->read_reg_select;
kpic->poll = s->poll;
kpic->special_mask = s->special_mask;
kpic->init_state = s->init_state;
kpic->auto_eoi = s->auto_eoi;
kpic->rotate_on_auto_eoi = s->rotate_on_auto_eoi;
kpic->special_fully_nested_mode = s->special_fully_nested_mode;
kpic->init4 = s->init4;
kpic->elcr = s->elcr;
kpic->elcr_mask = s->elcr_mask;
kvm_set_irqchip(kvm_state, &chip);
#endif
return 0;
}
#ifdef KVM_CAP_IRQCHIP
static void kvm_i8259_set_irq(void *opaque, int irq, int level)
{
int pic_ret;
if (kvm_set_irq(irq, level, &pic_ret)) {
if (pic_ret != 0)
apic_set_irq_delivered();
return;
}
}
static void kvm_pic_init1(int io_addr, PicState *s)
{
vmstate_register(NULL, io_addr, &vmstate_pic, s);
qemu_register_reset(pic_reset, s);
}
qemu_irq *kvm_i8259_init(qemu_irq parent_irq)
{
PicState2 *s;
s = qemu_mallocz(sizeof(PicState2));
kvm_pic_init1(0x20, &s->pics[0]);
kvm_pic_init1(0xa0, &s->pics[1]);
s->parent_irq = parent_irq;
s->pics[0].pics_state = s;
s->pics[1].pics_state = s;
isa_pic = s;
return qemu_allocate_irqs(kvm_i8259_set_irq, s, 24);
}
#endif

View File

@@ -28,6 +28,8 @@
#include "host-utils.h" #include "host-utils.h"
#include "sysbus.h" #include "sysbus.h"
#include "kvm.h"
//#define DEBUG_IOAPIC //#define DEBUG_IOAPIC
#ifdef DEBUG_IOAPIC #ifdef DEBUG_IOAPIC
@@ -268,6 +270,57 @@ ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
} }
} }
static void kvm_kernel_ioapic_save_to_user(IOAPICState *s)
{
#if defined(KVM_CAP_IRQCHIP) && defined(TARGET_I386)
struct kvm_irqchip chip;
struct kvm_ioapic_state *kioapic;
int i;
chip.chip_id = KVM_IRQCHIP_IOAPIC;
kvm_get_irqchip(kvm_state, &chip);
kioapic = &chip.chip.ioapic;
s->id = kioapic->id;
s->ioregsel = kioapic->ioregsel;
s->irr = kioapic->irr;
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
s->ioredtbl[i] = kioapic->redirtbl[i].bits;
}
#endif
}
static void kvm_kernel_ioapic_load_from_user(IOAPICState *s)
{
#if defined(KVM_CAP_IRQCHIP) && defined(TARGET_I386)
struct kvm_irqchip chip;
struct kvm_ioapic_state *kioapic;
int i;
chip.chip_id = KVM_IRQCHIP_IOAPIC;
kioapic = &chip.chip.ioapic;
kioapic->id = s->id;
kioapic->ioregsel = s->ioregsel;
kioapic->base_address = s->busdev.mmio[0].addr;
kioapic->irr = s->irr;
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
kioapic->redirtbl[i].bits = s->ioredtbl[i];
}
kvm_set_irqchip(kvm_state, &chip);
#endif
}
static void ioapic_pre_save(void *opaque)
{
IOAPICState *s = (void *)opaque;
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_ioapic_save_to_user(s);
}
}
static int ioapic_post_load(void *opaque, int version_id) static int ioapic_post_load(void *opaque, int version_id)
{ {
IOAPICState *s = opaque; IOAPICState *s = opaque;
@@ -276,15 +329,21 @@ static int ioapic_post_load(void *opaque, int version_id)
/* set sane value */ /* set sane value */
s->irr = 0; s->irr = 0;
} }
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_ioapic_load_from_user(s);
}
return 0; return 0;
} }
static const VMStateDescription vmstate_ioapic = { static const VMStateDescription vmstate_ioapic = {
.name = "ioapic", .name = "ioapic",
.version_id = 3, .version_id = 3,
.post_load = ioapic_post_load,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1, .minimum_version_id_old = 1,
.post_load = ioapic_post_load,
.pre_save = ioapic_pre_save,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_UINT8(id, IOAPICState), VMSTATE_UINT8(id, IOAPICState),
VMSTATE_UINT8(ioregsel, IOAPICState), VMSTATE_UINT8(ioregsel, IOAPICState),
@@ -306,6 +365,11 @@ static void ioapic_reset(DeviceState *d)
for (i = 0; i < IOAPIC_NUM_PINS; i++) { for (i = 0; i < IOAPIC_NUM_PINS; i++) {
s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT; s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
} }
#ifdef KVM_CAP_IRQCHIP
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_kernel_ioapic_load_from_user(s);
}
#endif
} }
static CPUReadMemoryFunc * const ioapic_mem_read[3] = { static CPUReadMemoryFunc * const ioapic_mem_read[3] = {

707
hw/ipf.c Normal file
View File

@@ -0,0 +1,707 @@
/*
* Itanium Platform Emulator derived from QEMU PC System Emulator
*
* Copyright (c) 2003-2004 Fabrice Bellard
*
* Copyright (c) 2007 Intel
* Ported for IA64 Platform Zhang Xiantao <xiantao.zhang@intel.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "hw.h"
#include "pc.h"
#include "fdc.h"
#include "pci.h"
#include "block.h"
#include "sysemu.h"
#include "audio/audio.h"
#include "net.h"
#include "smbus.h"
#include "boards.h"
#include "firmware.h"
#include "ia64intrin.h"
#include <unistd.h>
#include "device-assignment.h"
#include "virtio-blk.h"
#include "qemu-kvm.h"
#define FW_FILENAME "Flash.fd"
/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */
#define ACPI_DATA_SIZE 0x10000
#define MAX_IDE_BUS 2
static fdctrl_t *floppy_controller;
static RTCState *rtc_state;
static PCIDevice *i440fx_state;
static uint32_t ipf_to_legacy_io(target_phys_addr_t addr)
{
return (uint32_t)(((addr&0x3ffffff) >> 12 << 2)|((addr) & 0x3));
}
static void ipf_legacy_io_writeb(void *opaque, target_phys_addr_t addr,
uint32_t val) {
uint32_t port = ipf_to_legacy_io(addr);
cpu_outb(0, port, val);
}
static void ipf_legacy_io_writew(void *opaque, target_phys_addr_t addr,
uint32_t val) {
uint32_t port = ipf_to_legacy_io(addr);
cpu_outw(0, port, val);
}
static void ipf_legacy_io_writel(void *opaque, target_phys_addr_t addr,
uint32_t val) {
uint32_t port = ipf_to_legacy_io(addr);
cpu_outl(0, port, val);
}
static uint32_t ipf_legacy_io_readb(void *opaque, target_phys_addr_t addr)
{
uint32_t port = ipf_to_legacy_io(addr);
return cpu_inb(0, port);
}
static uint32_t ipf_legacy_io_readw(void *opaque, target_phys_addr_t addr)
{
uint32_t port = ipf_to_legacy_io(addr);
return cpu_inw(0, port);
}
static uint32_t ipf_legacy_io_readl(void *opaque, target_phys_addr_t addr)
{
uint32_t port = ipf_to_legacy_io(addr);
return cpu_inl(0, port);
}
static CPUReadMemoryFunc *ipf_legacy_io_read[3] = {
ipf_legacy_io_readb,
ipf_legacy_io_readw,
ipf_legacy_io_readl,
};
static CPUWriteMemoryFunc *ipf_legacy_io_write[3] = {
ipf_legacy_io_writeb,
ipf_legacy_io_writew,
ipf_legacy_io_writel,
};
static void pic_irq_request(void *opaque, int irq, int level)
{
fprintf(stderr,"pic_irq_request called!\n");
}
/* PC cmos mappings */
#define REG_EQUIPMENT_BYTE 0x14
static int cmos_get_fd_drive_type(int fd0)
{
int val;
switch (fd0) {
case 0:
/* 1.44 Mb 3"5 drive */
val = 4;
break;
case 1:
/* 2.88 Mb 3"5 drive */
val = 5;
break;
case 2:
/* 1.2 Mb 5"5 drive */
val = 2;
break;
default:
val = 0;
break;
}
return val;
}
static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd)
{
RTCState *s = rtc_state;
int cylinders, heads, sectors;
bdrv_get_geometry_hint(hd, &cylinders, &heads, &sectors);
rtc_set_memory(s, type_ofs, 47);
rtc_set_memory(s, info_ofs, cylinders);
rtc_set_memory(s, info_ofs + 1, cylinders >> 8);
rtc_set_memory(s, info_ofs + 2, heads);
rtc_set_memory(s, info_ofs + 3, 0xff);
rtc_set_memory(s, info_ofs + 4, 0xff);
rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3));
rtc_set_memory(s, info_ofs + 6, cylinders);
rtc_set_memory(s, info_ofs + 7, cylinders >> 8);
rtc_set_memory(s, info_ofs + 8, sectors);
}
/* convert boot_device letter to something recognizable by the bios */
static int boot_device2nibble(char boot_device)
{
switch(boot_device) {
case 'a':
case 'b':
return 0x01; /* floppy boot */
case 'c':
return 0x02; /* hard drive boot */
case 'd':
return 0x03; /* CD-ROM boot */
case 'n':
return 0x04; /* Network boot */
}
return 0;
}
/* hd_table must contain 4 block drivers */
static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
const char *boot_device, BlockDriverState **hd_table)
{
RTCState *s = rtc_state;
int nbds, bds[3] = { 0, };
int val;
int fd0, fd1, nb;
int i;
/* various important CMOS locations needed by PC/Bochs bios */
/* memory size */
val = 640; /* base memory in K */
rtc_set_memory(s, 0x15, val);
rtc_set_memory(s, 0x16, val >> 8);
val = (ram_size / 1024) - 1024;
if (val > 65535)
val = 65535;
rtc_set_memory(s, 0x17, val);
rtc_set_memory(s, 0x18, val >> 8);
rtc_set_memory(s, 0x30, val);
rtc_set_memory(s, 0x31, val >> 8);
if (above_4g_mem_size) {
rtc_set_memory(s, 0x5b, (unsigned int)above_4g_mem_size >> 16);
rtc_set_memory(s, 0x5c, (unsigned int)above_4g_mem_size >> 24);
rtc_set_memory(s, 0x5d, above_4g_mem_size >> 32);
}
rtc_set_memory(s, 0x5f, smp_cpus - 1);
if (ram_size > (16 * 1024 * 1024))
val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536);
else
val = 0;
if (val > 65535)
val = 65535;
rtc_set_memory(s, 0x34, val);
rtc_set_memory(s, 0x35, val >> 8);
/* set boot devices, and disable floppy signature check if requested */
#define PC_MAX_BOOT_DEVICES 3
nbds = strlen(boot_device);
if (nbds > PC_MAX_BOOT_DEVICES) {
fprintf(stderr, "Too many boot devices for PC\n");
exit(1);
}
for (i = 0; i < nbds; i++) {
bds[i] = boot_device2nibble(boot_device[i]);
if (bds[i] == 0) {
fprintf(stderr, "Invalid boot device for PC: '%c'\n",
boot_device[i]);
exit(1);
}
}
rtc_set_memory(s, 0x3d, (bds[1] << 4) | bds[0]);
rtc_set_memory(s, 0x38, (bds[2] << 4) | (fd_bootchk ? 0x0 : 0x1));
/* floppy type */
fd0 = fdctrl_get_drive_type(floppy_controller, 0);
fd1 = fdctrl_get_drive_type(floppy_controller, 1);
val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1);
rtc_set_memory(s, 0x10, val);
val = 0;
nb = 0;
if (fd0 < 3)
nb++;
if (fd1 < 3)
nb++;
switch (nb) {
case 0:
break;
case 1:
val |= 0x01; /* 1 drive, ready for boot */
break;
case 2:
val |= 0x41; /* 2 drives, ready for boot */
break;
}
val |= 0x02; /* FPU is there */
val |= 0x04; /* PS/2 mouse installed */
rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
/* hard drives */
rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
if (hd_table[0])
cmos_init_hd(0x19, 0x1b, hd_table[0]);
if (hd_table[1])
cmos_init_hd(0x1a, 0x24, hd_table[1]);
val = 0;
for (i = 0; i < 4; i++) {
if (hd_table[i]) {
int cylinders, heads, sectors, translation;
/* NOTE: bdrv_get_geometry_hint() returns the physical
geometry. It is always such that: 1 <= sects <= 63, 1
<= heads <= 16, 1 <= cylinders <= 16383. The BIOS
geometry can be different if a translation is done. */
translation = bdrv_get_translation_hint(hd_table[i]);
if (translation == BIOS_ATA_TRANSLATION_AUTO) {
bdrv_get_geometry_hint(hd_table[i], &cylinders,
&heads, &sectors);
if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
/* No translation. */
translation = 0;
} else {
/* LBA translation. */
translation = 1;
}
} else {
translation--;
}
val |= translation << (i * 2);
}
}
rtc_set_memory(s, 0x39, val);
}
static void main_cpu_reset(void *opaque)
{
CPUState *env = opaque;
cpu_reset(env);
}
static const int ide_iobase[2] = { 0x1f0, 0x170 };
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
static const int ide_irq[2] = { 14, 15 };
#define NE2000_NB_MAX 6
static int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340,
0x360, 0x280, 0x380 };
static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
#ifdef HAS_AUDIO
static void audio_init (PCIBus *pci_bus, qemu_irq *pic)
{
struct soundhw *c;
int audio_enabled = 0;
for (c = soundhw; !audio_enabled && c->name; ++c) {
audio_enabled = c->enabled;
}
if (audio_enabled) {
AudioState *s;
s = AUD_init ();
if (s) {
for (c = soundhw; c->name; ++c) {
if (c->enabled) {
if (c->isa) {
c->init.init_isa (s, pic);
} else {
if (pci_bus) {
c->init.init_pci (pci_bus, s);
}
}
}
}
}
}
}
#endif
static void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic)
{
static int nb_ne2k = 0;
if (nb_ne2k == NE2000_NB_MAX)
return;
isa_ne2000_init(ne2000_io[nb_ne2k], pic[ne2000_irq[nb_ne2k]], nd);
nb_ne2k++;
}
/* Itanium hardware initialisation */
static void ipf_init1(ram_addr_t ram_size,
const char *boot_device, DisplayState *ds,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename,
int pci_enabled, const char *cpu_model)
{
char buf[1024];
int i;
ram_addr_t ram_addr;
ram_addr_t above_4g_mem_size = 0;
PCIBus *pci_bus;
PCIDevice *pci_dev;
int piix3_devfn = -1;
CPUState *env;
qemu_irq *cpu_irq;
qemu_irq *i8259;
int page_size;
int index;
unsigned long ipf_legacy_io_base, ipf_legacy_io_mem;
BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
BlockDriverState *fd[MAX_FD];
page_size = getpagesize();
if (page_size != TARGET_PAGE_SIZE) {
fprintf(stderr,"Error! Host page size != qemu target page size,"
" you may need to change TARGET_PAGE_BITS in qemu!"
"host page size:0x%x\n", page_size);
exit(-1);
};
if (ram_size >= 0xc0000000 ) {
above_4g_mem_size = ram_size - 0xc0000000;
ram_size = 0xc0000000;
}
/* init CPUs */
if (cpu_model == NULL) {
cpu_model = "IA64";
}
for(i = 0; i < smp_cpus; i++) {
env = cpu_init(cpu_model);
if (!env) {
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
if (i != 0)
env->hflags |= HF_HALTED_MASK;
register_savevm("cpu", i, 4, cpu_save, cpu_load, env);
qemu_register_reset(main_cpu_reset, 0, env);
}
/* allocate RAM */
if (kvm_enabled()) {
ram_addr = qemu_ram_alloc(0xa0000);
cpu_register_physical_memory(0, 0xa0000, ram_addr);
ram_addr = qemu_ram_alloc(0x20000); // Workaround 0xa0000-0xc0000
ram_addr = qemu_ram_alloc(0x40000);
cpu_register_physical_memory(0xc0000, 0x40000, ram_addr);
ram_addr = qemu_ram_alloc(ram_size - 0x100000);
cpu_register_physical_memory(0x100000, ram_size - 0x100000, ram_addr);
} else {
ram_addr = qemu_ram_alloc(ram_size);
cpu_register_physical_memory(0, ram_size, ram_addr);
}
/* above 4giga memory allocation */
if (above_4g_mem_size > 0) {
ram_addr = qemu_ram_alloc(above_4g_mem_size);
cpu_register_physical_memory(0x100000000, above_4g_mem_size, ram_addr);
}
/*Load firware to its proper position.*/
if (kvm_enabled()) {
unsigned long image_size;
uint8_t *image = NULL;
unsigned long nvram_addr;
unsigned long nvram_fd = 0;
unsigned long type = READ_FROM_NVRAM;
unsigned long i = 0;
unsigned long fw_offset;
ram_addr_t fw_mem = qemu_ram_alloc(GFW_SIZE);
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, FW_FILENAME);
image = read_image(buf, &image_size );
if (NULL == image || !image_size) {
fprintf(stderr, "Error when reading Guest Firmware!\n");
fprintf(stderr, "Please check Guest firmware at %s\n", buf);
exit(1);
}
fw_offset = GFW_START + GFW_SIZE - image_size;
cpu_register_physical_memory(GFW_START, GFW_SIZE, fw_mem);
cpu_physical_memory_write(fw_offset, image, image_size);
free(image);
if (nvram) {
nvram_addr = NVRAM_START;
nvram_fd = kvm_ia64_nvram_init(type);
if (nvram_fd != -1) {
kvm_ia64_copy_from_nvram_to_GFW(nvram_fd);
close(nvram_fd);
}
i = atexit((void *)kvm_ia64_copy_from_GFW_to_nvram);
if (i != 0)
fprintf(stderr, "cannot set exit function\n");
} else
nvram_addr = 0;
kvm_ia64_build_hob(ram_size + above_4g_mem_size, smp_cpus, nvram_addr);
}
/*Register legacy io address space, size:64M*/
ipf_legacy_io_base = 0xE0000000;
ipf_legacy_io_mem = cpu_register_io_memory(0, ipf_legacy_io_read,
ipf_legacy_io_write, NULL);
cpu_register_physical_memory(ipf_legacy_io_base, 64*1024*1024,
ipf_legacy_io_mem);
cpu_irq = qemu_allocate_irqs(pic_irq_request, first_cpu, 1);
i8259 = kvm_i8259_init(cpu_irq[0]);
if (pci_enabled) {
pci_bus = i440fx_init(&i440fx_state, i8259);
piix3_devfn = piix3_init(pci_bus, -1);
} else {
pci_bus = NULL;
}
if (cirrus_vga_enabled) {
if (pci_enabled)
pci_cirrus_vga_init(pci_bus);
else
isa_cirrus_vga_init();
} else {
if (pci_enabled)
pci_vga_init(pci_bus, 0, 0);
else
isa_vga_init();
}
rtc_state = rtc_init(0x70, i8259[8], 2000);
if (pci_enabled) {
pic_set_alt_irq_func(isa_pic, NULL, NULL);
}
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
serial_init(serial_io[i], i8259[serial_irq[i]], 115200,
serial_hds[i]);
}
}
for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
if (parallel_hds[i]) {
parallel_init(parallel_io[i], i8259[parallel_irq[i]],
parallel_hds[i]);
}
}
for(i = 0; i < nb_nics; i++) {
NICInfo *nd = &nd_table[i];
if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0))
pc_init_ne2k_isa(nd, i8259);
else
pci_nic_init(nd, "e1000", NULL);
}
#undef USE_HYPERCALL //Disable it now, need to implement later!
#ifdef USE_HYPERCALL
pci_hypercall_init(pci_bus);
#endif
if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
fprintf(stderr, "qemu: too many IDE bus\n");
exit(1);
}
for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
if (index != -1)
hd[i] = drives_table[index].bdrv;
else
hd[i] = NULL;
}
if (pci_enabled) {
pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1, i8259);
} else {
for(i = 0; i < MAX_IDE_BUS; i++) {
isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
}
}
i8042_init(i8259[1], i8259[12], 0x60);
DMA_init(0);
#ifdef HAS_AUDIO
audio_init(pci_enabled ? pci_bus : NULL, i8259);
#endif
for(i = 0; i < MAX_FD; i++) {
index = drive_get_index(IF_FLOPPY, 0, i);
if (index != -1)
fd[i] = drives_table[index].bdrv;
else
fd[i] = NULL;
}
floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
cmos_init(ram_size, above_4g_mem_size, boot_device, hd);
if (pci_enabled && usb_enabled) {
usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
}
if (pci_enabled && acpi_enabled) {
uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
i2c_bus *smbus;
/* TODO: Populate SPD eeprom data. */
smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, i8259[9]);
for (i = 0; i < 8; i++) {
DeviceState *eeprom;
eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
qdev_set_prop_int(eeprom, "address", 0x50 + i);
qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256));
qdev_init(eeprom);
}
}
if (i440fx_state) {
i440fx_init_memory_mappings(i440fx_state);
}
if (pci_enabled) {
int max_bus;
int bus;
max_bus = drive_get_max_bus(IF_SCSI);
for (bus = 0; bus <= max_bus; bus++) {
pci_create_simple(pci_bus, -1, "lsi53c895a");
}
}
/* Add virtio block devices */
if (pci_enabled) {
int index;
int unit_id = 0;
while ((index = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) {
pci_dev = pci_create("virtio-blk-pci",
drives_table[index].devaddr);
qdev_init(&pci_dev->qdev);
unit_id++;
}
}
}
static void ipf_init_pci(ram_addr_t ram_size,
const char *boot_device, DisplayState *ds,
const char *kernel_filename,
const char *kernel_cmdline,
const char *initrd_filename,
const char *cpu_model)
{
ipf_init1(ram_size, boot_device, ds, kernel_filename,
kernel_cmdline, initrd_filename, 1, cpu_model);
}
QEMUMachine ipf_machine = {
.name = "itanium",
.desc = "Itanium Platform",
.init = (QEMUMachineInitFunc *)ipf_init_pci,
.max_cpus = 255,
.is_default = 1,
};
static void ipf_machine_init(void)
{
qemu_register_machine(&ipf_machine);
}
machine_init(ipf_machine_init);
#define IOAPIC_NUM_PINS 48
static int ioapic_irq_count[IOAPIC_NUM_PINS];
static int ioapic_map_irq(int devfn, int irq_num)
{
int irq, dev;
dev = devfn >> 3;
irq = ((((dev << 2) + (dev >> 3) + irq_num) & 31) + 16);
return irq;
}
/*
* Dummy function to provide match for call from hw/apic.c
*/
void apic_set_irq_delivered(void) {
}
void ioapic_set_irq(void *opaque, int irq_num, int level)
{
int vector, pic_ret;
PCIDevice *pci_dev = (PCIDevice *)opaque;
vector = ioapic_map_irq(pci_dev->devfn, irq_num);
if (level)
ioapic_irq_count[vector] += 1;
else
ioapic_irq_count[vector] -= 1;
if (kvm_enabled()) {
if (kvm_set_irq(vector, ioapic_irq_count[vector] == 0, &pic_ret))
if (pic_ret != 0)
apic_set_irq_delivered();
return;
}
}
int ipf_map_irq(PCIDevice *pci_dev, int irq_num)
{
return ioapic_map_irq(pci_dev->devfn, irq_num);
}

View File

@@ -66,7 +66,7 @@ void isa_bus_irqs(qemu_irq *irqs)
*/ */
qemu_irq isa_get_irq(int isairq) qemu_irq isa_get_irq(int isairq)
{ {
if (isairq < 0 || isairq > 15) { if (isairq < 0 || isairq > 23) {
hw_error("isa irq %d invalid", isairq); hw_error("isa irq %d invalid", isairq);
} }
return isabus->irqs[isairq]; return isabus->irqs[isairq];

131
hw/msi.c
View File

@@ -20,6 +20,7 @@
#include "msi.h" #include "msi.h"
#include "range.h" #include "range.h"
#include "kvm.h"
/* Eventually those constants should go to Linux pci_regs.h */ /* Eventually those constants should go to Linux pci_regs.h */
#define PCI_MSI_PENDING_32 0x10 #define PCI_MSI_PENDING_32 0x10
@@ -109,6 +110,94 @@ bool msi_enabled(const PCIDevice *dev)
PCI_MSI_FLAGS_ENABLE); PCI_MSI_FLAGS_ENABLE);
} }
static void kvm_msi_message_from_vector(PCIDevice *dev, unsigned vector,
KVMMsiMessage *kmm)
{
uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
bool msi64bit = flags & PCI_MSI_FLAGS_64BIT;
unsigned int nr_vectors = msi_nr_vectors(flags);
kmm->addr_lo = pci_get_long(dev->config + msi_address_lo_off(dev));
if (msi64bit) {
kmm->addr_hi = pci_get_long(dev->config + msi_address_hi_off(dev));
} else {
kmm->addr_hi = 0;
}
kmm->data = pci_get_word(dev->config + msi_data_off(dev, msi64bit));
if (nr_vectors > 1) {
kmm->data &= ~(nr_vectors - 1);
kmm->data |= vector;
}
}
static void kvm_msi_update(PCIDevice *dev)
{
uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
unsigned int max_vectors = 1 <<
((flags & PCI_MSI_FLAGS_QMASK) >> (ffs(PCI_MSI_FLAGS_QMASK) - 1));
unsigned int nr_vectors = msi_nr_vectors(flags);
KVMMsiMessage new_entry, *entry;
bool changed = false;
unsigned int vector;
int r;
for (vector = 0; vector < max_vectors; vector++) {
entry = dev->msi_irq_entries + vector;
if (vector >= nr_vectors) {
if (vector < dev->msi_entries_nr) {
kvm_msi_message_del(entry);
changed = true;
}
} else if (vector >= dev->msi_entries_nr) {
kvm_msi_message_from_vector(dev, vector, entry);
r = kvm_msi_message_add(entry);
if (r) {
fprintf(stderr, "%s: kvm_msi_add failed: %s\n", __func__,
strerror(-r));
exit(1);
}
changed = true;
} else {
kvm_msi_message_from_vector(dev, vector, &new_entry);
r = kvm_msi_message_update(entry, &new_entry);
if (r < 0) {
fprintf(stderr, "%s: kvm_update_msi failed: %s\n",
__func__, strerror(-r));
exit(1);
}
if (r > 0) {
*entry = new_entry;
changed = true;
}
}
}
dev->msi_entries_nr = nr_vectors;
if (changed) {
r = kvm_commit_irq_routes();
if (r) {
fprintf(stderr, "%s: kvm_commit_irq_routes failed: %s\n", __func__,
strerror(-r));
exit(1);
}
}
}
/* KVM specific MSI helpers */
static void kvm_msi_free(PCIDevice *dev)
{
unsigned int vector;
for (vector = 0; vector < dev->msi_entries_nr; ++vector) {
kvm_msi_message_del(&dev->msi_irq_entries[vector]);
}
if (dev->msi_entries_nr > 0) {
kvm_commit_irq_routes();
}
dev->msi_entries_nr = 0;
}
int msi_init(struct PCIDevice *dev, uint8_t offset, int msi_init(struct PCIDevice *dev, uint8_t offset,
unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask) unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask)
{ {
@@ -121,6 +210,10 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
" 64bit %d mask %d\n", " 64bit %d mask %d\n",
offset, nr_vectors, msi64bit, msi_per_vector_mask); offset, nr_vectors, msi64bit, msi_per_vector_mask);
if (kvm_enabled() && kvm_irqchip_in_kernel() && !kvm_has_gsi_routing()) {
return -ENOTSUP;
}
assert(!(nr_vectors & (nr_vectors - 1))); /* power of 2 */ assert(!(nr_vectors & (nr_vectors - 1))); /* power of 2 */
assert(nr_vectors > 0); assert(nr_vectors > 0);
assert(nr_vectors <= PCI_MSI_VECTORS_MAX); assert(nr_vectors <= PCI_MSI_VECTORS_MAX);
@@ -159,6 +252,12 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit), pci_set_long(dev->wmask + msi_mask_off(dev, msi64bit),
0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors)); 0xffffffff >> (PCI_MSI_VECTORS_MAX - nr_vectors));
} }
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
dev->msi_irq_entries = qemu_malloc(nr_vectors *
sizeof(*dev->msix_irq_entries));
}
return config_offset; return config_offset;
} }
@@ -172,6 +271,12 @@ void msi_uninit(struct PCIDevice *dev)
} }
flags = pci_get_word(dev->config + msi_flags_off(dev)); flags = pci_get_word(dev->config + msi_flags_off(dev));
cap_size = msi_cap_sizeof(flags); cap_size = msi_cap_sizeof(flags);
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_msi_free(dev);
qemu_free(dev->msi_irq_entries);
}
pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size); pci_del_capability(dev, PCI_CAP_ID_MSI, cap_size);
dev->cap_present &= ~QEMU_PCI_CAP_MSI; dev->cap_present &= ~QEMU_PCI_CAP_MSI;
@@ -183,6 +288,10 @@ void msi_reset(PCIDevice *dev)
uint16_t flags; uint16_t flags;
bool msi64bit; bool msi64bit;
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_msi_free(dev);
}
flags = pci_get_word(dev->config + msi_flags_off(dev)); flags = pci_get_word(dev->config + msi_flags_off(dev));
flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); flags &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
msi64bit = flags & PCI_MSI_FLAGS_64BIT; msi64bit = flags & PCI_MSI_FLAGS_64BIT;
@@ -232,6 +341,11 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
return; return;
} }
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_set_irq(dev->msi_irq_entries[vector].gsi, 1, NULL);
return;
}
if (msi64bit) { if (msi64bit) {
address = pci_get_quad(dev->config + msi_address_lo_off(dev)); address = pci_get_quad(dev->config + msi_address_lo_off(dev));
} else { } else {
@@ -320,6 +434,10 @@ void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len)
pci_set_word(dev->config + msi_flags_off(dev), flags); pci_set_word(dev->config + msi_flags_off(dev), flags);
} }
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_msi_update(dev);
}
if (!msi_per_vector_mask) { if (!msi_per_vector_mask) {
/* if per vector masking isn't supported, /* if per vector masking isn't supported,
there is no pending interrupt. */ there is no pending interrupt. */
@@ -350,3 +468,16 @@ unsigned int msi_nr_vectors_allocated(const PCIDevice *dev)
uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev)); uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
return msi_nr_vectors(flags); return msi_nr_vectors(flags);
} }
void msi_post_load(PCIDevice *dev)
{
uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
if (kvm_enabled() && dev->msi_irq_entries) {
kvm_msi_free(dev);
if (flags & PCI_MSI_FLAGS_ENABLE) {
kvm_msi_update(dev);
}
}
}

View File

@@ -32,6 +32,7 @@ void msi_reset(PCIDevice *dev);
void msi_notify(PCIDevice *dev, unsigned int vector); void msi_notify(PCIDevice *dev, unsigned int vector);
void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len); void msi_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, int len);
unsigned int msi_nr_vectors_allocated(const PCIDevice *dev); unsigned int msi_nr_vectors_allocated(const PCIDevice *dev);
void msi_post_load(PCIDevice *dev);
static inline bool msi_present(const PCIDevice *dev) static inline bool msi_present(const PCIDevice *dev)
{ {

275
hw/msix.c
View File

@@ -15,6 +15,7 @@
#include "msix.h" #include "msix.h"
#include "pci.h" #include "pci.h"
#include "range.h" #include "range.h"
#include "kvm.h"
#define MSIX_CAP_LENGTH 12 #define MSIX_CAP_LENGTH 12
@@ -35,6 +36,93 @@
/* Flag for interrupt controller to declare MSI-X support */ /* Flag for interrupt controller to declare MSI-X support */
int msix_supported; int msix_supported;
/* KVM specific MSIX helpers */
static void kvm_msix_free(PCIDevice *dev)
{
int vector, changed = 0;
for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
if (dev->msix_entry_used[vector]) {
kvm_msi_message_del(&dev->msix_irq_entries[vector]);
changed = 1;
}
}
if (changed) {
kvm_commit_irq_routes();
}
}
static void kvm_msix_message_from_vector(PCIDevice *dev, unsigned vector,
KVMMsiMessage *kmm)
{
uint8_t *table_entry = dev->msix_table_page + vector * PCI_MSIX_ENTRY_SIZE;
kmm->addr_lo = pci_get_long(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR);
kmm->addr_hi = pci_get_long(table_entry + PCI_MSIX_ENTRY_UPPER_ADDR);
kmm->data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA);
}
static void kvm_msix_update(PCIDevice *dev, int vector,
int was_masked, int is_masked)
{
KVMMsiMessage new_entry, *entry;
int mask_cleared = was_masked && !is_masked;
int r;
/* It is only legal to change an entry when it is masked. Therefore, it is
* enough to update the routing in kernel when mask is being cleared. */
if (!mask_cleared) {
return;
}
if (!dev->msix_entry_used[vector]) {
return;
}
entry = dev->msix_irq_entries + vector;
kvm_msix_message_from_vector(dev, vector, &new_entry);
r = kvm_msi_message_update(entry, &new_entry);
if (r < 0) {
fprintf(stderr, "%s: kvm_update_msix failed: %s\n", __func__,
strerror(-r));
exit(1);
}
if (r > 0) {
*entry = new_entry;
r = kvm_commit_irq_routes();
if (r) {
fprintf(stderr, "%s: kvm_commit_irq_routes failed: %s\n", __func__,
strerror(-r));
exit(1);
}
}
}
static int kvm_msix_vector_add(PCIDevice *dev, unsigned vector)
{
KVMMsiMessage *kmm = dev->msix_irq_entries + vector;
int r;
kvm_msix_message_from_vector(dev, vector, kmm);
r = kvm_msi_message_add(kmm);
if (r < 0) {
fprintf(stderr, "%s: kvm_add_msix failed: %s\n", __func__, strerror(-r));
return r;
}
r = kvm_commit_irq_routes();
if (r < 0) {
fprintf(stderr, "%s: kvm_commit_irq_routes failed: %s\n", __func__, strerror(-r));
return r;
}
return 0;
}
static void kvm_msix_vector_del(PCIDevice *dev, unsigned vector)
{
kvm_msi_message_del(&dev->msix_irq_entries[vector]);
kvm_commit_irq_routes();
}
/* Add MSI-X capability to the config space for the device. */ /* Add MSI-X capability to the config space for the device. */
/* Given a bar and its size, add MSI-X table on top of it /* Given a bar and its size, add MSI-X table on top of it
* and fill MSI-X capability in the config space. * and fill MSI-X capability in the config space.
@@ -45,36 +133,43 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries,
{ {
int config_offset; int config_offset;
uint8_t *config; uint8_t *config;
uint32_t new_size;
if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) pdev->msix_bar_size = bar_size;
return -EINVAL;
if (bar_size > 0x80000000)
return -ENOSPC;
/* Add space for MSI-X structures */ config_offset = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
if (!bar_size) {
new_size = MSIX_PAGE_SIZE; if (!config_offset) {
} else if (bar_size < MSIX_PAGE_SIZE) { uint32_t new_size;
bar_size = MSIX_PAGE_SIZE;
new_size = MSIX_PAGE_SIZE * 2; if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1)
} else { return -EINVAL;
new_size = bar_size * 2; if (bar_size > 0x80000000)
return -ENOSPC;
/* Add space for MSI-X structures */
if (!bar_size) {
new_size = MSIX_PAGE_SIZE;
} else if (bar_size < MSIX_PAGE_SIZE) {
bar_size = MSIX_PAGE_SIZE;
new_size = MSIX_PAGE_SIZE * 2;
} else {
new_size = bar_size * 2;
}
pdev->msix_bar_size = new_size;
config_offset = pci_add_capability(pdev, PCI_CAP_ID_MSIX,
0, MSIX_CAP_LENGTH);
if (config_offset < 0)
return config_offset;
config = pdev->config + config_offset;
pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1);
/* Table on top of BAR */
pci_set_long(config + PCI_MSIX_TABLE, bar_size | bar_nr);
/* Pending bits on top of that */
pci_set_long(config + PCI_MSIX_PBA, (bar_size + MSIX_PAGE_PENDING) |
bar_nr);
} }
pdev->msix_bar_size = new_size;
config_offset = pci_add_capability(pdev, PCI_CAP_ID_MSIX,
0, MSIX_CAP_LENGTH);
if (config_offset < 0)
return config_offset;
config = pdev->config + config_offset;
pci_set_word(config + PCI_MSIX_FLAGS, nentries - 1);
/* Table on top of BAR */
pci_set_long(config + PCI_MSIX_TABLE, bar_size | bar_nr);
/* Pending bits on top of that */
pci_set_long(config + PCI_MSIX_PBA, (bar_size + MSIX_PAGE_PENDING) |
bar_nr);
pdev->msix_cap = config_offset; pdev->msix_cap = config_offset;
/* Make flags bit writable. */ /* Make flags bit writable. */
pdev->wmask[config_offset + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK | pdev->wmask[config_offset + MSIX_CONTROL_OFFSET] |= MSIX_ENABLE_MASK |
@@ -175,7 +270,16 @@ static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
PCIDevice *dev = opaque; PCIDevice *dev = opaque;
unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3; unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
int vector = offset / PCI_MSIX_ENTRY_SIZE; int vector = offset / PCI_MSIX_ENTRY_SIZE;
int was_masked = msix_is_masked(dev, vector);
pci_set_long(dev->msix_table_page + offset, val); pci_set_long(dev->msix_table_page + offset, val);
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_msix_update(dev, vector, was_masked, msix_is_masked(dev, vector));
}
if (was_masked != msix_is_masked(dev, vector) && dev->msix_mask_notifier) {
int r = dev->msix_mask_notifier(dev, vector,
msix_is_masked(dev, vector));
assert(r >= 0);
}
msix_handle_mask_update(dev, vector); msix_handle_mask_update(dev, vector);
} }
@@ -208,17 +312,25 @@ void msix_mmio_map(PCIDevice *d, int region_num,
return; return;
if (size <= offset) if (size <= offset)
return; return;
cpu_register_physical_memory(addr + offset, size - offset, cpu_register_physical_memory(addr + offset,
MIN(size - offset, MSIX_PAGE_SIZE),
d->msix_mmio_index); d->msix_mmio_index);
} }
static void msix_mask_all(struct PCIDevice *dev, unsigned nentries) static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
{ {
int vector; int vector, r;
for (vector = 0; vector < nentries; ++vector) { for (vector = 0; vector < nentries; ++vector) {
unsigned offset = unsigned offset =
vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL; vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
int was_masked = msix_is_masked(dev, vector);
dev->msix_table_page[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT; dev->msix_table_page[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
if (was_masked != msix_is_masked(dev, vector) &&
dev->msix_mask_notifier) {
r = dev->msix_mask_notifier(dev, vector,
msix_is_masked(dev, vector));
assert(r >= 0);
}
} }
} }
@@ -229,12 +341,15 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
{ {
int ret; int ret;
/* Nothing to do if MSI is not supported by interrupt controller */ /* Nothing to do if MSI is not supported by interrupt controller */
if (!msix_supported) if (!msix_supported ||
(kvm_enabled() && kvm_irqchip_in_kernel() && !kvm_has_gsi_routing())) {
return -ENOTSUP; return -ENOTSUP;
}
if (nentries > MSIX_MAX_ENTRIES) if (nentries > MSIX_MAX_ENTRIES)
return -EINVAL; return -EINVAL;
dev->msix_mask_notifier = NULL;
dev->msix_entry_used = qemu_mallocz(MSIX_MAX_ENTRIES * dev->msix_entry_used = qemu_mallocz(MSIX_MAX_ENTRIES *
sizeof *dev->msix_entry_used); sizeof *dev->msix_entry_used);
@@ -254,6 +369,11 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
if (ret) if (ret)
goto err_config; goto err_config;
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
dev->msix_irq_entries = qemu_malloc(nentries *
sizeof *dev->msix_irq_entries);
}
dev->cap_present |= QEMU_PCI_CAP_MSIX; dev->cap_present |= QEMU_PCI_CAP_MSIX;
return 0; return 0;
@@ -272,6 +392,10 @@ static void msix_free_irq_entries(PCIDevice *dev)
{ {
int vector; int vector;
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_msix_free(dev);
}
for (vector = 0; vector < dev->msix_entries_nr; ++vector) { for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
dev->msix_entry_used[vector] = 0; dev->msix_entry_used[vector] = 0;
msix_clr_pending(dev, vector); msix_clr_pending(dev, vector);
@@ -292,6 +416,8 @@ int msix_uninit(PCIDevice *dev)
dev->msix_table_page = NULL; dev->msix_table_page = NULL;
qemu_free(dev->msix_entry_used); qemu_free(dev->msix_entry_used);
dev->msix_entry_used = NULL; dev->msix_entry_used = NULL;
qemu_free(dev->msix_irq_entries);
dev->msix_irq_entries = NULL;
dev->cap_present &= ~QEMU_PCI_CAP_MSIX; dev->cap_present &= ~QEMU_PCI_CAP_MSIX;
return 0; return 0;
} }
@@ -300,10 +426,13 @@ void msix_save(PCIDevice *dev, QEMUFile *f)
{ {
unsigned n = dev->msix_entries_nr; unsigned n = dev->msix_entries_nr;
if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) { if (!msix_supported) {
return; return;
} }
if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
return;
}
qemu_put_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE); qemu_put_buffer(f, dev->msix_table_page, n * PCI_MSIX_ENTRY_SIZE);
qemu_put_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8); qemu_put_buffer(f, dev->msix_table_page + MSIX_PAGE_PENDING, (n + 7) / 8);
} }
@@ -313,6 +442,9 @@ void msix_load(PCIDevice *dev, QEMUFile *f)
{ {
unsigned n = dev->msix_entries_nr; unsigned n = dev->msix_entries_nr;
if (!msix_supported)
return;
if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) { if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) {
return; return;
} }
@@ -357,6 +489,11 @@ void msix_notify(PCIDevice *dev, unsigned vector)
return; return;
} }
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_set_irq(dev->msix_irq_entries[vector].gsi, 1, NULL);
return;
}
address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR); address = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR);
data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA); data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA);
stl_le_phys(address, data); stl_le_phys(address, data);
@@ -384,9 +521,17 @@ void msix_reset(PCIDevice *dev)
/* Mark vector as used. */ /* Mark vector as used. */
int msix_vector_use(PCIDevice *dev, unsigned vector) int msix_vector_use(PCIDevice *dev, unsigned vector)
{ {
int ret;
if (vector >= dev->msix_entries_nr) if (vector >= dev->msix_entries_nr)
return -EINVAL; return -EINVAL;
dev->msix_entry_used[vector]++; if (kvm_enabled() && kvm_irqchip_in_kernel() &&
!dev->msix_entry_used[vector]) {
ret = kvm_msix_vector_add(dev, vector);
if (ret) {
return ret;
}
}
++dev->msix_entry_used[vector];
return 0; return 0;
} }
@@ -399,6 +544,9 @@ void msix_vector_unuse(PCIDevice *dev, unsigned vector)
if (--dev->msix_entry_used[vector]) { if (--dev->msix_entry_used[vector]) {
return; return;
} }
if (kvm_enabled() && kvm_irqchip_in_kernel()) {
kvm_msix_vector_del(dev, vector);
}
msix_clr_pending(dev, vector); msix_clr_pending(dev, vector);
} }
@@ -408,3 +556,66 @@ void msix_unuse_all_vectors(PCIDevice *dev)
return; return;
msix_free_irq_entries(dev); msix_free_irq_entries(dev);
} }
/* Invoke the notifier if vector entry is used and unmasked. */
static int msix_notify_if_unmasked(PCIDevice *dev, unsigned vector, int masked)
{
assert(dev->msix_mask_notifier);
if (!dev->msix_entry_used[vector] || msix_is_masked(dev, vector)) {
return 0;
}
return dev->msix_mask_notifier(dev, vector, masked);
}
static int msix_set_mask_notifier_for_vector(PCIDevice *dev, unsigned vector)
{
/* Notifier has been set. Invoke it on unmasked vectors. */
return msix_notify_if_unmasked(dev, vector, 0);
}
static int msix_unset_mask_notifier_for_vector(PCIDevice *dev, unsigned vector)
{
/* Notifier will be unset. Invoke it to mask unmasked entries. */
return msix_notify_if_unmasked(dev, vector, 1);
}
int msix_set_mask_notifier(PCIDevice *dev, msix_mask_notifier_func f)
{
int r, n;
assert(!dev->msix_mask_notifier);
dev->msix_mask_notifier = f;
for (n = 0; n < dev->msix_entries_nr; ++n) {
r = msix_set_mask_notifier_for_vector(dev, n);
if (r < 0) {
goto undo;
}
}
return 0;
undo:
while (--n >= 0) {
msix_unset_mask_notifier_for_vector(dev, n);
}
dev->msix_mask_notifier = NULL;
return r;
}
int msix_unset_mask_notifier(PCIDevice *dev)
{
int r, n;
assert(dev->msix_mask_notifier);
for (n = 0; n < dev->msix_entries_nr; ++n) {
r = msix_unset_mask_notifier_for_vector(dev, n);
if (r < 0) {
goto undo;
}
}
dev->msix_mask_notifier = NULL;
return 0;
undo:
while (--n >= 0) {
msix_set_mask_notifier_for_vector(dev, n);
}
return r;
}

View File

@@ -33,4 +33,6 @@ void msix_reset(PCIDevice *dev);
extern int msix_supported; extern int msix_supported;
int msix_set_mask_notifier(PCIDevice *dev, msix_mask_notifier_func);
int msix_unset_mask_notifier(PCIDevice *dev);
#endif #endif

46
hw/pc.c
View File

@@ -39,6 +39,7 @@
#include "msix.h" #include "msix.h"
#include "sysbus.h" #include "sysbus.h"
#include "sysemu.h" #include "sysemu.h"
#include "kvm.h"
#include "blockdev.h" #include "blockdev.h"
#include "ui/qemu-spice.h" #include "ui/qemu-spice.h"
@@ -56,6 +57,8 @@
#endif #endif
#define BIOS_FILENAME "bios.bin" #define BIOS_FILENAME "bios.bin"
#define EXTBOOT_FILENAME "extboot.bin"
#define VAPIC_FILENAME "vapic.bin"
#define PC_MAX_BIOS_SIZE (4 * 1024 * 1024) #define PC_MAX_BIOS_SIZE (4 * 1024 * 1024)
@@ -601,7 +604,7 @@ static void *bochs_bios_init(void)
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, (uint8_t *)acpi_tables, fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, (uint8_t *)acpi_tables,
acpi_tables_len); acpi_tables_len);
fw_cfg_add_bytes(fw_cfg, FW_CFG_IRQ0_OVERRIDE, &irq0override, 1); fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override());
smbios_table = smbios_get_table(&smbios_len); smbios_table = smbios_get_table(&smbios_len);
if (smbios_table) if (smbios_table)
@@ -921,10 +924,18 @@ static void pc_cpu_reset(void *opaque)
env->halted = !cpu_is_bsp(env); env->halted = !cpu_is_bsp(env);
} }
static CPUState *pc_new_cpu(const char *cpu_model) CPUState *pc_new_cpu(const char *cpu_model)
{ {
CPUState *env; CPUState *env;
if (cpu_model == NULL) {
#ifdef TARGET_X86_64
cpu_model = "qemu64";
#else
cpu_model = "qemu32";
#endif
}
env = cpu_init(cpu_model); env = cpu_init(cpu_model);
if (!env) { if (!env) {
fprintf(stderr, "Unable to find x86 CPU definition\n"); fprintf(stderr, "Unable to find x86 CPU definition\n");
@@ -944,14 +955,6 @@ void pc_cpus_init(const char *cpu_model)
int i; int i;
/* init CPUs */ /* init CPUs */
if (cpu_model == NULL) {
#ifdef TARGET_X86_64
cpu_model = "qemu64";
#else
cpu_model = "qemu32";
#endif
}
for(i = 0; i < smp_cpus; i++) { for(i = 0; i < smp_cpus; i++) {
pc_new_cpu(cpu_model); pc_new_cpu(cpu_model);
} }
@@ -1010,10 +1013,21 @@ void pc_memory_init(const char *kernel_filename,
isa_bios_size = bios_size; isa_bios_size = bios_size;
if (isa_bios_size > (128 * 1024)) if (isa_bios_size > (128 * 1024))
isa_bios_size = 128 * 1024; isa_bios_size = 128 * 1024;
cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size,
IO_MEM_UNASSIGNED);
cpu_register_physical_memory(0x100000 - isa_bios_size, cpu_register_physical_memory(0x100000 - isa_bios_size,
isa_bios_size, isa_bios_size,
(bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM); (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
if (extboot_drive) {
option_rom[nb_option_roms].name = qemu_strdup(EXTBOOT_FILENAME);
option_rom[nb_option_roms].bootindex = 0;
nb_option_roms++;
}
option_rom[nb_option_roms].name = qemu_strdup(VAPIC_FILENAME);
option_rom[nb_option_roms].bootindex = -1;
nb_option_roms++;
option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE); option_rom_offset = qemu_ram_alloc(NULL, "pc.rom", PC_ROM_SIZE);
cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE, option_rom_offset); cpu_register_physical_memory(PC_ROM_MIN_VGA, PC_ROM_SIZE, option_rom_offset);
@@ -1168,4 +1182,16 @@ void pc_pci_device_init(PCIBus *pci_bus)
for (bus = 0; bus <= max_bus; bus++) { for (bus = 0; bus <= max_bus; bus++) {
pci_create_simple(pci_bus, -1, "lsi53c895a"); pci_create_simple(pci_bus, -1, "lsi53c895a");
} }
if (extboot_drive) {
DriveInfo *info = extboot_drive;
int cyls, heads, secs;
if (info->type != IF_IDE && info->type != IF_VIRTIO) {
bdrv_guess_geometry(info->bdrv, &cyls, &heads, &secs);
bdrv_set_geometry_hint(info->bdrv, cyls, heads, secs);
}
extboot_init(info->bdrv);
}
} }

12
hw/pc.h
View File

@@ -62,6 +62,7 @@ extern PicState2 *isa_pic;
void pic_set_irq(int irq, int level); void pic_set_irq(int irq, int level);
void pic_set_irq_new(void *opaque, int irq, int level); void pic_set_irq_new(void *opaque, int irq, int level);
qemu_irq *i8259_init(qemu_irq parent_irq); qemu_irq *i8259_init(qemu_irq parent_irq);
qemu_irq *kvm_i8259_init(qemu_irq parent_irq);
int pic_read_irq(PicState2 *s); int pic_read_irq(PicState2 *s);
void pic_update_irq(PicState2 *s); void pic_update_irq(PicState2 *s);
uint32_t pic_intack_read(PicState2 *s); uint32_t pic_intack_read(PicState2 *s);
@@ -172,6 +173,9 @@ void pcspk_init(ISADevice *pit);
int pcspk_audio_init(qemu_irq *pic); int pcspk_audio_init(qemu_irq *pic);
/* piix_pci.c */ /* piix_pci.c */
/* config space register for IRQ routing */
#define PIIX_CONFIG_IRQ_ROUTE 0x60
struct PCII440FXState; struct PCII440FXState;
typedef struct PCII440FXState PCII440FXState; typedef struct PCII440FXState PCII440FXState;
@@ -182,6 +186,10 @@ void i440fx_init_memory_mappings(PCII440FXState *d);
extern PCIDevice *piix4_dev; extern PCIDevice *piix4_dev;
int piix4_init(PCIBus *bus, int devfn); int piix4_init(PCIBus *bus, int devfn);
int piix_get_irq(int pin);
int ipf_map_irq(PCIDevice *pci_dev, int irq_num);
/* vga.c */ /* vga.c */
enum vga_retrace_method { enum vga_retrace_method {
VGA_RETRACE_DUMB, VGA_RETRACE_DUMB,
@@ -229,6 +237,10 @@ static inline bool isa_ne2000_init(int base, int irq, NICInfo *nd)
return true; return true;
} }
/* extboot.c */
void extboot_init(BlockDriverState *bs);
/* e820 types */ /* e820 types */
#define E820_RAM 1 #define E820_RAM 1
#define E820_RESERVED 2 #define E820_RESERVED 2

View File

@@ -43,12 +43,16 @@
# include <xen/hvm/hvm_info_table.h> # include <xen/hvm/hvm_info_table.h>
#endif #endif
qemu_irq *ioapic_irq_hack;
#define MAX_IDE_BUS 2 #define MAX_IDE_BUS 2
static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 }; static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 }; static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
static const int ide_irq[MAX_IDE_BUS] = { 14, 15 }; static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
const char *global_cpu_model; /* cpu hotadd */
static void ioapic_init(IsaIrqState *isa_irq_state) static void ioapic_init(IsaIrqState *isa_irq_state)
{ {
DeviceState *dev; DeviceState *dev;
@@ -90,6 +94,8 @@ static void pc_init1(ram_addr_t ram_size,
BusState *idebus[MAX_IDE_BUS]; BusState *idebus[MAX_IDE_BUS];
ISADevice *rtc_state; ISADevice *rtc_state;
global_cpu_model = cpu_model;
pc_cpus_init(cpu_model); pc_cpus_init(cpu_model);
if (kvmclock_enabled) { if (kvmclock_enabled) {
@@ -112,7 +118,11 @@ static void pc_init1(ram_addr_t ram_size,
if (!xen_enabled()) { if (!xen_enabled()) {
cpu_irq = pc_allocate_cpu_irq(); cpu_irq = pc_allocate_cpu_irq();
i8259 = i8259_init(cpu_irq[0]); if (!(kvm_enabled() && kvm_irqchip_in_kernel())) {
i8259 = i8259_init(cpu_irq[0]);
} else {
i8259 = kvm_i8259_init(cpu_irq[0]);
}
} else { } else {
i8259 = xen_interrupt_controller_init(); i8259 = xen_interrupt_controller_init();
} }
@@ -121,7 +131,11 @@ static void pc_init1(ram_addr_t ram_size,
if (pci_enabled) { if (pci_enabled) {
ioapic_init(isa_irq_state); ioapic_init(isa_irq_state);
} }
isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24); if (!(kvm_enabled() && kvm_irqchip_in_kernel())) {
isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
} else {
isa_irq = i8259;
}
if (pci_enabled) { if (pci_enabled) {
pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size); pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
@@ -149,7 +163,7 @@ static void pc_init1(ram_addr_t ram_size,
if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0))
pc_init_ne2k_isa(nd); pc_init_ne2k_isa(nd);
else else
pci_nic_init_nofail(nd, "e1000", NULL); pci_nic_init_nofail(nd, "rtl8139", NULL);
} }
ide_drive_get(hd, MAX_IDE_BUS); ide_drive_get(hd, MAX_IDE_BUS);

140
hw/pci.c
View File

@@ -29,8 +29,12 @@
#include "net.h" #include "net.h"
#include "sysemu.h" #include "sysemu.h"
#include "loader.h" #include "loader.h"
#include "hw/pc.h"
#include "kvm.h"
#include "device-assignment.h"
#include "qemu-objects.h" #include "qemu-objects.h"
#include "range.h" #include "range.h"
#include "msi.h"
//#define DEBUG_PCI //#define DEBUG_PCI
#ifdef DEBUG_PCI #ifdef DEBUG_PCI
@@ -346,6 +350,7 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size)
memcpy(s->config, config, size); memcpy(s->config, config, size);
pci_update_mappings(s); pci_update_mappings(s);
msi_post_load(s);
qemu_free(config); qemu_free(config);
return 0; return 0;
@@ -537,6 +542,83 @@ int pci_parse_devaddr(const char *addr, int *domp, int *busp,
return 0; return 0;
} }
/*
* Parse device seg and bdf in device assignment command:
*
* -pcidevice host=[seg:]bus:dev.func
*
* Parse [seg:]<bus>:<slot>.<func> return -1 on error
*/
int pci_parse_host_devaddr(const char *addr, int *segp, int *busp,
int *slotp, int *funcp)
{
const char *p;
char *e;
int val;
int seg = 0, bus = 0, slot = 0, func = 0;
/* parse optional seg */
p = addr;
val = 0;
while (1) {
p = strchr(p, ':');
if (p) {
val++;
p++;
} else
break;
}
if (val <= 0 || val > 2)
return -1;
p = addr;
if (val == 2) {
val = strtoul(p, &e, 16);
if (e == p)
return -1;
if (*e == ':') {
seg = val;
p = e + 1;
}
} else
seg = 0;
/* parse bdf */
val = strtoul(p, &e, 16);
if (e == p)
return -1;
if (*e == ':') {
bus = val;
p = e + 1;
val = strtoul(p, &e, 16);
if (e == p)
return -1;
if (*e == '.') {
slot = val;
p = e + 1;
val = strtoul(p, &e, 16);
if (e == p)
return -1;
func = val;
} else
return -1;
} else
return -1;
if (seg > 0xffff || bus > 0xff || slot > 0x1f || func > 0x7)
return -1;
if (*e)
return -1;
*segp = seg;
*busp = bus;
*slotp = slot;
*funcp = func;
return 0;
}
int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
unsigned *slotp) unsigned *slotp)
{ {
@@ -711,7 +793,7 @@ static void pci_config_alloc(PCIDevice *pci_dev)
pci_dev->cmask = qemu_mallocz(config_size); pci_dev->cmask = qemu_mallocz(config_size);
pci_dev->wmask = qemu_mallocz(config_size); pci_dev->wmask = qemu_mallocz(config_size);
pci_dev->w1cmask = qemu_mallocz(config_size); pci_dev->w1cmask = qemu_mallocz(config_size);
pci_dev->used = qemu_mallocz(config_size); pci_dev->config_map = qemu_mallocz(config_size);
} }
static void pci_config_free(PCIDevice *pci_dev) static void pci_config_free(PCIDevice *pci_dev)
@@ -720,7 +802,7 @@ static void pci_config_free(PCIDevice *pci_dev)
qemu_free(pci_dev->cmask); qemu_free(pci_dev->cmask);
qemu_free(pci_dev->wmask); qemu_free(pci_dev->wmask);
qemu_free(pci_dev->w1cmask); qemu_free(pci_dev->w1cmask);
qemu_free(pci_dev->used); qemu_free(pci_dev->config_map);
} }
/* -1 for devfn means auto assign */ /* -1 for devfn means auto assign */
@@ -751,6 +833,8 @@ static PCIDevice *do_pci_register_device(PCIDevice *pci_dev, PCIBus *bus,
pci_dev->irq_state = 0; pci_dev->irq_state = 0;
pci_config_alloc(pci_dev); pci_config_alloc(pci_dev);
memset(pci_dev->config_map, 0xff, PCI_CONFIG_HEADER_SIZE);
pci_config_set_vendor_id(pci_dev->config, info->vendor_id); pci_config_set_vendor_id(pci_dev->config, info->vendor_id);
pci_config_set_device_id(pci_dev->config, info->device_id); pci_config_set_device_id(pci_dev->config, info->device_id);
pci_config_set_revision(pci_dev->config, info->revision); pci_config_set_revision(pci_dev->config, info->revision);
@@ -1126,6 +1210,14 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask); d->config[addr + i] = (d->config[addr + i] & ~wmask) | (val & wmask);
d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */ d->config[addr + i] &= ~(val & w1cmask); /* W1C: Write 1 to Clear */
} }
#ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
if (kvm_enabled() && kvm_irqchip_in_kernel() &&
addr >= PIIX_CONFIG_IRQ_ROUTE &&
addr < PIIX_CONFIG_IRQ_ROUTE + 4)
assigned_dev_update_irqs();
#endif /* CONFIG_KVM_DEVICE_ASSIGNMENT */
if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) || if (ranges_overlap(addr, l, PCI_BASE_ADDRESS_0, 24) ||
ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) || ranges_overlap(addr, l, PCI_ROM_ADDRESS, 4) ||
ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) || ranges_overlap(addr, l, PCI_ROM_ADDRESS1, 4) ||
@@ -1149,6 +1241,10 @@ static void pci_set_irq(void *opaque, int irq_num, int level)
if (!change) if (!change)
return; return;
#if defined(TARGET_IA64)
ioapic_set_irq(pci_dev, irq_num, level);
#endif
pci_set_irq_state(pci_dev, irq_num, level); pci_set_irq_state(pci_dev, irq_num, level);
pci_update_irq_status(pci_dev); pci_update_irq_status(pci_dev);
if (pci_irq_disabled(pci_dev)) if (pci_irq_disabled(pci_dev))
@@ -1156,6 +1252,11 @@ static void pci_set_irq(void *opaque, int irq_num, int level)
pci_change_irq_level(pci_dev, irq_num, change); pci_change_irq_level(pci_dev, irq_num, change);
} }
int pci_map_irq(PCIDevice *pci_dev, int pin)
{
return pci_dev->bus->map_irq(pci_dev, pin);
}
/***********************************************************/ /***********************************************************/
/* monitor info on PCI */ /* monitor info on PCI */
@@ -1798,7 +1899,7 @@ static int pci_find_space(PCIDevice *pdev, uint8_t size)
int offset = PCI_CONFIG_HEADER_SIZE; int offset = PCI_CONFIG_HEADER_SIZE;
int i; int i;
for (i = PCI_CONFIG_HEADER_SIZE; i < config_size; ++i) for (i = PCI_CONFIG_HEADER_SIZE; i < config_size; ++i)
if (pdev->used[i]) if (pdev->config_map[i])
offset = i + 1; offset = i + 1;
else if (i - offset + 1 == size) else if (i - offset + 1 == size)
return offset; return offset;
@@ -1823,7 +1924,7 @@ static uint8_t pci_find_capability_list(PCIDevice *pdev, uint8_t cap_id,
return next; return next;
} }
static void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr, pcibus_t size, int type) void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr, pcibus_t size, int type)
{ {
cpu_register_physical_memory(addr, size, pdev->rom_offset); cpu_register_physical_memory(addr, size, pdev->rom_offset);
} }
@@ -1975,18 +2076,34 @@ int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
if (!offset) { if (!offset) {
return -ENOSPC; return -ENOSPC;
} }
} else {
int i;
for (i = offset; i < offset + size; i++) {
if (pdev->config_map[i]) {
fprintf(stderr, "ERROR: %04x:%02x:%02x.%x "
"Attempt to add PCI capability %x at offset "
"%x overlaps existing capability %x at offset %x\n",
pci_find_domain(pdev->bus), pci_bus_num(pdev->bus),
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
cap_id, offset, pdev->config_map[i], i);
return -EINVAL;
}
}
} }
config = pdev->config + offset; config = pdev->config + offset;
config[PCI_CAP_LIST_ID] = cap_id; config[PCI_CAP_LIST_ID] = cap_id;
config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST]; config[PCI_CAP_LIST_NEXT] = pdev->config[PCI_CAPABILITY_LIST];
pdev->config[PCI_CAPABILITY_LIST] = offset; pdev->config[PCI_CAPABILITY_LIST] = offset;
pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST; memset(pdev->config_map + offset, cap_id, size);
memset(pdev->used + offset, 0xFF, size);
/* Make capability read-only by default */ /* Make capability read-only by default */
memset(pdev->wmask + offset, 0, size); memset(pdev->wmask + offset, 0, size);
/* Check capability by default */ /* Check capability by default */
memset(pdev->cmask + offset, 0xFF, size); memset(pdev->cmask + offset, 0xFF, size);
pdev->config[PCI_STATUS] |= PCI_STATUS_CAP_LIST;
return offset; return offset;
} }
@@ -2002,16 +2119,11 @@ void pci_del_capability(PCIDevice *pdev, uint8_t cap_id, uint8_t size)
memset(pdev->w1cmask + offset, 0, size); memset(pdev->w1cmask + offset, 0, size);
/* Clear cmask as device-specific registers can't be checked */ /* Clear cmask as device-specific registers can't be checked */
memset(pdev->cmask + offset, 0, size); memset(pdev->cmask + offset, 0, size);
memset(pdev->used + offset, 0, size); memset(pdev->config_map + offset, 0, size);
if (!pdev->config[PCI_CAPABILITY_LIST]) if (!pdev->config[PCI_CAPABILITY_LIST]) {
pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST; pdev->config[PCI_STATUS] &= ~PCI_STATUS_CAP_LIST;
} }
/* Reserve space for capability at a known offset (to call after load). */
void pci_reserve_capability(PCIDevice *pdev, uint8_t offset, uint8_t size)
{
memset(pdev->used + offset, 0xff, size);
} }
uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id) uint8_t pci_find_capability(PCIDevice *pdev, uint8_t cap_id)

View File

@@ -5,6 +5,7 @@
#include "qobject.h" #include "qobject.h"
#include "qdev.h" #include "qdev.h"
#include "kvm.h"
/* PCI includes legacy ISA access. */ /* PCI includes legacy ISA access. */
#include "isa.h" #include "isa.h"
@@ -127,6 +128,9 @@ enum {
QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR), QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR),
}; };
typedef int (*msix_mask_notifier_func)(PCIDevice *, unsigned vector,
int masked);
struct PCIDevice { struct PCIDevice {
DeviceState qdev; DeviceState qdev;
/* PCI config space */ /* PCI config space */
@@ -142,8 +146,8 @@ struct PCIDevice {
/* Used to implement RW1C(Write 1 to Clear) bytes */ /* Used to implement RW1C(Write 1 to Clear) bytes */
uint8_t *w1cmask; uint8_t *w1cmask;
/* Used to allocate config space for capabilities. */ /* Used to allocate config space and track capabilities. */
uint8_t *used; uint8_t *config_map;
/* the following fields are read only */ /* the following fields are read only */
PCIBus *bus; PCIBus *bus;
@@ -191,6 +195,21 @@ struct PCIDevice {
char *romfile; char *romfile;
ram_addr_t rom_offset; ram_addr_t rom_offset;
uint32_t rom_bar; uint32_t rom_bar;
/* MSI entries */
int msi_entries_nr;
struct KVMMsiMessage *msi_irq_entries;
/* How much space does an MSIX table need. */
/* The spec requires giving the table structure
* a 4K aligned region all by itself. Align it to
* target pages so that drivers can do passthrough
* on the rest of the region. */
target_phys_addr_t msix_page_size;
KVMMsiMessage *msix_irq_entries;
msix_mask_notifier_func msix_mask_notifier;
}; };
PCIDevice *pci_register_device(PCIBus *bus, const char *name, PCIDevice *pci_register_device(PCIBus *bus, const char *name,
@@ -204,23 +223,24 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
void pci_register_bar_simple(PCIDevice *pci_dev, int region_num, void pci_register_bar_simple(PCIDevice *pci_dev, int region_num,
pcibus_t size, uint8_t attr, ram_addr_t ram_addr); pcibus_t size, uint8_t attr, ram_addr_t ram_addr);
void pci_map_option_rom(PCIDevice *pdev, int region_num, pcibus_t addr,
pcibus_t size, int type);
int pci_map_irq(PCIDevice *pci_dev, int pin);
int pci_add_capability(PCIDevice *pdev, uint8_t cap_id, int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
uint8_t offset, uint8_t size); uint8_t offset, uint8_t size);
void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size); void pci_del_capability(PCIDevice *pci_dev, uint8_t cap_id, uint8_t cap_size);
void pci_reserve_capability(PCIDevice *pci_dev, uint8_t offset, uint8_t size);
uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id); uint8_t pci_find_capability(PCIDevice *pci_dev, uint8_t cap_id);
uint32_t pci_default_read_config(PCIDevice *d, uint32_t pci_default_read_config(PCIDevice *d,
uint32_t address, int len); uint32_t address, int len);
void pci_default_write_config(PCIDevice *d, void pci_default_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len); uint32_t address, uint32_t val, int len);
void pci_device_save(PCIDevice *s, QEMUFile *f); void pci_device_save(PCIDevice *s, QEMUFile *f);
int pci_device_load(PCIDevice *s, QEMUFile *f); int pci_device_load(PCIDevice *s, QEMUFile *f);
typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level); typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level);
typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num); typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
@@ -265,6 +285,9 @@ int pci_parse_devaddr(const char *addr, int *domp, int *busp,
int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp, int pci_read_devaddr(Monitor *mon, const char *addr, int *domp, int *busp,
unsigned *slotp); unsigned *slotp);
int pci_parse_host_devaddr(const char *addr, int *segp, int *busp,
int *slotp, int *funcp);
void do_pci_info_print(Monitor *mon, const QObject *data); void do_pci_info_print(Monitor *mon, const QObject *data);
void do_pci_info(Monitor *mon, QObject **ret_data); void do_pci_info(Monitor *mon, QObject **ret_data);
void pci_bridge_update_mappings(PCIBus *b); void pci_bridge_update_mappings(PCIBus *b);

View File

@@ -44,9 +44,16 @@
#define PCI_STATUS 0x06 /* 16 bits */ #define PCI_STATUS 0x06 /* 16 bits */
#define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */ #define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */
#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ #define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */
#ifndef PCI_STATUS_66MHZ
#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ #define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
#endif
#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ #define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */
#ifndef PCI_STATUS_FAST_BACK
#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ #define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */
#endif
#define PCI_STATUS_PARITY 0x100 /* Detected parity error */ #define PCI_STATUS_PARITY 0x100 /* Detected parity error */
#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ #define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */
#define PCI_STATUS_DEVSEL_FAST 0x000 #define PCI_STATUS_DEVSEL_FAST 0x000

View File

@@ -27,6 +27,8 @@
#include "isa.h" #include "isa.h"
#include "audio/audio.h" #include "audio/audio.h"
#include "qemu-timer.h" #include "qemu-timer.h"
#include "i8254.h"
#include "qemu-kvm.h"
#define PCSPK_BUF_LEN 1792 #define PCSPK_BUF_LEN 1792
#define PCSPK_SAMPLE_RATE 32000 #define PCSPK_SAMPLE_RATE 32000
@@ -48,6 +50,46 @@ typedef struct {
static const char *s_spk = "pcspk"; static const char *s_spk = "pcspk";
static PCSpkState pcspk_state; static PCSpkState pcspk_state;
#ifdef CONFIG_KVM_PIT
static void kvm_get_pit_ch2(ISADevice *dev,
struct kvm_pit_state *inkernel_state)
{
struct PITState *pit = DO_UPCAST(struct PITState, dev, dev);
struct kvm_pit_state pit_state;
if (kvm_enabled() && kvm_pit_in_kernel()) {
kvm_get_pit(kvm_state, &pit_state);
pit->channels[2].mode = pit_state.channels[2].mode;
pit->channels[2].count = pit_state.channels[2].count;
pit->channels[2].count_load_time = pit_state.channels[2].count_load_time;
pit->channels[2].gate = pit_state.channels[2].gate;
if (inkernel_state) {
memcpy(inkernel_state, &pit_state, sizeof(*inkernel_state));
}
}
}
static void kvm_set_pit_ch2(ISADevice *dev,
struct kvm_pit_state *inkernel_state)
{
struct PITState *pit = DO_UPCAST(struct PITState, dev, dev);
if (kvm_enabled() && kvm_pit_in_kernel()) {
inkernel_state->channels[2].mode = pit->channels[2].mode;
inkernel_state->channels[2].count = pit->channels[2].count;
inkernel_state->channels[2].count_load_time =
pit->channels[2].count_load_time;
inkernel_state->channels[2].gate = pit->channels[2].gate;
kvm_set_pit(kvm_state, inkernel_state);
}
}
#else
static inline void kvm_get_pit_ch2(ISADevice *dev,
struct kvm_pit_state *inkernel_state) { }
static inline void kvm_set_pit_ch2(ISADevice *dev,
struct kvm_pit_state *inkernel_state) { }
#endif
static inline void generate_samples(PCSpkState *s) static inline void generate_samples(PCSpkState *s)
{ {
unsigned int i; unsigned int i;
@@ -72,6 +114,8 @@ static void pcspk_callback(void *opaque, int free)
PCSpkState *s = opaque; PCSpkState *s = opaque;
unsigned int n; unsigned int n;
kvm_get_pit_ch2(s->pit, NULL);
if (pit_get_mode(s->pit, 2) != 3) if (pit_get_mode(s->pit, 2) != 3)
return; return;
@@ -117,6 +161,8 @@ static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr)
PCSpkState *s = opaque; PCSpkState *s = opaque;
int out; int out;
kvm_get_pit_ch2(s->pit, NULL);
s->dummy_refresh_clock ^= (1 << 4); s->dummy_refresh_clock ^= (1 << 4);
out = pit_get_out(s->pit, 2, qemu_get_clock_ns(vm_clock)) << 5; out = pit_get_out(s->pit, 2, qemu_get_clock_ns(vm_clock)) << 5;
@@ -125,9 +171,12 @@ static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr)
static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val) static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{ {
struct kvm_pit_state inkernel_state;
PCSpkState *s = opaque; PCSpkState *s = opaque;
const int gate = val & 1; const int gate = val & 1;
kvm_get_pit_ch2(s->pit, &inkernel_state);
s->data_on = (val >> 1) & 1; s->data_on = (val >> 1) & 1;
pit_set_gate(s->pit, 2, gate); pit_set_gate(s->pit, 2, gate);
if (s->voice) { if (s->voice) {
@@ -135,6 +184,8 @@ static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val)
s->play_pos = 0; s->play_pos = 0;
AUD_set_active_out(s->voice, gate & s->data_on); AUD_set_active_out(s->voice, gate & s->data_on);
} }
kvm_set_pit_ch2(s->pit, &inkernel_state);
} }
void pcspk_init(ISADevice *pit) void pcspk_init(ISADevice *pit)

View File

@@ -30,6 +30,7 @@
#include "sysbus.h" #include "sysbus.h"
#include "range.h" #include "range.h"
#include "xen.h" #include "xen.h"
#include "kvm.h"
/* /*
* I440FX chipset data sheet. * I440FX chipset data sheet.
@@ -238,6 +239,8 @@ static int i440fx_initfn(PCIDevice *dev)
return 0; return 0;
} }
static PIIX3State *piix3_dev;
static PCIBus *i440fx_common_init(const char *device_name, static PCIBus *i440fx_common_init(const char *device_name,
PCII440FXState **pi440fx_state, PCII440FXState **pi440fx_state,
int *piix3_devfn, int *piix3_devfn,
@@ -284,6 +287,8 @@ static PCIBus *i440fx_common_init(const char *device_name,
ram_size = 255; ram_size = 255;
(*pi440fx_state)->dev.config[0x57]=ram_size; (*pi440fx_state)->dev.config[0x57]=ram_size;
piix3_dev = piix3;
return b; return b;
} }
@@ -354,6 +359,13 @@ static void piix3_write_config(PCIDevice *dev,
} }
} }
int piix_get_irq(int pin)
{
if (piix3_dev)
return piix3_dev->dev.config[0x60+pin];
return 0;
}
static void piix3_write_config_xen(PCIDevice *dev, static void piix3_write_config_xen(PCIDevice *dev,
uint32_t address, uint32_t val, int len) uint32_t address, uint32_t val, int len)
{ {

140
hw/testdev.c Normal file
View File

@@ -0,0 +1,140 @@
#include <sys/mman.h>
#include "hw.h"
#include "qdev.h"
#include "isa.h"
struct testdev {
ISADevice dev;
CharDriverState *chr;
};
static void test_device_serial_write(void *opaque, uint32_t addr, uint32_t data)
{
struct testdev *dev = opaque;
uint8_t buf[1] = { data };
if (dev->chr) {
qemu_chr_write(dev->chr, buf, 1);
}
}
static void test_device_exit(void *opaque, uint32_t addr, uint32_t data)
{
exit(data);
}
static uint32_t test_device_memsize_read(void *opaque, uint32_t addr)
{
return ram_size;
}
static void test_device_irq_line(void *opaque, uint32_t addr, uint32_t data)
{
qemu_set_irq(isa_get_irq(addr - 0x2000), !!data);
}
static uint32 test_device_ioport_data;
static void test_device_ioport_write(void *opaque, uint32_t addr, uint32_t data)
{
test_device_ioport_data = data;
}
static uint32_t test_device_ioport_read(void *opaque, uint32_t addr)
{
return test_device_ioport_data;
}
static void test_device_flush_page(void *opaque, uint32_t addr, uint32_t data)
{
target_phys_addr_t len = 4096;
void *a = cpu_physical_memory_map(data & ~0xffful, &len, 0);
mprotect(a, 4096, PROT_NONE);
mprotect(a, 4096, PROT_READ|PROT_WRITE);
cpu_physical_memory_unmap(a, len, 0, 0);
}
static char *iomem_buf;
static uint32_t test_iomem_readb(void *opaque, target_phys_addr_t addr)
{
return iomem_buf[addr];
}
static uint32_t test_iomem_readw(void *opaque, target_phys_addr_t addr)
{
return *(uint16_t*)(iomem_buf + addr);
}
static uint32_t test_iomem_readl(void *opaque, target_phys_addr_t addr)
{
return *(uint32_t*)(iomem_buf + addr);
}
static void test_iomem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
iomem_buf[addr] = val;
}
static void test_iomem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
*(uint16_t*)(iomem_buf + addr) = val;
}
static void test_iomem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
*(uint32_t*)(iomem_buf + addr) = val;
}
static CPUReadMemoryFunc * const test_iomem_read[3] = {
test_iomem_readb,
test_iomem_readw,
test_iomem_readl,
};
static CPUWriteMemoryFunc * const test_iomem_write[3] = {
test_iomem_writeb,
test_iomem_writew,
test_iomem_writel,
};
static int init_test_device(ISADevice *isa)
{
struct testdev *dev = DO_UPCAST(struct testdev, dev, isa);
int iomem;
register_ioport_write(0xf1, 1, 1, test_device_serial_write, dev);
register_ioport_write(0xf4, 1, 4, test_device_exit, dev);
register_ioport_read(0xd1, 1, 4, test_device_memsize_read, dev);
register_ioport_read(0xe0, 1, 1, test_device_ioport_read, dev);
register_ioport_write(0xe0, 1, 1, test_device_ioport_write, dev);
register_ioport_read(0xe0, 1, 2, test_device_ioport_read, dev);
register_ioport_write(0xe0, 1, 2, test_device_ioport_write, dev);
register_ioport_read(0xe0, 1, 4, test_device_ioport_read, dev);
register_ioport_write(0xe0, 1, 4, test_device_ioport_write, dev);
register_ioport_write(0xe4, 1, 4, test_device_flush_page, dev);
register_ioport_write(0x2000, 24, 1, test_device_irq_line, NULL);
iomem_buf = qemu_mallocz(0x10000);
iomem = cpu_register_io_memory(test_iomem_read, test_iomem_write, NULL,
DEVICE_NATIVE_ENDIAN);
cpu_register_physical_memory(0xff000000, 0x10000, iomem);
return 0;
}
static ISADeviceInfo testdev_info = {
.qdev.name = "testdev",
.qdev.size = sizeof(struct testdev),
.init = init_test_device,
.qdev.props = (Property[]) {
DEFINE_PROP_CHR("chardev", struct testdev, chr),
DEFINE_PROP_END_OF_LIST(),
},
};
static void testdev_register_devices(void)
{
isa_qdev_register(&testdev_info);
}
device_init(testdev_register_devices)

View File

@@ -1885,6 +1885,9 @@ static void vga_update_display(void *opaque)
vga_draw_text(s, full_update); vga_draw_text(s, full_update);
break; break;
case GMODE_GRAPH: case GMODE_GRAPH:
#ifdef TARGET_IA64
full_update = 1;
#endif
vga_draw_graphic(s, full_update); vga_draw_graphic(s, full_update);
break; break;
case GMODE_BLANK: case GMODE_BLANK:

View File

@@ -33,8 +33,8 @@
/* bochs VBE support */ /* bochs VBE support */
#define CONFIG_BOCHS_VBE #define CONFIG_BOCHS_VBE
#define VBE_DISPI_MAX_XRES 1600 #define VBE_DISPI_MAX_XRES 2560
#define VBE_DISPI_MAX_YRES 1200 #define VBE_DISPI_MAX_YRES 1600
#define VBE_DISPI_MAX_BPP 32 #define VBE_DISPI_MAX_BPP 32
#define VBE_DISPI_INDEX_ID 0x0 #define VBE_DISPI_INDEX_ID 0x0
@@ -225,7 +225,7 @@ void vga_init_vbe(VGACommonState *s);
extern const uint8_t sr_mask[8]; extern const uint8_t sr_mask[8];
extern const uint8_t gr_mask[16]; extern const uint8_t gr_mask[16];
#define VGA_RAM_SIZE (8192 * 1024) #define VGA_RAM_SIZE (16 * 1024 * 1024)
#define VGABIOS_FILENAME "vgabios.bin" #define VGABIOS_FILENAME "vgabios.bin"
#define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin" #define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"

View File

@@ -545,6 +545,57 @@ static void virtio_pci_guest_notifier_read(void *opaque)
} }
} }
static int virtio_pci_mask_vq(PCIDevice *dev, unsigned vector,
VirtQueue *vq, int masked)
{
EventNotifier *notifier = virtio_queue_get_guest_notifier(vq);
int r = kvm_set_irqfd(dev->msix_irq_entries[vector].gsi,
event_notifier_get_fd(notifier),
!masked);
if (r < 0) {
return (r == -ENOSYS) ? 0 : r;
}
if (masked) {
qemu_set_fd_handler(event_notifier_get_fd(notifier),
virtio_pci_guest_notifier_read, NULL, vq);
} else {
qemu_set_fd_handler(event_notifier_get_fd(notifier),
NULL, NULL, NULL);
}
return 0;
}
static int virtio_pci_mask_notifier(PCIDevice *dev, unsigned vector,
int masked)
{
VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev);
VirtIODevice *vdev = proxy->vdev;
int r, n;
for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
if (!virtio_queue_get_num(vdev, n)) {
break;
}
if (virtio_queue_vector(vdev, n) != vector) {
continue;
}
r = virtio_pci_mask_vq(dev, vector, virtio_get_queue(vdev, n), masked);
if (r < 0) {
goto undo;
}
}
return 0;
undo:
while (--n >= 0) {
if (virtio_queue_vector(vdev, n) != vector) {
continue;
}
virtio_pci_mask_vq(dev, vector, virtio_get_queue(vdev, n), !masked);
}
return r;
}
static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign) static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign)
{ {
VirtIOPCIProxy *proxy = opaque; VirtIOPCIProxy *proxy = opaque;
@@ -561,6 +612,9 @@ static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign)
} else { } else {
qemu_set_fd_handler(event_notifier_get_fd(notifier), qemu_set_fd_handler(event_notifier_get_fd(notifier),
NULL, NULL, NULL); NULL, NULL, NULL);
/* Test and clear notifier before closing it,
* in case poll callback didn't have time to run. */
virtio_pci_guest_notifier_read(vq);
event_notifier_cleanup(notifier); event_notifier_cleanup(notifier);
} }
@@ -579,6 +633,13 @@ static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
VirtIODevice *vdev = proxy->vdev; VirtIODevice *vdev = proxy->vdev;
int r, n; int r, n;
/* Must unset mask notifier while guest notifier
* is still assigned */
if (!assign) {
r = msix_unset_mask_notifier(&proxy->pci_dev);
assert(r >= 0);
}
for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) { for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
if (!virtio_queue_get_num(vdev, n)) { if (!virtio_queue_get_num(vdev, n)) {
break; break;
@@ -590,6 +651,16 @@ static int virtio_pci_set_guest_notifiers(void *opaque, bool assign)
} }
} }
/* Must set mask notifier after guest notifier
* has been assigned */
if (assign) {
r = msix_set_mask_notifier(&proxy->pci_dev,
virtio_pci_mask_notifier);
if (r < 0) {
goto assign_error;
}
}
return 0; return 0;
assign_error: assign_error:
@@ -597,6 +668,11 @@ assign_error:
while (--n >= 0) { while (--n >= 0) {
virtio_pci_set_guest_notifier(opaque, n, !assign); virtio_pci_set_guest_notifier(opaque, n, !assign);
} }
if (!assign) {
msix_set_mask_notifier(&proxy->pci_dev,
virtio_pci_mask_notifier);
}
return r; return r;
} }

View File

@@ -7,7 +7,7 @@ ENTRY(_start)
SECTIONS SECTIONS
{ {
/* Read-only sections, merged into text segment: */ /* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = 0x60000000); . = 0x60000000 + SIZEOF_HEADERS; PROVIDE (__executable_start = 0x4000000060000000); . = 0x4000000060000000 + SIZEOF_HEADERS;
.interp : { *(.interp) } .interp : { *(.interp) }
.hash : { *(.hash) } .hash : { *(.hash) }
.dynsym : { *(.dynsym) } .dynsym : { *(.dynsym) }

150
ia64intrin.h Normal file
View File

@@ -0,0 +1,150 @@
#ifndef IA64_INTRINSIC_H
#define IA64_INTRINSIC_H
/*
* Compiler-dependent Intrinsics
*
* Copyright (C) 2002,2003 Jun Nakajima <jun.nakajima@intel.com>
* Copyright (C) 2002,2003 Suresh Siddha <suresh.b.siddha@intel.com>
*
*/
extern long ia64_cmpxchg_called_with_bad_pointer (void);
extern void ia64_bad_param_for_getreg (void);
#define ia64_cmpxchg(sem,ptr,o,n,s) ({ \
uint64_t _o, _r; \
switch(s) { \
case 1: _o = (uint8_t)(long)(o); break; \
case 2: _o = (uint16_t)(long)(o); break; \
case 4: _o = (uint32_t)(long)(o); break; \
case 8: _o = (uint64_t)(long)(o); break; \
default: break; \
} \
switch(s) { \
case 1: \
_r = ia64_cmpxchg1_##sem((uint8_t*)ptr,n,_o); break; \
case 2: \
_r = ia64_cmpxchg2_##sem((uint16_t*)ptr,n,_o); break; \
case 4: \
_r = ia64_cmpxchg4_##sem((uint32_t*)ptr,n,_o); break; \
case 8: \
_r = ia64_cmpxchg8_##sem((uint64_t*)ptr,n,_o); break; \
default: \
_r = ia64_cmpxchg_called_with_bad_pointer(); break; \
} \
(__typeof__(o)) _r; \
})
#define cmpxchg_acq(ptr,o,n) ia64_cmpxchg(acq,ptr,o,n,sizeof(*ptr))
#define cmpxchg_rel(ptr,o,n) ia64_cmpxchg(rel,ptr,o,n,sizeof(*ptr))
#ifdef __INTEL_COMPILER
void __fc(uint64_t *addr);
void __synci(void);
void __isrlz(void);
void __dsrlz(void);
uint64_t __getReg(const int whichReg);
uint64_t _InterlockedCompareExchange8_rel(volatile uint8_t *dest, uint64_t xchg, uint64_t comp);
uint64_t _InterlockedCompareExchange8_acq(volatile uint8_t *dest, uint64_t xchg, uint64_t comp);
uint64_t _InterlockedCompareExchange16_rel(volatile uint16_t *dest, uint64_t xchg, uint64_t comp);
uint64_t _InterlockedCompareExchange16_acq(volatile uint16_t *dest, uint64_t xchg, uint64_t comp);
uint64_t _InterlockedCompareExchange_rel(volatile uint32_t *dest, uint64_t xchg, uint64_t comp);
uint64_t _InterlockedCompareExchange_acq(volatile uint32_t *dest, uint64_t xchg, uint64_t comp);
uint64_t _InterlockedCompareExchange64_rel(volatile uint64_t *dest, uint64_t xchg, uint64_t comp);
u64_t _InterlockedCompareExchange64_acq(volatile uint64_t *dest, uint64_t xchg, uint64_t comp);
#define ia64_cmpxchg1_rel _InterlockedCompareExchange8_rel
#define ia64_cmpxchg1_acq _InterlockedCompareExchange8_acq
#define ia64_cmpxchg2_rel _InterlockedCompareExchange16_rel
#define ia64_cmpxchg2_acq _InterlockedCompareExchange16_acq
#define ia64_cmpxchg4_rel _InterlockedCompareExchange_rel
#define ia64_cmpxchg4_acq _InterlockedCompareExchange_acq
#define ia64_cmpxchg8_rel _InterlockedCompareExchange64_rel
#define ia64_cmpxchg8_acq _InterlockedCompareExchange64_acq
#define ia64_srlz_d __dsrlz
#define ia64_srlz_i __isrlz
#define __ia64_fc __fc
#define ia64_sync_i __synci
#define __ia64_getreg __getReg
#else /* __INTEL_COMPILER */
#define ia64_cmpxchg1_acq(ptr, new, old) \
({ \
uint64_t ia64_intri_res; \
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \
asm volatile ("cmpxchg1.acq %0=[%1],%2,ar.ccv": \
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \
ia64_intri_res; \
})
#define ia64_cmpxchg1_rel(ptr, new, old) \
({ \
uint64_t ia64_intri_res; \
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \
asm volatile ("cmpxchg1.rel %0=[%1],%2,ar.ccv": \
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \
ia64_intri_res; \
})
#define ia64_cmpxchg2_acq(ptr, new, old) \
({ \
uint64_t ia64_intri_res; \
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \
asm volatile ("cmpxchg2.acq %0=[%1],%2,ar.ccv": \
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \
ia64_intri_res; \
})
#define ia64_cmpxchg2_rel(ptr, new, old) \
({ \
uint64_t ia64_intri_res; \
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \
\
asm volatile ("cmpxchg2.rel %0=[%1],%2,ar.ccv": \
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \
ia64_intri_res; \
})
#define ia64_cmpxchg4_acq(ptr, new, old) \
({ \
uint64_t ia64_intri_res; \
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \
asm volatile ("cmpxchg4.acq %0=[%1],%2,ar.ccv": \
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \
ia64_intri_res; \
})
#define ia64_cmpxchg4_rel(ptr, new, old) \
({ \
uint64_t ia64_intri_res; \
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \
asm volatile ("cmpxchg4.rel %0=[%1],%2,ar.ccv": \
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \
ia64_intri_res; \
})
#define ia64_cmpxchg8_acq(ptr, new, old) \
({ \
uint64_t ia64_intri_res; \
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \
asm volatile ("cmpxchg8.acq %0=[%1],%2,ar.ccv": \
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \
ia64_intri_res; \
})
#define ia64_cmpxchg8_rel(ptr, new, old) \
({ \
uint64_t ia64_intri_res; \
asm volatile ("mov ar.ccv=%0;;" :: "rO"(old)); \
\
asm volatile ("cmpxchg8.rel %0=[%1],%2,ar.ccv": \
"=r"(ia64_intri_res) : "r"(ptr), "r"(new) : "memory"); \
ia64_intri_res; \
})
#define ia64_srlz_i() asm volatile (";; srlz.i ;;" ::: "memory")
#define ia64_srlz_d() asm volatile (";; srlz.d" ::: "memory");
#define __ia64_fc(addr) asm volatile ("fc %0" :: "r"(addr) : "memory")
#define ia64_sync_i() asm volatile (";; sync.i" ::: "memory")
#endif /* __INTEL_COMPILER */
#endif /* IA64_INTRINSIC_H */

View File

@@ -76,6 +76,15 @@ struct KVMState
int pit_in_kernel; int pit_in_kernel;
int xsave, xcrs; int xsave, xcrs;
int many_ioeventfds; int many_ioeventfds;
int pit_state2;
int irqchip_inject_ioctl;
#ifdef KVM_CAP_IRQ_ROUTING
struct kvm_irq_routing *irq_routes;
int nr_allocated_irq_routes;
#endif
void *used_gsi_bitmap;
int max_gsi;
}; };
KVMState *kvm_state; KVMState *kvm_state;
@@ -781,6 +790,13 @@ int kvm_init(void)
s->xcrs = kvm_check_extension(s, KVM_CAP_XCRS); s->xcrs = kvm_check_extension(s, KVM_CAP_XCRS);
#endif #endif
s->pit_state2 = 0;
#ifdef KVM_CAP_PIT_STATE2
s->pit_state2 = kvm_check_extension(s, KVM_CAP_PIT_STATE2);
#endif
s->pit_in_kernel = kvm_pit;
ret = kvm_arch_init(s); ret = kvm_arch_init(s);
if (ret < 0) { if (ret < 0) {
goto err; goto err;
@@ -791,6 +807,11 @@ int kvm_init(void)
s->many_ioeventfds = kvm_check_many_ioeventfds(); s->many_ioeventfds = kvm_check_many_ioeventfds();
ret = kvm_create_irqchip(s);
if (ret < 0) {
return ret;
}
cpu_interrupt_handler = kvm_handle_interrupt; cpu_interrupt_handler = kvm_handle_interrupt;
return 0; return 0;
@@ -1103,6 +1124,11 @@ int kvm_has_xcrs(void)
return kvm_state->xcrs; return kvm_state->xcrs;
} }
int kvm_has_pit_state2(void)
{
return kvm_state->pit_state2;
}
int kvm_has_many_ioeventfds(void) int kvm_has_many_ioeventfds(void)
{ {
if (!kvm_enabled()) { if (!kvm_enabled()) {
@@ -1111,6 +1137,11 @@ int kvm_has_many_ioeventfds(void)
return kvm_state->many_ioeventfds; return kvm_state->many_ioeventfds;
} }
int kvm_allows_irq0_override(void)
{
return !kvm_enabled() || !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
}
void kvm_setup_guest_memory(void *start, size_t size) void kvm_setup_guest_memory(void *start, size_t size)
{ {
if (!kvm_has_sync_mmu()) { if (!kvm_has_sync_mmu()) {
@@ -1385,6 +1416,23 @@ int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign)
#endif #endif
} }
int kvm_set_irqfd(int gsi, int fd, bool assigned)
{
struct kvm_irqfd irqfd = {
.fd = fd,
.gsi = gsi,
.flags = assigned ? 0 : KVM_IRQFD_FLAG_DEASSIGN,
};
int r;
if (!kvm_enabled() || !kvm_irqchip_in_kernel())
return -ENOSYS;
r = kvm_vm_ioctl(kvm_state, KVM_IRQFD, &irqfd);
if (r < 0)
return r;
return 0;
}
int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr) int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr)
{ {
return kvm_arch_on_sigbus_vcpu(env, code, addr); return kvm_arch_on_sigbus_vcpu(env, code, addr);
@@ -1394,3 +1442,6 @@ int kvm_on_sigbus(int code, void *addr)
{ {
return kvm_arch_on_sigbus(code, addr); return kvm_arch_on_sigbus(code, addr);
} }
#undef PAGE_SIZE
#include "qemu-kvm.c"

View File

@@ -78,6 +78,16 @@ int kvm_has_many_ioeventfds(void)
return 0; return 0;
} }
int kvm_allows_irq0_override(void)
{
return 1;
}
int kvm_has_pit_state2(void)
{
return 0;
}
void kvm_setup_guest_memory(void *start, size_t size) void kvm_setup_guest_memory(void *start, size_t size)
{ {
} }
@@ -120,6 +130,42 @@ int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign)
return -ENOSYS; return -ENOSYS;
} }
int kvm_has_gsi_routing(void)
{
return 0;
}
int kvm_get_irq_route_gsi(void)
{
return -ENOSYS;
}
int kvm_msi_message_add(KVMMsiMessage *msg)
{
return -ENOSYS;
}
int kvm_msi_message_del(KVMMsiMessage *msg)
{
return -ENOSYS;
}
int kvm_msi_message_update(KVMMsiMessage *old, KVMMsiMessage *new)
{
return -ENOSYS;
}
int kvm_commit_irq_routes(void)
{
return -ENOSYS;
}
int kvm_set_irq(int irq, int level, int *status)
{
assert(0);
return -ENOSYS;
}
int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr) int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr)
{ {
return 1; return 1;
@@ -129,3 +175,8 @@ int kvm_on_sigbus(int code, void *addr)
{ {
return 1; return 1;
} }
int kvm_set_irqfd(int gsi, int fd, bool assigned)
{
return -ENOSYS;
}

380
kvm-tpr-opt.c Normal file
View File

@@ -0,0 +1,380 @@
/*
* tpr optimization for qemu/kvm
*
* Copyright (C) 2007-2008 Qumranet Technologies
*
* Licensed under the terms of the GNU GPL version 2 or higher.
*/
#include "config.h"
#include "config-host.h"
#include <string.h>
#include "hw/hw.h"
#include "hw/isa.h"
#include "sysemu.h"
#include "kvm.h"
#include "cpu.h"
#include <stdio.h>
static uint64_t map_addr(CPUState *env, target_ulong virt, unsigned *perms)
{
uint64_t mask = ((1ull << 48) - 1) & ~4095ull;
uint64_t p, pp = 7;
p = env->cr[3];
if (env->cr[4] & 0x20) {
p &= ~31ull;
p = ldq_phys(p + 8 * (virt >> 30));
if (!(p & 1))
return -1ull;
p &= mask;
p = ldq_phys(p + 8 * ((virt >> 21) & 511));
if (!(p & 1))
return -1ull;
pp &= p;
if (p & 128) {
p += ((virt >> 12) & 511) << 12;
} else {
p &= mask;
p = ldq_phys(p + 8 * ((virt >> 12) & 511));
if (!(p & 1))
return -1ull;
pp &= p;
}
} else {
p &= mask;
p = ldl_phys(p + 4 * ((virt >> 22) & 1023));
if (!(p & 1))
return -1ull;
pp &= p;
if (p & 128) {
p += ((virt >> 12) & 1023) << 12;
} else {
p &= mask;
p = ldl_phys(p + 4 * ((virt >> 12) & 1023));
pp &= p;
if (!(p & 1))
return -1ull;
}
}
if (perms)
*perms = pp >> 1;
p &= mask;
return p + (virt & 4095);
}
static uint8_t read_byte_virt(CPUState *env, target_ulong virt)
{
return ldub_phys(map_addr(env, virt, NULL));
}
static void write_byte_virt(CPUState *env, target_ulong virt, uint8_t b)
{
cpu_physical_memory_write_rom(map_addr(env, virt, NULL), &b, 1);
}
struct vapic_bios {
char signature[8];
uint32_t virt_base;
uint32_t fixup_start;
uint32_t fixup_end;
uint32_t vapic;
uint32_t vapic_size;
uint32_t vcpu_shift;
uint32_t real_tpr;
struct vapic_patches {
uint32_t set_tpr;
uint32_t set_tpr_eax;
uint32_t get_tpr[8];
uint32_t get_tpr_stack;
} __attribute__((packed)) up, mp;
} __attribute__((packed));
static struct vapic_bios vapic_bios;
static uint32_t real_tpr;
static uint32_t bios_addr;
static uint32_t vapic_phys;
static uint32_t bios_enabled;
static uint32_t vbios_desc_phys;
static uint32_t vapic_bios_addr;
static void update_vbios_real_tpr(void)
{
cpu_physical_memory_rw(vbios_desc_phys, (void *)&vapic_bios, sizeof vapic_bios, 0);
vapic_bios.real_tpr = real_tpr;
vapic_bios.vcpu_shift = 7;
cpu_physical_memory_write_rom(vbios_desc_phys, (void *)&vapic_bios, sizeof vapic_bios);
}
static unsigned modrm_reg(uint8_t modrm)
{
return (modrm >> 3) & 7;
}
static int is_abs_modrm(uint8_t modrm)
{
return (modrm & 0xc7) == 0x05;
}
static int instruction_is_ok(CPUState *env, uint64_t rip, int is_write)
{
uint8_t b1, b2;
unsigned addr_offset;
uint32_t addr;
uint64_t p;
if ((rip & 0xf0000000) != 0x80000000 && (rip & 0xf0000000) != 0xe0000000)
return 0;
if (env->regs[R_ESP] == 0)
return 0;
b1 = read_byte_virt(env, rip);
b2 = read_byte_virt(env, rip + 1);
switch (b1) {
case 0xc7: /* mov imm32, r/m32 (c7/0) */
if (modrm_reg(b2) != 0)
return 0;
/* fall through */
case 0x89: /* mov r32 to r/m32 */
case 0x8b: /* mov r/m32 to r32 */
if (!is_abs_modrm(b2))
return 0;
addr_offset = 2;
break;
case 0xa1: /* mov abs to eax */
case 0xa3: /* mov eax to abs */
addr_offset = 1;
break;
case 0xff: /* push r/m32 */
if (modrm_reg(b2) != 6 || !is_abs_modrm(b2))
return 0;
addr_offset = 2;
default:
return 0;
}
p = rip + addr_offset;
addr = read_byte_virt(env, p++);
addr |= read_byte_virt(env, p++) << 8;
addr |= read_byte_virt(env, p++) << 16;
addr |= read_byte_virt(env, p++) << 24;
if ((addr & 0xfff) != 0x80)
return 0;
real_tpr = addr;
update_vbios_real_tpr();
return 1;
}
static int bios_is_mapped(CPUState *env, uint64_t rip)
{
uint32_t probe;
uint64_t phys;
unsigned perms;
uint32_t i;
uint32_t offset, fixup, start = vapic_bios_addr ? : 0xe0000;
uint32_t patch;
if (bios_enabled)
return 1;
probe = (rip & 0xf0000000) + start;
phys = map_addr(env, probe, &perms);
if (phys != start)
return 0;
bios_addr = probe;
for (i = 0; i < 64; ++i) {
cpu_physical_memory_read(phys, (void *)&vapic_bios, sizeof(vapic_bios));
if (memcmp(vapic_bios.signature, "kvm aPiC", 8) == 0)
break;
phys += 1024;
bios_addr += 1024;
}
if (i == 64)
return 0;
if (bios_addr == vapic_bios.virt_base)
return 1;
vbios_desc_phys = phys;
for (i = vapic_bios.fixup_start; i < vapic_bios.fixup_end; i += 4) {
offset = ldl_phys(phys + i - vapic_bios.virt_base);
fixup = phys + offset;
patch = ldl_phys(fixup) + bios_addr - vapic_bios.virt_base;
cpu_physical_memory_write_rom(fixup, (uint8_t *)&patch, 4);
}
vapic_phys = vapic_bios.vapic - vapic_bios.virt_base + phys;
return 1;
}
static int get_pcr_cpu(CPUState *env)
{
uint8_t b;
cpu_synchronize_state(env);
if (cpu_memory_rw_debug(env, env->segs[R_FS].base + 0x51, &b, 1, 0) < 0)
return -1;
return (int)b;
}
int kvm_tpr_enable_vapic(CPUState *env)
{
static uint8_t one = 1;
int pcr_cpu = get_pcr_cpu(env);
if (pcr_cpu < 0)
return 0;
kvm_enable_vapic(env, vapic_phys + (pcr_cpu << 7));
cpu_physical_memory_write_rom(vapic_phys + (pcr_cpu << 7) + 4, &one, 1);
env->kvm_vcpu_update_vapic = 0;
bios_enabled = 1;
return 1;
}
static void patch_call(CPUState *env, uint64_t rip, uint32_t target)
{
uint32_t offset;
offset = target - vapic_bios.virt_base + bios_addr - rip - 5;
write_byte_virt(env, rip, 0xe8); /* call near */
write_byte_virt(env, rip + 1, offset);
write_byte_virt(env, rip + 2, offset >> 8);
write_byte_virt(env, rip + 3, offset >> 16);
write_byte_virt(env, rip + 4, offset >> 24);
}
static void patch_instruction(CPUState *env, uint64_t rip)
{
uint8_t b1, b2;
struct vapic_patches *vp;
vp = smp_cpus == 1 ? &vapic_bios.up : &vapic_bios.mp;
b1 = read_byte_virt(env, rip);
b2 = read_byte_virt(env, rip + 1);
switch (b1) {
case 0x89: /* mov r32 to r/m32 */
write_byte_virt(env, rip, 0x50 + modrm_reg(b2)); /* push reg */
patch_call(env, rip + 1, vp->set_tpr);
break;
case 0x8b: /* mov r/m32 to r32 */
write_byte_virt(env, rip, 0x90);
patch_call(env, rip + 1, vp->get_tpr[modrm_reg(b2)]);
break;
case 0xa1: /* mov abs to eax */
patch_call(env, rip, vp->get_tpr[0]);
break;
case 0xa3: /* mov eax to abs */
patch_call(env, rip, vp->set_tpr_eax);
break;
case 0xc7: /* mov imm32, r/m32 (c7/0) */
write_byte_virt(env, rip, 0x68); /* push imm32 */
write_byte_virt(env, rip + 1, read_byte_virt(env, rip+6));
write_byte_virt(env, rip + 2, read_byte_virt(env, rip+7));
write_byte_virt(env, rip + 3, read_byte_virt(env, rip+8));
write_byte_virt(env, rip + 4, read_byte_virt(env, rip+9));
patch_call(env, rip + 5, vp->set_tpr);
break;
case 0xff: /* push r/m32 */
printf("patching push\n");
write_byte_virt(env, rip, 0x50); /* push eax */
patch_call(env, rip + 1, vp->get_tpr_stack);
break;
default:
printf("funny insn %02x %02x\n", b1, b2);
}
}
void kvm_tpr_access_report(CPUState *env, uint64_t rip, int is_write)
{
cpu_synchronize_state(env);
if (!instruction_is_ok(env, rip, is_write))
return;
if (!bios_is_mapped(env, rip))
return;
if (!kvm_tpr_enable_vapic(env))
return;
patch_instruction(env, rip);
}
static void tpr_save(QEMUFile *f, void *s)
{
int i;
for (i = 0; i < (sizeof vapic_bios) / 4; ++i)
qemu_put_be32s(f, &((uint32_t *)&vapic_bios)[i]);
qemu_put_be32s(f, &bios_enabled);
qemu_put_be32s(f, &real_tpr);
qemu_put_be32s(f, &bios_addr);
qemu_put_be32s(f, &vapic_phys);
qemu_put_be32s(f, &vbios_desc_phys);
}
static int tpr_load(QEMUFile *f, void *s, int version_id)
{
int i;
if (version_id != 1)
return -EINVAL;
for (i = 0; i < (sizeof vapic_bios) / 4; ++i)
qemu_get_be32s(f, &((uint32_t *)&vapic_bios)[i]);
qemu_get_be32s(f, &bios_enabled);
qemu_get_be32s(f, &real_tpr);
qemu_get_be32s(f, &bios_addr);
qemu_get_be32s(f, &vapic_phys);
qemu_get_be32s(f, &vbios_desc_phys);
if (bios_enabled) {
CPUState *env = first_cpu->next_cpu;
for (env = first_cpu; env != NULL; env = env->next_cpu)
env->kvm_vcpu_update_vapic = 1;
}
return 0;
}
static void vtpr_ioport_write16(void *opaque, uint32_t addr, uint32_t val)
{
CPUState *env = cpu_single_env;
cpu_synchronize_state(env);
vapic_bios_addr = ((env->segs[R_CS].base + env->eip) & ~(512 - 1)) + val;
bios_enabled = 0;
}
static void vtpr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
{
CPUState *env = cpu_single_env;
uint32_t rip;
cpu_synchronize_state(env);
rip = env->eip - 2;
write_byte_virt(env, rip, 0x66);
write_byte_virt(env, rip + 1, 0x90);
if (bios_enabled)
return;
if (!bios_is_mapped(env, rip))
printf("bios not mapped?\n");
for (addr = 0xfffff000u; addr >= 0x80000000u; addr -= 4096)
if (map_addr(env, addr, NULL) == 0xfee00000u) {
real_tpr = addr + 0x80;
break;
}
bios_enabled = 1;
update_vbios_real_tpr();
kvm_tpr_enable_vapic(env);
}
static void kvm_tpr_opt_setup(void)
{
register_savevm(NULL, "kvm-tpr-opt", 0, 1, tpr_save, tpr_load, NULL);
register_ioport_write(0x7e, 1, 1, vtpr_ioport_write, NULL);
register_ioport_write(0x7e, 2, 2, vtpr_ioport_write16, NULL);
}
device_init(kvm_tpr_opt_setup);

33
kvm.h
View File

@@ -51,6 +51,7 @@ int kvm_has_debugregs(void);
int kvm_has_xsave(void); int kvm_has_xsave(void);
int kvm_has_xcrs(void); int kvm_has_xcrs(void);
int kvm_has_many_ioeventfds(void); int kvm_has_many_ioeventfds(void);
int kvm_has_pit_state2(void);
#ifdef NEED_CPU_H #ifdef NEED_CPU_H
int kvm_init_vcpu(CPUState *env); int kvm_init_vcpu(CPUState *env);
@@ -76,10 +77,10 @@ int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset);
#endif #endif
int kvm_pit_in_kernel(void); int kvm_pit_in_kernel(void);
int kvm_irqchip_in_kernel(void);
int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr); int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr);
int kvm_on_sigbus(int code, void *addr); int kvm_on_sigbus(int code, void *addr);
#endif /* NEED_CPU_H */
/* internal API */ /* internal API */
@@ -91,6 +92,7 @@ int kvm_ioctl(KVMState *s, int type, ...);
int kvm_vm_ioctl(KVMState *s, int type, ...); int kvm_vm_ioctl(KVMState *s, int type, ...);
#ifdef NEED_CPU_H
int kvm_vcpu_ioctl(CPUState *env, int type, ...); int kvm_vcpu_ioctl(CPUState *env, int type, ...);
/* Arch specific hooks */ /* Arch specific hooks */
@@ -186,7 +188,6 @@ static inline void cpu_synchronize_post_init(CPUState *env)
} }
} }
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr, int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr,
target_phys_addr_t *phys_addr); target_phys_addr_t *phys_addr);
@@ -195,5 +196,33 @@ int kvm_physical_memory_addr_from_ram(KVMState *s, ram_addr_t ram_addr,
#endif #endif
int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign); int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign);
int kvm_set_irqfd(int gsi, int fd, bool assigned);
int kvm_set_ioeventfd_pio_word(int fd, uint16_t adr, uint16_t val, bool assign); int kvm_set_ioeventfd_pio_word(int fd, uint16_t adr, uint16_t val, bool assign);
typedef struct KVMMsiMessage {
uint32_t gsi;
uint32_t addr_lo;
uint32_t addr_hi;
uint32_t data;
} KVMMsiMessage;
int kvm_has_gsi_routing(void);
int kvm_allows_irq0_override(void);
int kvm_get_irq_route_gsi(void);
int kvm_msi_message_add(KVMMsiMessage *msg);
int kvm_msi_message_del(KVMMsiMessage *msg);
int kvm_msi_message_update(KVMMsiMessage *old, KVMMsiMessage *new);
int kvm_commit_irq_routes(void);
int kvm_irqchip_in_kernel(void);
int kvm_set_irq(int irq, int level, int *status);
#ifdef NEED_CPU_H
#include "qemu-kvm.h"
#endif
#endif #endif

66
kvm/.gitignore vendored Normal file
View File

@@ -0,0 +1,66 @@
*.o
*.d
*~
*.flat
*.a
config.mak
.*.cmd
qemu/config-host.h
qemu/config-host.mak
user/test/bootstrap
user/kvmctl
qemu/dyngen
qemu/x86_64-softmmu
qemu/qemu-img
qemu/qemu-nbd
*.ko
*.mod.c
bios/*.bin
bios/*.sym
bios/*.txt
bios/acpi-dsdt.aml
vgabios/*.bin
vgabios/*.txt
extboot/extboot.bin
extboot/extboot.img
extboot/signrom
kernel/config.kbuild
kernel/modules.order
kernel/Module.symvers
kernel/Modules.symvers
kernel/Module.markers
kernel/.tmp_versions
kernel/include-compat/asm
kernel/include-compat/asm-x86/asm-x86
kernel/include
kernel/x86/modules.order
kernel/x86/i825[49].[ch]
kernel/x86/kvm_main.c
kernel/x86/kvm_svm.h
kernel/x86/vmx.[ch]
kernel/x86/svm.[ch]
kernel/x86/mmu.[ch]
kernel/x86/paging_tmpl.h
kernel/x86/x86_emulate.[ch]
kernel/x86/ioapic.[ch]
kernel/x86/iodev.h
kernel/x86/irq.[ch]
kernel/x86/kvm_trace.c
kernel/x86/lapic.[ch]
kernel/x86/tss.h
kernel/x86/x86.[ch]
kernel/x86/coalesced_mmio.[ch]
kernel/x86/kvm_cache_regs.h
kernel/x86/vtd.c
kernel/x86/irq_comm.c
kernel/x86/timer.c
kernel/x86/kvm_timer.h
kernel/x86/iommu.c
qemu/pc-bios/extboot.bin
qemu/qemu-doc.html
qemu/*.[18]
qemu/*.pod
qemu/qemu-tech.html
qemu/qemu-options.texi
user/kvmtrace
user/test/x86/bootstrap

125
kvm/Makefile Normal file
View File

@@ -0,0 +1,125 @@
include config.mak
DESTDIR=
rpmrelease = devel
sane-arch = $(subst i386,x86,$(subst x86_64,x86,$(subst s390x,s390,$(ARCH))))
.PHONY: kernel user libkvm qemu bios vgabios extboot clean libfdt cscope
all: libkvm qemu
ifneq '$(filter $(ARCH), x86_64 i386 ia64)' ''
all: $(if $(WANT_MODULE), kernel) user
endif
kcmd = $(if $(WANT_MODULE),,@\#)
qemu kernel user libkvm:
$(MAKE) -C $@
qemu: libkvm
ifneq '$(filter $(ARCH), i386 x86_64)' ''
qemu: extboot
endif
ifneq '$(filter $(ARCH), powerpc ia64)' ''
qemu: libfdt
endif
user: libkvm
# sync if kernel/Makefile exists and if using --with-patched-kernel
user libkvm qemu: header-sync-$(if $(wildcard kernel/Makefile),$(if $(WANT_MODULE),n,y),n)
header-sync-n:
header-sync-y:
make -C kernel \
LINUX=$(if $(KERNELSOURCEDIR),$(KERNELSOURCEDIR),$(KERNELDIR)) \
header-sync
rm -f kernel/include/asm
ln -sf asm-$(sane-arch) kernel/include/asm
bios:
$(MAKE) -C $@
cp bios/BIOS-bochs-latest qemu/pc-bios/bios.bin
vgabios:
$(MAKE) -C $@
cp vgabios/VGABIOS-lgpl-latest.bin qemu/pc-bios/vgabios.bin
cp vgabios/VGABIOS-lgpl-latest.cirrus.bin qemu/pc-bios/vgabios-cirrus.bin
extboot:
$(MAKE) -C $@
if ! [ -f qemu/pc-bios/extboot.bin ] \
|| ! cmp -s qemu/pc-bios/extboot.bin extboot/extboot.bin; then \
cp extboot/extboot.bin qemu/pc-bios/extboot.bin; \
fi
libfdt:
$(MAKE) -C $@
LINUX=linux-2.6
sync:
make -C kernel sync LINUX=$(shell readlink -f "$(LINUX)")
bindir = /usr/bin
bin = $(bindir)/kvm
initdir = /etc/init.d
confdir = /etc/kvm
utilsdir = /etc/kvm/utils
install-rpm:
mkdir -p $(DESTDIR)/$(bindir)
mkdir -p $(DESTDIR)/$(confdir)
mkdir -p $(DESTDIR)/$(initdir)
mkdir -p $(DESTDIR)/$(utilsdir)
mkdir -p $(DESTDIR)/etc/udev/rules.d
make -C qemu DESTDIR=$(DESTDIR)/ install
ln -sf /usr/kvm/bin/qemu-system-x86_64 $(DESTDIR)/$(bin)
install -m 755 kvm_stat $(DESTDIR)/$(bindir)/kvm_stat
cp scripts/kvm $(DESTDIR)/$(initdir)/kvm
cp scripts/qemu-ifup $(DESTDIR)/$(confdir)/qemu-ifup
install -t $(DESTDIR)/etc/udev/rules.d scripts/*kvm*.rules
install:
$(kcmd)make -C kernel DESTDIR="$(DESTDIR)" install
make -C libkvm DESTDIR="$(DESTDIR)" install
make -C qemu DESTDIR="$(DESTDIR)" install
tmpspec = .tmp.kvm.spec
RPMTOPDIR = $$(pwd)/rpmtop
rpm: srpm
rm -rf $(RPMTOPDIR)/BUILD
mkdir -p $(RPMTOPDIR)/{BUILD,RPMS/$$(uname -i)}
rpmbuild --rebuild \
--define="_topdir $(RPMTOPDIR)" \
$(RPMTOPDIR)/SRPMS/kvm-0.0-$(rpmrelease).src.rpm
srpm:
mkdir -p $(RPMTOPDIR)/{SOURCES,SRPMS}
sed 's/^Release:.*/Release: $(rpmrelease)/' kvm.spec > $(tmpspec)
tar czf $(RPMTOPDIR)/SOURCES/kvm.tar.gz qemu
tar czf $(RPMTOPDIR)/SOURCES/user.tar.gz user
tar czf $(RPMTOPDIR)/SOURCES/libkvm.tar.gz libkvm
tar czf $(RPMTOPDIR)/SOURCES/kernel.tar.gz kernel
tar czf $(RPMTOPDIR)/SOURCES/scripts.tar.gz scripts
tar czf $(RPMTOPDIR)/SOURCES/extboot.tar.gz extboot
cp Makefile configure kvm_stat $(RPMTOPDIR)/SOURCES
rpmbuild --define="_topdir $(RPMTOPDIR)" -bs $(tmpspec)
$(RM) $(tmpspec)
clean:
for i in $(if $(WANT_MODULE), kernel) user libkvm qemu libfdt; do \
make -C $$i clean; \
done
rm -f ./cscope.*
distclean: clean
rm -f config.mak user/config.mak
cscope:
rm -f ./cscope.*
find . -wholename './kernel' -prune -o -name "*.[ch]" -print > ./cscope.files
cscope -b

142
kvm/configure vendored Executable file
View File

@@ -0,0 +1,142 @@
#!/bin/bash
prefix=/usr/local
kerneldir=/lib/modules/$(uname -r)/build
cc=gcc
ld=ld
objcopy=objcopy
ar=ar
want_module=1
qemu_cflags=
qemu_ldflags=
kvm_trace=
qemu_opts=()
cross_prefix=
arch=`uname -m`
target_exec=
# don't use uname if kerneldir is set
no_uname=
if [ -z "TMPDIR" ] ; then
TMPDIR=.
fi
if [ ! -e kernel/Makefile ]; then
want_module=
fi
usage() {
cat <<-EOF
Usage: $0 [options]
Options include:
--arch=ARCH architecture to compile for ($arch)
--cross-prefix=PREFIX prefix for cross compile
--prefix=PREFIX where to install things ($prefix)
--with-patched-kernel don't use external module
--with-kvm-trace Enable kvm_trace
--kerneldir=DIR kernel build directory ($kerneldir)
--qemu-cflags=CFLAGS CFLAGS to add to qemu configuration
--qemu-ldflags=LDFLAGS LDFLAGS to add to qemu configuration
EOF
exit 1
}
while [[ "$1" = -* ]]; do
opt="$1"; shift
arg=
hasarg=
if [[ "$opt" = *=* ]]; then
arg="${opt#*=}"
opt="${opt%%=*}"
hasarg=1
fi
case "$opt" in
--prefix)
prefix="$arg"
;;
--kerneldir)
kerneldir="$arg"
no_uname=1
;;
--with-patched-kernel)
want_module=
;;
--with-kvm-trace)
kvm_trace=y
;;
--qemu-cflags)
qemu_cflags="$arg"
;;
--qemu-ldflags)
qemu_ldflags="$arg"
;;
--arch)
arch="$arg"
;;
--cross-prefix)
cross_prefix="$arg"
;;
--help)
usage
;;
*)
qemu_opts=("${qemu_opts[@]}" "$opt${hasarg:+=$arg}")
;;
esac
done
#set kenel directory
libkvm_kerneldir=$(readlink -f kernel)
case $arch in
i?86*|x86_64*)
arch=${arch/#i?86/i386}
target_exec="x86_64-softmmu"
qemu_cflags="$qemu_cflags -DCONFIG_X86"
;;
ia64*)
target_exec="ia64-softmmu"
;;
powerpc*)
target_exec="ppcemb-softmmu"
qemu_cflags="$qemu_cflags -I $PWD/libfdt"
qemu_ldflags="$qemu_ldflags -L $PWD/libfdt"
;;
esac
processor=${arch#*-}
arch=${arch%%-*}
#configure kernel module
[ -e kernel/Makefile ] && (cd kernel;
./configure \
--kerneldir="$kerneldir" \
--arch="$arch" \
$([ -z ${want_module} ] && echo "--with-patched-kernel") \
${cross_prefix:+"--cross-prefix=$cross_prefix"} \
${kvm_trace:+"--with-kvm-trace"}
)
#configure user dir
(cd user; ./configure --prefix="$prefix" --kerneldir="$libkvm_kerneldir" \
--arch="$arch" --processor="$processor" \
${cross_prefix:+"--cross-prefix=$cross_prefix"})
cat <<EOF > config.mak
ARCH=$arch
PROCESSOR=$processor
PREFIX=$prefix
KERNELDIR=$kerneldir
KERNELSOURCEDIR=$kernelsourcedir
LIBKVM_KERNELDIR=$libkvm_kerneldir
WANT_MODULE=$want_module
CROSS_COMPILE=$cross_prefix
CC=$cross_prefix$cc
LD=$cross_prefix$ld
OBJCOPY=$cross_prefix$objcopy
AR=$cross_prefix$ar
EOF

41
kvm/extboot/Makefile Normal file
View File

@@ -0,0 +1,41 @@
OBJCOPY=objcopy
# from kernel sources - scripts/Kbuild.include
# try-run
# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
# Exit code chooses option. "$$TMP" is can be used as temporary file and
# is automatically cleaned up.
try-run = $(shell set -e; \
TMP="$(TMPOUT).$$$$.tmp"; \
if ($(1)) >/dev/null 2>&1; \
then echo "$(2)"; \
else echo "$(3)"; \
fi; \
rm -f "$$TMP")
# cc-option-yn
# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
cc-option-yn = $(call try-run,\
$(CC) $(KBUILD_CFLAGS) $(1) -S -xc /dev/null -o "$$TMP",y,n)
CFLAGS = -Wall -Wstrict-prototypes -Werror -fomit-frame-pointer -fno-builtin
ifeq ($(call cc-option-yn,-fno-stack-protector),y)
CFLAGS += -fno-stack-protector
endif
all: extboot.bin
%.o: %.S
$(CC) $(CFLAGS) -o $@ -c $<
extboot.img: extboot.o
$(LD) --oformat binary -Ttext 0 -o $@ $<
extboot.bin: extboot.img signrom
./signrom extboot.img extboot.bin
signrom: signrom.c
$(CC) -o $@ -g -Wall $^
clean:
$(RM) *.o *.img *.bin signrom *~

6
kvm/extboot/STATUS Normal file
View File

@@ -0,0 +1,6 @@
Working
-------
Ubuntu Server 7.04 (i386)
Windows 2000 Professional (i386)
Windows XP SP2 (i386)

79
kvm/extboot/signrom.c Normal file
View File

@@ -0,0 +1,79 @@
/*
* Extended Boot Option ROM
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright IBM Corporation, 2007
* Authors: Anthony Liguori <aliguori@us.ibm.com>
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
int main(int argc, char **argv)
{
FILE *fin, *fout;
char buffer[512], oldbuffer[512];
int i, size, lag = 0;
uint8_t sum = 0;
if (argc != 3) {
printf("Usage: %s ROM OUTPUT\n", argv[0]);
return 1;
}
fin = fopen(argv[1], "rb");
fout = fopen(argv[2], "wb");
if (fin == NULL || fout == NULL) {
fprintf(stderr, "Could not open input/output files\n");
return 1;
}
do {
size = fread(buffer, 512, 1, fin);
if (size == 1) {
for (i = 0; i < 512; i++)
sum += buffer[i];
if (lag) {
if (fwrite(oldbuffer, 512, 1, fout) != 1) {
fprintf(stderr, "Write failed\n");
return 1;
}
}
lag = 1;
memcpy(oldbuffer, buffer, 512);
}
} while (size == 1);
if (size != 0) {
fprintf(stderr, "Failed to read from input file\n");
return 1;
}
oldbuffer[511] = -sum;
if (fwrite(oldbuffer, 512, 1, fout) != 1) {
fprintf(stderr, "Failed to write to output file\n");
return 1;
}
fclose(fin);
fclose(fout);
return 0;
}

264
kvm/include/ia64/asm/kvm.h Normal file
View File

@@ -0,0 +1,264 @@
#ifndef __ASM_IA64_KVM_H
#define __ASM_IA64_KVM_H
/*
* kvm structure definitions for ia64
*
* Copyright (C) 2007 Xiantao Zhang <xiantao.zhang@intel.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*
*/
#include <linux/types.h>
#include <linux/ioctl.h>
/* Select x86 specific features in <linux/kvm.h> */
#define __KVM_HAVE_IOAPIC
#define __KVM_HAVE_DEVICE_ASSIGNMENT
/* Architectural interrupt line count. */
#define KVM_NR_INTERRUPTS 256
#define KVM_IOAPIC_NUM_PINS 48
struct kvm_ioapic_state {
__u64 base_address;
__u32 ioregsel;
__u32 id;
__u32 irr;
__u32 pad;
union {
__u64 bits;
struct {
__u8 vector;
__u8 delivery_mode:3;
__u8 dest_mode:1;
__u8 delivery_status:1;
__u8 polarity:1;
__u8 remote_irr:1;
__u8 trig_mode:1;
__u8 mask:1;
__u8 reserve:7;
__u8 reserved[4];
__u8 dest_id;
} fields;
} redirtbl[KVM_IOAPIC_NUM_PINS];
};
#define KVM_IRQCHIP_PIC_MASTER 0
#define KVM_IRQCHIP_PIC_SLAVE 1
#define KVM_IRQCHIP_IOAPIC 2
#define KVM_NR_IRQCHIPS 3
#define KVM_CONTEXT_SIZE 8*1024
struct kvm_fpreg {
union {
unsigned long bits[2];
long double __dummy; /* force 16-byte alignment */
} u;
};
union context {
/* 8K size */
char dummy[KVM_CONTEXT_SIZE];
struct {
unsigned long psr;
unsigned long pr;
unsigned long caller_unat;
unsigned long pad;
unsigned long gr[32];
unsigned long ar[128];
unsigned long br[8];
unsigned long cr[128];
unsigned long rr[8];
unsigned long ibr[8];
unsigned long dbr[8];
unsigned long pkr[8];
struct kvm_fpreg fr[128];
};
};
struct thash_data {
union {
struct {
unsigned long p : 1; /* 0 */
unsigned long rv1 : 1; /* 1 */
unsigned long ma : 3; /* 2-4 */
unsigned long a : 1; /* 5 */
unsigned long d : 1; /* 6 */
unsigned long pl : 2; /* 7-8 */
unsigned long ar : 3; /* 9-11 */
unsigned long ppn : 38; /* 12-49 */
unsigned long rv2 : 2; /* 50-51 */
unsigned long ed : 1; /* 52 */
unsigned long ig1 : 11; /* 53-63 */
};
struct {
unsigned long __rv1 : 53; /* 0-52 */
unsigned long contiguous : 1; /*53 */
unsigned long tc : 1; /* 54 TR or TC */
unsigned long cl : 1;
/* 55 I side or D side cache line */
unsigned long len : 4; /* 56-59 */
unsigned long io : 1; /* 60 entry is for io or not */
unsigned long nomap : 1;
/* 61 entry cann't be inserted into machine TLB.*/
unsigned long checked : 1;
/* 62 for VTLB/VHPT sanity check */
unsigned long invalid : 1;
/* 63 invalid entry */
};
unsigned long page_flags;
}; /* same for VHPT and TLB */
union {
struct {
unsigned long rv3 : 2;
unsigned long ps : 6;
unsigned long key : 24;
unsigned long rv4 : 32;
};
unsigned long itir;
};
union {
struct {
unsigned long ig2 : 12;
unsigned long vpn : 49;
unsigned long vrn : 3;
};
unsigned long ifa;
unsigned long vadr;
struct {
unsigned long tag : 63;
unsigned long ti : 1;
};
unsigned long etag;
};
union {
struct thash_data *next;
unsigned long rid;
unsigned long gpaddr;
};
};
#define NITRS 8
#define NDTRS 8
struct saved_vpd {
unsigned long vhpi;
unsigned long vgr[16];
unsigned long vbgr[16];
unsigned long vnat;
unsigned long vbnat;
unsigned long vcpuid[5];
unsigned long vpsr;
unsigned long vpr;
union {
unsigned long vcr[128];
struct {
unsigned long dcr;
unsigned long itm;
unsigned long iva;
unsigned long rsv1[5];
unsigned long pta;
unsigned long rsv2[7];
unsigned long ipsr;
unsigned long isr;
unsigned long rsv3;
unsigned long iip;
unsigned long ifa;
unsigned long itir;
unsigned long iipa;
unsigned long ifs;
unsigned long iim;
unsigned long iha;
unsigned long rsv4[38];
unsigned long lid;
unsigned long ivr;
unsigned long tpr;
unsigned long eoi;
unsigned long irr[4];
unsigned long itv;
unsigned long pmv;
unsigned long cmcv;
unsigned long rsv5[5];
unsigned long lrr0;
unsigned long lrr1;
unsigned long rsv6[46];
};
};
};
struct kvm_regs {
struct saved_vpd vpd;
/*Arch-regs*/
int mp_state;
unsigned long vmm_rr;
/* TR and TC. */
struct thash_data itrs[NITRS];
struct thash_data dtrs[NDTRS];
/* Bit is set if there is a tr/tc for the region. */
unsigned char itr_regions;
unsigned char dtr_regions;
unsigned char tc_regions;
char irq_check;
unsigned long saved_itc;
unsigned long itc_check;
unsigned long timer_check;
unsigned long timer_pending;
unsigned long last_itc;
unsigned long vrr[8];
unsigned long ibr[8];
unsigned long dbr[8];
unsigned long insvc[4]; /* Interrupt in service. */
unsigned long xtp;
unsigned long metaphysical_rr0; /* from kvm_arch (so is pinned) */
unsigned long metaphysical_rr4; /* from kvm_arch (so is pinned) */
unsigned long metaphysical_saved_rr0; /* from kvm_arch */
unsigned long metaphysical_saved_rr4; /* from kvm_arch */
unsigned long fp_psr; /*used for lazy float register */
unsigned long saved_gp;
/*for phycial emulation */
union context saved_guest;
unsigned long reserved[64]; /* for future use */
};
struct kvm_sregs {
};
struct kvm_fpu {
};
#define KVM_IA64_VCPU_STACK_SHIFT 16
#define KVM_IA64_VCPU_STACK_SIZE (1UL << KVM_IA64_VCPU_STACK_SHIFT)
struct kvm_ia64_vcpu_stack {
unsigned char stack[KVM_IA64_VCPU_STACK_SIZE];
};
struct kvm_debug_exit_arch {
};
/* for KVM_SET_GUEST_DEBUG */
struct kvm_guest_debug_arch {
};
#endif

View File

@@ -0,0 +1,31 @@
#ifndef __IA64_KVM_PARA_H
#define __IA64_KVM_PARA_H
/*
* Copyright (C) 2007 Xiantao Zhang <xiantao.zhang@intel.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307 USA.
*
*/
#ifdef __KERNEL__
static inline unsigned int kvm_arch_para_features(void)
{
return 0;
}
#endif
#endif

View File

@@ -0,0 +1,2 @@
/* dummy file */

View File

@@ -0,0 +1,43 @@
#ifndef KVM_UNIFDEF_H
#define KVM_UNIFDEF_H
#ifdef __i386__
#ifndef CONFIG_X86_32
#define CONFIG_X86_32 1
#endif
#endif
#ifdef __x86_64__
#ifndef CONFIG_X86_64
#define CONFIG_X86_64 1
#endif
#endif
#if defined(__i386__) || defined (__x86_64__)
#ifndef CONFIG_X86
#define CONFIG_X86 1
#endif
#endif
#ifdef __ia64__
#ifndef CONFIG_IA64
#define CONFIG_IA64 1
#endif
#endif
#ifdef __PPC__
#ifndef CONFIG_PPC
#define CONFIG_PPC 1
#endif
#endif
#ifdef __s390__
#ifndef CONFIG_S390
#define CONFIG_S390 1
#endif
#endif
#endif
#define __user

784
kvm/include/linux/kvm.h Normal file
View File

@@ -0,0 +1,784 @@
#ifndef __LINUX_KVM_H
#define __LINUX_KVM_H
/*
* Userspace interface for /dev/kvm - kernel based virtual machine
*
* Note: you must update KVM_API_VERSION if you change this interface.
*/
#include <linux/types.h>
#include <linux/compiler.h>
#include <linux/ioctl.h>
#include <asm/kvm.h>
#define KVM_API_VERSION 12
/* *** Deprecated interfaces *** */
#define KVM_TRC_SHIFT 16
#define KVM_TRC_ENTRYEXIT (1 << KVM_TRC_SHIFT)
#define KVM_TRC_HANDLER (1 << (KVM_TRC_SHIFT + 1))
#define KVM_TRC_VMENTRY (KVM_TRC_ENTRYEXIT + 0x01)
#define KVM_TRC_VMEXIT (KVM_TRC_ENTRYEXIT + 0x02)
#define KVM_TRC_PAGE_FAULT (KVM_TRC_HANDLER + 0x01)
#define KVM_TRC_HEAD_SIZE 12
#define KVM_TRC_CYCLE_SIZE 8
#define KVM_TRC_EXTRA_MAX 7
#define KVM_TRC_INJ_VIRQ (KVM_TRC_HANDLER + 0x02)
#define KVM_TRC_REDELIVER_EVT (KVM_TRC_HANDLER + 0x03)
#define KVM_TRC_PEND_INTR (KVM_TRC_HANDLER + 0x04)
#define KVM_TRC_IO_READ (KVM_TRC_HANDLER + 0x05)
#define KVM_TRC_IO_WRITE (KVM_TRC_HANDLER + 0x06)
#define KVM_TRC_CR_READ (KVM_TRC_HANDLER + 0x07)
#define KVM_TRC_CR_WRITE (KVM_TRC_HANDLER + 0x08)
#define KVM_TRC_DR_READ (KVM_TRC_HANDLER + 0x09)
#define KVM_TRC_DR_WRITE (KVM_TRC_HANDLER + 0x0A)
#define KVM_TRC_MSR_READ (KVM_TRC_HANDLER + 0x0B)
#define KVM_TRC_MSR_WRITE (KVM_TRC_HANDLER + 0x0C)
#define KVM_TRC_CPUID (KVM_TRC_HANDLER + 0x0D)
#define KVM_TRC_INTR (KVM_TRC_HANDLER + 0x0E)
#define KVM_TRC_NMI (KVM_TRC_HANDLER + 0x0F)
#define KVM_TRC_VMMCALL (KVM_TRC_HANDLER + 0x10)
#define KVM_TRC_HLT (KVM_TRC_HANDLER + 0x11)
#define KVM_TRC_CLTS (KVM_TRC_HANDLER + 0x12)
#define KVM_TRC_LMSW (KVM_TRC_HANDLER + 0x13)
#define KVM_TRC_APIC_ACCESS (KVM_TRC_HANDLER + 0x14)
#define KVM_TRC_TDP_FAULT (KVM_TRC_HANDLER + 0x15)
#define KVM_TRC_GTLB_WRITE (KVM_TRC_HANDLER + 0x16)
#define KVM_TRC_STLB_WRITE (KVM_TRC_HANDLER + 0x17)
#define KVM_TRC_STLB_INVAL (KVM_TRC_HANDLER + 0x18)
#define KVM_TRC_PPC_INSTR (KVM_TRC_HANDLER + 0x19)
struct kvm_user_trace_setup {
__u32 buf_size;
__u32 buf_nr;
};
#define __KVM_DEPRECATED_MAIN_W_0x06 \
_IOW(KVMIO, 0x06, struct kvm_user_trace_setup)
#define __KVM_DEPRECATED_MAIN_0x07 _IO(KVMIO, 0x07)
#define __KVM_DEPRECATED_MAIN_0x08 _IO(KVMIO, 0x08)
#define __KVM_DEPRECATED_VM_R_0x70 _IOR(KVMIO, 0x70, struct kvm_assigned_irq)
struct kvm_breakpoint {
__u32 enabled;
__u32 padding;
__u64 address;
};
struct kvm_debug_guest {
__u32 enabled;
__u32 pad;
struct kvm_breakpoint breakpoints[4];
__u32 singlestep;
};
#define __KVM_DEPRECATED_VCPU_W_0x87 _IOW(KVMIO, 0x87, struct kvm_debug_guest)
/* *** End of deprecated interfaces *** */
/* for KVM_CREATE_MEMORY_REGION */
struct kvm_memory_region {
__u32 slot;
__u32 flags;
__u64 guest_phys_addr;
__u64 memory_size; /* bytes */
};
/* for KVM_SET_USER_MEMORY_REGION */
struct kvm_userspace_memory_region {
__u32 slot;
__u32 flags;
__u64 guest_phys_addr;
__u64 memory_size; /* bytes */
__u64 userspace_addr; /* start of the userspace allocated memory */
};
/* for kvm_memory_region::flags */
#define KVM_MEM_LOG_DIRTY_PAGES 1UL
#define KVM_MEMSLOT_INVALID (1UL << 1)
/* for KVM_IRQ_LINE */
struct kvm_irq_level {
/*
* ACPI gsi notion of irq.
* For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
* For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
*/
union {
__u32 irq;
__s32 status;
};
__u32 level;
};
struct kvm_irqchip {
__u32 chip_id;
__u32 pad;
union {
char dummy[512]; /* reserving space */
#ifdef __KVM_HAVE_PIT
struct kvm_pic_state pic;
#endif
#ifdef __KVM_HAVE_IOAPIC
struct kvm_ioapic_state ioapic;
#endif
} chip;
};
/* for KVM_CREATE_PIT2 */
struct kvm_pit_config {
__u32 flags;
__u32 pad[15];
};
#define KVM_PIT_SPEAKER_DUMMY 1
#define KVM_EXIT_UNKNOWN 0
#define KVM_EXIT_EXCEPTION 1
#define KVM_EXIT_IO 2
#define KVM_EXIT_HYPERCALL 3
#define KVM_EXIT_DEBUG 4
#define KVM_EXIT_HLT 5
#define KVM_EXIT_MMIO 6
#define KVM_EXIT_IRQ_WINDOW_OPEN 7
#define KVM_EXIT_SHUTDOWN 8
#define KVM_EXIT_FAIL_ENTRY 9
#define KVM_EXIT_INTR 10
#define KVM_EXIT_SET_TPR 11
#define KVM_EXIT_TPR_ACCESS 12
#define KVM_EXIT_S390_SIEIC 13
#define KVM_EXIT_S390_RESET 14
#define KVM_EXIT_DCR 15
#define KVM_EXIT_NMI 16
#define KVM_EXIT_INTERNAL_ERROR 17
#define KVM_EXIT_OSI 18
/* For KVM_EXIT_INTERNAL_ERROR */
#define KVM_INTERNAL_ERROR_EMULATION 1
#define KVM_INTERNAL_ERROR_SIMUL_EX 2
/* for KVM_RUN, returned by mmap(vcpu_fd, offset=0) */
struct kvm_run {
/* in */
__u8 request_interrupt_window;
__u8 padding1[7];
/* out */
__u32 exit_reason;
__u8 ready_for_interrupt_injection;
__u8 if_flag;
__u8 padding2[2];
/* in (pre_kvm_run), out (post_kvm_run) */
__u64 cr8;
__u64 apic_base;
#ifdef __KVM_S390
/* the processor status word for s390 */
__u64 psw_mask; /* psw upper half */
__u64 psw_addr; /* psw lower half */
#endif
union {
/* KVM_EXIT_UNKNOWN */
struct {
__u64 hardware_exit_reason;
} hw;
/* KVM_EXIT_FAIL_ENTRY */
struct {
__u64 hardware_entry_failure_reason;
} fail_entry;
/* KVM_EXIT_EXCEPTION */
struct {
__u32 exception;
__u32 error_code;
} ex;
/* KVM_EXIT_IO */
struct {
#define KVM_EXIT_IO_IN 0
#define KVM_EXIT_IO_OUT 1
__u8 direction;
__u8 size; /* bytes */
__u16 port;
__u32 count;
__u64 data_offset; /* relative to kvm_run start */
} io;
struct {
struct kvm_debug_exit_arch arch;
} debug;
/* KVM_EXIT_MMIO */
struct {
__u64 phys_addr;
__u8 data[8];
__u32 len;
__u8 is_write;
} mmio;
/* KVM_EXIT_HYPERCALL */
struct {
__u64 nr;
__u64 args[6];
__u64 ret;
__u32 longmode;
__u32 pad;
} hypercall;
/* KVM_EXIT_TPR_ACCESS */
struct {
__u64 rip;
__u32 is_write;
__u32 pad;
} tpr_access;
/* KVM_EXIT_S390_SIEIC */
struct {
__u8 icptcode;
__u16 ipa;
__u32 ipb;
} s390_sieic;
/* KVM_EXIT_S390_RESET */
#define KVM_S390_RESET_POR 1
#define KVM_S390_RESET_CLEAR 2
#define KVM_S390_RESET_SUBSYSTEM 4
#define KVM_S390_RESET_CPU_INIT 8
#define KVM_S390_RESET_IPL 16
__u64 s390_reset_flags;
/* KVM_EXIT_DCR */
struct {
__u32 dcrn;
__u32 data;
__u8 is_write;
} dcr;
struct {
__u32 suberror;
/* Available with KVM_CAP_INTERNAL_ERROR_DATA: */
__u32 ndata;
__u64 data[16];
} internal;
/* KVM_EXIT_OSI */
struct {
__u64 gprs[32];
} osi;
/* Fix the size of the union. */
char padding[256];
};
};
/* for KVM_REGISTER_COALESCED_MMIO / KVM_UNREGISTER_COALESCED_MMIO */
struct kvm_coalesced_mmio_zone {
__u64 addr;
__u32 size;
__u32 pad;
};
struct kvm_coalesced_mmio {
__u64 phys_addr;
__u32 len;
__u32 pad;
__u8 data[8];
};
struct kvm_coalesced_mmio_ring {
__u32 first, last;
struct kvm_coalesced_mmio coalesced_mmio[0];
};
#define KVM_COALESCED_MMIO_MAX \
((PAGE_SIZE - sizeof(struct kvm_coalesced_mmio_ring)) / \
sizeof(struct kvm_coalesced_mmio))
/* for KVM_TRANSLATE */
struct kvm_translation {
/* in */
__u64 linear_address;
/* out */
__u64 physical_address;
__u8 valid;
__u8 writeable;
__u8 usermode;
__u8 pad[5];
};
/* for KVM_INTERRUPT */
struct kvm_interrupt {
/* in */
__u32 irq;
};
/* for KVM_GET_DIRTY_LOG */
struct kvm_dirty_log {
__u32 slot;
__u32 padding1;
union {
void *dirty_bitmap; /* one bit per page */
__u64 padding2;
};
};
/* for KVM_SET_SIGNAL_MASK */
struct kvm_signal_mask {
__u32 len;
__u8 sigset[0];
};
/* for KVM_TPR_ACCESS_REPORTING */
struct kvm_tpr_access_ctl {
__u32 enabled;
__u32 flags;
__u32 reserved[8];
};
/* for KVM_SET_VAPIC_ADDR */
struct kvm_vapic_addr {
__u64 vapic_addr;
};
/* for KVM_SET_MPSTATE */
#define KVM_MP_STATE_RUNNABLE 0
#define KVM_MP_STATE_UNINITIALIZED 1
#define KVM_MP_STATE_INIT_RECEIVED 2
#define KVM_MP_STATE_HALTED 3
#define KVM_MP_STATE_SIPI_RECEIVED 4
struct kvm_mp_state {
__u32 mp_state;
};
struct kvm_s390_psw {
__u64 mask;
__u64 addr;
};
/* valid values for type in kvm_s390_interrupt */
#define KVM_S390_SIGP_STOP 0xfffe0000u
#define KVM_S390_PROGRAM_INT 0xfffe0001u
#define KVM_S390_SIGP_SET_PREFIX 0xfffe0002u
#define KVM_S390_RESTART 0xfffe0003u
#define KVM_S390_INT_VIRTIO 0xffff2603u
#define KVM_S390_INT_SERVICE 0xffff2401u
#define KVM_S390_INT_EMERGENCY 0xffff1201u
struct kvm_s390_interrupt {
__u32 type;
__u32 parm;
__u64 parm64;
};
/* for KVM_SET_GUEST_DEBUG */
#define KVM_GUESTDBG_ENABLE 0x00000001
#define KVM_GUESTDBG_SINGLESTEP 0x00000002
struct kvm_guest_debug {
__u32 control;
__u32 pad;
struct kvm_guest_debug_arch arch;
};
enum {
kvm_ioeventfd_flag_nr_datamatch,
kvm_ioeventfd_flag_nr_pio,
kvm_ioeventfd_flag_nr_deassign,
kvm_ioeventfd_flag_nr_max,
};
#define KVM_IOEVENTFD_FLAG_DATAMATCH (1 << kvm_ioeventfd_flag_nr_datamatch)
#define KVM_IOEVENTFD_FLAG_PIO (1 << kvm_ioeventfd_flag_nr_pio)
#define KVM_IOEVENTFD_FLAG_DEASSIGN (1 << kvm_ioeventfd_flag_nr_deassign)
#define KVM_IOEVENTFD_VALID_FLAG_MASK ((1 << kvm_ioeventfd_flag_nr_max) - 1)
struct kvm_ioeventfd {
__u64 datamatch;
__u64 addr; /* legal pio/mmio address */
__u32 len; /* 1, 2, 4, or 8 bytes */
__s32 fd;
__u32 flags;
__u8 pad[36];
};
/* for KVM_ENABLE_CAP */
struct kvm_enable_cap {
/* in */
__u32 cap;
__u32 flags;
__u64 args[4];
__u8 pad[64];
};
#define KVMIO 0xAE
/*
* ioctls for /dev/kvm fds:
*/
#define KVM_GET_API_VERSION _IO(KVMIO, 0x00)
#define KVM_CREATE_VM _IO(KVMIO, 0x01) /* returns a VM fd */
#define KVM_GET_MSR_INDEX_LIST _IOWR(KVMIO, 0x02, struct kvm_msr_list)
#define KVM_S390_ENABLE_SIE _IO(KVMIO, 0x06)
/*
* Check if a kvm extension is available. Argument is extension number,
* return is 1 (yes) or 0 (no, sorry).
*/
#define KVM_CHECK_EXTENSION _IO(KVMIO, 0x03)
/*
* Get size for mmap(vcpu_fd)
*/
#define KVM_GET_VCPU_MMAP_SIZE _IO(KVMIO, 0x04) /* in bytes */
#define KVM_GET_SUPPORTED_CPUID _IOWR(KVMIO, 0x05, struct kvm_cpuid2)
#define KVM_TRACE_ENABLE __KVM_DEPRECATED_MAIN_W_0x06
#define KVM_TRACE_PAUSE __KVM_DEPRECATED_MAIN_0x07
#define KVM_TRACE_DISABLE __KVM_DEPRECATED_MAIN_0x08
/*
* Extension capability list.
*/
#define KVM_CAP_IRQCHIP 0
#define KVM_CAP_HLT 1
#define KVM_CAP_MMU_SHADOW_CACHE_CONTROL 2
#define KVM_CAP_USER_MEMORY 3
#define KVM_CAP_SET_TSS_ADDR 4
#define KVM_CAP_VAPIC 6
#define KVM_CAP_EXT_CPUID 7
#define KVM_CAP_CLOCKSOURCE 8
#define KVM_CAP_NR_VCPUS 9 /* returns max vcpus per vm */
#define KVM_CAP_NR_MEMSLOTS 10 /* returns max memory slots per vm */
#define KVM_CAP_PIT 11
#define KVM_CAP_NOP_IO_DELAY 12
#define KVM_CAP_PV_MMU 13
#define KVM_CAP_MP_STATE 14
#define KVM_CAP_COALESCED_MMIO 15
#define KVM_CAP_SYNC_MMU 16 /* Changes to host mmap are reflected in guest */
#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
#define KVM_CAP_DEVICE_ASSIGNMENT 17
#endif
#define KVM_CAP_IOMMU 18
#ifdef __KVM_HAVE_MSI
#define KVM_CAP_DEVICE_MSI 20
#endif
/* Bug in KVM_SET_USER_MEMORY_REGION fixed: */
#define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21
#ifdef __KVM_HAVE_USER_NMI
#define KVM_CAP_USER_NMI 22
#endif
#ifdef __KVM_HAVE_GUEST_DEBUG
#define KVM_CAP_SET_GUEST_DEBUG 23
#endif
#ifdef __KVM_HAVE_PIT
#define KVM_CAP_REINJECT_CONTROL 24
#endif
#ifdef __KVM_HAVE_IOAPIC
#define KVM_CAP_IRQ_ROUTING 25
#endif
#define KVM_CAP_IRQ_INJECT_STATUS 26
#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
#define KVM_CAP_DEVICE_DEASSIGNMENT 27
#endif
#ifdef __KVM_HAVE_MSIX
#define KVM_CAP_DEVICE_MSIX 28
#endif
#define KVM_CAP_ASSIGN_DEV_IRQ 29
/* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
#define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30
#ifdef __KVM_HAVE_MCE
#define KVM_CAP_MCE 31
#endif
#define KVM_CAP_IRQFD 32
#ifdef __KVM_HAVE_PIT
#define KVM_CAP_PIT2 33
#endif
#define KVM_CAP_SET_BOOT_CPU_ID 34
#ifdef __KVM_HAVE_PIT_STATE2
#define KVM_CAP_PIT_STATE2 35
#endif
#define KVM_CAP_IOEVENTFD 36
#define KVM_CAP_SET_IDENTITY_MAP_ADDR 37
#ifdef __KVM_HAVE_XEN_HVM
#define KVM_CAP_XEN_HVM 38
#endif
#define KVM_CAP_ADJUST_CLOCK 39
#define KVM_CAP_INTERNAL_ERROR_DATA 40
#ifdef __KVM_HAVE_VCPU_EVENTS
#define KVM_CAP_VCPU_EVENTS 41
#endif
#define KVM_CAP_S390_PSW 42
#define KVM_CAP_PPC_SEGSTATE 43
#define KVM_CAP_HYPERV 44
#define KVM_CAP_HYPERV_VAPIC 45
#define KVM_CAP_HYPERV_SPIN 46
#define KVM_CAP_PCI_SEGMENT 47
#define KVM_CAP_PPC_PAIRED_SINGLES 48
#define KVM_CAP_INTR_SHADOW 49
#ifdef __KVM_HAVE_DEBUGREGS
#define KVM_CAP_DEBUGREGS 50
#endif
#define KVM_CAP_X86_ROBUST_SINGLESTEP 51
#define KVM_CAP_PPC_OSI 52
#define KVM_CAP_PPC_UNSET_IRQ 53
#define KVM_CAP_ENABLE_CAP 54
#ifdef __KVM_HAVE_XSAVE
#define KVM_CAP_XSAVE 55
#endif
#ifdef __KVM_HAVE_XCRS
#define KVM_CAP_XCRS 56
#endif
#ifdef KVM_CAP_IRQ_ROUTING
struct kvm_irq_routing_irqchip {
__u32 irqchip;
__u32 pin;
};
struct kvm_irq_routing_msi {
__u32 address_lo;
__u32 address_hi;
__u32 data;
__u32 pad;
};
/* gsi routing entry types */
#define KVM_IRQ_ROUTING_IRQCHIP 1
#define KVM_IRQ_ROUTING_MSI 2
struct kvm_irq_routing_entry {
__u32 gsi;
__u32 type;
__u32 flags;
__u32 pad;
union {
struct kvm_irq_routing_irqchip irqchip;
struct kvm_irq_routing_msi msi;
__u32 pad[8];
} u;
};
struct kvm_irq_routing {
__u32 nr;
__u32 flags;
struct kvm_irq_routing_entry entries[0];
};
#endif
#ifdef KVM_CAP_MCE
/* x86 MCE */
struct kvm_x86_mce {
__u64 status;
__u64 addr;
__u64 misc;
__u64 mcg_status;
__u8 bank;
__u8 pad1[7];
__u64 pad2[3];
};
#endif
#ifdef KVM_CAP_XEN_HVM
struct kvm_xen_hvm_config {
__u32 flags;
__u32 msr;
__u64 blob_addr_32;
__u64 blob_addr_64;
__u8 blob_size_32;
__u8 blob_size_64;
__u8 pad2[30];
};
#endif
#define KVM_IRQFD_FLAG_DEASSIGN (1 << 0)
struct kvm_irqfd {
__u32 fd;
__u32 gsi;
__u32 flags;
__u8 pad[20];
};
struct kvm_clock_data {
__u64 clock;
__u32 flags;
__u32 pad[9];
};
/*
* ioctls for VM fds
*/
#define KVM_SET_MEMORY_REGION _IOW(KVMIO, 0x40, struct kvm_memory_region)
/*
* KVM_CREATE_VCPU receives as a parameter the vcpu slot, and returns
* a vcpu fd.
*/
#define KVM_CREATE_VCPU _IO(KVMIO, 0x41)
#define KVM_GET_DIRTY_LOG _IOW(KVMIO, 0x42, struct kvm_dirty_log)
#define KVM_SET_MEMORY_ALIAS _IOW(KVMIO, 0x43, struct kvm_memory_alias)
#define KVM_SET_NR_MMU_PAGES _IO(KVMIO, 0x44)
#define KVM_GET_NR_MMU_PAGES _IO(KVMIO, 0x45)
#define KVM_SET_USER_MEMORY_REGION _IOW(KVMIO, 0x46, \
struct kvm_userspace_memory_region)
#define KVM_SET_TSS_ADDR _IO(KVMIO, 0x47)
#define KVM_SET_IDENTITY_MAP_ADDR _IOW(KVMIO, 0x48, __u64)
/* Device model IOC */
#define KVM_CREATE_IRQCHIP _IO(KVMIO, 0x60)
#define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level)
#define KVM_GET_IRQCHIP _IOWR(KVMIO, 0x62, struct kvm_irqchip)
#define KVM_SET_IRQCHIP _IOR(KVMIO, 0x63, struct kvm_irqchip)
#define KVM_CREATE_PIT _IO(KVMIO, 0x64)
#define KVM_GET_PIT _IOWR(KVMIO, 0x65, struct kvm_pit_state)
#define KVM_SET_PIT _IOR(KVMIO, 0x66, struct kvm_pit_state)
#define KVM_IRQ_LINE_STATUS _IOWR(KVMIO, 0x67, struct kvm_irq_level)
#define KVM_REGISTER_COALESCED_MMIO \
_IOW(KVMIO, 0x67, struct kvm_coalesced_mmio_zone)
#define KVM_UNREGISTER_COALESCED_MMIO \
_IOW(KVMIO, 0x68, struct kvm_coalesced_mmio_zone)
#define KVM_ASSIGN_PCI_DEVICE _IOR(KVMIO, 0x69, \
struct kvm_assigned_pci_dev)
#define KVM_SET_GSI_ROUTING _IOW(KVMIO, 0x6a, struct kvm_irq_routing)
/* deprecated, replaced by KVM_ASSIGN_DEV_IRQ */
#define KVM_ASSIGN_IRQ __KVM_DEPRECATED_VM_R_0x70
#define KVM_ASSIGN_DEV_IRQ _IOW(KVMIO, 0x70, struct kvm_assigned_irq)
#define KVM_REINJECT_CONTROL _IO(KVMIO, 0x71)
#define KVM_DEASSIGN_PCI_DEVICE _IOW(KVMIO, 0x72, \
struct kvm_assigned_pci_dev)
#define KVM_ASSIGN_SET_MSIX_NR _IOW(KVMIO, 0x73, \
struct kvm_assigned_msix_nr)
#define KVM_ASSIGN_SET_MSIX_ENTRY _IOW(KVMIO, 0x74, \
struct kvm_assigned_msix_entry)
#define KVM_DEASSIGN_DEV_IRQ _IOW(KVMIO, 0x75, struct kvm_assigned_irq)
#define KVM_IRQFD _IOW(KVMIO, 0x76, struct kvm_irqfd)
#define KVM_CREATE_PIT2 _IOW(KVMIO, 0x77, struct kvm_pit_config)
#define KVM_SET_BOOT_CPU_ID _IO(KVMIO, 0x78)
#define KVM_IOEVENTFD _IOW(KVMIO, 0x79, struct kvm_ioeventfd)
#define KVM_XEN_HVM_CONFIG _IOW(KVMIO, 0x7a, struct kvm_xen_hvm_config)
#define KVM_SET_CLOCK _IOW(KVMIO, 0x7b, struct kvm_clock_data)
#define KVM_GET_CLOCK _IOR(KVMIO, 0x7c, struct kvm_clock_data)
/* Available with KVM_CAP_PIT_STATE2 */
#define KVM_GET_PIT2 _IOR(KVMIO, 0x9f, struct kvm_pit_state2)
#define KVM_SET_PIT2 _IOW(KVMIO, 0xa0, struct kvm_pit_state2)
/*
* ioctls for vcpu fds
*/
#define KVM_RUN _IO(KVMIO, 0x80)
#define KVM_GET_REGS _IOR(KVMIO, 0x81, struct kvm_regs)
#define KVM_SET_REGS _IOW(KVMIO, 0x82, struct kvm_regs)
#define KVM_GET_SREGS _IOR(KVMIO, 0x83, struct kvm_sregs)
#define KVM_SET_SREGS _IOW(KVMIO, 0x84, struct kvm_sregs)
#define KVM_TRANSLATE _IOWR(KVMIO, 0x85, struct kvm_translation)
#define KVM_INTERRUPT _IOW(KVMIO, 0x86, struct kvm_interrupt)
/* KVM_DEBUG_GUEST is no longer supported, use KVM_SET_GUEST_DEBUG instead */
#define KVM_DEBUG_GUEST __KVM_DEPRECATED_VCPU_W_0x87
#define KVM_GET_MSRS _IOWR(KVMIO, 0x88, struct kvm_msrs)
#define KVM_SET_MSRS _IOW(KVMIO, 0x89, struct kvm_msrs)
#define KVM_SET_CPUID _IOW(KVMIO, 0x8a, struct kvm_cpuid)
#define KVM_SET_SIGNAL_MASK _IOW(KVMIO, 0x8b, struct kvm_signal_mask)
#define KVM_GET_FPU _IOR(KVMIO, 0x8c, struct kvm_fpu)
#define KVM_SET_FPU _IOW(KVMIO, 0x8d, struct kvm_fpu)
#define KVM_GET_LAPIC _IOR(KVMIO, 0x8e, struct kvm_lapic_state)
#define KVM_SET_LAPIC _IOW(KVMIO, 0x8f, struct kvm_lapic_state)
#define KVM_SET_CPUID2 _IOW(KVMIO, 0x90, struct kvm_cpuid2)
#define KVM_GET_CPUID2 _IOWR(KVMIO, 0x91, struct kvm_cpuid2)
/* Available with KVM_CAP_VAPIC */
#define KVM_TPR_ACCESS_REPORTING _IOWR(KVMIO, 0x92, struct kvm_tpr_access_ctl)
/* Available with KVM_CAP_VAPIC */
#define KVM_SET_VAPIC_ADDR _IOW(KVMIO, 0x93, struct kvm_vapic_addr)
/* valid for virtual machine (for floating interrupt)_and_ vcpu */
#define KVM_S390_INTERRUPT _IOW(KVMIO, 0x94, struct kvm_s390_interrupt)
/* store status for s390 */
#define KVM_S390_STORE_STATUS_NOADDR (-1ul)
#define KVM_S390_STORE_STATUS_PREFIXED (-2ul)
#define KVM_S390_STORE_STATUS _IOW(KVMIO, 0x95, unsigned long)
/* initial ipl psw for s390 */
#define KVM_S390_SET_INITIAL_PSW _IOW(KVMIO, 0x96, struct kvm_s390_psw)
/* initial reset for s390 */
#define KVM_S390_INITIAL_RESET _IO(KVMIO, 0x97)
#define KVM_GET_MP_STATE _IOR(KVMIO, 0x98, struct kvm_mp_state)
#define KVM_SET_MP_STATE _IOW(KVMIO, 0x99, struct kvm_mp_state)
/* Available with KVM_CAP_NMI */
#define KVM_NMI _IO(KVMIO, 0x9a)
/* Available with KVM_CAP_SET_GUEST_DEBUG */
#define KVM_SET_GUEST_DEBUG _IOW(KVMIO, 0x9b, struct kvm_guest_debug)
/* MCE for x86 */
#define KVM_X86_SETUP_MCE _IOW(KVMIO, 0x9c, __u64)
#define KVM_X86_GET_MCE_CAP_SUPPORTED _IOR(KVMIO, 0x9d, __u64)
#define KVM_X86_SET_MCE _IOW(KVMIO, 0x9e, struct kvm_x86_mce)
/* IA64 stack access */
#define KVM_IA64_VCPU_GET_STACK _IOR(KVMIO, 0x9a, void *)
#define KVM_IA64_VCPU_SET_STACK _IOW(KVMIO, 0x9b, void *)
/* Available with KVM_CAP_VCPU_EVENTS */
#define KVM_GET_VCPU_EVENTS _IOR(KVMIO, 0x9f, struct kvm_vcpu_events)
#define KVM_SET_VCPU_EVENTS _IOW(KVMIO, 0xa0, struct kvm_vcpu_events)
/* Available with KVM_CAP_DEBUGREGS */
#define KVM_GET_DEBUGREGS _IOR(KVMIO, 0xa1, struct kvm_debugregs)
#define KVM_SET_DEBUGREGS _IOW(KVMIO, 0xa2, struct kvm_debugregs)
#define KVM_ENABLE_CAP _IOW(KVMIO, 0xa3, struct kvm_enable_cap)
/* Available with KVM_CAP_XSAVE */
#define KVM_GET_XSAVE _IOR(KVMIO, 0xa4, struct kvm_xsave)
#define KVM_SET_XSAVE _IOW(KVMIO, 0xa5, struct kvm_xsave)
/* Available with KVM_CAP_XCRS */
#define KVM_GET_XCRS _IOR(KVMIO, 0xa6, struct kvm_xcrs)
#define KVM_SET_XCRS _IOW(KVMIO, 0xa7, struct kvm_xcrs)
#define KVM_DEV_ASSIGN_ENABLE_IOMMU (1 << 0)
struct kvm_assigned_pci_dev {
__u32 assigned_dev_id;
__u32 busnr;
__u32 devfn;
__u32 flags;
__u32 segnr;
union {
__u32 reserved[11];
};
};
#define KVM_DEV_IRQ_HOST_INTX (1 << 0)
#define KVM_DEV_IRQ_HOST_MSI (1 << 1)
#define KVM_DEV_IRQ_HOST_MSIX (1 << 2)
#define KVM_DEV_IRQ_GUEST_INTX (1 << 8)
#define KVM_DEV_IRQ_GUEST_MSI (1 << 9)
#define KVM_DEV_IRQ_GUEST_MSIX (1 << 10)
#define KVM_DEV_IRQ_HOST_MASK 0x00ff
#define KVM_DEV_IRQ_GUEST_MASK 0xff00
struct kvm_assigned_irq {
__u32 assigned_dev_id;
__u32 host_irq;
__u32 guest_irq;
__u32 flags;
union {
struct {
__u32 addr_lo;
__u32 addr_hi;
__u32 data;
} guest_msi;
__u32 reserved[12];
};
};
struct kvm_assigned_msix_nr {
__u32 assigned_dev_id;
__u16 entry_nr;
__u16 padding;
};
#define KVM_MAX_MSIX_PER_DEV 256
struct kvm_assigned_msix_entry {
__u32 assigned_dev_id;
__u32 gsi;
__u16 entry; /* The index of entry in the MSI-X table */
__u16 padding[3];
};
#endif /* __LINUX_KVM_H */

View File

@@ -0,0 +1,41 @@
#ifndef __LINUX_KVM_PARA_H
#define __LINUX_KVM_PARA_H
/*
* This header file provides a method for making a hypercall to the host
* Architectures should define:
* - kvm_hypercall0, kvm_hypercall1...
* - kvm_arch_para_features
* - kvm_para_available
*/
/* Return values for hypercalls */
#define KVM_ENOSYS 1000
#define KVM_EFAULT EFAULT
#define KVM_E2BIG E2BIG
#define KVM_EPERM EPERM
#define KVM_HC_VAPIC_POLL_IRQ 1
#define KVM_HC_MMU_OP 2
/*
* hypercalls use architecture specific
*/
#include <asm/kvm_para.h>
#ifdef __KERNEL__
#ifdef CONFIG_KVM_GUEST
void __init kvm_guest_init(void);
#else
#define kvm_guest_init() do { } while (0)
#endif
static inline int kvm_para_has_feature(unsigned int feature)
{
if (kvm_arch_para_features() & (1UL << feature))
return 1;
return 0;
}
#endif /* __KERNEL__ */
#endif /* __LINUX_KVM_PARA_H */

130
kvm/include/linux/vhost.h Normal file
View File

@@ -0,0 +1,130 @@
#ifndef _LINUX_VHOST_H
#define _LINUX_VHOST_H
/* Userspace interface for in-kernel virtio accelerators. */
/* vhost is used to reduce the number of system calls involved in virtio.
*
* Existing virtio net code is used in the guest without modification.
*
* This header includes interface used by userspace hypervisor for
* device configuration.
*/
#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/virtio_config.h>
#include <linux/virtio_ring.h>
struct vhost_vring_state {
unsigned int index;
unsigned int num;
};
struct vhost_vring_file {
unsigned int index;
int fd; /* Pass -1 to unbind from file. */
};
struct vhost_vring_addr {
unsigned int index;
/* Option flags. */
unsigned int flags;
/* Flag values: */
/* Whether log address is valid. If set enables logging. */
#define VHOST_VRING_F_LOG 0
/* Start of array of descriptors (virtually contiguous) */
__u64 desc_user_addr;
/* Used structure address. Must be 32 bit aligned */
__u64 used_user_addr;
/* Available structure address. Must be 16 bit aligned */
__u64 avail_user_addr;
/* Logging support. */
/* Log writes to used structure, at offset calculated from specified
* address. Address must be 32 bit aligned. */
__u64 log_guest_addr;
};
struct vhost_memory_region {
__u64 guest_phys_addr;
__u64 memory_size; /* bytes */
__u64 userspace_addr;
__u64 flags_padding; /* No flags are currently specified. */
};
/* All region addresses and sizes must be 4K aligned. */
#define VHOST_PAGE_SIZE 0x1000
struct vhost_memory {
__u32 nregions;
__u32 padding;
struct vhost_memory_region regions[0];
};
/* ioctls */
#define VHOST_VIRTIO 0xAF
/* Features bitmask for forward compatibility. Transport bits are used for
* vhost specific features. */
#define VHOST_GET_FEATURES _IOR(VHOST_VIRTIO, 0x00, __u64)
#define VHOST_SET_FEATURES _IOW(VHOST_VIRTIO, 0x00, __u64)
/* Set current process as the (exclusive) owner of this file descriptor. This
* must be called before any other vhost command. Further calls to
* VHOST_OWNER_SET fail until VHOST_OWNER_RESET is called. */
#define VHOST_SET_OWNER _IO(VHOST_VIRTIO, 0x01)
/* Give up ownership, and reset the device to default values.
* Allows subsequent call to VHOST_OWNER_SET to succeed. */
#define VHOST_RESET_OWNER _IO(VHOST_VIRTIO, 0x02)
/* Set up/modify memory layout */
#define VHOST_SET_MEM_TABLE _IOW(VHOST_VIRTIO, 0x03, struct vhost_memory)
/* Write logging setup. */
/* Memory writes can optionally be logged by setting bit at an offset
* (calculated from the physical address) from specified log base.
* The bit is set using an atomic 32 bit operation. */
/* Set base address for logging. */
#define VHOST_SET_LOG_BASE _IOW(VHOST_VIRTIO, 0x04, __u64)
/* Specify an eventfd file descriptor to signal on log write. */
#define VHOST_SET_LOG_FD _IOW(VHOST_VIRTIO, 0x07, int)
/* Ring setup. */
/* Set number of descriptors in ring. This parameter can not
* be modified while ring is running (bound to a device). */
#define VHOST_SET_VRING_NUM _IOW(VHOST_VIRTIO, 0x10, struct vhost_vring_state)
/* Set addresses for the ring. */
#define VHOST_SET_VRING_ADDR _IOW(VHOST_VIRTIO, 0x11, struct vhost_vring_addr)
/* Base value where queue looks for available descriptors */
#define VHOST_SET_VRING_BASE _IOW(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
/* Get accessor: reads index, writes value in num */
#define VHOST_GET_VRING_BASE _IOWR(VHOST_VIRTIO, 0x12, struct vhost_vring_state)
/* The following ioctls use eventfd file descriptors to signal and poll
* for events. */
/* Set eventfd to poll for added buffers */
#define VHOST_SET_VRING_KICK _IOW(VHOST_VIRTIO, 0x20, struct vhost_vring_file)
/* Set eventfd to signal when buffers have beed used */
#define VHOST_SET_VRING_CALL _IOW(VHOST_VIRTIO, 0x21, struct vhost_vring_file)
/* Set eventfd to signal an error */
#define VHOST_SET_VRING_ERR _IOW(VHOST_VIRTIO, 0x22, struct vhost_vring_file)
/* VHOST_NET specific defines */
/* Attach virtio net ring to a raw socket, or tap device.
* The socket must be already bound to an ethernet device, this device will be
* used for transmit. Pass fd -1 to unbind from the socket and the transmit
* device. This can be used to stop the ring (e.g. for migration). */
#define VHOST_NET_SET_BACKEND _IOW(VHOST_VIRTIO, 0x30, struct vhost_vring_file)
/* Feature bits */
/* Log all write descriptors. Can be changed while device is active. */
#define VHOST_F_LOG_ALL 26
/* vhost-net should add virtio_net_hdr for RX, and strip for TX packets. */
#define VHOST_NET_F_VIRTIO_NET_HDR 27
#endif

View File

@@ -0,0 +1,62 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright IBM Corp. 2007
*
* Authors: Hollis Blanchard <hollisb@us.ibm.com>
*/
#ifndef __LINUX_KVM_POWERPC_H
#define __LINUX_KVM_POWERPC_H
#include <linux/types.h>
struct kvm_regs {
__u64 pc;
__u64 cr;
__u64 ctr;
__u64 lr;
__u64 xer;
__u64 msr;
__u64 srr0;
__u64 srr1;
__u64 pid;
__u64 sprg0;
__u64 sprg1;
__u64 sprg2;
__u64 sprg3;
__u64 sprg4;
__u64 sprg5;
__u64 sprg6;
__u64 sprg7;
__u64 gpr[32];
};
struct kvm_sregs {
};
struct kvm_fpu {
__u64 fpr[32];
};
struct kvm_debug_exit_arch {
};
/* for KVM_SET_GUEST_DEBUG */
struct kvm_guest_debug_arch {
};
#endif /* __LINUX_KVM_POWERPC_H */

View File

@@ -0,0 +1,37 @@
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright IBM Corp. 2008
*
* Authors: Hollis Blanchard <hollisb@us.ibm.com>
*/
#ifndef __POWERPC_KVM_PARA_H__
#define __POWERPC_KVM_PARA_H__
#ifdef __KERNEL__
static inline int kvm_para_available(void)
{
return 0;
}
static inline unsigned int kvm_arch_para_features(void)
{
return 0;
}
#endif /* __KERNEL__ */
#endif /* __POWERPC_KVM_PARA_H__ */

324
kvm/include/x86/asm/kvm.h Normal file
View File

@@ -0,0 +1,324 @@
#ifndef _ASM_X86_KVM_H
#define _ASM_X86_KVM_H
/*
* KVM x86 specific structures and definitions
*
*/
#include <linux/types.h>
#include <linux/ioctl.h>
/* Select x86 specific features in <linux/kvm.h> */
#define __KVM_HAVE_PIT
#define __KVM_HAVE_IOAPIC
#define __KVM_HAVE_DEVICE_ASSIGNMENT
#define __KVM_HAVE_MSI
#define __KVM_HAVE_USER_NMI
#define __KVM_HAVE_GUEST_DEBUG
#define __KVM_HAVE_MSIX
#define __KVM_HAVE_MCE
#define __KVM_HAVE_PIT_STATE2
#define __KVM_HAVE_XEN_HVM
#define __KVM_HAVE_VCPU_EVENTS
#define __KVM_HAVE_DEBUGREGS
#define __KVM_HAVE_XSAVE
#define __KVM_HAVE_XCRS
/* Architectural interrupt line count. */
#define KVM_NR_INTERRUPTS 256
struct kvm_memory_alias {
__u32 slot; /* this has a different namespace than memory slots */
__u32 flags;
__u64 guest_phys_addr;
__u64 memory_size;
__u64 target_phys_addr;
};
/* for KVM_GET_IRQCHIP and KVM_SET_IRQCHIP */
struct kvm_pic_state {
__u8 last_irr; /* edge detection */
__u8 irr; /* interrupt request register */
__u8 imr; /* interrupt mask register */
__u8 isr; /* interrupt service register */
__u8 priority_add; /* highest irq priority */
__u8 irq_base;
__u8 read_reg_select;
__u8 poll;
__u8 special_mask;
__u8 init_state;
__u8 auto_eoi;
__u8 rotate_on_auto_eoi;
__u8 special_fully_nested_mode;
__u8 init4; /* true if 4 byte init */
__u8 elcr; /* PIIX edge/trigger selection */
__u8 elcr_mask;
};
#define KVM_IOAPIC_NUM_PINS 24
struct kvm_ioapic_state {
__u64 base_address;
__u32 ioregsel;
__u32 id;
__u32 irr;
__u32 pad;
union {
__u64 bits;
struct {
__u8 vector;
__u8 delivery_mode:3;
__u8 dest_mode:1;
__u8 delivery_status:1;
__u8 polarity:1;
__u8 remote_irr:1;
__u8 trig_mode:1;
__u8 mask:1;
__u8 reserve:7;
__u8 reserved[4];
__u8 dest_id;
} fields;
} redirtbl[KVM_IOAPIC_NUM_PINS];
};
#define KVM_IRQCHIP_PIC_MASTER 0
#define KVM_IRQCHIP_PIC_SLAVE 1
#define KVM_IRQCHIP_IOAPIC 2
#define KVM_NR_IRQCHIPS 3
/* for KVM_GET_REGS and KVM_SET_REGS */
struct kvm_regs {
/* out (KVM_GET_REGS) / in (KVM_SET_REGS) */
__u64 rax, rbx, rcx, rdx;
__u64 rsi, rdi, rsp, rbp;
__u64 r8, r9, r10, r11;
__u64 r12, r13, r14, r15;
__u64 rip, rflags;
};
/* for KVM_GET_LAPIC and KVM_SET_LAPIC */
#define KVM_APIC_REG_SIZE 0x400
struct kvm_lapic_state {
char regs[KVM_APIC_REG_SIZE];
};
struct kvm_segment {
__u64 base;
__u32 limit;
__u16 selector;
__u8 type;
__u8 present, dpl, db, s, l, g, avl;
__u8 unusable;
__u8 padding;
};
struct kvm_dtable {
__u64 base;
__u16 limit;
__u16 padding[3];
};
/* for KVM_GET_SREGS and KVM_SET_SREGS */
struct kvm_sregs {
/* out (KVM_GET_SREGS) / in (KVM_SET_SREGS) */
struct kvm_segment cs, ds, es, fs, gs, ss;
struct kvm_segment tr, ldt;
struct kvm_dtable gdt, idt;
__u64 cr0, cr2, cr3, cr4, cr8;
__u64 efer;
__u64 apic_base;
__u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64];
};
/* for KVM_GET_FPU and KVM_SET_FPU */
struct kvm_fpu {
__u8 fpr[8][16];
__u16 fcw;
__u16 fsw;
__u8 ftwx; /* in fxsave format */
__u8 pad1;
__u16 last_opcode;
__u64 last_ip;
__u64 last_dp;
__u8 xmm[16][16];
__u32 mxcsr;
__u32 pad2;
};
struct kvm_msr_entry {
__u32 index;
__u32 reserved;
__u64 data;
};
/* for KVM_GET_MSRS and KVM_SET_MSRS */
struct kvm_msrs {
__u32 nmsrs; /* number of msrs in entries */
__u32 pad;
struct kvm_msr_entry entries[0];
};
/* for KVM_GET_MSR_INDEX_LIST */
struct kvm_msr_list {
__u32 nmsrs; /* number of msrs in entries */
__u32 indices[0];
};
struct kvm_cpuid_entry {
__u32 function;
__u32 eax;
__u32 ebx;
__u32 ecx;
__u32 edx;
__u32 padding;
};
/* for KVM_SET_CPUID */
struct kvm_cpuid {
__u32 nent;
__u32 padding;
struct kvm_cpuid_entry entries[0];
};
struct kvm_cpuid_entry2 {
__u32 function;
__u32 index;
__u32 flags;
__u32 eax;
__u32 ebx;
__u32 ecx;
__u32 edx;
__u32 padding[3];
};
#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX 1
#define KVM_CPUID_FLAG_STATEFUL_FUNC 2
#define KVM_CPUID_FLAG_STATE_READ_NEXT 4
/* for KVM_SET_CPUID2 */
struct kvm_cpuid2 {
__u32 nent;
__u32 padding;
struct kvm_cpuid_entry2 entries[0];
};
/* for KVM_GET_PIT and KVM_SET_PIT */
struct kvm_pit_channel_state {
__u32 count; /* can be 65536 */
__u16 latched_count;
__u8 count_latched;
__u8 status_latched;
__u8 status;
__u8 read_state;
__u8 write_state;
__u8 write_latch;
__u8 rw_mode;
__u8 mode;
__u8 bcd;
__u8 gate;
__s64 count_load_time;
};
struct kvm_debug_exit_arch {
__u32 exception;
__u32 pad;
__u64 pc;
__u64 dr6;
__u64 dr7;
};
#define KVM_GUESTDBG_USE_SW_BP 0x00010000
#define KVM_GUESTDBG_USE_HW_BP 0x00020000
#define KVM_GUESTDBG_INJECT_DB 0x00040000
#define KVM_GUESTDBG_INJECT_BP 0x00080000
/* for KVM_SET_GUEST_DEBUG */
struct kvm_guest_debug_arch {
__u64 debugreg[8];
};
struct kvm_pit_state {
struct kvm_pit_channel_state channels[3];
};
#define KVM_PIT_FLAGS_HPET_LEGACY 0x00000001
struct kvm_pit_state2 {
struct kvm_pit_channel_state channels[3];
__u32 flags;
__u32 reserved[9];
};
struct kvm_reinject_control {
__u8 pit_reinject;
__u8 reserved[31];
};
/* When set in flags, include corresponding fields on KVM_SET_VCPU_EVENTS */
#define KVM_VCPUEVENT_VALID_NMI_PENDING 0x00000001
#define KVM_VCPUEVENT_VALID_SIPI_VECTOR 0x00000002
#define KVM_VCPUEVENT_VALID_SHADOW 0x00000004
/* Interrupt shadow states */
#define KVM_X86_SHADOW_INT_MOV_SS 0x01
#define KVM_X86_SHADOW_INT_STI 0x02
/* for KVM_GET/SET_VCPU_EVENTS */
struct kvm_vcpu_events {
struct {
__u8 injected;
__u8 nr;
__u8 has_error_code;
__u8 pad;
__u32 error_code;
} exception;
struct {
__u8 injected;
__u8 nr;
__u8 soft;
__u8 shadow;
} interrupt;
struct {
__u8 injected;
__u8 pending;
__u8 masked;
__u8 pad;
} nmi;
__u32 sipi_vector;
__u32 flags;
__u32 reserved[10];
};
/* for KVM_GET/SET_DEBUGREGS */
struct kvm_debugregs {
__u64 db[4];
__u64 dr6;
__u64 dr7;
__u64 flags;
__u64 reserved[9];
};
/* for KVM_CAP_XSAVE */
struct kvm_xsave {
__u32 region[1024];
};
#define KVM_MAX_XCRS 16
struct kvm_xcr {
__u32 xcr;
__u32 reserved;
__u64 value;
};
struct kvm_xcrs {
__u32 nr_xcrs;
__u32 flags;
struct kvm_xcr xcrs[KVM_MAX_XCRS];
__u64 padding[16];
};
#endif /* _ASM_X86_KVM_H */

View File

@@ -0,0 +1,149 @@
#ifndef _ASM_X86_KVM_PARA_H
#define _ASM_X86_KVM_PARA_H
#include <linux/types.h>
/* This CPUID returns the signature 'KVMKVMKVM' in ebx, ecx, and edx. It
* should be used to determine that a VM is running under KVM.
*/
#define KVM_CPUID_SIGNATURE 0x40000000
/* This CPUID returns a feature bitmap in eax. Before enabling a particular
* paravirtualization, the appropriate feature bit should be checked.
*/
#define KVM_CPUID_FEATURES 0x40000001
#define KVM_FEATURE_CLOCKSOURCE 0
#define KVM_FEATURE_NOP_IO_DELAY 1
#define KVM_FEATURE_MMU_OP 2
#define MSR_KVM_WALL_CLOCK 0x11
#define MSR_KVM_SYSTEM_TIME 0x12
#define KVM_MAX_MMU_OP_BATCH 32
/* Operations for KVM_HC_MMU_OP */
#define KVM_MMU_OP_WRITE_PTE 1
#define KVM_MMU_OP_FLUSH_TLB 2
#define KVM_MMU_OP_RELEASE_PT 3
/* Payload for KVM_HC_MMU_OP */
struct kvm_mmu_op_header {
__u32 op;
__u32 pad;
};
struct kvm_mmu_op_write_pte {
struct kvm_mmu_op_header header;
__u64 pte_phys;
__u64 pte_val;
};
struct kvm_mmu_op_flush_tlb {
struct kvm_mmu_op_header header;
};
struct kvm_mmu_op_release_pt {
struct kvm_mmu_op_header header;
__u64 pt_phys;
};
#ifdef __KERNEL__
#include <asm/processor.h>
extern void kvmclock_init(void);
/* This instruction is vmcall. On non-VT architectures, it will generate a
* trap that we will then rewrite to the appropriate instruction.
*/
#define KVM_HYPERCALL ".byte 0x0f,0x01,0xc1"
/* For KVM hypercalls, a three-byte sequence of either the vmrun or the vmmrun
* instruction. The hypervisor may replace it with something else but only the
* instructions are guaranteed to be supported.
*
* Up to four arguments may be passed in rbx, rcx, rdx, and rsi respectively.
* The hypercall number should be placed in rax and the return value will be
* placed in rax. No other registers will be clobbered unless explicited
* noted by the particular hypercall.
*/
static inline long kvm_hypercall0(unsigned int nr)
{
long ret;
asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr)
: "memory");
return ret;
}
static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
{
long ret;
asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr), "b"(p1)
: "memory");
return ret;
}
static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
unsigned long p2)
{
long ret;
asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr), "b"(p1), "c"(p2)
: "memory");
return ret;
}
static inline long kvm_hypercall3(unsigned int nr, unsigned long p1,
unsigned long p2, unsigned long p3)
{
long ret;
asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr), "b"(p1), "c"(p2), "d"(p3)
: "memory");
return ret;
}
static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
unsigned long p2, unsigned long p3,
unsigned long p4)
{
long ret;
asm volatile(KVM_HYPERCALL
: "=a"(ret)
: "a"(nr), "b"(p1), "c"(p2), "d"(p3), "S"(p4)
: "memory");
return ret;
}
static inline int kvm_para_available(void)
{
unsigned int eax, ebx, ecx, edx;
char signature[13];
cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx);
memcpy(signature + 0, &ebx, 4);
memcpy(signature + 4, &ecx, 4);
memcpy(signature + 8, &edx, 4);
signature[12] = 0;
if (strcmp(signature, "KVMKVMKVM") == 0)
return 1;
return 0;
}
static inline unsigned int kvm_arch_para_features(void)
{
return cpuid_eax(KVM_CPUID_FEATURES);
}
#endif
#endif /* _ASM_X86_KVM_PARA_H */

139
kvm/kvm.spec Normal file
View File

@@ -0,0 +1,139 @@
Name: kvm
Version: 0.0
Release: 0
Summary: Kernel Virtual Machine virtualization environment
Group: System Environment/Kernel
License: GPL
URL: http://www.qumranet.com
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}
ExclusiveArch: i386 x86_64 ia64
Requires: kvm-kmod bridge-utils
%define Distribution %(rpm -q -qf /etc/redhat-release --qf '%%{name}' | cut -d"-" -f 1)
%define os_version %(rpm -q --qf '%%{version}' %{Distribution}-release)
%define os_release %(rpm -q --qf '%%{release}' %{Distribution}-release | cut -d"." -f 1)
%if %([ x"%{Distribution}" = x"fedora" -a x"%{os_version}" = x"5" ] && echo 1 || echo 0)
%define require_gccver 32
%endif
%if %([ x"%{Distribution}" = x"fedora" -a 0"%{os_version}" -ge "8" ] && echo 1 || echo 0)
%define qemuldflags --qemu-ldflags=-Wl,--build-id
%else
%define qemuldflags ""
%endif
%if %([ x"%{Distribution}" = x"centos" -a x"%{os_version}" = x"4" ] && echo 1 || echo 0)
%define require_gccver 32
%endif
%if %([ x"%{Distribution}" = x"redhat" -a x"%{os_release}" = x"5" ] && echo 1 || echo 0)
%define require_gccver 34
%endif
%if %( [ x"%{require_gccver}" = x"32" ] && echo 1 || echo 0)
BuildRequires: compat-gcc-32
%else
BuildRequires: compat-gcc-34
%endif
BuildRequires: SDL-devel zlib-devel alsa-lib-devel
%define _prebuilt %{?prebuilt:1}%{!?prebuilt:0}
%if !%{_prebuilt}
Source0: kvm.tar.gz
Source1: user.tar.gz
Source2: kernel.tar.gz
Source3: scripts.tar.gz
Source4: Makefile
Source5: configure
Source6: kvm_stat
Source7: libkvm.tar.gz
Source8: extboot.tar.gz
%endif
%description
The Kernel Virtual Machine provides a virtualization enviroment for processors
with hardware support for virtualization: Intel's VT-x&VT-i and AMD's AMD-V.
%prep
%if !%{_prebuilt}
%setup -T -b 0 -n qemu
%setup -T -b 1 -n user -D
%setup -T -b 2 -n kernel -D
%setup -T -b 7 -n libkvm -D
%setup -T -b 3 -n scripts -D
%setup -T -b 8 -n extboot -D
cd ..
cp %{_sourcedir}/Makefile %{_sourcedir}/configure %{_sourcedir}/kvm_stat .
%endif
%build
rm -rf %{buildroot}
%if !%{_prebuilt}
cd ..
./configure --prefix=/usr/kvm %{qemuldflags}
make -C libkvm
make -C user
%ifarch i386 x86_64
make extboot
%endif
#(cd qemu;
# ./co
# kpath="$(readlink -f ../kernel/include)"
# upath="$(readlink -f ../user)"
# ./configure --target-list=$(uname -i)-softmmu \
# --extra-cflags="-I$kpath -I$upath" \
# --extra-ldflags="-L$upath" \
# --disable-kqemu --enable-kvm --prefix=/usr/kvm
#)
make -C qemu
%endif
%install
%if !%{_prebuilt}
cd ..
%else
cd %{objdir}
%endif
make DESTDIR=%{buildroot} install-rpm
%define bindir /usr/bin
%define bin %{bindir}/kvm
%define initdir /etc/init.d
%define confdir /etc/kvm
%define utilsdir /etc/kvm/utils
%post
/sbin/chkconfig --add kvm
/sbin/chkconfig --level 2345 kvm on
/sbin/chkconfig --level 16 kvm off
/usr/sbin/groupadd -fg 444 kvm
%preun
if [ "$1" != 0 ]; then
/sbin/service kvm stop
/sbin/chkconfig --level 2345 kvm off
/sbin/chkconfig --del kvm
fi
%clean
%{__rm} -rf %{buildroot}
%files
/usr/bin/kvm
/usr/bin/kvm_stat
%{confdir}/qemu-ifup
%{initdir}/kvm
/etc/udev/rules.d/*kvm*.rules
/usr/kvm
%changelog

469
kvm/kvm_stat Executable file
View File

@@ -0,0 +1,469 @@
#!/usr/bin/python
import curses
import sys, os, time, optparse
class DebugfsProvider(object):
def __init__(self):
self.base = '/sys/kernel/debug/kvm'
self._fields = os.listdir(self.base)
def fields(self):
return self._fields
def select(self, fields):
self._fields = fields
def read(self):
def val(key):
return int(file(self.base + '/' + key).read())
return dict([(key, val(key)) for key in self._fields])
vmx_exit_reasons = {
0: 'EXCEPTION_NMI',
1: 'EXTERNAL_INTERRUPT',
2: 'TRIPLE_FAULT',
7: 'PENDING_INTERRUPT',
8: 'NMI_WINDOW',
9: 'TASK_SWITCH',
10: 'CPUID',
12: 'HLT',
14: 'INVLPG',
15: 'RDPMC',
16: 'RDTSC',
18: 'VMCALL',
19: 'VMCLEAR',
20: 'VMLAUNCH',
21: 'VMPTRLD',
22: 'VMPTRST',
23: 'VMREAD',
24: 'VMRESUME',
25: 'VMWRITE',
26: 'VMOFF',
27: 'VMON',
28: 'CR_ACCESS',
29: 'DR_ACCESS',
30: 'IO_INSTRUCTION',
31: 'MSR_READ',
32: 'MSR_WRITE',
33: 'INVALID_STATE',
36: 'MWAIT_INSTRUCTION',
39: 'MONITOR_INSTRUCTION',
40: 'PAUSE_INSTRUCTION',
41: 'MCE_DURING_VMENTRY',
43: 'TPR_BELOW_THRESHOLD',
44: 'APIC_ACCESS',
48: 'EPT_VIOLATION',
49: 'EPT_MISCONFIG',
54: 'WBINVD',
55: 'XSETBV',
}
svm_exit_reasons = {
0x000: 'READ_CR0',
0x003: 'READ_CR3',
0x004: 'READ_CR4',
0x008: 'READ_CR8',
0x010: 'WRITE_CR0',
0x013: 'WRITE_CR3',
0x014: 'WRITE_CR4',
0x018: 'WRITE_CR8',
0x020: 'READ_DR0',
0x021: 'READ_DR1',
0x022: 'READ_DR2',
0x023: 'READ_DR3',
0x024: 'READ_DR4',
0x025: 'READ_DR5',
0x026: 'READ_DR6',
0x027: 'READ_DR7',
0x030: 'WRITE_DR0',
0x031: 'WRITE_DR1',
0x032: 'WRITE_DR2',
0x033: 'WRITE_DR3',
0x034: 'WRITE_DR4',
0x035: 'WRITE_DR5',
0x036: 'WRITE_DR6',
0x037: 'WRITE_DR7',
0x040: 'EXCP_BASE',
0x060: 'INTR',
0x061: 'NMI',
0x062: 'SMI',
0x063: 'INIT',
0x064: 'VINTR',
0x065: 'CR0_SEL_WRITE',
0x066: 'IDTR_READ',
0x067: 'GDTR_READ',
0x068: 'LDTR_READ',
0x069: 'TR_READ',
0x06a: 'IDTR_WRITE',
0x06b: 'GDTR_WRITE',
0x06c: 'LDTR_WRITE',
0x06d: 'TR_WRITE',
0x06e: 'RDTSC',
0x06f: 'RDPMC',
0x070: 'PUSHF',
0x071: 'POPF',
0x072: 'CPUID',
0x073: 'RSM',
0x074: 'IRET',
0x075: 'SWINT',
0x076: 'INVD',
0x077: 'PAUSE',
0x078: 'HLT',
0x079: 'INVLPG',
0x07a: 'INVLPGA',
0x07b: 'IOIO',
0x07c: 'MSR',
0x07d: 'TASK_SWITCH',
0x07e: 'FERR_FREEZE',
0x07f: 'SHUTDOWN',
0x080: 'VMRUN',
0x081: 'VMMCALL',
0x082: 'VMLOAD',
0x083: 'VMSAVE',
0x084: 'STGI',
0x085: 'CLGI',
0x086: 'SKINIT',
0x087: 'RDTSCP',
0x088: 'ICEBP',
0x089: 'WBINVD',
0x08a: 'MONITOR',
0x08b: 'MWAIT',
0x08c: 'MWAIT_COND',
0x400: 'NPF',
}
vendor_exit_reasons = {
'vmx': vmx_exit_reasons,
'svm': svm_exit_reasons,
}
exit_reasons = None
for line in file('/proc/cpuinfo').readlines():
if line.startswith('flags'):
for flag in line.split():
if flag in vendor_exit_reasons:
exit_reasons = vendor_exit_reasons[flag]
filters = {
'kvm_exit': ('exit_reason', exit_reasons)
}
def invert(d):
return dict((x[1], x[0]) for x in d.iteritems())
for f in filters:
filters[f] = (filters[f][0], invert(filters[f][1]))
import ctypes, struct, array
libc = ctypes.CDLL('libc.so.6')
syscall = libc.syscall
class perf_event_attr(ctypes.Structure):
_fields_ = [('type', ctypes.c_uint32),
('size', ctypes.c_uint32),
('config', ctypes.c_uint64),
('sample_freq', ctypes.c_uint64),
('sample_type', ctypes.c_uint64),
('read_format', ctypes.c_uint64),
('flags', ctypes.c_uint64),
('wakeup_events', ctypes.c_uint32),
('bp_type', ctypes.c_uint32),
('bp_addr', ctypes.c_uint64),
('bp_len', ctypes.c_uint64),
]
def _perf_event_open(attr, pid, cpu, group_fd, flags):
return syscall(298, ctypes.pointer(attr), ctypes.c_int(pid),
ctypes.c_int(cpu), ctypes.c_int(group_fd),
ctypes.c_long(flags))
PERF_TYPE_HARDWARE = 0
PERF_TYPE_SOFTWARE = 1
PERF_TYPE_TRACEPOINT = 2
PERF_TYPE_HW_CACHE = 3
PERF_TYPE_RAW = 4
PERF_TYPE_BREAKPOINT = 5
PERF_SAMPLE_IP = 1 << 0
PERF_SAMPLE_TID = 1 << 1
PERF_SAMPLE_TIME = 1 << 2
PERF_SAMPLE_ADDR = 1 << 3
PERF_SAMPLE_READ = 1 << 4
PERF_SAMPLE_CALLCHAIN = 1 << 5
PERF_SAMPLE_ID = 1 << 6
PERF_SAMPLE_CPU = 1 << 7
PERF_SAMPLE_PERIOD = 1 << 8
PERF_SAMPLE_STREAM_ID = 1 << 9
PERF_SAMPLE_RAW = 1 << 10
PERF_FORMAT_TOTAL_TIME_ENABLED = 1 << 0
PERF_FORMAT_TOTAL_TIME_RUNNING = 1 << 1
PERF_FORMAT_ID = 1 << 2
PERF_FORMAT_GROUP = 1 << 3
import re
sys_tracing = '/sys/kernel/debug/tracing'
class Group(object):
def __init__(self, cpu):
self.events = []
self.group_leader = None
self.cpu = cpu
def add_event(self, name, event_set, tracepoint, filter = None):
self.events.append(Event(group = self,
name = name, event_set = event_set,
tracepoint = tracepoint, filter = filter))
if len(self.events) == 1:
self.file = os.fdopen(self.events[0].fd)
def read(self):
bytes = 8 * (1 + len(self.events))
fmt = 'xxxxxxxx' + 'q' * len(self.events)
return dict(zip([event.name for event in self.events],
struct.unpack(fmt, self.file.read(bytes))))
class Event(object):
def __init__(self, group, name, event_set, tracepoint, filter = None):
self.name = name
attr = perf_event_attr()
attr.type = PERF_TYPE_TRACEPOINT
attr.size = ctypes.sizeof(attr)
id_path = os.path.join(sys_tracing, 'events', event_set,
tracepoint, 'id')
id = int(file(id_path).read())
attr.config = id
attr.sample_type = (PERF_SAMPLE_RAW
| PERF_SAMPLE_TIME
| PERF_SAMPLE_CPU)
attr.sample_period = 1
attr.read_format = PERF_FORMAT_GROUP
group_leader = -1
if group.events:
group_leader = group.events[0].fd
fd = _perf_event_open(attr, -1, group.cpu, group_leader, 0)
if fd == -1:
raise Exception('perf_event_open failed')
if filter:
import fcntl
fcntl.ioctl(fd, 0x40082406, filter)
self.fd = fd
def enable(self):
import fcntl
fcntl.ioctl(self.fd, 0x00002400, 0)
def disable(self):
import fcntl
fcntl.ioctl(self.fd, 0x00002401, 0)
class TracepointProvider(object):
def __init__(self):
path = os.path.join(sys_tracing, 'events', 'kvm')
fields = [f
for f in os.listdir(path)
if os.path.isdir(os.path.join(path, f))]
extra = []
for f in fields:
if f in filters:
subfield, values = filters[f]
for name, number in values.iteritems():
extra.append(f + '(' + name + ')')
fields += extra
self._setup(fields)
self.select(fields)
def fields(self):
return self._fields
def _setup(self, _fields):
self._fields = _fields
cpure = r'cpu([0-9]+)'
self.cpus = [int(re.match(cpure, x).group(1))
for x in os.listdir('/sys/devices/system/cpu')
if re.match(cpure, x)]
import resource
nfiles = len(self.cpus) * 1000
resource.setrlimit(resource.RLIMIT_NOFILE, (nfiles, nfiles))
events = []
self.group_leaders = []
for cpu in self.cpus:
group = Group(cpu)
for name in _fields:
tracepoint = name
filter = None
m = re.match(r'(.*)\((.*)\)', name)
if m:
tracepoint, sub = m.groups()
filter = '%s==%d\0' % (filters[tracepoint][0],
filters[tracepoint][1][sub])
event = group.add_event(name, event_set = 'kvm',
tracepoint = tracepoint,
filter = filter)
self.group_leaders.append(group)
def select(self, fields):
for group in self.group_leaders:
for event in group.events:
if event.name in fields:
event.enable()
else:
event.disable()
def read(self):
from collections import defaultdict
ret = defaultdict(int)
for group in self.group_leaders:
for name, val in group.read().iteritems():
ret[name] += val
return ret
class Stats:
def __init__(self, provider, fields = None):
self.provider = provider
self.fields_filter = fields
self._update()
def _update(self):
def wanted(key):
import re
if not self.fields_filter:
return True
return re.match(self.fields_filter, key) is not None
self.values = dict([(key, None)
for key in provider.fields()
if wanted(key)])
self.provider.select(self.values.keys())
def set_fields_filter(self, fields_filter):
self.fields_filter = fields_filter
self._update()
def get(self):
new = self.provider.read()
for key in self.provider.fields():
oldval = self.values.get(key, (0, 0))
newval = new[key]
newdelta = None
if oldval is not None:
newdelta = newval - oldval[0]
self.values[key] = (newval, newdelta)
return self.values
if not os.access('/sys/kernel/debug', os.F_OK):
print 'Please enable CONFIG_DEBUG_FS in your kernel'
sys.exit(1)
if not os.access('/sys/kernel/debug/kvm', os.F_OK):
print "Please mount debugfs ('mount -t debugfs debugfs /sys/kernel/debug')"
print "and ensure the kvm modules are loaded"
sys.exit(1)
label_width = 40
number_width = 10
def tui(screen, stats):
curses.use_default_colors()
curses.noecho()
drilldown = False
fields_filter = stats.fields_filter
def update_drilldown():
if not fields_filter:
if drilldown:
stats.set_fields_filter(None)
else:
stats.set_fields_filter(r'^[^\(]*$')
update_drilldown()
def refresh(sleeptime):
screen.erase()
screen.addstr(0, 0, 'kvm statistics')
row = 2
s = stats.get()
def sortkey(x):
if s[x][1]:
return (-s[x][1], -s[x][0])
else:
return (0, -s[x][0])
for key in sorted(s.keys(), key = sortkey):
if row >= screen.getmaxyx()[0]:
break
values = s[key]
if not values[0] and not values[1]:
break
col = 1
screen.addstr(row, col, key)
col += label_width
screen.addstr(row, col, '%10d' % (values[0],))
col += number_width
if values[1] is not None:
screen.addstr(row, col, '%8d' % (values[1] / sleeptime,))
row += 1
screen.refresh()
sleeptime = 0.25
while True:
refresh(sleeptime)
curses.halfdelay(int(sleeptime * 10))
sleeptime = 3
try:
c = screen.getkey()
if c == 'x':
drilldown = not drilldown
update_drilldown()
if c == 'q':
break
except KeyboardInterrupt:
break
except curses.error:
continue
def batch(stats):
s = stats.get()
time.sleep(1)
s = stats.get()
for key in sorted(s.keys()):
values = s[key]
print '%-22s%10d%10d' % (key, values[0], values[1])
def log(stats):
keys = sorted(stats.get().iterkeys())
def banner():
for k in keys:
print '%10s' % k[0:9],
print
def statline():
s = stats.get()
for k in keys:
print ' %9d' % s[k][1],
print
line = 0
banner_repeat = 20
while True:
time.sleep(1)
if line % banner_repeat == 0:
banner()
statline()
line += 1
options = optparse.OptionParser()
options.add_option('-1', '--once', '--batch',
action = 'store_true',
default = False,
dest = 'once',
help = 'run in batch mode for one second',
)
options.add_option('-l', '--log',
action = 'store_true',
default = False,
dest = 'log',
help = 'run in logging mode (like vmstat)',
)
options.add_option('-f', '--fields',
action = 'store',
default = None,
dest = 'fields',
help = 'fields to display (regex)',
)
(options, args) = options.parse_args(sys.argv)
try:
provider = TracepointProvider()
except:
provider = DebugfsProvider()
stats = Stats(provider, fields = options.fields)
if options.log:
log(stats)
elif not options.once:
import curses.wrapper
curses.wrapper(tui, stats)
else:
batch(stats)

19
kvm/libfdt/Makefile Normal file
View File

@@ -0,0 +1,19 @@
include ../config.mak
include ../user/config.mak
LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
LIBFDT_INCLUDES = fdt.h libfdt.h
LIBFDT_EXTRA = libfdt_internal.h
LIBFDT_LIB = libfdt.a
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
CFLAGS += -I .
$(LIBFDT_LIB): $(LIBFDT_OBJS)
$(AR) rcs $@ $^
all: $(LIBFDT_LIB)
clean:
rm -rf *.o *.a

3
kvm/libfdt/README Normal file
View File

@@ -0,0 +1,3 @@
libfdt was grabbed from dtc source. This is the upstream source for libfdt.
It can be found here:
http://www.jdl.com/software/

194
kvm/libfdt/fdt.c Normal file
View File

@@ -0,0 +1,194 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
int fdt_check_header(const void *fdt)
{
if (fdt_magic(fdt) == FDT_MAGIC) {
/* Complete tree */
if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
} else if (fdt_magic(fdt) == SW_MAGIC) {
/* Unfinished sequential-write blob */
if (fdt_size_dt_struct(fdt) == 0)
return -FDT_ERR_BADSTATE;
} else {
return -FDT_ERR_BADMAGIC;
}
return 0;
}
const void *fdt_offset_ptr(const void *fdt, int offset, int len)
{
const void *p;
if (fdt_version(fdt) >= 0x11)
if (((offset + len) < offset)
|| ((offset + len) > fdt_size_dt_struct(fdt)))
return NULL;
p = _fdt_offset_ptr(fdt, offset);
if (p + len < p)
return NULL;
return p;
}
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset)
{
const uint32_t *tagp, *lenp;
uint32_t tag;
const char *p;
if (offset % FDT_TAGSIZE)
return -1;
tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
if (! tagp)
return FDT_END; /* premature end */
tag = fdt32_to_cpu(*tagp);
offset += FDT_TAGSIZE;
switch (tag) {
case FDT_BEGIN_NODE:
/* skip name */
do {
p = fdt_offset_ptr(fdt, offset++, 1);
} while (p && (*p != '\0'));
if (! p)
return FDT_END;
break;
case FDT_PROP:
lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
if (! lenp)
return FDT_END;
/* skip name offset, length and value */
offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp);
break;
}
if (nextoffset)
*nextoffset = ALIGN(offset, FDT_TAGSIZE);
return tag;
}
int fdt_next_node(const void *fdt, int offset, int *depth)
{
int nextoffset = 0;
uint32_t tag;
if (offset >= 0) {
tag = fdt_next_tag(fdt, offset, &nextoffset);
if (tag != FDT_BEGIN_NODE)
return -FDT_ERR_BADOFFSET;
}
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
switch (tag) {
case FDT_PROP:
case FDT_NOP:
break;
case FDT_BEGIN_NODE:
if (depth)
(*depth)++;
break;
case FDT_END_NODE:
if (depth)
(*depth)--;
break;
case FDT_END:
return -FDT_ERR_NOTFOUND;
default:
return -FDT_ERR_BADSTRUCTURE;
}
} while (tag != FDT_BEGIN_NODE);
return offset;
}
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
{
int len = strlen(s) + 1;
const char *last = strtab + tabsize - len;
const char *p;
for (p = strtab; p <= last; p++)
if (memeq(p, s, len))
return p;
return NULL;
}
int fdt_move(const void *fdt, void *buf, int bufsize)
{
CHECK_HEADER(fdt);
if (fdt_totalsize(fdt) > bufsize)
return -FDT_ERR_NOSPACE;
memmove(buf, fdt, fdt_totalsize(fdt));
return 0;
}

60
kvm/libfdt/fdt.h Normal file
View File

@@ -0,0 +1,60 @@
#ifndef _FDT_H
#define _FDT_H
#ifndef __ASSEMBLY__
struct fdt_header {
uint32_t magic; /* magic word FDT_MAGIC */
uint32_t totalsize; /* total size of DT block */
uint32_t off_dt_struct; /* offset to structure */
uint32_t off_dt_strings; /* offset to strings */
uint32_t off_mem_rsvmap; /* offset to memory reserve map */
uint32_t version; /* format version */
uint32_t last_comp_version; /* last compatible version */
/* version 2 fields below */
uint32_t boot_cpuid_phys; /* Which physical CPU id we're
booting on */
/* version 3 fields below */
uint32_t size_dt_strings; /* size of the strings block */
/* version 17 fields below */
uint32_t size_dt_struct; /* size of the structure block */
};
struct fdt_reserve_entry {
uint64_t address;
uint64_t size;
};
struct fdt_node_header {
uint32_t tag;
char name[0];
};
struct fdt_property {
uint32_t tag;
uint32_t len;
uint32_t nameoff;
char data[0];
};
#endif /* !__ASSEMBLY */
#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */
#define FDT_TAGSIZE sizeof(uint32_t)
#define FDT_BEGIN_NODE 0x1 /* Start node: full name */
#define FDT_END_NODE 0x2 /* End node */
#define FDT_PROP 0x3 /* Property: name off,
size, content */
#define FDT_NOP 0x4 /* nop */
#define FDT_END 0x9
#define FDT_V1_SIZE (7*sizeof(uint32_t))
#define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(uint32_t))
#define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(uint32_t))
#define FDT_V16_SIZE FDT_V3_SIZE
#define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(uint32_t))
#endif /* _FDT_H */

476
kvm/libfdt/fdt_ro.c Normal file
View File

@@ -0,0 +1,476 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
static int nodename_eq(const void *fdt, int offset,
const char *s, int len)
{
const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
if (! p)
/* short match */
return 0;
if (memcmp(p, s, len) != 0)
return 0;
if (p[len] == '\0')
return 1;
else if (!memchr(s, '@', len) && (p[len] == '@'))
return 1;
else
return 0;
}
const char *fdt_string(const void *fdt, int stroffset)
{
return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
}
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{
CHECK_HEADER(fdt);
*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
return 0;
}
int fdt_num_mem_rsv(const void *fdt)
{
int i = 0;
while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
i++;
return i;
}
int fdt_subnode_offset_namelen(const void *fdt, int offset,
const char *name, int namelen)
{
int depth;
CHECK_HEADER(fdt);
for (depth = 0;
offset >= 0;
offset = fdt_next_node(fdt, offset, &depth)) {
if (depth < 0)
return -FDT_ERR_NOTFOUND;
else if ((depth == 1)
&& nodename_eq(fdt, offset, name, namelen))
return offset;
}
return offset; /* error */
}
int fdt_subnode_offset(const void *fdt, int parentoffset,
const char *name)
{
return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
}
int fdt_path_offset(const void *fdt, const char *path)
{
const char *end = path + strlen(path);
const char *p = path;
int offset = 0;
CHECK_HEADER(fdt);
if (*path != '/')
return -FDT_ERR_BADPATH;
while (*p) {
const char *q;
while (*p == '/')
p++;
if (! *p)
return offset;
q = strchr(p, '/');
if (! q)
q = end;
offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
if (offset < 0)
return offset;
p = q;
}
return offset;
}
const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
{
const struct fdt_node_header *nh;
int err;
if ((err = fdt_check_header(fdt)) != 0)
goto fail;
err = -FDT_ERR_BADOFFSET;
nh = fdt_offset_ptr(fdt, nodeoffset, sizeof(*nh));
if (!nh || (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE))
goto fail;
if (len)
*len = strlen(nh->name);
return nh->name;
fail:
if (len)
*len = err;
return NULL;
}
const struct fdt_property *fdt_get_property(const void *fdt,
int nodeoffset,
const char *name, int *lenp)
{
uint32_t tag;
const struct fdt_property *prop;
int namestroff;
int offset, nextoffset;
int err;
if ((err = fdt_check_header(fdt)) != 0)
goto fail;
err = -FDT_ERR_BADOFFSET;
if (nodeoffset % FDT_TAGSIZE)
goto fail;
tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
if (tag != FDT_BEGIN_NODE)
goto fail;
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
switch (tag) {
case FDT_END:
err = -FDT_ERR_TRUNCATED;
goto fail;
case FDT_BEGIN_NODE:
case FDT_END_NODE:
case FDT_NOP:
break;
case FDT_PROP:
err = -FDT_ERR_BADSTRUCTURE;
prop = fdt_offset_ptr(fdt, offset, sizeof(*prop));
if (! prop)
goto fail;
namestroff = fdt32_to_cpu(prop->nameoff);
if (streq(fdt_string(fdt, namestroff), name)) {
/* Found it! */
int len = fdt32_to_cpu(prop->len);
prop = fdt_offset_ptr(fdt, offset,
sizeof(*prop)+len);
if (! prop)
goto fail;
if (lenp)
*lenp = len;
return prop;
}
break;
default:
err = -FDT_ERR_BADSTRUCTURE;
goto fail;
}
} while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
err = -FDT_ERR_NOTFOUND;
fail:
if (lenp)
*lenp = err;
return NULL;
}
const void *fdt_getprop(const void *fdt, int nodeoffset,
const char *name, int *lenp)
{
const struct fdt_property *prop;
prop = fdt_get_property(fdt, nodeoffset, name, lenp);
if (! prop)
return NULL;
return prop->data;
}
uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
{
const uint32_t *php;
int len;
php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
if (!php || (len != sizeof(*php)))
return 0;
return fdt32_to_cpu(*php);
}
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
{
int pdepth = 0, p = 0;
int offset, depth, namelen;
const char *name;
CHECK_HEADER(fdt);
if (buflen < 2)
return -FDT_ERR_NOSPACE;
for (offset = 0, depth = 0;
(offset >= 0) && (offset <= nodeoffset);
offset = fdt_next_node(fdt, offset, &depth)) {
if (pdepth < depth)
continue; /* overflowed buffer */
while (pdepth > depth) {
do {
p--;
} while (buf[p-1] != '/');
pdepth--;
}
name = fdt_get_name(fdt, offset, &namelen);
if (!name)
return namelen;
if ((p + namelen + 1) <= buflen) {
memcpy(buf + p, name, namelen);
p += namelen;
buf[p++] = '/';
pdepth++;
}
if (offset == nodeoffset) {
if (pdepth < (depth + 1))
return -FDT_ERR_NOSPACE;
if (p > 1) /* special case so that root path is "/", not "" */
p--;
buf[p] = '\0';
return p;
}
}
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
return -FDT_ERR_BADOFFSET;
else if (offset == -FDT_ERR_BADOFFSET)
return -FDT_ERR_BADSTRUCTURE;
return offset; /* error from fdt_next_node() */
}
int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
int supernodedepth, int *nodedepth)
{
int offset, depth;
int supernodeoffset = -FDT_ERR_INTERNAL;
CHECK_HEADER(fdt);
if (supernodedepth < 0)
return -FDT_ERR_NOTFOUND;
for (offset = 0, depth = 0;
(offset >= 0) && (offset <= nodeoffset);
offset = fdt_next_node(fdt, offset, &depth)) {
if (depth == supernodedepth)
supernodeoffset = offset;
if (offset == nodeoffset) {
if (nodedepth)
*nodedepth = depth;
if (supernodedepth > depth)
return -FDT_ERR_NOTFOUND;
else
return supernodeoffset;
}
}
if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
return -FDT_ERR_BADOFFSET;
else if (offset == -FDT_ERR_BADOFFSET)
return -FDT_ERR_BADSTRUCTURE;
return offset; /* error from fdt_next_node() */
}
int fdt_node_depth(const void *fdt, int nodeoffset)
{
int nodedepth;
int err;
err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
if (err)
return (err < 0) ? err : -FDT_ERR_INTERNAL;
return nodedepth;
}
int fdt_parent_offset(const void *fdt, int nodeoffset)
{
int nodedepth = fdt_node_depth(fdt, nodeoffset);
if (nodedepth < 0)
return nodedepth;
return fdt_supernode_atdepth_offset(fdt, nodeoffset,
nodedepth - 1, NULL);
}
int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
const char *propname,
const void *propval, int proplen)
{
int offset;
const void *val;
int len;
CHECK_HEADER(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_getprop(), then if that didn't
* find what we want, we scan over them again making our way
* to the next node. Still it's the easiest to implement
* approach; performance can come later. */
for (offset = fdt_next_node(fdt, startoffset, NULL);
offset >= 0;
offset = fdt_next_node(fdt, offset, NULL)) {
val = fdt_getprop(fdt, offset, propname, &len);
if (val && (len == proplen)
&& (memcmp(val, propval, len) == 0))
return offset;
}
return offset; /* error from fdt_next_node() */
}
int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
{
if ((phandle == 0) || (phandle == -1))
return -FDT_ERR_BADPHANDLE;
phandle = cpu_to_fdt32(phandle);
return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle",
&phandle, sizeof(phandle));
}
int _stringlist_contains(const void *strlist, int listlen, const char *str)
{
int len = strlen(str);
const void *p;
while (listlen >= len) {
if (memcmp(str, strlist, len+1) == 0)
return 1;
p = memchr(strlist, '\0', listlen);
if (!p)
return 0; /* malformed strlist.. */
listlen -= (p-strlist) + 1;
strlist = p + 1;
}
return 0;
}
int fdt_node_check_compatible(const void *fdt, int nodeoffset,
const char *compatible)
{
const void *prop;
int len;
prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
if (!prop)
return len;
if (_stringlist_contains(prop, len, compatible))
return 0;
else
return 1;
}
int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
const char *compatible)
{
int offset, err;
CHECK_HEADER(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_node_check_compatible(), then if
* that didn't find what we want, we scan over them again
* making our way to the next node. Still it's the easiest to
* implement approach; performance can come later. */
for (offset = fdt_next_node(fdt, startoffset, NULL);
offset >= 0;
offset = fdt_next_node(fdt, offset, NULL)) {
err = fdt_node_check_compatible(fdt, offset, compatible);
if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
return err;
else if (err == 0)
return offset;
}
return offset; /* error from fdt_next_node() */
}

467
kvm/libfdt/fdt_rw.c Normal file
View File

@@ -0,0 +1,467 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
static int _blocks_misordered(const void *fdt,
int mem_rsv_size, int struct_size)
{
return (fdt_off_mem_rsvmap(fdt) < ALIGN(sizeof(struct fdt_header), 8))
|| (fdt_off_dt_struct(fdt) <
(fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
|| (fdt_off_dt_strings(fdt) <
(fdt_off_dt_struct(fdt) + struct_size))
|| (fdt_totalsize(fdt) <
(fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
}
static int rw_check_header(void *fdt)
{
CHECK_HEADER(fdt);
if (fdt_version(fdt) < 17)
return -FDT_ERR_BADVERSION;
if (_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
fdt_size_dt_struct(fdt)))
return -FDT_ERR_BADLAYOUT;
if (fdt_version(fdt) > 17)
fdt_set_version(fdt, 17);
return 0;
}
#define RW_CHECK_HEADER(fdt) \
{ \
int err; \
if ((err = rw_check_header(fdt)) != 0) \
return err; \
}
static inline int _blob_data_size(void *fdt)
{
return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
}
static int _blob_splice(void *fdt, void *p, int oldlen, int newlen)
{
void *end = fdt + _blob_data_size(fdt);
if (((p + oldlen) < p) || ((p + oldlen) > end))
return -FDT_ERR_BADOFFSET;
if ((end - oldlen + newlen) > (fdt + fdt_totalsize(fdt)))
return -FDT_ERR_NOSPACE;
memmove(p + newlen, p + oldlen, end - p - oldlen);
return 0;
}
static int _blob_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
int oldn, int newn)
{
int delta = (newn - oldn) * sizeof(*p);
int err;
err = _blob_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
if (err)
return err;
fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
return 0;
}
static int _blob_splice_struct(void *fdt, void *p,
int oldlen, int newlen)
{
int delta = newlen - oldlen;
int err;
if ((err = _blob_splice(fdt, p, oldlen, newlen)))
return err;
fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
return 0;
}
static int _blob_splice_string(void *fdt, int newlen)
{
void *p = fdt + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
int err;
if ((err = _blob_splice(fdt, p, 0, newlen)))
return err;
fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
return 0;
}
static int _find_add_string(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
const char *p;
char *new;
int len = strlen(s) + 1;
int err;
p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
if (p)
/* found it */
return (p - strtab);
new = strtab + fdt_size_dt_strings(fdt);
err = _blob_splice_string(fdt, len);
if (err)
return err;
memcpy(new, s, len);
return (new - strtab);
}
int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
{
struct fdt_reserve_entry *re;
int err;
if ((err = rw_check_header(fdt)))
return err;
re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
err = _blob_splice_mem_rsv(fdt, re, 0, 1);
if (err)
return err;
re->address = cpu_to_fdt64(address);
re->size = cpu_to_fdt64(size);
return 0;
}
int fdt_del_mem_rsv(void *fdt, int n)
{
struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
int err;
if ((err = rw_check_header(fdt)))
return err;
if (n >= fdt_num_mem_rsv(fdt))
return -FDT_ERR_NOTFOUND;
err = _blob_splice_mem_rsv(fdt, re, 1, 0);
if (err)
return err;
return 0;
}
static int _resize_property(void *fdt, int nodeoffset, const char *name, int len,
struct fdt_property **prop)
{
int oldlen;
int err;
*prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
if (! (*prop))
return oldlen;
if ((err = _blob_splice_struct(fdt, (*prop)->data,
ALIGN(oldlen, FDT_TAGSIZE),
ALIGN(len, FDT_TAGSIZE))))
return err;
(*prop)->len = cpu_to_fdt32(len);
return 0;
}
static int _add_property(void *fdt, int nodeoffset, const char *name, int len,
struct fdt_property **prop)
{
uint32_t tag;
int proplen;
int nextoffset;
int namestroff;
int err;
tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
if (tag != FDT_BEGIN_NODE)
return -FDT_ERR_BADOFFSET;
namestroff = _find_add_string(fdt, name);
if (namestroff < 0)
return namestroff;
*prop = _fdt_offset_ptr_w(fdt, nextoffset);
proplen = sizeof(**prop) + ALIGN(len, FDT_TAGSIZE);
err = _blob_splice_struct(fdt, *prop, 0, proplen);
if (err)
return err;
(*prop)->tag = cpu_to_fdt32(FDT_PROP);
(*prop)->nameoff = cpu_to_fdt32(namestroff);
(*prop)->len = cpu_to_fdt32(len);
return 0;
}
int fdt_set_name(void *fdt, int nodeoffset, const char *name)
{
char *namep;
int oldlen, newlen;
int err;
if ((err = rw_check_header(fdt)))
return err;
namep = (char *)fdt_get_name(fdt, nodeoffset, &oldlen);
if (!namep)
return oldlen;
newlen = strlen(name);
err = _blob_splice_struct(fdt, namep, ALIGN(oldlen+1, FDT_TAGSIZE),
ALIGN(newlen+1, FDT_TAGSIZE));
if (err)
return err;
memcpy(namep, name, newlen+1);
return 0;
}
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
struct fdt_property *prop;
int err;
if ((err = rw_check_header(fdt)))
return err;
err = _resize_property(fdt, nodeoffset, name, len, &prop);
if (err == -FDT_ERR_NOTFOUND)
err = _add_property(fdt, nodeoffset, name, len, &prop);
if (err)
return err;
memcpy(prop->data, val, len);
return 0;
}
int fdt_delprop(void *fdt, int nodeoffset, const char *name)
{
struct fdt_property *prop;
int len, proplen;
RW_CHECK_HEADER(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (! prop)
return len;
proplen = sizeof(*prop) + ALIGN(len, FDT_TAGSIZE);
return _blob_splice_struct(fdt, prop, proplen, 0);
}
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
const char *name, int namelen)
{
struct fdt_node_header *nh;
int offset, nextoffset;
int nodelen;
int err;
uint32_t tag;
uint32_t *endtag;
RW_CHECK_HEADER(fdt);
offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
if (offset >= 0)
return -FDT_ERR_EXISTS;
else if (offset != -FDT_ERR_NOTFOUND)
return offset;
/* Try to place the new node after the parent's properties */
fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
} while ((tag == FDT_PROP) || (tag == FDT_NOP));
nh = _fdt_offset_ptr_w(fdt, offset);
nodelen = sizeof(*nh) + ALIGN(namelen+1, FDT_TAGSIZE) + FDT_TAGSIZE;
err = _blob_splice_struct(fdt, nh, 0, nodelen);
if (err)
return err;
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
memset(nh->name, 0, ALIGN(namelen+1, FDT_TAGSIZE));
memcpy(nh->name, name, namelen);
endtag = (uint32_t *)((void *)nh + nodelen - FDT_TAGSIZE);
*endtag = cpu_to_fdt32(FDT_END_NODE);
return offset;
}
int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
{
return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
}
int fdt_del_node(void *fdt, int nodeoffset)
{
int endoffset;
RW_CHECK_HEADER(fdt);
endoffset = _fdt_node_end_offset(fdt, nodeoffset);
if (endoffset < 0)
return endoffset;
return _blob_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
endoffset - nodeoffset, 0);
}
static void _packblocks(const void *fdt, void *buf,
int mem_rsv_size, int struct_size)
{
int mem_rsv_off, struct_off, strings_off;
mem_rsv_off = ALIGN(sizeof(struct fdt_header), 8);
struct_off = mem_rsv_off + mem_rsv_size;
strings_off = struct_off + struct_size;
memmove(buf + mem_rsv_off, fdt + fdt_off_mem_rsvmap(fdt), mem_rsv_size);
fdt_set_off_mem_rsvmap(buf, mem_rsv_off);
memmove(buf + struct_off, fdt + fdt_off_dt_struct(fdt), struct_size);
fdt_set_off_dt_struct(buf, struct_off);
fdt_set_size_dt_struct(buf, struct_size);
memmove(buf + strings_off, fdt + fdt_off_dt_strings(fdt),
fdt_size_dt_strings(fdt));
fdt_set_off_dt_strings(buf, strings_off);
fdt_set_size_dt_strings(buf, fdt_size_dt_strings(fdt));
}
int fdt_open_into(const void *fdt, void *buf, int bufsize)
{
int err;
int mem_rsv_size, struct_size;
int newsize;
void *tmp;
CHECK_HEADER(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
if (fdt_version(fdt) >= 17) {
struct_size = fdt_size_dt_struct(fdt);
} else {
struct_size = 0;
while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
;
}
if (!_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
/* no further work necessary */
err = fdt_move(fdt, buf, bufsize);
if (err)
return err;
fdt_set_version(buf, 17);
fdt_set_size_dt_struct(buf, struct_size);
fdt_set_totalsize(buf, bufsize);
return 0;
}
/* Need to reorder */
newsize = ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+ struct_size + fdt_size_dt_strings(fdt);
if (bufsize < newsize)
return -FDT_ERR_NOSPACE;
if (((buf + newsize) <= fdt)
|| (buf >= (fdt + fdt_totalsize(fdt)))) {
tmp = buf;
} else {
tmp = (void *)fdt + fdt_totalsize(fdt);
if ((tmp + newsize) > (buf + bufsize))
return -FDT_ERR_NOSPACE;
}
_packblocks(fdt, tmp, mem_rsv_size, struct_size);
memmove(buf, tmp, newsize);
fdt_set_magic(buf, FDT_MAGIC);
fdt_set_totalsize(buf, bufsize);
fdt_set_version(buf, 17);
fdt_set_last_comp_version(buf, 16);
fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
return 0;
}
int fdt_pack(void *fdt)
{
int mem_rsv_size;
int err;
err = rw_check_header(fdt);
if (err)
return err;
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
fdt_set_totalsize(fdt, _blob_data_size(fdt));
return 0;
}

96
kvm/libfdt/fdt_strerror.c Normal file
View File

@@ -0,0 +1,96 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
struct errtabent {
const char *str;
};
#define ERRTABENT(val) \
[(val)] = { .str = #val, }
static struct errtabent errtable[] = {
ERRTABENT(FDT_ERR_NOTFOUND),
ERRTABENT(FDT_ERR_EXISTS),
ERRTABENT(FDT_ERR_NOSPACE),
ERRTABENT(FDT_ERR_BADOFFSET),
ERRTABENT(FDT_ERR_BADPATH),
ERRTABENT(FDT_ERR_BADSTATE),
ERRTABENT(FDT_ERR_TRUNCATED),
ERRTABENT(FDT_ERR_BADMAGIC),
ERRTABENT(FDT_ERR_BADVERSION),
ERRTABENT(FDT_ERR_BADSTRUCTURE),
ERRTABENT(FDT_ERR_BADLAYOUT),
};
#define ERRTABSIZE (sizeof(errtable) / sizeof(errtable[0]))
const char *fdt_strerror(int errval)
{
if (errval > 0)
return "<valid offset/length>";
else if (errval == 0)
return "<no error>";
else if (errval > -ERRTABSIZE) {
const char *s = errtable[-errval].str;
if (s)
return s;
}
return "<unknown error>";
}

258
kvm/libfdt/fdt_sw.c Normal file
View File

@@ -0,0 +1,258 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
static int check_header_sw(void *fdt)
{
if (fdt_magic(fdt) != SW_MAGIC)
return -FDT_ERR_BADMAGIC;
return 0;
}
static void *grab_space(void *fdt, int len)
{
int offset = fdt_size_dt_struct(fdt);
int spaceleft;
spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
- fdt_size_dt_strings(fdt);
if ((offset + len < offset) || (offset + len > spaceleft))
return NULL;
fdt_set_size_dt_struct(fdt, offset + len);
return fdt_offset_ptr_w(fdt, offset, len);
}
int fdt_create(void *buf, int bufsize)
{
void *fdt = buf;
if (bufsize < sizeof(struct fdt_header))
return -FDT_ERR_NOSPACE;
memset(buf, 0, bufsize);
fdt_set_magic(fdt, SW_MAGIC);
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
fdt_set_totalsize(fdt, bufsize);
fdt_set_off_mem_rsvmap(fdt, ALIGN(sizeof(struct fdt_header),
sizeof(struct fdt_reserve_entry)));
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
fdt_set_off_dt_strings(fdt, bufsize);
return 0;
}
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
{
struct fdt_reserve_entry *re;
int err = check_header_sw(fdt);
int offset;
if (err)
return err;
if (fdt_size_dt_struct(fdt))
return -FDT_ERR_BADSTATE;
offset = fdt_off_dt_struct(fdt);
if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
return -FDT_ERR_NOSPACE;
re = (struct fdt_reserve_entry *)(fdt + offset);
re->address = cpu_to_fdt64(addr);
re->size = cpu_to_fdt64(size);
fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
return 0;
}
int fdt_finish_reservemap(void *fdt)
{
return fdt_add_reservemap_entry(fdt, 0, 0);
}
int fdt_begin_node(void *fdt, const char *name)
{
struct fdt_node_header *nh;
int err = check_header_sw(fdt);
int namelen = strlen(name) + 1;
if (err)
return err;
nh = grab_space(fdt, sizeof(*nh) + ALIGN(namelen, FDT_TAGSIZE));
if (! nh)
return -FDT_ERR_NOSPACE;
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
memcpy(nh->name, name, namelen);
return 0;
}
int fdt_end_node(void *fdt)
{
uint32_t *en;
int err = check_header_sw(fdt);
if (err)
return err;
en = grab_space(fdt, FDT_TAGSIZE);
if (! en)
return -FDT_ERR_NOSPACE;
*en = cpu_to_fdt32(FDT_END_NODE);
return 0;
}
static int find_add_string(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_totalsize(fdt);
const char *p;
int strtabsize = fdt_size_dt_strings(fdt);
int len = strlen(s) + 1;
int struct_top, offset;
p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
if (p)
return p - strtab;
/* Add it */
offset = -strtabsize - len;
struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
if (fdt_totalsize(fdt) + offset < struct_top)
return 0; /* no more room :( */
memcpy(strtab + offset, s, len);
fdt_set_size_dt_strings(fdt, strtabsize + len);
return offset;
}
int fdt_property(void *fdt, const char *name, const void *val, int len)
{
struct fdt_property *prop;
int err = check_header_sw(fdt);
int nameoff;
if (err)
return err;
nameoff = find_add_string(fdt, name);
if (nameoff == 0)
return -FDT_ERR_NOSPACE;
prop = grab_space(fdt, sizeof(*prop) + ALIGN(len, FDT_TAGSIZE));
if (! prop)
return -FDT_ERR_NOSPACE;
prop->tag = cpu_to_fdt32(FDT_PROP);
prop->nameoff = cpu_to_fdt32(nameoff);
prop->len = cpu_to_fdt32(len);
memcpy(prop->data, val, len);
return 0;
}
int fdt_finish(void *fdt)
{
int err = check_header_sw(fdt);
char *p = (char *)fdt;
uint32_t *end;
int oldstroffset, newstroffset;
uint32_t tag;
int offset, nextoffset;
if (err)
return err;
/* Add terminator */
end = grab_space(fdt, sizeof(*end));
if (! end)
return -FDT_ERR_NOSPACE;
*end = cpu_to_fdt32(FDT_END);
/* Relocate the string table */
oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
fdt_set_off_dt_strings(fdt, newstroffset);
/* Walk the structure, correcting string offsets */
offset = 0;
while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
if (tag == FDT_PROP) {
struct fdt_property *prop =
fdt_offset_ptr_w(fdt, offset, sizeof(*prop));
int nameoff;
if (! prop)
return -FDT_ERR_BADSTRUCTURE;
nameoff = fdt32_to_cpu(prop->nameoff);
nameoff += fdt_size_dt_strings(fdt);
prop->nameoff = cpu_to_fdt32(nameoff);
}
offset = nextoffset;
}
/* Finally, adjust the header */
fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
fdt_set_magic(fdt, FDT_MAGIC);
return 0;
}

144
kvm/libfdt/fdt_wip.c Normal file
View File

@@ -0,0 +1,144 @@
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "libfdt_env.h"
#include <fdt.h>
#include <libfdt.h>
#include "libfdt_internal.h"
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
void *propval;
int proplen;
propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
if (! propval)
return proplen;
if (proplen != len)
return -FDT_ERR_NOSPACE;
memcpy(propval, val, len);
return 0;
}
static void nop_region(void *start, int len)
{
uint32_t *p;
for (p = start; (void *)p < (start + len); p++)
*p = cpu_to_fdt32(FDT_NOP);
}
int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
{
struct fdt_property *prop;
int len;
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (! prop)
return len;
nop_region(prop, len + sizeof(*prop));
return 0;
}
int _fdt_node_end_offset(void *fdt, int nodeoffset)
{
int level = 0;
uint32_t tag;
int offset, nextoffset;
tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
if (tag != FDT_BEGIN_NODE)
return -FDT_ERR_BADOFFSET;
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
switch (tag) {
case FDT_END:
return offset;
case FDT_BEGIN_NODE:
level++;
break;
case FDT_END_NODE:
level--;
break;
case FDT_PROP:
case FDT_NOP:
break;
default:
return -FDT_ERR_BADSTRUCTURE;
}
} while (level >= 0);
return nextoffset;
}
int fdt_nop_node(void *fdt, int nodeoffset)
{
int endoffset;
endoffset = _fdt_node_end_offset(fdt, nodeoffset);
if (endoffset < 0)
return endoffset;
nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), endoffset - nodeoffset);
return 0;
}

1076
kvm/libfdt/libfdt.h Normal file

File diff suppressed because it is too large Load Diff

22
kvm/libfdt/libfdt_env.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef _LIBFDT_ENV_H
#define _LIBFDT_ENV_H
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <endian.h>
#include <byteswap.h>
#if __BYTE_ORDER == __BIG_ENDIAN
#define fdt32_to_cpu(x) (x)
#define cpu_to_fdt32(x) (x)
#define fdt64_to_cpu(x) (x)
#define cpu_to_fdt64(x) (x)
#else
#define fdt32_to_cpu(x) (bswap_32((x)))
#define cpu_to_fdt32(x) (bswap_32((x)))
#define fdt64_to_cpu(x) (bswap_64((x)))
#define cpu_to_fdt64(x) (bswap_64((x)))
#endif
#endif /* _LIBFDT_ENV_H */

View File

@@ -0,0 +1,96 @@
#ifndef _LIBFDT_INTERNAL_H
#define _LIBFDT_INTERNAL_H
/*
* libfdt - Flat Device Tree manipulation
* Copyright (C) 2006 David Gibson, IBM Corporation.
*
* libfdt is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
*
* a) This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
* Alternatively,
*
* b) Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <fdt.h>
#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
#define PALIGN(p, a) ((void *)ALIGN((unsigned long)(p), (a)))
#define memeq(p, q, n) (memcmp((p), (q), (n)) == 0)
#define streq(p, q) (strcmp((p), (q)) == 0)
#define CHECK_HEADER(fdt) \
{ \
int err; \
if ((err = fdt_check_header(fdt)) != 0) \
return err; \
}
uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset);
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
int _fdt_node_end_offset(void *fdt, int nodeoffset);
static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
{
return fdt + fdt_off_dt_struct(fdt) + offset;
}
static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
{
return (void *)_fdt_offset_ptr(fdt, offset);
}
static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
{
const struct fdt_reserve_entry *rsv_table =
fdt + fdt_off_mem_rsvmap(fdt);
return rsv_table + n;
}
static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
{
return (void *)_fdt_mem_rsv(fdt, n);
}
#define SW_MAGIC (~FDT_MAGIC)
#endif /* _LIBFDT_INTERNAL_H */

54
kvm/libkvm/Makefile Normal file
View File

@@ -0,0 +1,54 @@
all: libkvm.a
include ../../config-host.mak
ifneq ($(VPATH),)
srcdir=$(VPATH)/kvm/libkvm
else
srcdir=.
endif
include $(srcdir)/config-$(ARCH).mak
# libkvm is not -Wredundant-decls friendly yet
CFLAGS += -Wno-redundant-decls
# cc-option
# Usage: OP_CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0)
cc-option = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \
> /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
CFLAGS += $(autodepend-flags) -g -fomit-frame-pointer -Wall
CFLAGS += $(call cc-option, -fno-stack-protector, "")
CFLAGS += $(call cc-option, -fno-stack-protector-all, "")
CFLAGS += $(KVM_CFLAGS)
LDFLAGS += $(CFLAGS)
CXXFLAGS = $(autodepend-flags)
VPATH:=$(VPATH)/kvm/libkvm
autodepend-flags = -MMD -MF $(dir $*).$(notdir $*).d
libkvm.a: libkvm.o $(libkvm-$(ARCH)-objs)
$(AR) rcs $@ $^
install:
@echo skipping libkvm install
install-libkvm:
install -D libkvm.h $(DESTDIR)/$(PREFIX)/include/libkvm.h
install -D libkvm.a $(DESTDIR)/$(PREFIX)/$(LIBDIR)/libkvm.a
install-kernel-headers:
install -D $(LIBKVM_KERNELDIR)/include/linux/kvm.h \
$(DESTDIR)/$(PREFIX)/include/linux/kvm.h
install -D $(LIBKVM_KERNELDIR)/include/linux/kvm_para.h \
$(DESTDIR)/$(PREFIX)/include/linux/kvm_para.h
-include .*.d
clean:
$(RM) *.o *.a .*.d

View File

@@ -0,0 +1,6 @@
LIBDIR := /lib
CFLAGS += -m32
CFLAGS += -D__i386__
libkvm-$(ARCH)-objs := libkvm-x86.o

View File

@@ -0,0 +1,5 @@
LIBDIR := /lib
CFLAGS += -D__ia64__
libkvm-$(ARCH)-objs := libkvm-ia64.o

View File

@@ -0,0 +1,4 @@
LIBDIR := /lib
libkvm-$(ARCH)-objs := libkvm-powerpc.o

View File

@@ -0,0 +1,3 @@
# s390 31bit mode
LIBDIR := /lib
libkvm-$(ARCH)-objs := libkvm-s390.o

View File

@@ -0,0 +1,3 @@
# s390 64 bit mode (arch=s390x)
LIBDIR := /lib64
libkvm-$(ARCH)-objs := libkvm-s390.o

View File

@@ -0,0 +1,6 @@
LIBDIR := /lib64
CFLAGS += -m64
CFLAGS += -D__x86_64__
libkvm-$(ARCH)-objs := libkvm-x86.o

94
kvm/libkvm/kvm-common.h Normal file
View File

@@ -0,0 +1,94 @@
/*
* This header is for functions & variables that will ONLY be
* used inside libkvm.
*
* derived from libkvm.c
*
* Copyright (C) 2006 Qumranet, Inc.
*
* Authors:
* Avi Kivity <avi@qumranet.com>
* Yaniv Kamay <yaniv@qumranet.com>
*
* This work is licensed under the GNU LGPL license, version 2.
*/
#ifndef KVM_COMMON_H
#define KVM_COMMON_H
/* FIXME: share this number with kvm */
/* FIXME: or dynamically alloc/realloc regions */
#ifdef __s390__
#define KVM_MAX_NUM_MEM_REGIONS 1u
#define MAX_VCPUS 64
#define LIBKVM_S390_ORIGIN (0UL)
#elif defined(__ia64__)
#define KVM_MAX_NUM_MEM_REGIONS 32u
#define MAX_VCPUS 256
#else
#define KVM_MAX_NUM_MEM_REGIONS 32u
#define MAX_VCPUS 16
#endif
/* kvm abi verison variable */
extern int kvm_abi;
/**
* \brief The KVM context
*
* The verbose KVM context
*/
struct kvm_context {
/// Filedescriptor to /dev/kvm
int fd;
int vm_fd;
int vcpu_fd[MAX_VCPUS];
struct kvm_run *run[MAX_VCPUS];
/// Callbacks that KVM uses to emulate various unvirtualizable functionality
struct kvm_callbacks *callbacks;
void *opaque;
/// is dirty pages logging enabled for all regions or not
int dirty_pages_log_all;
/// do not create in-kernel irqchip if set
int no_irqchip_creation;
/// in-kernel irqchip status
int irqchip_in_kernel;
/// ioctl to use to inject interrupts
int irqchip_inject_ioctl;
/// do not create in-kernel pit if set
int no_pit_creation;
/// in-kernel pit status
int pit_in_kernel;
/// in-kernel coalesced mmio
int coalesced_mmio;
#ifdef KVM_CAP_IRQ_ROUTING
struct kvm_irq_routing *irq_routes;
int nr_allocated_irq_routes;
#endif
void *used_gsi_bitmap;
int max_gsi;
};
int kvm_alloc_kernel_memory(kvm_context_t kvm, unsigned long memory,
void **vm_mem);
int kvm_alloc_userspace_memory(kvm_context_t kvm, unsigned long memory,
void **vm_mem);
int kvm_arch_create(kvm_context_t kvm, unsigned long phys_mem_bytes,
void **vm_mem);
int kvm_arch_run(struct kvm_run *run, kvm_context_t kvm, int vcpu);
void kvm_show_code(kvm_context_t kvm, int vcpu);
int handle_halt(kvm_context_t kvm, int vcpu);
int handle_shutdown(kvm_context_t kvm, void *env);
void post_kvm_run(kvm_context_t kvm, void *env);
int pre_kvm_run(kvm_context_t kvm, void *env);
int handle_io_window(kvm_context_t kvm);
int handle_debug(kvm_context_t kvm, int vcpu, void *env);
int try_push_interrupts(kvm_context_t kvm);
#endif

31
kvm/libkvm/kvm-ia64.h Normal file
View File

@@ -0,0 +1,31 @@
/*
* This header is for functions & variables that will ONLY be
* used inside libkvm for x86.
* THESE ARE NOT EXPOSED TO THE USER AND ARE ONLY FOR USE
* WITHIN LIBKVM.
*
* derived from libkvm.c
*
* Copyright (C) 2006 Qumranet, Inc.
*
* Authors:
* Avi Kivity <avi@qumranet.com>
* Yaniv Kamay <yaniv@qumranet.com>
*
* This work is licensed under the GNU LGPL license, version 2.
*/
#ifndef KVM_IA64_H
#define KVM_IA64_H
#include "kvm-common.h"
extern int kvm_page_size;
#define PAGE_SIZE kvm_page_size
#define PAGE_MASK (~(kvm_page_size - 1))
#define ia64_mf() asm volatile ("mf" ::: "memory")
#define smp_wmb() ia64_mf()
#endif

36
kvm/libkvm/kvm-powerpc.h Normal file
View File

@@ -0,0 +1,36 @@
/*
* This header is for functions & variables that will ONLY be
* used inside libkvm for powerpc.
* THESE ARE NOT EXPOSED TO THE USER AND ARE ONLY FOR USE
* WITHIN LIBKVM.
*
* Copyright (C) 2006 Qumranet, Inc.
*
* Authors:
* Avi Kivity <avi@qumranet.com>
* Yaniv Kamay <yaniv@qumranet.com>
*
* Copyright 2007 IBM Corporation.
* Added by: Jerone Young <jyoung5@us.ibm.com>
*
* This work is licensed under the GNU LGPL license, version 2.
*/
#ifndef KVM_POWERPC_H
#define KVM_POWERPC_H
#include "kvm-common.h"
extern int kvm_page_size;
#define PAGE_SIZE kvm_page_size
#define PAGE_MASK (~(PAGE_SIZE - 1))
static inline void eieio(void)
{
asm volatile("eieio" : : : "memory");
}
#define smp_wmb() eieio()
#endif

31
kvm/libkvm/kvm-s390.h Normal file
View File

@@ -0,0 +1,31 @@
/*
* This header is for functions & variables that will ONLY be
* used inside libkvm for s390.
* THESE ARE NOT EXPOSED TO THE USER AND ARE ONLY FOR USE
* WITHIN LIBKVM.
*
* Copyright (C) 2006 Qumranet, Inc.
*
* Authors:
* Avi Kivity <avi@qumranet.com>
* Yaniv Kamay <yaniv@qumranet.com>
*
* Copyright 2008 IBM Corporation.
* Authors:
* Carsten Otte <cotte@de.ibm.com>
*
* This work is licensed under the GNU LGPL license, version 2.
*/
#ifndef KVM_S390_H
#define KVM_S390_H
#include <asm/ptrace.h>
#include "kvm-common.h"
#define PAGE_SIZE 4096ul
#define PAGE_MASK (~(PAGE_SIZE - 1))
#define smp_wmb() asm volatile("" ::: "memory")
#endif

55
kvm/libkvm/kvm-x86.h Normal file
View File

@@ -0,0 +1,55 @@
/*
* This header is for functions & variables that will ONLY be
* used inside libkvm for x86.
* THESE ARE NOT EXPOSED TO THE USER AND ARE ONLY FOR USE
* WITHIN LIBKVM.
*
* derived from libkvm.c
*
* Copyright (C) 2006 Qumranet, Inc.
*
* Authors:
* Avi Kivity <avi@qumranet.com>
* Yaniv Kamay <yaniv@qumranet.com>
*
* This work is licensed under the GNU LGPL license, version 2.
*/
#ifndef KVM_X86_H
#define KVM_X86_H
#include "kvm-common.h"
#define PAGE_SIZE 4096ul
#define PAGE_MASK (~(PAGE_SIZE - 1))
int kvm_set_tss_addr(kvm_context_t kvm, unsigned long addr);
#ifdef KVM_CAP_VAPIC
/*!
* \brief Enable kernel tpr access reporting
*
* When tpr access reporting is enabled, the kernel will call the
* ->tpr_access() callback every time the guest vcpu accesses the tpr.
*
* \param kvm Pointer to the current kvm_context
* \param vcpu vcpu to enable tpr access reporting on
*/
int kvm_enable_tpr_access_reporting(kvm_context_t kvm, int vcpu);
/*!
* \brief Disable kernel tpr access reporting
*
* Undoes the effect of kvm_enable_tpr_access_reporting().
*
* \param kvm Pointer to the current kvm_context
* \param vcpu vcpu to disable tpr access reporting on
*/
int kvm_disable_tpr_access_reporting(kvm_context_t kvm, int vcpu);
#endif
#define smp_wmb() asm volatile("" ::: "memory")
#endif

82
kvm/libkvm/libkvm-ia64.c Normal file
View File

@@ -0,0 +1,82 @@
/*
* libkvm-ia64.c :Kernel-based Virtual Machine control library for ia64.
*
* This library provides an API to control the kvm hardware virtualization
* module.
*
* Copyright (C) 2006 Qumranet
*
* Authors:
*
* Avi Kivity <avi@qumranet.com>
* Yaniv Kamay <yaniv@qumranet.com>
*
* Copyright (C) 2007 Intel
* Added by : Zhang Xiantao <xiantao.zhang@intel.com>
*
* This work is licensed under the GNU LGPL license, version 2.
*
*/
#include "libkvm.h"
#include "kvm-ia64.h"
#include <errno.h>
#include <sys/ioctl.h>
#include <string.h>
#include <unistd.h>
#include <stropts.h>
#include <sys/mman.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int kvm_arch_create(kvm_context_t kvm, unsigned long phys_mem_bytes,
void **vm_mem)
{
int r;
r = kvm_init_coalesced_mmio(kvm);
if (r < 0)
return r;
return 0;
}
int kvm_arch_run(struct kvm_run *run,kvm_context_t kvm, int vcpu)
{
int r = 0;
switch (run->exit_reason) {
default:
r = 1;
break;
}
return r;
}
void kvm_show_code(kvm_context_t kvm, int vcpu)
{
fprintf(stderr, "kvm_show_code not supported yet!\n");
}
void kvm_show_regs(kvm_context_t kvm, int vcpu)
{
fprintf(stderr,"kvm_show_regs not supportted today!\n");
}
int kvm_create_memory_alias(kvm_context_t kvm,
uint64_t phys_start,
uint64_t len,
uint64_t target_phys)
{
return 0;
}
int kvm_destroy_memory_alias(kvm_context_t kvm, uint64_t phys_start)
{
return 0;
}

100
kvm/libkvm/libkvm-powerpc.c Normal file
View File

@@ -0,0 +1,100 @@
/*
* This file contains the powerpc specific implementation for the
* architecture dependent functions defined in kvm-common.h and
* libkvm.h
*
* Copyright (C) 2006 Qumranet, Inc.
*
* Authors:
* Avi Kivity <avi@qumranet.com>
* Yaniv Kamay <yaniv@qumranet.com>
*
* Copyright IBM Corp. 2007,2008
* Authors:
* Jerone Young <jyoung5@us.ibm.com>
* Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
*
* This work is licensed under the GNU LGPL license, version 2.
*/
#include "libkvm.h"
#include "kvm-powerpc.h"
#include <errno.h>
#include <stdio.h>
#include <inttypes.h>
int handle_dcr(struct kvm_run *run, kvm_context_t kvm, int vcpu)
{
int ret = 0;
if (run->dcr.is_write)
ret = kvm->callbacks->powerpc_dcr_write(vcpu,
run->dcr.dcrn,
run->dcr.data);
else
ret = kvm->callbacks->powerpc_dcr_read(vcpu,
run->dcr.dcrn,
&(run->dcr.data));
return ret;
}
void kvm_show_code(kvm_context_t kvm, int vcpu)
{
fprintf(stderr, "%s: Operation not supported\n", __FUNCTION__);
}
void kvm_show_regs(kvm_context_t kvm, int vcpu)
{
struct kvm_regs regs;
int i;
if (kvm_get_regs(kvm, vcpu, &regs))
return;
fprintf(stderr,"guest vcpu #%d\n", vcpu);
fprintf(stderr,"pc: %016"PRIx64" msr: %016"PRIx64"\n",
regs.pc, regs.msr);
fprintf(stderr,"lr: %016"PRIx64" ctr: %016"PRIx64"\n",
regs.lr, regs.ctr);
fprintf(stderr,"srr0: %016"PRIx64" srr1: %016"PRIx64"\n",
regs.srr0, regs.srr1);
for (i=0; i<32; i+=4)
{
fprintf(stderr, "gpr%02d: %016"PRIx64" %016"PRIx64" %016"PRIx64
" %016"PRIx64"\n", i,
regs.gpr[i],
regs.gpr[i+1],
regs.gpr[i+2],
regs.gpr[i+3]);
}
fflush(stdout);
}
int kvm_arch_create(kvm_context_t kvm, unsigned long phys_mem_bytes,
void **vm_mem)
{
int r;
r = kvm_init_coalesced_mmio(kvm);
if (r < 0)
return r;
return 0;
}
int kvm_arch_run(struct kvm_run *run, kvm_context_t kvm, int vcpu)
{
int ret = 0;
switch (run->exit_reason){
case KVM_EXIT_DCR:
ret = handle_dcr(run, kvm, vcpu);
break;
default:
ret = 1;
break;
}
return ret;
}

110
kvm/libkvm/libkvm-s390.c Normal file
View File

@@ -0,0 +1,110 @@
/*
* This file contains the s390 specific implementation for the
* architecture dependent functions defined in kvm-common.h and
* libkvm.h
*
* Copyright (C) 2006 Qumranet
* Copyright IBM Corp. 2008
*
* Authors:
* Carsten Otte <cotte@de.ibm.com>
* Christian Borntraeger <borntraeger@de.ibm.com>
*
* This work is licensed under the GNU LGPL license, version 2.
*/
#include <sys/ioctl.h>
#include <asm/ptrace.h>
#include "libkvm.h"
#include "kvm-common.h"
#include <errno.h>
#include <stdio.h>
#include <inttypes.h>
void kvm_show_code(kvm_context_t kvm, int vcpu)
{
fprintf(stderr, "%s: Operation not supported\n", __FUNCTION__);
}
void kvm_show_regs(kvm_context_t kvm, int vcpu)
{
struct kvm_regs regs;
struct kvm_sregs sregs;
int i;
if (kvm_get_regs(kvm, vcpu, &regs))
return;
if (kvm_get_sregs(kvm, vcpu, &sregs))
return;
fprintf(stderr, "guest vcpu #%d\n", vcpu);
fprintf(stderr, "PSW:\t%16.16lx %16.16lx\n",
kvm->run[vcpu]->s390_sieic.mask,
kvm->run[vcpu]->s390_sieic.addr);
fprintf(stderr,"GPRS:");
for (i=0; i<15; i+=4)
fprintf(stderr, "\t%16.16lx %16.16lx %16.16lx %16.16lx\n",
regs.gprs[i],
regs.gprs[i+1],
regs.gprs[i+2],
regs.gprs[i+3]);
fprintf(stderr,"ACRS:");
for (i=0; i<15; i+=4)
fprintf(stderr, "\t%8.8x %8.8x %8.8x %8.8x\n",
sregs.acrs[i],
sregs.acrs[i+1],
sregs.acrs[i+2],
sregs.acrs[i+3]);
fprintf(stderr,"CRS:");
for (i=0; i<15; i+=4)
fprintf(stderr, "\t%16.16lx %16.16lx %16.16lx %16.16lx\n",
sregs.crs[i],
sregs.crs[i+1],
sregs.crs[i+2],
sregs.crs[i+3]);
}
int kvm_arch_create(kvm_context_t kvm, unsigned long phys_mem_bytes,
void **vm_mem)
{
return 0;
}
int kvm_arch_run(struct kvm_run *run, kvm_context_t kvm, int vcpu)
{
int ret = 0;
switch (run->exit_reason){
default:
ret = 1;
break;
}
return ret;
}
int kvm_s390_initial_reset(kvm_context_t kvm, int slot)
{
return ioctl(kvm->vcpu_fd[slot], KVM_S390_INITIAL_RESET, NULL);
}
int kvm_s390_interrupt(kvm_context_t kvm, int slot,
struct kvm_s390_interrupt *kvmint)
{
if (slot>=0)
return ioctl(kvm->vcpu_fd[slot], KVM_S390_INTERRUPT, kvmint);
else
return ioctl(kvm->vm_fd, KVM_S390_INTERRUPT, kvmint);
}
int kvm_s390_set_initial_psw(kvm_context_t kvm, int slot, psw_t psw)
{
return ioctl(kvm->vcpu_fd[slot], KVM_S390_SET_INITIAL_PSW, &psw);
}
int kvm_s390_store_status(kvm_context_t kvm, int slot, unsigned long addr)
{
return ioctl(kvm->vcpu_fd[slot], KVM_S390_STORE_STATUS, addr);
}

637
kvm/libkvm/libkvm-x86.c Normal file
View File

@@ -0,0 +1,637 @@
#include "libkvm.h"
#include "kvm-x86.h"
#include <errno.h>
#include <sys/ioctl.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
int kvm_set_tss_addr(kvm_context_t kvm, unsigned long addr)
{
#ifdef KVM_CAP_SET_TSS_ADDR
int r;
r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_SET_TSS_ADDR);
if (r > 0) {
r = ioctl(kvm->vm_fd, KVM_SET_TSS_ADDR, addr);
if (r == -1) {
fprintf(stderr, "kvm_set_tss_addr: %m\n");
return -errno;
}
return 0;
}
#endif
return -ENOSYS;
}
static int kvm_init_tss(kvm_context_t kvm)
{
#ifdef KVM_CAP_SET_TSS_ADDR
int r;
r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_SET_TSS_ADDR);
if (r > 0) {
/*
* this address is 3 pages before the bios, and the bios should present
* as unavaible memory
*/
r = kvm_set_tss_addr(kvm, 0xfffbd000);
if (r < 0) {
fprintf(stderr, "kvm_init_tss: unable to set tss addr\n");
return r;
}
}
#endif
return 0;
}
static int kvm_create_pit(kvm_context_t kvm)
{
#ifdef KVM_CAP_PIT
int r;
kvm->pit_in_kernel = 0;
if (!kvm->no_pit_creation) {
#ifdef KVM_CAP_PIT2
struct kvm_pit_config config = { .flags = 0 };
r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_PIT2);
if (r > 0)
r = ioctl(kvm->vm_fd, KVM_CREATE_PIT2, &config);
else
#endif
{
r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_PIT);
if (r <= 0)
return 0;
r = ioctl(kvm->vm_fd, KVM_CREATE_PIT);
}
if (r < 0) {
fprintf(stderr, "Create kernel PIC irqchip failed\n");
return r;
}
kvm->pit_in_kernel = 1;
}
#endif
return 0;
}
int kvm_arch_create(kvm_context_t kvm, unsigned long phys_mem_bytes,
void **vm_mem)
{
int r = 0;
r = kvm_init_tss(kvm);
if (r < 0)
return r;
r = kvm_create_pit(kvm);
if (r < 0)
return r;
r = kvm_init_coalesced_mmio(kvm);
if (r < 0)
return r;
return 0;
}
#ifdef KVM_EXIT_TPR_ACCESS
static int handle_tpr_access(kvm_context_t kvm, struct kvm_run *run, int vcpu)
{
return kvm->callbacks->tpr_access(kvm->opaque, vcpu,
run->tpr_access.rip,
run->tpr_access.is_write);
}
int kvm_enable_vapic(kvm_context_t kvm, int vcpu, uint64_t vapic)
{
int r;
struct kvm_vapic_addr va = {
.vapic_addr = vapic,
};
r = ioctl(kvm->vcpu_fd[vcpu], KVM_SET_VAPIC_ADDR, &va);
if (r == -1) {
r = -errno;
perror("kvm_enable_vapic");
return r;
}
return 0;
}
#endif
int kvm_arch_run(struct kvm_run *run,kvm_context_t kvm, int vcpu)
{
int r = 0;
switch (run->exit_reason) {
#ifdef KVM_EXIT_SET_TPR
case KVM_EXIT_SET_TPR:
break;
#endif
#ifdef KVM_EXIT_TPR_ACCESS
case KVM_EXIT_TPR_ACCESS:
r = handle_tpr_access(kvm, run, vcpu);
break;
#endif
default:
r = 1;
break;
}
return r;
}
#define MAX_ALIAS_SLOTS 4
static struct {
uint64_t start;
uint64_t len;
} kvm_aliases[MAX_ALIAS_SLOTS];
static int get_alias_slot(uint64_t start)
{
int i;
for (i=0; i<MAX_ALIAS_SLOTS; i++)
if (kvm_aliases[i].start == start)
return i;
return -1;
}
static int get_free_alias_slot(void)
{
int i;
for (i=0; i<MAX_ALIAS_SLOTS; i++)
if (kvm_aliases[i].len == 0)
return i;
return -1;
}
static void register_alias(int slot, uint64_t start, uint64_t len)
{
kvm_aliases[slot].start = start;
kvm_aliases[slot].len = len;
}
int kvm_create_memory_alias(kvm_context_t kvm,
uint64_t phys_start,
uint64_t len,
uint64_t target_phys)
{
struct kvm_memory_alias alias = {
.flags = 0,
.guest_phys_addr = phys_start,
.memory_size = len,
.target_phys_addr = target_phys,
};
int fd = kvm->vm_fd;
int r;
int slot;
slot = get_alias_slot(phys_start);
if (slot < 0)
slot = get_free_alias_slot();
if (slot < 0)
return -EBUSY;
alias.slot = slot;
r = ioctl(fd, KVM_SET_MEMORY_ALIAS, &alias);
if (r == -1)
return -errno;
register_alias(slot, phys_start, len);
return 0;
}
int kvm_destroy_memory_alias(kvm_context_t kvm, uint64_t phys_start)
{
return kvm_create_memory_alias(kvm, phys_start, 0, 0);
}
#ifdef KVM_CAP_IRQCHIP
int kvm_get_lapic(kvm_context_t kvm, int vcpu, struct kvm_lapic_state *s)
{
int r;
if (!kvm->irqchip_in_kernel)
return 0;
r = ioctl(kvm->vcpu_fd[vcpu], KVM_GET_LAPIC, s);
if (r == -1) {
r = -errno;
perror("kvm_get_lapic");
}
return r;
}
int kvm_set_lapic(kvm_context_t kvm, int vcpu, struct kvm_lapic_state *s)
{
int r;
if (!kvm->irqchip_in_kernel)
return 0;
r = ioctl(kvm->vcpu_fd[vcpu], KVM_SET_LAPIC, s);
if (r == -1) {
r = -errno;
perror("kvm_set_lapic");
}
return r;
}
#endif
#ifdef KVM_CAP_PIT
int kvm_get_pit(kvm_context_t kvm, struct kvm_pit_state *s)
{
int r;
if (!kvm->pit_in_kernel)
return 0;
r = ioctl(kvm->vm_fd, KVM_GET_PIT, s);
if (r == -1) {
r = -errno;
perror("kvm_get_pit");
}
return r;
}
int kvm_set_pit(kvm_context_t kvm, struct kvm_pit_state *s)
{
int r;
if (!kvm->pit_in_kernel)
return 0;
r = ioctl(kvm->vm_fd, KVM_SET_PIT, s);
if (r == -1) {
r = -errno;
perror("kvm_set_pit");
}
return r;
}
#endif
void kvm_show_code(kvm_context_t kvm, int vcpu)
{
#define SHOW_CODE_LEN 50
int fd = kvm->vcpu_fd[vcpu];
struct kvm_regs regs;
struct kvm_sregs sregs;
int r, n;
int back_offset;
unsigned char code;
char code_str[SHOW_CODE_LEN * 3 + 1];
unsigned long rip;
r = ioctl(fd, KVM_GET_SREGS, &sregs);
if (r == -1) {
perror("KVM_GET_SREGS");
return;
}
r = ioctl(fd, KVM_GET_REGS, &regs);
if (r == -1) {
perror("KVM_GET_REGS");
return;
}
rip = sregs.cs.base + regs.rip;
back_offset = regs.rip;
if (back_offset > 20)
back_offset = 20;
*code_str = 0;
for (n = -back_offset; n < SHOW_CODE_LEN-back_offset; ++n) {
if (n == 0)
strcat(code_str, " -->");
r = kvm->callbacks->mmio_read(kvm->opaque, rip + n, &code, 1);
if (r < 0) {
strcat(code_str, " xx");
continue;
}
sprintf(code_str + strlen(code_str), " %02x", code);
}
fprintf(stderr, "code:%s\n", code_str);
}
/*
* Returns available msr list. User must free.
*/
struct kvm_msr_list *kvm_get_msr_list(kvm_context_t kvm)
{
struct kvm_msr_list sizer, *msrs;
int r, e;
sizer.nmsrs = 0;
r = ioctl(kvm->fd, KVM_GET_MSR_INDEX_LIST, &sizer);
if (r == -1 && errno != E2BIG)
return NULL;
msrs = malloc(sizeof *msrs + sizer.nmsrs * sizeof *msrs->indices);
if (!msrs) {
errno = ENOMEM;
return NULL;
}
msrs->nmsrs = sizer.nmsrs;
r = ioctl(kvm->fd, KVM_GET_MSR_INDEX_LIST, msrs);
if (r == -1) {
e = errno;
free(msrs);
errno = e;
return NULL;
}
return msrs;
}
int kvm_get_msrs(kvm_context_t kvm, int vcpu, struct kvm_msr_entry *msrs,
int n)
{
struct kvm_msrs *kmsrs = malloc(sizeof *kmsrs + n * sizeof *msrs);
int r, e;
if (!kmsrs) {
errno = ENOMEM;
return -1;
}
kmsrs->nmsrs = n;
memcpy(kmsrs->entries, msrs, n * sizeof *msrs);
r = ioctl(kvm->vcpu_fd[vcpu], KVM_GET_MSRS, kmsrs);
e = errno;
memcpy(msrs, kmsrs->entries, n * sizeof *msrs);
free(kmsrs);
errno = e;
return r;
}
int kvm_set_msrs(kvm_context_t kvm, int vcpu, struct kvm_msr_entry *msrs,
int n)
{
struct kvm_msrs *kmsrs = malloc(sizeof *kmsrs + n * sizeof *msrs);
int r, e;
if (!kmsrs) {
errno = ENOMEM;
return -1;
}
kmsrs->nmsrs = n;
memcpy(kmsrs->entries, msrs, n * sizeof *msrs);
r = ioctl(kvm->vcpu_fd[vcpu], KVM_SET_MSRS, kmsrs);
e = errno;
free(kmsrs);
errno = e;
return r;
}
static void print_seg(FILE *file, const char *name, struct kvm_segment *seg)
{
fprintf(stderr,
"%s %04x (%08llx/%08x p %d dpl %d db %d s %d type %x l %d"
" g %d avl %d)\n",
name, seg->selector, seg->base, seg->limit, seg->present,
seg->dpl, seg->db, seg->s, seg->type, seg->l, seg->g,
seg->avl);
}
static void print_dt(FILE *file, const char *name, struct kvm_dtable *dt)
{
fprintf(stderr, "%s %llx/%x\n", name, dt->base, dt->limit);
}
void kvm_show_regs(kvm_context_t kvm, int vcpu)
{
int fd = kvm->vcpu_fd[vcpu];
struct kvm_regs regs;
struct kvm_sregs sregs;
int r;
r = ioctl(fd, KVM_GET_REGS, &regs);
if (r == -1) {
perror("KVM_GET_REGS");
return;
}
fprintf(stderr,
"rax %016llx rbx %016llx rcx %016llx rdx %016llx\n"
"rsi %016llx rdi %016llx rsp %016llx rbp %016llx\n"
"r8 %016llx r9 %016llx r10 %016llx r11 %016llx\n"
"r12 %016llx r13 %016llx r14 %016llx r15 %016llx\n"
"rip %016llx rflags %08llx\n",
regs.rax, regs.rbx, regs.rcx, regs.rdx,
regs.rsi, regs.rdi, regs.rsp, regs.rbp,
regs.r8, regs.r9, regs.r10, regs.r11,
regs.r12, regs.r13, regs.r14, regs.r15,
regs.rip, regs.rflags);
r = ioctl(fd, KVM_GET_SREGS, &sregs);
if (r == -1) {
perror("KVM_GET_SREGS");
return;
}
print_seg(stderr, "cs", &sregs.cs);
print_seg(stderr, "ds", &sregs.ds);
print_seg(stderr, "es", &sregs.es);
print_seg(stderr, "ss", &sregs.ss);
print_seg(stderr, "fs", &sregs.fs);
print_seg(stderr, "gs", &sregs.gs);
print_seg(stderr, "tr", &sregs.tr);
print_seg(stderr, "ldt", &sregs.ldt);
print_dt(stderr, "gdt", &sregs.gdt);
print_dt(stderr, "idt", &sregs.idt);
fprintf(stderr, "cr0 %llx cr2 %llx cr3 %llx cr4 %llx cr8 %llx"
" efer %llx\n",
sregs.cr0, sregs.cr2, sregs.cr3, sregs.cr4, sregs.cr8,
sregs.efer);
}
uint64_t kvm_get_apic_base(kvm_context_t kvm, int vcpu)
{
struct kvm_run *run = kvm->run[vcpu];
return run->apic_base;
}
void kvm_set_cr8(kvm_context_t kvm, int vcpu, uint64_t cr8)
{
struct kvm_run *run = kvm->run[vcpu];
run->cr8 = cr8;
}
__u64 kvm_get_cr8(kvm_context_t kvm, int vcpu)
{
return kvm->run[vcpu]->cr8;
}
int kvm_set_shadow_pages(kvm_context_t kvm, unsigned int nrshadow_pages)
{
#ifdef KVM_CAP_MMU_SHADOW_CACHE_CONTROL
int r;
r = ioctl(kvm->fd, KVM_CHECK_EXTENSION,
KVM_CAP_MMU_SHADOW_CACHE_CONTROL);
if (r > 0) {
r = ioctl(kvm->vm_fd, KVM_SET_NR_MMU_PAGES, nrshadow_pages);
if (r == -1) {
fprintf(stderr, "kvm_set_shadow_pages: %m\n");
return -errno;
}
return 0;
}
#endif
return -1;
}
int kvm_get_shadow_pages(kvm_context_t kvm, unsigned int *nrshadow_pages)
{
#ifdef KVM_CAP_MMU_SHADOW_CACHE_CONTROL
int r;
r = ioctl(kvm->fd, KVM_CHECK_EXTENSION,
KVM_CAP_MMU_SHADOW_CACHE_CONTROL);
if (r > 0) {
*nrshadow_pages = ioctl(kvm->vm_fd, KVM_GET_NR_MMU_PAGES);
return 0;
}
#endif
return -1;
}
#ifdef KVM_CAP_VAPIC
static int tpr_access_reporting(kvm_context_t kvm, int vcpu, int enabled)
{
int r;
struct kvm_tpr_access_ctl tac = {
.enabled = enabled,
};
r = ioctl(kvm->fd, KVM_CHECK_EXTENSION, KVM_CAP_VAPIC);
if (r == -1 || r == 0)
return -ENOSYS;
r = ioctl(kvm->vcpu_fd[vcpu], KVM_TPR_ACCESS_REPORTING, &tac);
if (r == -1) {
r = -errno;
perror("KVM_TPR_ACCESS_REPORTING");
return r;
}
return 0;
}
int kvm_enable_tpr_access_reporting(kvm_context_t kvm, int vcpu)
{
return tpr_access_reporting(kvm, vcpu, 1);
}
int kvm_disable_tpr_access_reporting(kvm_context_t kvm, int vcpu)
{
return tpr_access_reporting(kvm, vcpu, 0);
}
#endif
#ifdef KVM_CAP_EXT_CPUID
static struct kvm_cpuid2 *try_get_cpuid(kvm_context_t kvm, int max)
{
struct kvm_cpuid2 *cpuid;
int r, size;
size = sizeof(*cpuid) + max * sizeof(*cpuid->entries);
cpuid = (struct kvm_cpuid2 *)malloc(size);
cpuid->nent = max;
r = ioctl(kvm->fd, KVM_GET_SUPPORTED_CPUID, cpuid);
if (r == -1)
r = -errno;
else if (r == 0 && cpuid->nent >= max)
r = -E2BIG;
if (r < 0) {
if (r == -E2BIG) {
free(cpuid);
return NULL;
} else {
fprintf(stderr, "KVM_GET_SUPPORTED_CPUID failed: %s\n",
strerror(-r));
exit(1);
}
}
return cpuid;
}
#define R_EAX 0
#define R_ECX 1
#define R_EDX 2
#define R_EBX 3
#define R_ESP 4
#define R_EBP 5
#define R_ESI 6
#define R_EDI 7
uint32_t kvm_get_supported_cpuid(kvm_context_t kvm, uint32_t function, int reg)
{
struct kvm_cpuid2 *cpuid;
int i, max;
uint32_t ret = 0;
uint32_t cpuid_1_edx;
if (!kvm_check_extension(kvm, KVM_CAP_EXT_CPUID)) {
return -1U;
}
max = 1;
while ((cpuid = try_get_cpuid(kvm, max)) == NULL) {
max *= 2;
}
for (i = 0; i < cpuid->nent; ++i) {
if (cpuid->entries[i].function == function) {
switch (reg) {
case R_EAX:
ret = cpuid->entries[i].eax;
break;
case R_EBX:
ret = cpuid->entries[i].ebx;
break;
case R_ECX:
ret = cpuid->entries[i].ecx;
break;
case R_EDX:
ret = cpuid->entries[i].edx;
if (function == 1) {
/* kvm misreports the following features
*/
ret |= 1 << 12; /* MTRR */
ret |= 1 << 16; /* PAT */
ret |= 1 << 7; /* MCE */
ret |= 1 << 14; /* MCA */
}
/* On Intel, kvm returns cpuid according to
* the Intel spec, so add missing bits
* according to the AMD spec:
*/
if (function == 0x80000001) {
cpuid_1_edx = kvm_get_supported_cpuid(kvm, 1, R_EDX);
ret |= cpuid_1_edx & 0xdfeff7ff;
}
break;
}
}
}
free(cpuid);
return ret;
}
#else
uint32_t kvm_get_supported_cpuid(kvm_context_t kvm, uint32_t function, int reg)
{
return -1U;
}
#endif

1497
kvm/libkvm/libkvm.c Normal file

File diff suppressed because it is too large Load Diff

838
kvm/libkvm/libkvm.h Normal file
View File

@@ -0,0 +1,838 @@
/** \file libkvm.h
* libkvm API
*/
#ifndef LIBKVM_H
#define LIBKVM_H
#if defined(__s390__)
#include <asm/ptrace.h>
#endif
#include <stdint.h>
#ifndef __user
#define __user /* temporary, until installed via make headers_install */
#endif
#include <linux/kvm.h>
#include <signal.h>
struct kvm_context;
typedef struct kvm_context *kvm_context_t;
#if defined(__x86_64__) || defined(__i386__)
struct kvm_msr_list *kvm_get_msr_list(kvm_context_t);
int kvm_get_msrs(kvm_context_t, int vcpu, struct kvm_msr_entry *msrs, int n);
int kvm_set_msrs(kvm_context_t, int vcpu, struct kvm_msr_entry *msrs, int n);
#endif
/*!
* \brief KVM callbacks structure
*
* This structure holds pointers to various functions that KVM will call
* when it encounters something that cannot be virtualized, such as
* accessing hardware devices via MMIO or regular IO.
*/
struct kvm_callbacks {
/// For 8bit IO reads from the guest (Usually when executing 'inb')
int (*inb)(void *opaque, uint16_t addr, uint8_t *data);
/// For 16bit IO reads from the guest (Usually when executing 'inw')
int (*inw)(void *opaque, uint16_t addr, uint16_t *data);
/// For 32bit IO reads from the guest (Usually when executing 'inl')
int (*inl)(void *opaque, uint16_t addr, uint32_t *data);
/// For 8bit IO writes from the guest (Usually when executing 'outb')
int (*outb)(void *opaque, uint16_t addr, uint8_t data);
/// For 16bit IO writes from the guest (Usually when executing 'outw')
int (*outw)(void *opaque, uint16_t addr, uint16_t data);
/// For 32bit IO writes from the guest (Usually when executing 'outl')
int (*outl)(void *opaque, uint16_t addr, uint32_t data);
/// generic memory reads to unmapped memory (For MMIO devices)
int (*mmio_read)(void *opaque, uint64_t addr, uint8_t *data,
int len);
/// generic memory writes to unmapped memory (For MMIO devices)
int (*mmio_write)(void *opaque, uint64_t addr, uint8_t *data,
int len);
#ifdef KVM_CAP_SET_GUEST_DEBUG
int (*debug)(void *opaque, void *env,
struct kvm_debug_exit_arch *arch_info);
#endif
/*!
* \brief Called when the VCPU issues an 'hlt' instruction.
*
* Typically, you should yeild here to prevent 100% CPU utilization
* on the host CPU.
*/
int (*halt)(void *opaque, int vcpu);
int (*shutdown)(void *opaque, void *env);
int (*io_window)(void *opaque);
int (*try_push_interrupts)(void *opaque);
#ifdef KVM_CAP_USER_NMI
void (*push_nmi)(void *opaque);
#endif
void (*post_kvm_run)(void *opaque, void *env);
int (*pre_kvm_run)(void *opaque, void *env);
int (*tpr_access)(void *opaque, int vcpu, uint64_t rip, int is_write);
#if defined(__powerpc__)
int (*powerpc_dcr_read)(int vcpu, uint32_t dcrn, uint32_t *data);
int (*powerpc_dcr_write)(int vcpu, uint32_t dcrn, uint32_t data);
#endif
#if defined(__s390__)
int (*s390_handle_intercept)(kvm_context_t context, int vcpu,
struct kvm_run *run);
int (*s390_handle_reset)(kvm_context_t context, int vcpu,
struct kvm_run *run);
#endif
};
/*!
* \brief Create new KVM context
*
* This creates a new kvm_context. A KVM context is a small area of data that
* holds information about the KVM instance that gets created by this call.\n
* This should always be your first call to KVM.
*
* \param callbacks Pointer to a valid kvm_callbacks structure
* \param opaque Not used
* \return NULL on failure
*/
kvm_context_t kvm_init(struct kvm_callbacks *callbacks,
void *opaque);
/*!
* \brief Cleanup the KVM context
*
* Should always be called when closing down KVM.\n
* Exception: If kvm_init() fails, this function should not be called, as the
* context would be invalid
*
* \param kvm Pointer to the kvm_context that is to be freed
*/
void kvm_finalize(kvm_context_t kvm);
/*!
* \brief Disable the in-kernel IRQCHIP creation
*
* In-kernel irqchip is enabled by default. If userspace irqchip is to be used,
* this should be called prior to kvm_create().
*
* \param kvm Pointer to the kvm_context
*/
void kvm_disable_irqchip_creation(kvm_context_t kvm);
/*!
* \brief Disable the in-kernel PIT creation
*
* In-kernel pit is enabled by default. If userspace pit is to be used,
* this should be called prior to kvm_create().
*
* \param kvm Pointer to the kvm_context
*/
void kvm_disable_pit_creation(kvm_context_t kvm);
/*!
* \brief Create new virtual machine
*
* This creates a new virtual machine, maps physical RAM to it, and creates a
* virtual CPU for it.\n
* \n
* Memory gets mapped for addresses 0->0xA0000, 0xC0000->phys_mem_bytes
*
* \param kvm Pointer to the current kvm_context
* \param phys_mem_bytes The amount of physical ram you want the VM to have
* \param phys_mem This pointer will be set to point to the memory that
* kvm_create allocates for physical RAM
* \return 0 on success
*/
int kvm_create(kvm_context_t kvm,
unsigned long phys_mem_bytes,
void **phys_mem);
int kvm_create_vm(kvm_context_t kvm);
int kvm_check_extension(kvm_context_t kvm, int ext);
void kvm_create_irqchip(kvm_context_t kvm);
/*!
* \brief Create a new virtual cpu
*
* This creates a new virtual cpu (the first vcpu is created by kvm_create()).
* Should be called from a thread dedicated to the vcpu.
*
* \param kvm kvm context
* \param slot vcpu number (> 0)
* \return 0 on success, -errno on failure
*/
int kvm_create_vcpu(kvm_context_t kvm, int slot);
/*!
* \brief Start the VCPU
*
* This starts the VCPU and virtualization is started.\n
* \n
* This function will not return until any of these conditions are met:
* - An IO/MMIO handler does not return "0"
* - An exception that neither the guest OS, nor KVM can handle occurs
*
* \note This function will call the callbacks registered in kvm_init()
* to emulate those functions
* \note If you at any point want to interrupt the VCPU, kvm_run() will
* listen to the EINTR signal. This allows you to simulate external interrupts
* and asyncronous IO.
*
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should be started
* \return 0 on success, but you really shouldn't expect this function to
* return except for when an error has occured, or when you have sent it
* an EINTR signal.
*/
int kvm_run(kvm_context_t kvm, int vcpu, void *env);
/*!
* \brief Get interrupt flag from on last exit to userspace
*
* This gets the CPU interrupt flag as it was on the last exit to userspace.
*
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should get dumped
* \return interrupt flag value (0 or 1)
*/
int kvm_get_interrupt_flag(kvm_context_t kvm, int vcpu);
/*!
* \brief Get the value of the APIC_BASE msr as of last exit to userspace
*
* This gets the APIC_BASE msr as it was on the last exit to userspace.
*
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should get dumped
* \return APIC_BASE msr contents
*/
uint64_t kvm_get_apic_base(kvm_context_t kvm, int vcpu);
/*!
* \brief Check if a vcpu is ready for interrupt injection
*
* This checks if vcpu interrupts are not masked by mov ss or sti.
*
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should get dumped
* \return boolean indicating interrupt injection readiness
*/
int kvm_is_ready_for_interrupt_injection(kvm_context_t kvm, int vcpu);
/*!
* \brief Read VCPU registers
*
* This gets the GP registers from the VCPU and outputs them
* into a kvm_regs structure
*
* \note This function returns a \b copy of the VCPUs registers.\n
* If you wish to modify the VCPUs GP registers, you should call kvm_set_regs()
*
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should get dumped
* \param regs Pointer to a kvm_regs which will be populated with the VCPUs
* registers values
* \return 0 on success
*/
int kvm_get_regs(kvm_context_t kvm, int vcpu, struct kvm_regs *regs);
/*!
* \brief Write VCPU registers
*
* This sets the GP registers on the VCPU from a kvm_regs structure
*
* \note When this function returns, the regs pointer and the data it points to
* can be discarded
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should get dumped
* \param regs Pointer to a kvm_regs which will be populated with the VCPUs
* registers values
* \return 0 on success
*/
int kvm_set_regs(kvm_context_t kvm, int vcpu, struct kvm_regs *regs);
/*!
* \brief Read VCPU fpu registers
*
* This gets the FPU registers from the VCPU and outputs them
* into a kvm_fpu structure
*
* \note This function returns a \b copy of the VCPUs registers.\n
* If you wish to modify the VCPU FPU registers, you should call kvm_set_fpu()
*
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should get dumped
* \param fpu Pointer to a kvm_fpu which will be populated with the VCPUs
* fpu registers values
* \return 0 on success
*/
int kvm_get_fpu(kvm_context_t kvm, int vcpu, struct kvm_fpu *fpu);
/*!
* \brief Write VCPU fpu registers
*
* This sets the FPU registers on the VCPU from a kvm_fpu structure
*
* \note When this function returns, the fpu pointer and the data it points to
* can be discarded
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should get dumped
* \param fpu Pointer to a kvm_fpu which holds the new vcpu fpu state
* \return 0 on success
*/
int kvm_set_fpu(kvm_context_t kvm, int vcpu, struct kvm_fpu *fpu);
/*!
* \brief Read VCPU system registers
*
* This gets the non-GP registers from the VCPU and outputs them
* into a kvm_sregs structure
*
* \note This function returns a \b copy of the VCPUs registers.\n
* If you wish to modify the VCPUs non-GP registers, you should call
* kvm_set_sregs()
*
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should get dumped
* \param regs Pointer to a kvm_sregs which will be populated with the VCPUs
* registers values
* \return 0 on success
*/
int kvm_get_sregs(kvm_context_t kvm, int vcpu, struct kvm_sregs *regs);
/*!
* \brief Write VCPU system registers
*
* This sets the non-GP registers on the VCPU from a kvm_sregs structure
*
* \note When this function returns, the regs pointer and the data it points to
* can be discarded
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should get dumped
* \param regs Pointer to a kvm_sregs which will be populated with the VCPUs
* registers values
* \return 0 on success
*/
int kvm_set_sregs(kvm_context_t kvm, int vcpu, struct kvm_sregs *regs);
#ifdef KVM_CAP_MP_STATE
/*!
* * \brief Read VCPU MP state
*
*/
int kvm_get_mpstate(kvm_context_t kvm, int vcpu,
struct kvm_mp_state *mp_state);
/*!
* * \brief Write VCPU MP state
*
*/
int kvm_set_mpstate(kvm_context_t kvm, int vcpu,
struct kvm_mp_state *mp_state);
/*!
* * \brief Reset VCPU MP state
*
*/
static inline int kvm_reset_mpstate(kvm_context_t kvm, int vcpu)
{
struct kvm_mp_state mp_state = {.mp_state = KVM_MP_STATE_UNINITIALIZED};
return kvm_set_mpstate(kvm, vcpu, &mp_state);
}
#endif
/*!
* \brief Simulate an external vectored interrupt
*
* This allows you to simulate an external vectored interrupt.
*
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should get dumped
* \param irq Vector number
* \return 0 on success
*/
int kvm_inject_irq(kvm_context_t kvm, int vcpu, unsigned irq);
#ifdef KVM_CAP_SET_GUEST_DEBUG
int kvm_set_guest_debug(kvm_context_t, int vcpu, struct kvm_guest_debug *dbg);
#endif
#if defined(__i386__) || defined(__x86_64__)
/*!
* \brief Setting the number of shadow pages to be allocated to the vm
*
* \param kvm pointer to kvm_context
* \param nrshadow_pages number of pages to be allocated
*/
int kvm_set_shadow_pages(kvm_context_t kvm, unsigned int nrshadow_pages);
/*!
* \brief Getting the number of shadow pages that are allocated to the vm
*
* \param kvm pointer to kvm_context
* \param nrshadow_pages number of pages to be allocated
*/
int kvm_get_shadow_pages(kvm_context_t kvm , unsigned int *nrshadow_pages);
/*!
* \brief Set up cr8 for next time the vcpu is executed
*
* This is a fast setter for cr8, which will be applied when the
* vcpu next enters guest mode.
*
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should get dumped
* \param cr8 next cr8 value
*/
void kvm_set_cr8(kvm_context_t kvm, int vcpu, uint64_t cr8);
/*!
* \brief Get cr8 for sync tpr in qemu apic emulation
*
* This is a getter for cr8, which used to sync with the tpr in qemu
* apic emualtion.
*
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should get dumped
*/
__u64 kvm_get_cr8(kvm_context_t kvm, int vcpu);
#endif
/*!
* \brief Set a vcpu's signal mask for guest mode
*
* A vcpu can have different signals blocked in guest mode and user mode.
* This allows guest execution to be interrupted on a signal, without requiring
* that the signal be delivered to a signal handler (the signal can be
* dequeued using sigwait(2).
*
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should be initialized
* \param sigset signal mask for guest mode
* \return 0 on success, or -errno on error
*/
int kvm_set_signal_mask(kvm_context_t kvm, int vcpu, const sigset_t *sigset);
/*!
* \brief Dump all VCPU information
*
* This dumps \b all the information that KVM has about a virtual CPU, namely:
* - GP Registers
* - System registers (selectors, descriptors, etc)
* - VMCS Data
* - MSRS
* - Pending interrupts
*
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should get dumped
* \return 0 on success
*/
int kvm_dump_vcpu(kvm_context_t kvm, int vcpu);
/*!
* \brief Dump VCPU registers
*
* This dumps some of the information that KVM has about a virtual CPU, namely:
* - GP Registers
*
* A much more verbose version of this is available as kvm_dump_vcpu()
*
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should get dumped
* \return 0 on success
*/
void kvm_show_regs(kvm_context_t kvm, int vcpu);
void *kvm_create_phys_mem(kvm_context_t, unsigned long phys_start,
unsigned long len, int log, int writable);
void kvm_destroy_phys_mem(kvm_context_t, unsigned long phys_start,
unsigned long len);
void kvm_unregister_memory_area(kvm_context_t, uint64_t phys_start,
unsigned long len);
int kvm_is_containing_region(kvm_context_t kvm, unsigned long phys_start, unsigned long size);
int kvm_register_phys_mem(kvm_context_t kvm,
unsigned long phys_start, void *userspace_addr,
unsigned long len, int log);
int kvm_get_dirty_pages(kvm_context_t, unsigned long phys_addr, void *buf);
int kvm_get_dirty_pages_range(kvm_context_t kvm, unsigned long phys_addr,
unsigned long end_addr, void *buf, void*opaque,
int (*cb)(unsigned long start, unsigned long len,
void*bitmap, void *opaque));
int kvm_register_coalesced_mmio(kvm_context_t kvm,
uint64_t addr, uint32_t size);
int kvm_unregister_coalesced_mmio(kvm_context_t kvm,
uint64_t addr, uint32_t size);
/*!
* \brief Create a memory alias
*
* Aliases a portion of physical memory to another portion. If the guest
* accesses the alias region, it will behave exactly as if it accessed
* the target memory.
*/
int kvm_create_memory_alias(kvm_context_t,
uint64_t phys_start, uint64_t len,
uint64_t target_phys);
/*!
* \brief Destroy a memory alias
*
* Removes an alias created with kvm_create_memory_alias().
*/
int kvm_destroy_memory_alias(kvm_context_t, uint64_t phys_start);
/*!
* \brief Get a bitmap of guest ram pages which are allocated to the guest.
*
* \param kvm Pointer to the current kvm_context
* \param phys_addr Memory slot phys addr
* \param bitmap Long aligned address of a big enough bitmap (one bit per page)
*/
int kvm_get_mem_map(kvm_context_t kvm, unsigned long phys_addr, void *bitmap);
int kvm_get_mem_map_range(kvm_context_t kvm, unsigned long phys_addr,
unsigned long len, void *buf, void *opaque,
int (*cb)(unsigned long start,unsigned long len,
void* bitmap, void* opaque));
int kvm_set_irq_level(kvm_context_t kvm, int irq, int level, int *status);
int kvm_dirty_pages_log_enable_slot(kvm_context_t kvm,
uint64_t phys_start,
uint64_t len);
int kvm_dirty_pages_log_disable_slot(kvm_context_t kvm,
uint64_t phys_start,
uint64_t len);
/*!
* \brief Enable dirty-pages-logging for all memory regions
*
* \param kvm Pointer to the current kvm_context
*/
int kvm_dirty_pages_log_enable_all(kvm_context_t kvm);
/*!
* \brief Disable dirty-page-logging for some memory regions
*
* Disable dirty-pages-logging for those memory regions that were
* created with dirty-page-logging disabled.
*
* \param kvm Pointer to the current kvm_context
*/
int kvm_dirty_pages_log_reset(kvm_context_t kvm);
/*!
* \brief Query whether in kernel irqchip is used
*
* \param kvm Pointer to the current kvm_context
*/
int kvm_irqchip_in_kernel(kvm_context_t kvm);
int kvm_has_sync_mmu(kvm_context_t kvm);
#ifdef KVM_CAP_IRQCHIP
/*!
* \brief Dump in kernel IRQCHIP contents
*
* Dump one of the in kernel irq chip devices, including PIC (master/slave)
* and IOAPIC into a kvm_irqchip structure
*
* \param kvm Pointer to the current kvm_context
* \param chip The irq chip device to be dumped
*/
int kvm_get_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip);
/*!
* \brief Set in kernel IRQCHIP contents
*
* Write one of the in kernel irq chip devices, including PIC (master/slave)
* and IOAPIC
*
*
* \param kvm Pointer to the current kvm_context
* \param chip THe irq chip device to be written
*/
int kvm_set_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip);
#if defined(__i386__) || defined(__x86_64__)
/*!
* \brief Get in kernel local APIC for vcpu
*
* Save the local apic state including the timer of a virtual CPU
*
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should be accessed
* \param s Local apic state of the specific virtual CPU
*/
int kvm_get_lapic(kvm_context_t kvm, int vcpu, struct kvm_lapic_state *s);
/*!
* \brief Set in kernel local APIC for vcpu
*
* Restore the local apic state including the timer of a virtual CPU
*
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should be accessed
* \param s Local apic state of the specific virtual CPU
*/
int kvm_set_lapic(kvm_context_t kvm, int vcpu, struct kvm_lapic_state *s);
#endif
/*!
* \brief Simulate an NMI
*
* This allows you to simulate a non-maskable interrupt.
*
* \param kvm Pointer to the current kvm_context
* \param vcpu Which virtual CPU should get dumped
* \return 0 on success
*/
int kvm_inject_nmi(kvm_context_t kvm, int vcpu);
#endif
/*!
* \brief Query wheather in kernel pit is used
*
* \param kvm Pointer to the current kvm_context
*/
int kvm_pit_in_kernel(kvm_context_t kvm);
/*!
* \brief Initialize coalesced MMIO
*
* Check for coalesced MMIO capability and store in context
*
* \param kvm Pointer to the current kvm_context
*/
int kvm_init_coalesced_mmio(kvm_context_t kvm);
#ifdef KVM_CAP_PIT
#if defined(__i386__) || defined(__x86_64__)
/*!
* \brief Get in kernel PIT of the virtual domain
*
* Save the PIT state.
*
* \param kvm Pointer to the current kvm_context
* \param s PIT state of the virtual domain
*/
int kvm_get_pit(kvm_context_t kvm, struct kvm_pit_state *s);
/*!
* \brief Set in kernel PIT of the virtual domain
*
* Restore the PIT state.
* Timer would be retriggerred after restored.
*
* \param kvm Pointer to the current kvm_context
* \param s PIT state of the virtual domain
*/
int kvm_set_pit(kvm_context_t kvm, struct kvm_pit_state *s);
#endif
int kvm_reinject_control(kvm_context_t kvm, int pit_reinject);
#endif
#ifdef KVM_CAP_VAPIC
/*!
* \brief Enable kernel tpr access reporting
*
* When tpr access reporting is enabled, the kernel will call the
* ->tpr_access() callback every time the guest vcpu accesses the tpr.
*
* \param kvm Pointer to the current kvm_context
* \param vcpu vcpu to enable tpr access reporting on
*/
int kvm_enable_tpr_access_reporting(kvm_context_t kvm, int vcpu);
/*!
* \brief Disable kernel tpr access reporting
*
* Undoes the effect of kvm_enable_tpr_access_reporting().
*
* \param kvm Pointer to the current kvm_context
* \param vcpu vcpu to disable tpr access reporting on
*/
int kvm_disable_tpr_access_reporting(kvm_context_t kvm, int vcpu);
int kvm_enable_vapic(kvm_context_t kvm, int vcpu, uint64_t vapic);
#endif
#if defined(__s390__)
int kvm_s390_initial_reset(kvm_context_t kvm, int slot);
int kvm_s390_interrupt(kvm_context_t kvm, int slot,
struct kvm_s390_interrupt *kvmint);
int kvm_s390_set_initial_psw(kvm_context_t kvm, int slot, psw_t psw);
int kvm_s390_store_status(kvm_context_t kvm, int slot, unsigned long addr);
#endif
#ifdef KVM_CAP_DEVICE_ASSIGNMENT
/*!
* \brief Notifies host kernel about a PCI device to be assigned to a guest
*
* Used for PCI device assignment, this function notifies the host
* kernel about the assigning of the physical PCI device to a guest.
*
* \param kvm Pointer to the current kvm_context
* \param assigned_dev Parameters, like bus, devfn number, etc
*/
int kvm_assign_pci_device(kvm_context_t kvm,
struct kvm_assigned_pci_dev *assigned_dev);
/*!
* \brief Assign IRQ for an assigned device
*
* Used for PCI device assignment, this function assigns IRQ numbers for
* an physical device and guest IRQ handling.
*
* \param kvm Pointer to the current kvm_context
* \param assigned_irq Parameters, like dev id, host irq, guest irq, etc
*/
int kvm_assign_irq(kvm_context_t kvm,
struct kvm_assigned_irq *assigned_irq);
#ifdef KVM_CAP_ASSIGN_DEV_IRQ
/*!
* \brief Deassign IRQ for an assigned device
*
* Used for PCI device assignment, this function deassigns IRQ numbers
* for an assigned device.
*
* \param kvm Pointer to the current kvm_context
* \param assigned_irq Parameters, like dev id, host irq, guest irq, etc
*/
int kvm_deassign_irq(kvm_context_t kvm,
struct kvm_assigned_irq *assigned_irq);
#endif
#endif
/*!
* \brief Determines whether destroying memory regions is allowed
*
* KVM before 2.6.29 had a bug when destroying memory regions.
*
* \param kvm Pointer to the current kvm_context
*/
int kvm_destroy_memory_region_works(kvm_context_t kvm);
#ifdef KVM_CAP_DEVICE_DEASSIGNMENT
/*!
* \brief Notifies host kernel about a PCI device to be deassigned from a guest
*
* Used for hot remove PCI device, this function notifies the host
* kernel about the deassigning of the physical PCI device from a guest.
*
* \param kvm Pointer to the current kvm_context
* \param assigned_dev Parameters, like bus, devfn number, etc
*/
int kvm_deassign_pci_device(kvm_context_t kvm,
struct kvm_assigned_pci_dev *assigned_dev);
#endif
/*!
* \brief Checks whether the generic irq routing capability is present
*
* Checks whether kvm can reroute interrupts among the various interrupt
* controllers.
*
* \param kvm Pointer to the current kvm_context
*/
int kvm_has_gsi_routing(kvm_context_t kvm);
/*!
* \brief Determines the number of gsis that can be routed
*
* Returns the number of distinct gsis that can be routed by kvm. This is
* also the number of distinct routes (if a gsi has two routes, than another
* gsi cannot be used...)
*
* \param kvm Pointer to the current kvm_context
*/
int kvm_get_gsi_count(kvm_context_t kvm);
/*!
* \brief Clears the temporary irq routing table
*
* Clears the temporary irq routing table. Nothing is committed to the
* running VM.
*
* \param kvm Pointer to the current kvm_context
*/
int kvm_clear_gsi_routes(kvm_context_t kvm);
/*!
* \brief Adds an irq route to the temporary irq routing table
*
* Adds an irq route to the temporary irq routing table. Nothing is
* committed to the running VM.
*
* \param kvm Pointer to the current kvm_context
*/
int kvm_add_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin);
/*!
* \brief Removes an irq route from the temporary irq routing table
*
* Adds an irq route to the temporary irq routing table. Nothing is
* committed to the running VM.
*
* \param kvm Pointer to the current kvm_context
*/
int kvm_del_irq_route(kvm_context_t kvm, int gsi, int irqchip, int pin);
struct kvm_irq_routing_entry;
/*!
* \brief Adds a routing entry to the temporary irq routing table
*
* Adds a filled routing entry to the temporary irq routing table. Nothing is
* committed to the running VM.
*
* \param kvm Pointer to the current kvm_context
*/
int kvm_add_routing_entry(kvm_context_t kvm,
struct kvm_irq_routing_entry* entry);
/*!
* \brief Removes a routing from the temporary irq routing table
*
* Remove a routing to the temporary irq routing table. Nothing is
* committed to the running VM.
*
* \param kvm Pointer to the current kvm_context
*/
int kvm_del_routing_entry(kvm_context_t kvm,
struct kvm_irq_routing_entry* entry);
/*!
* \brief Commit the temporary irq routing table
*
* Commit the temporary irq routing table to the running VM.
*
* \param kvm Pointer to the current kvm_context
*/
int kvm_commit_irq_routes(kvm_context_t kvm);
/*!
* \brief Get unused GSI number for irq routing table
*
* Get unused GSI number for irq routing table
*
* \param kvm Pointer to the current kvm_context
*/
int kvm_get_irq_route_gsi(kvm_context_t kvm);
#ifdef KVM_CAP_DEVICE_MSIX
int kvm_assign_set_msix_nr(kvm_context_t kvm,
struct kvm_assigned_msix_nr *msix_nr);
int kvm_assign_set_msix_entry(kvm_context_t kvm,
struct kvm_assigned_msix_entry *entry);
#endif
uint32_t kvm_get_supported_cpuid(kvm_context_t kvm, uint32_t function, int reg);
#endif

Some files were not shown because too many files have changed in this diff Show More