Compare commits
	
		
			46 Commits
		
	
	
		
			v9.1.0
			...
			v0.15.1-qe
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 36f5bc4fdb | ||
|  | 82b2b32a32 | ||
|  | 4a81ab81e4 | ||
|  | 68e3508eaf | ||
|  | fb524042db | ||
|  | 336398391a | ||
|  | 672aefeb5e | ||
|  | 6a10ccca80 | ||
|  | 7095e71576 | ||
|  | 91b31d6158 | ||
|  | b89f4a7d2a | ||
|  | fbdd7c8bd5 | ||
|  | e19a4e89ae | ||
|  | ff5acedd8f | ||
|  | 2af86a2ff7 | ||
|  | e62ad8314a | ||
|  | 76e4e1d237 | ||
|  | 4fbe5233fd | ||
|  | 4bea41dbaa | ||
|  | e2f775205a | ||
|  | 51dd7a94c7 | ||
|  | 9096de69ff | ||
|  | 09afeef1ab | ||
|  | 01825a8ddf | ||
|  | ae2dd33693 | ||
|  | a80f53aee3 | ||
|  | 88ca9f047b | ||
|  | 898517b0bc | ||
|  | 9dc9f2b820 | ||
|  | ef942b795a | ||
|  | 868aa386b8 | ||
|  | 7e10be8c74 | ||
|  | 9843621e3b | ||
|  | ab640dbfc0 | ||
|  | eaa8b2778c | ||
|  | 7ec7f28019 | ||
|  | 31b1308046 | ||
|  | 4ec648dd6e | ||
|  | e961d129e1 | ||
|  | 8959459386 | ||
|  | e2b40e003a | ||
|  | 1a39b0fcff | ||
|  | 4a97e18b87 | ||
|  | f1ee0a0ebd | ||
|  | 3583bc031e | ||
|  | 2798b5e174 | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -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
									
									
								
							
							
						
						
									
										2
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							| @@ -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/ | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								Makefile
									
									
									
									
									
								
							| @@ -192,8 +192,10 @@ test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types | |||||||
| test-qmp-commands: test-qmp-commands.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o | test-qmp-commands: test-qmp-commands.o qfloat.o qint.o qdict.o qstring.o qlist.o qbool.o $(qapi-obj-y) error.o osdep.o qemu-malloc.o $(oslib-obj-y) qjson.o json-streamer.o json-lexer.o json-parser.o qerror.o qemu-error.o qemu-tool.o $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o | ||||||
|  |  | ||||||
| QGALIB=qga/guest-agent-command-state.o qga/guest-agent-commands.o | QGALIB=qga/guest-agent-command-state.o qga/guest-agent-commands.o | ||||||
|  | QGALIB_GEN=$(addprefix $(qapi-dir)/, qga-qapi-types.c qga-qapi-types.h qga-qapi-visit.c qga-qmp-marshal.c) | ||||||
|  |  | ||||||
| qemu-ga.o: $(addprefix $(qapi-dir)/, qga-qapi-types.c qga-qapi-types.h qga-qapi-visit.c qga-qmp-marshal.c) $(qapi-obj-y) | $(QGALIB_GEN): $(GENERATED_HEADERS) | ||||||
|  | $(QGALIB) qemu-ga.o: $(QGALIB_GEN) $(qapi-obj-y) | ||||||
| qemu-ga$(EXESUF): qemu-ga.o $(QGALIB) qemu-tool.o qemu-error.o error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) $(qapi-obj-y) qemu-timer-common.o qemu-sockets.o module.o qapi/qmp-dispatch.o qapi/qmp-registry.o $(qapi-dir)/qga-qapi-visit.o $(qapi-dir)/qga-qapi-types.o $(qapi-dir)/qga-qmp-marshal.o | qemu-ga$(EXESUF): qemu-ga.o $(QGALIB) qemu-tool.o qemu-error.o error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) $(qapi-obj-y) qemu-timer-common.o qemu-sockets.o module.o qapi/qmp-dispatch.o qapi/qmp-registry.o $(qapi-dir)/qga-qapi-visit.o $(qapi-dir)/qga-qapi-types.o $(qapi-dir)/qga-qmp-marshal.o | ||||||
|  |  | ||||||
| QEMULIBS=libhw32 libhw64 libuser libdis libdis-user | QEMULIBS=libhw32 libhw64 libuser libdis libdis-user | ||||||
| @@ -244,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 | ||||||
| @@ -270,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" | ||||||
| @@ -391,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 \ | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								arm.ld
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								arm.ld
									
									
									
									
									
								
							| @@ -71,23 +71,23 @@ SECTIONS | |||||||
|   .data1   : { *(.data1) } |   .data1   : { *(.data1) } | ||||||
|   .preinit_array     : |   .preinit_array     : | ||||||
|   { |   { | ||||||
|     PROVIDE_HIDDEN (__preinit_array_start = .); |     PROVIDE (__preinit_array_start = .); | ||||||
|     KEEP (*(.preinit_array)) |     KEEP (*(.preinit_array)) | ||||||
|     PROVIDE_HIDDEN (__preinit_array_end = .); |     PROVIDE (__preinit_array_end = .); | ||||||
|   } |   } | ||||||
|   .init_array     : |   .init_array     : | ||||||
|   { |   { | ||||||
|      PROVIDE_HIDDEN (__init_array_start = .); |      PROVIDE (__init_array_start = .); | ||||||
|      KEEP (*(SORT(.init_array.*))) |      KEEP (*(SORT(.init_array.*))) | ||||||
|      KEEP (*(.init_array)) |      KEEP (*(.init_array)) | ||||||
|      PROVIDE_HIDDEN (__init_array_end = .); |      PROVIDE (__init_array_end = .); | ||||||
|   } |   } | ||||||
|   .fini_array     : |   .fini_array     : | ||||||
|   { |   { | ||||||
|     PROVIDE_HIDDEN (__fini_array_start = .); |     PROVIDE (__fini_array_start = .); | ||||||
|     KEEP (*(.fini_array)) |     KEEP (*(.fini_array)) | ||||||
|     KEEP (*(SORT(.fini_array.*))) |     KEEP (*(SORT(.fini_array.*))) | ||||||
|     PROVIDE_HIDDEN (__fini_array_end = .); |     PROVIDE (__fini_array_end = .); | ||||||
|   } |   } | ||||||
|   .ctors         : |   .ctors         : | ||||||
|   { |   { | ||||||
|   | |||||||
							
								
								
									
										61
									
								
								balloon.c
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								balloon.c
									
									
									
									
									
								
							| @@ -1,7 +1,9 @@ | |||||||
| /* | /* | ||||||
|  * QEMU System Emulator |  * Generic Balloon handlers and management | ||||||
|  * |  * | ||||||
|  * Copyright (c) 2003-2008 Fabrice Bellard |  * Copyright (c) 2003-2008 Fabrice Bellard | ||||||
|  |  * Copyright (C) 2011 Red Hat, Inc. | ||||||
|  |  * Copyright (C) 2011 Amit Shah <amit.shah@redhat.com> | ||||||
|  * |  * | ||||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy |  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||||
|  * of this software and associated documentation files (the "Software"), to deal |  * of this software and associated documentation files (the "Software"), to deal | ||||||
| @@ -30,44 +32,53 @@ | |||||||
| #include "balloon.h" | #include "balloon.h" | ||||||
| #include "trace.h" | #include "trace.h" | ||||||
|  |  | ||||||
|  | static QEMUBalloonEvent *balloon_event_fn; | ||||||
|  | static QEMUBalloonStatus *balloon_stat_fn; | ||||||
|  | static void *balloon_opaque; | ||||||
|  |  | ||||||
| static QEMUBalloonEvent *qemu_balloon_event; | int qemu_add_balloon_handler(QEMUBalloonEvent *event_func, | ||||||
| void *qemu_balloon_event_opaque; |                              QEMUBalloonStatus *stat_func, void *opaque) | ||||||
|  |  | ||||||
| void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque) |  | ||||||
| { | { | ||||||
|     qemu_balloon_event = func; |     if (balloon_event_fn || balloon_stat_fn || balloon_opaque) { | ||||||
|     qemu_balloon_event_opaque = opaque; |         /* We're already registered one balloon handler.  How many can | ||||||
|  |          * a guest really have? | ||||||
|  |          */ | ||||||
|  |         error_report("Another balloon device already registered"); | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |     balloon_event_fn = event_func; | ||||||
|  |     balloon_stat_fn = stat_func; | ||||||
|  |     balloon_opaque = opaque; | ||||||
|  |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque) | static int qemu_balloon(ram_addr_t target) | ||||||
| { | { | ||||||
|     if (qemu_balloon_event) { |     if (!balloon_event_fn) { | ||||||
|         trace_balloon_event(qemu_balloon_event_opaque, target); |  | ||||||
|         qemu_balloon_event(qemu_balloon_event_opaque, target, cb, opaque); |  | ||||||
|         return 1; |  | ||||||
|     } else { |  | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|  |     trace_balloon_event(balloon_opaque, target); | ||||||
|  |     balloon_event_fn(balloon_opaque, target); | ||||||
|  |     return 1; | ||||||
| } | } | ||||||
|  |  | ||||||
| int qemu_balloon_status(MonitorCompletion cb, void *opaque) | static int qemu_balloon_status(MonitorCompletion cb, void *opaque) | ||||||
| { | { | ||||||
|     if (qemu_balloon_event) { |     if (!balloon_stat_fn) { | ||||||
|         qemu_balloon_event(qemu_balloon_event_opaque, 0, cb, opaque); |  | ||||||
|         return 1; |  | ||||||
|     } else { |  | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|  |     balloon_stat_fn(balloon_opaque, cb, opaque); | ||||||
|  |     return 1; | ||||||
| } | } | ||||||
|  |  | ||||||
| static void print_balloon_stat(const char *key, QObject *obj, void *opaque) | static void print_balloon_stat(const char *key, QObject *obj, void *opaque) | ||||||
| { | { | ||||||
|     Monitor *mon = opaque; |     Monitor *mon = opaque; | ||||||
|  |  | ||||||
|     if (strcmp(key, "actual")) |     if (strcmp(key, "actual")) { | ||||||
|         monitor_printf(mon, ",%s=%" PRId64, key, |         monitor_printf(mon, ",%s=%" PRId64, key, | ||||||
|                        qint_get_int(qobject_to_qint(obj))); |                        qint_get_int(qobject_to_qint(obj))); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void monitor_print_balloon(Monitor *mon, const QObject *data) | void monitor_print_balloon(Monitor *mon, const QObject *data) | ||||||
| @@ -75,9 +86,9 @@ void monitor_print_balloon(Monitor *mon, const QObject *data) | |||||||
|     QDict *qdict; |     QDict *qdict; | ||||||
|  |  | ||||||
|     qdict = qobject_to_qdict(data); |     qdict = qobject_to_qdict(data); | ||||||
|     if (!qdict_haskey(qdict, "actual")) |     if (!qdict_haskey(qdict, "actual")) { | ||||||
|         return; |         return; | ||||||
|  |     } | ||||||
|     monitor_printf(mon, "balloon: actual=%" PRId64, |     monitor_printf(mon, "balloon: actual=%" PRId64, | ||||||
|                    qdict_get_int(qdict, "actual") >> 20); |                    qdict_get_int(qdict, "actual") >> 20); | ||||||
|     qdict_iter(qdict, print_balloon_stat, mon); |     qdict_iter(qdict, print_balloon_stat, mon); | ||||||
| @@ -129,6 +140,7 @@ int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque) | |||||||
| int do_balloon(Monitor *mon, const QDict *params, | int do_balloon(Monitor *mon, const QDict *params, | ||||||
| 	       MonitorCompletion cb, void *opaque) | 	       MonitorCompletion cb, void *opaque) | ||||||
| { | { | ||||||
|  |     int64_t target; | ||||||
|     int ret; |     int ret; | ||||||
|  |  | ||||||
|     if (kvm_enabled() && !kvm_has_sync_mmu()) { |     if (kvm_enabled() && !kvm_has_sync_mmu()) { | ||||||
| @@ -136,7 +148,12 @@ int do_balloon(Monitor *mon, const QDict *params, | |||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     ret = qemu_balloon(qdict_get_int(params, "value"), cb, opaque); |     target = qdict_get_int(params, "value"); | ||||||
|  |     if (target <= 0) { | ||||||
|  |         qerror_report(QERR_INVALID_PARAMETER_VALUE, "target", "a size"); | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  |     ret = qemu_balloon(target); | ||||||
|     if (ret == 0) { |     if (ret == 0) { | ||||||
|         qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon"); |         qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon"); | ||||||
|         return -1; |         return -1; | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								balloon.h
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								balloon.h
									
									
									
									
									
								
							| @@ -16,14 +16,12 @@ | |||||||
|  |  | ||||||
| #include "monitor.h" | #include "monitor.h" | ||||||
|  |  | ||||||
| typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target, | typedef void (QEMUBalloonEvent)(void *opaque, ram_addr_t target); | ||||||
|                                 MonitorCompletion cb, void *cb_data); | typedef void (QEMUBalloonStatus)(void *opaque, MonitorCompletion cb, | ||||||
|  |                                  void *cb_data); | ||||||
|  |  | ||||||
| void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque); | int qemu_add_balloon_handler(QEMUBalloonEvent *event_func, | ||||||
|  | 			     QEMUBalloonStatus *stat_func, void *opaque); | ||||||
| int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque); |  | ||||||
|  |  | ||||||
| int qemu_balloon_status(MonitorCompletion cb, void *opaque); |  | ||||||
|  |  | ||||||
| void monitor_print_balloon(Monitor *mon, const QObject *data); | void monitor_print_balloon(Monitor *mon, const QObject *data); | ||||||
| int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque); | int do_info_balloon(Monitor *mon, MonitorCompletion cb, void *opaque); | ||||||
|   | |||||||
| @@ -317,7 +317,8 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) | |||||||
| { | { | ||||||
|     BDRVQcowState *s = bs->opaque; |     BDRVQcowState *s = bs->opaque; | ||||||
|     QCowSnapshot *sn; |     QCowSnapshot *sn; | ||||||
|     int i, snapshot_index, l1_size2; |     int i, snapshot_index; | ||||||
|  |     int cur_l1_bytes, sn_l1_bytes; | ||||||
|  |  | ||||||
|     snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id); |     snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id); | ||||||
|     if (snapshot_index < 0) |     if (snapshot_index < 0) | ||||||
| @@ -330,14 +331,19 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) | |||||||
|     if (qcow2_grow_l1_table(bs, sn->l1_size, true) < 0) |     if (qcow2_grow_l1_table(bs, sn->l1_size, true) < 0) | ||||||
|         goto fail; |         goto fail; | ||||||
|  |  | ||||||
|     s->l1_size = sn->l1_size; |     cur_l1_bytes = s->l1_size * sizeof(uint64_t); | ||||||
|     l1_size2 = s->l1_size * sizeof(uint64_t); |     sn_l1_bytes = sn->l1_size * sizeof(uint64_t); | ||||||
|  |  | ||||||
|  |     if (cur_l1_bytes > sn_l1_bytes) { | ||||||
|  |         memset(s->l1_table + sn->l1_size, 0, cur_l1_bytes - sn_l1_bytes); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /* copy the snapshot l1 table to the current l1 table */ |     /* copy the snapshot l1 table to the current l1 table */ | ||||||
|     if (bdrv_pread(bs->file, sn->l1_table_offset, |     if (bdrv_pread(bs->file, sn->l1_table_offset, | ||||||
|                    s->l1_table, l1_size2) != l1_size2) |                    s->l1_table, sn_l1_bytes) < 0) | ||||||
|         goto fail; |         goto fail; | ||||||
|     if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, |     if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, | ||||||
|                     s->l1_table, l1_size2) < 0) |                     s->l1_table, cur_l1_bytes) < 0) | ||||||
|         goto fail; |         goto fail; | ||||||
|     for(i = 0;i < s->l1_size; i++) { |     for(i = 0;i < s->l1_size; i++) { | ||||||
|         be64_to_cpus(&s->l1_table[i]); |         be64_to_cpus(&s->l1_table[i]); | ||||||
|   | |||||||
| @@ -230,21 +230,21 @@ static void qed_read_l2_table_cb(void *opaque, int ret) | |||||||
|     QEDRequest *request = read_l2_table_cb->request; |     QEDRequest *request = read_l2_table_cb->request; | ||||||
|     BDRVQEDState *s = read_l2_table_cb->s; |     BDRVQEDState *s = read_l2_table_cb->s; | ||||||
|     CachedL2Table *l2_table = request->l2_table; |     CachedL2Table *l2_table = request->l2_table; | ||||||
|  |     uint64_t l2_offset = read_l2_table_cb->l2_offset; | ||||||
|  |  | ||||||
|     if (ret) { |     if (ret) { | ||||||
|         /* can't trust loaded L2 table anymore */ |         /* can't trust loaded L2 table anymore */ | ||||||
|         qed_unref_l2_cache_entry(l2_table); |         qed_unref_l2_cache_entry(l2_table); | ||||||
|         request->l2_table = NULL; |         request->l2_table = NULL; | ||||||
|     } else { |     } else { | ||||||
|         l2_table->offset = read_l2_table_cb->l2_offset; |         l2_table->offset = l2_offset; | ||||||
|  |  | ||||||
|         qed_commit_l2_cache_entry(&s->l2_cache, l2_table); |         qed_commit_l2_cache_entry(&s->l2_cache, l2_table); | ||||||
|  |  | ||||||
|         /* This is guaranteed to succeed because we just committed the entry |         /* This is guaranteed to succeed because we just committed the entry | ||||||
|          * to the cache. |          * to the cache. | ||||||
|          */ |          */ | ||||||
|         request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, |         request->l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset); | ||||||
|                                                     l2_table->offset); |  | ||||||
|         assert(request->l2_table != NULL); |         assert(request->l2_table != NULL); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -915,14 +915,14 @@ static void qed_commit_l2_update(void *opaque, int ret) | |||||||
|     QEDAIOCB *acb = opaque; |     QEDAIOCB *acb = opaque; | ||||||
|     BDRVQEDState *s = acb_to_s(acb); |     BDRVQEDState *s = acb_to_s(acb); | ||||||
|     CachedL2Table *l2_table = acb->request.l2_table; |     CachedL2Table *l2_table = acb->request.l2_table; | ||||||
|  |     uint64_t l2_offset = l2_table->offset; | ||||||
|  |  | ||||||
|     qed_commit_l2_cache_entry(&s->l2_cache, l2_table); |     qed_commit_l2_cache_entry(&s->l2_cache, l2_table); | ||||||
|  |  | ||||||
|     /* This is guaranteed to succeed because we just committed the entry to the |     /* This is guaranteed to succeed because we just committed the entry to the | ||||||
|      * cache. |      * cache. | ||||||
|      */ |      */ | ||||||
|     acb->request.l2_table = qed_find_l2_cache_entry(&s->l2_cache, |     acb->request.l2_table = qed_find_l2_cache_entry(&s->l2_cache, l2_offset); | ||||||
|                                                     l2_table->offset); |  | ||||||
|     assert(acb->request.l2_table != NULL); |     assert(acb->request.l2_table != NULL); | ||||||
|  |  | ||||||
|     qed_aio_next_io(opaque, ret); |     qed_aio_next_io(opaque, ret); | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								blockdev.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								blockdev.c
									
									
									
									
									
								
							| @@ -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) { | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -856,9 +856,6 @@ int main(int argc, char **argv) | |||||||
|             usage(); |             usage(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     if (optind >= argc) |  | ||||||
|         usage(); |  | ||||||
|     filename = argv[optind]; |  | ||||||
|  |  | ||||||
|     /* init debug */ |     /* init debug */ | ||||||
|     cpu_set_log_filename(log_file); |     cpu_set_log_filename(log_file); | ||||||
| @@ -877,6 +874,11 @@ int main(int argc, char **argv) | |||||||
|         cpu_set_log(mask); |         cpu_set_log(mask); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (optind >= argc) { | ||||||
|  |         usage(); | ||||||
|  |     } | ||||||
|  |     filename = argv[optind]; | ||||||
|  |  | ||||||
|     /* Zero out regs */ |     /* Zero out regs */ | ||||||
|     memset(regs, 0, sizeof(struct target_pt_regs)); |     memset(regs, 0, sizeof(struct target_pt_regs)); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -33,7 +33,8 @@ START_TEST(escaped_string) | |||||||
|         { "\"\\n\"", "\n" }, |         { "\"\\n\"", "\n" }, | ||||||
|         { "\"\\r\"", "\r" }, |         { "\"\\r\"", "\r" }, | ||||||
|         { "\"\\t\"", "\t" }, |         { "\"\\t\"", "\t" }, | ||||||
|         { "\"\\/\"", "\\/" }, |         { "\"/\"", "/" }, | ||||||
|  |         { "\"\\/\"", "/", .skip = 1 }, | ||||||
|         { "\"\\\\\"", "\\" }, |         { "\"\\\\\"", "\\" }, | ||||||
|         { "\"\\\"\"", "\"" }, |         { "\"\\\"\"", "\"" }, | ||||||
|         { "\"hello world \\\"embedded string\\\"\"", |         { "\"hello world \\\"embedded string\\\"\"", | ||||||
|   | |||||||
							
								
								
									
										150
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										150
									
								
								configure
									
									
									
									
										vendored
									
									
								
							| @@ -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="" | ||||||
| @@ -179,6 +192,7 @@ smartcard="" | |||||||
| smartcard_nss="" | smartcard_nss="" | ||||||
| usb_redir="" | usb_redir="" | ||||||
| opengl="" | opengl="" | ||||||
|  | guest_agent="yes" | ||||||
|  |  | ||||||
| # parse CC options first | # parse CC options first | ||||||
| for opt do | for opt do | ||||||
| @@ -408,6 +422,7 @@ SunOS) | |||||||
|   make="${MAKE-gmake}" |   make="${MAKE-gmake}" | ||||||
|   install="${INSTALL-ginstall}" |   install="${INSTALL-ginstall}" | ||||||
|   ld="gld" |   ld="gld" | ||||||
|  |   smbd="${SMBD-/usr/sfw/sbin/smbd}" | ||||||
|   needs_libsunmath="no" |   needs_libsunmath="no" | ||||||
|   solarisrev=`uname -r | cut -f2 -d.` |   solarisrev=`uname -r | cut -f2 -d.` | ||||||
|   # have to select again, because `uname -m` returns i86pc |   # have to select again, because `uname -m` returns i86pc | ||||||
| @@ -463,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 | ||||||
|  |  | ||||||
| @@ -476,6 +498,7 @@ fi | |||||||
| : ${make=${MAKE-make}} | : ${make=${MAKE-make}} | ||||||
| : ${install=${INSTALL-install}} | : ${install=${INSTALL-install}} | ||||||
| : ${python=${PYTHON-python}} | : ${python=${PYTHON-python}} | ||||||
|  | : ${smbd=${SMBD-/usr/sbin/smbd}} | ||||||
|  |  | ||||||
| if test "$mingw32" = "yes" ; then | if test "$mingw32" = "yes" ; then | ||||||
|   EXESUF=".exe" |   EXESUF=".exe" | ||||||
| @@ -519,6 +542,8 @@ for opt do | |||||||
|   ;; |   ;; | ||||||
|   --python=*) python="$optarg" |   --python=*) python="$optarg" | ||||||
|   ;; |   ;; | ||||||
|  |   --smbd=*) smbd="$optarg" | ||||||
|  |   ;; | ||||||
|   --extra-cflags=*) |   --extra-cflags=*) | ||||||
|   ;; |   ;; | ||||||
|   --extra-ldflags=*) |   --extra-ldflags=*) | ||||||
| @@ -636,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" | ||||||
| @@ -725,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" | ||||||
| @@ -751,6 +786,10 @@ for opt do | |||||||
|   ;; |   ;; | ||||||
|   --enable-usb-redir) usb_redir="yes" |   --enable-usb-redir) usb_redir="yes" | ||||||
|   ;; |   ;; | ||||||
|  |   --enable-guest-agent) guest_agent="yes" | ||||||
|  |   ;; | ||||||
|  |   --disable-guest-agent) guest_agent="no" | ||||||
|  |   ;; | ||||||
|   *) echo "ERROR: unknown option $opt"; show_help="yes" |   *) echo "ERROR: unknown option $opt"; show_help="yes" | ||||||
|   ;; |   ;; | ||||||
|   esac |   esac | ||||||
| @@ -840,7 +879,6 @@ if [ "$softmmu" = "yes" ] ; then | |||||||
|     default_target_list="\ |     default_target_list="\ | ||||||
| i386-softmmu \ | i386-softmmu \ | ||||||
| x86_64-softmmu \ | x86_64-softmmu \ | ||||||
| alpha-softmmu \ |  | ||||||
| arm-softmmu \ | arm-softmmu \ | ||||||
| cris-softmmu \ | cris-softmmu \ | ||||||
| lm32-softmmu \ | lm32-softmmu \ | ||||||
| @@ -928,6 +966,7 @@ echo "  --extra-ldflags=LDFLAGS  append extra linker flags LDFLAGS" | |||||||
| echo "  --make=MAKE              use specified make [$make]" | echo "  --make=MAKE              use specified make [$make]" | ||||||
| echo "  --install=INSTALL        use specified install [$install]" | echo "  --install=INSTALL        use specified install [$install]" | ||||||
| echo "  --python=PYTHON          use specified python [$python]" | echo "  --python=PYTHON          use specified python [$python]" | ||||||
|  | echo "  --smbd=SMBD              use specified smbd [$smbd]" | ||||||
| echo "  --static                 enable static build [$static]" | echo "  --static                 enable static build [$static]" | ||||||
| echo "  --mandir=PATH            install man pages in PATH" | echo "  --mandir=PATH            install man pages in PATH" | ||||||
| echo "  --datadir=PATH           install firmware in PATH" | echo "  --datadir=PATH           install firmware in PATH" | ||||||
| @@ -980,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" | ||||||
| @@ -1012,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" | ||||||
| @@ -1029,6 +1073,8 @@ echo "  --disable-smartcard-nss  disable smartcard nss support" | |||||||
| echo "  --enable-smartcard-nss   enable smartcard nss support" | echo "  --enable-smartcard-nss   enable smartcard nss support" | ||||||
| echo "  --disable-usb-redir      disable usb network redirection support" | echo "  --disable-usb-redir      disable usb network redirection support" | ||||||
| echo "  --enable-usb-redir       enable usb network redirection support" | echo "  --enable-usb-redir       enable usb network redirection support" | ||||||
|  | echo "  --disable-guest-agent    disable building of the QEMU Guest Agent" | ||||||
|  | echo "  --enable-guest-agent     enable building of the QEMU Guest Agent" | ||||||
| echo "" | echo "" | ||||||
| echo "NOTE: The object files are built at the place where configure is launched" | echo "NOTE: The object files are built at the place where configure is launched" | ||||||
| exit 1 | exit 1 | ||||||
| @@ -1088,11 +1134,13 @@ if test "$solaris" = "yes" ; then | |||||||
|   fi |   fi | ||||||
| fi | fi | ||||||
|  |  | ||||||
| if has $python; then | if test "$guest_agent" != "no" ; then | ||||||
|  |   if has $python; then | ||||||
|     : |     : | ||||||
| else |   else | ||||||
|     echo "Python not found. Use --python=/path/to/python" |     echo "Python not found. Use --python=/path/to/python" | ||||||
|     exit 1 |     exit 1 | ||||||
|  |   fi | ||||||
| fi | fi | ||||||
|  |  | ||||||
| if test -z "$target_list" ; then | if test -z "$target_list" ; then | ||||||
| @@ -1505,11 +1553,17 @@ int main(void) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| EOF | EOF | ||||||
|  |   if $pkg_config libpng --modversion >/dev/null 2>&1; then | ||||||
|  |     vnc_png_cflags=`$pkg_config libpng --cflags 2> /dev/null` | ||||||
|  |     vnc_png_libs=`$pkg_config libpng --libs 2> /dev/null` | ||||||
|  |   else | ||||||
|     vnc_png_cflags="" |     vnc_png_cflags="" | ||||||
|     vnc_png_libs="-lpng" |     vnc_png_libs="-lpng" | ||||||
|  |   fi | ||||||
|   if compile_prog "$vnc_png_cflags" "$vnc_png_libs" ; then |   if compile_prog "$vnc_png_cflags" "$vnc_png_libs" ; then | ||||||
|     vnc_png=yes |     vnc_png=yes | ||||||
|     libs_softmmu="$vnc_png_libs $libs_softmmu" |     libs_softmmu="$vnc_png_libs $libs_softmmu" | ||||||
|  |     QEMU_CFLAGS="$QEMU_CFLAGS $vnc_png_cflags" | ||||||
|   else |   else | ||||||
|     if test "$vnc_png" = "yes" ; then |     if test "$vnc_png" = "yes" ; then | ||||||
|       feature_not_found "vnc-png" |       feature_not_found "vnc-png" | ||||||
| @@ -1822,19 +1876,42 @@ fi | |||||||
|  |  | ||||||
| ########################################## | ########################################## | ||||||
| # glib support probe | # glib support probe | ||||||
| if $pkg_config --modversion glib-2.0 > /dev/null 2>&1 ; then | if test "$guest_agent" != "no" ; then | ||||||
|  |     if $pkg_config --modversion glib-2.0 > /dev/null 2>&1 ; then | ||||||
|         glib_cflags=`$pkg_config --cflags glib-2.0 2>/dev/null` |         glib_cflags=`$pkg_config --cflags glib-2.0 2>/dev/null` | ||||||
|         glib_libs=`$pkg_config --libs glib-2.0 2>/dev/null` |         glib_libs=`$pkg_config --libs glib-2.0 2>/dev/null` | ||||||
|         libs_softmmu="$glib_libs $libs_softmmu" |         libs_softmmu="$glib_libs $libs_softmmu" | ||||||
|         libs_tools="$glib_libs $libs_tools" |         libs_tools="$glib_libs $libs_tools" | ||||||
| else |     else | ||||||
|         echo "glib-2.0 required to compile QEMU" |         echo "glib-2.0 required to compile QEMU" | ||||||
|         exit 1 |         exit 1 | ||||||
|  |     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 | fi | ||||||
|  |  | ||||||
| ########################################## | ########################################## | ||||||
| # pthread probe | # pthread probe | ||||||
| PTHREADLIBS_LIST="-lpthread -lpthreadGC2" | PTHREADLIBS_LIST="-pthread -lpthread -lpthreadGC2" | ||||||
|  |  | ||||||
| pthread=no | pthread=no | ||||||
| cat > $TMPC << EOF | cat > $TMPC << EOF | ||||||
| @@ -2509,6 +2586,29 @@ if test "$trace_backend" = "dtrace"; then | |||||||
|   fi |   fi | ||||||
| fi | fi | ||||||
|  |  | ||||||
|  | ########################################## | ||||||
|  | # __sync_fetch_and_and requires at least -march=i486. Many toolchains | ||||||
|  | # use i686 as default anyway, but for those that don't, an explicit | ||||||
|  | # specification is necessary | ||||||
|  | if test $vhost_net = "yes" && test $cpu = "i386"; then | ||||||
|  |   cat > $TMPC << EOF | ||||||
|  | int sfaa(unsigned *ptr) | ||||||
|  | { | ||||||
|  |   return __sync_fetch_and_and(ptr, 0); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int main(int argc, char **argv) | ||||||
|  | { | ||||||
|  |   int val = 42; | ||||||
|  |   sfaa(&val); | ||||||
|  |   return val; | ||||||
|  | } | ||||||
|  | EOF | ||||||
|  |   if ! compile_prog "" "" ; then | ||||||
|  |     CFLAGS+="-march=i486" | ||||||
|  |   fi | ||||||
|  | fi | ||||||
|  |  | ||||||
| ########################################## | ########################################## | ||||||
| # End of CC checks | # End of CC checks | ||||||
| # After here, no more $cc or $ld runs | # After here, no more $cc or $ld runs | ||||||
| @@ -2566,7 +2666,9 @@ if test "$softmmu" = yes ; then | |||||||
|   tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools" |   tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools" | ||||||
|   if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then |   if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then | ||||||
|       tools="qemu-nbd\$(EXESUF) $tools" |       tools="qemu-nbd\$(EXESUF) $tools" | ||||||
|  |     if [ "$guest_agent" = "yes" ]; then | ||||||
|       tools="qemu-ga\$(EXESUF) $tools" |       tools="qemu-ga\$(EXESUF) $tools" | ||||||
|  |     fi | ||||||
|     if [ "$check_utests" = "yes" ]; then |     if [ "$check_utests" = "yes" ]; then | ||||||
|       tools="check-qint check-qstring check-qdict check-qlist $tools" |       tools="check-qint check-qstring check-qdict check-qlist $tools" | ||||||
|       tools="check-qfloat check-qjson $tools" |       tools="check-qfloat check-qjson $tools" | ||||||
| @@ -2603,6 +2705,9 @@ echo "LDFLAGS           $LDFLAGS" | |||||||
| echo "make              $make" | echo "make              $make" | ||||||
| echo "install           $install" | echo "install           $install" | ||||||
| echo "python            $python" | echo "python            $python" | ||||||
|  | if test "$slirp" = "yes" ; then | ||||||
|  |     echo "smbd              $smbd" | ||||||
|  | fi | ||||||
| echo "host CPU          $cpu" | echo "host CPU          $cpu" | ||||||
| echo "host big endian   $bigendian" | echo "host big endian   $bigendian" | ||||||
| echo "target list       $target_list" | echo "target list       $target_list" | ||||||
| @@ -2638,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" | ||||||
| @@ -2652,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" | ||||||
| @@ -2667,6 +2775,7 @@ echo "xfsctl support    $xfs" | |||||||
| echo "nss used          $smartcard_nss" | echo "nss used          $smartcard_nss" | ||||||
| echo "usb net redir     $usb_redir" | echo "usb net redir     $usb_redir" | ||||||
| echo "OpenGL support    $opengl" | echo "OpenGL support    $opengl" | ||||||
|  | echo "build guest agent $guest_agent" | ||||||
|  |  | ||||||
| if test $sdl_too_old = "yes"; then | if test $sdl_too_old = "yes"; then | ||||||
| echo "-> Your SDL version is too old - please upgrade to have SDL support" | echo "-> Your SDL version is too old - please upgrade to have SDL support" | ||||||
| @@ -2760,6 +2869,7 @@ if test $profiler = "yes" ; then | |||||||
| fi | fi | ||||||
| if test "$slirp" = "yes" ; then | if test "$slirp" = "yes" ; then | ||||||
|   echo "CONFIG_SLIRP=y" >> $config_host_mak |   echo "CONFIG_SLIRP=y" >> $config_host_mak | ||||||
|  |   echo "CONFIG_SMBD_COMMAND=\"$smbd\"" >> $config_host_mak | ||||||
|   QEMU_INCLUDES="-I\$(SRC_PATH)/slirp $QEMU_INCLUDES" |   QEMU_INCLUDES="-I\$(SRC_PATH)/slirp $QEMU_INCLUDES" | ||||||
| fi | fi | ||||||
| if test "$vde" = "yes" ; then | if test "$vde" = "yes" ; then | ||||||
| @@ -2941,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 | ||||||
| @@ -3012,9 +3127,9 @@ echo "TOOLS=$tools" >> $config_host_mak | |||||||
| echo "ROMS=$roms" >> $config_host_mak | echo "ROMS=$roms" >> $config_host_mak | ||||||
| echo "MAKE=$make" >> $config_host_mak | echo "MAKE=$make" >> $config_host_mak | ||||||
| echo "INSTALL=$install" >> $config_host_mak | echo "INSTALL=$install" >> $config_host_mak | ||||||
| echo "INSTALL_DIR=$install -d -m0755 -p" >> $config_host_mak | echo "INSTALL_DIR=$install -d -m 0755" >> $config_host_mak | ||||||
| echo "INSTALL_DATA=$install -m0644 -p" >> $config_host_mak | echo "INSTALL_DATA=$install -c -m 0644" >> $config_host_mak | ||||||
| echo "INSTALL_PROG=$install -m0755 -p" >> $config_host_mak | echo "INSTALL_PROG=$install -c -m 0755" >> $config_host_mak | ||||||
| echo "PYTHON=$python" >> $config_host_mak | echo "PYTHON=$python" >> $config_host_mak | ||||||
| echo "CC=$cc" >> $config_host_mak | echo "CC=$cc" >> $config_host_mak | ||||||
| echo "CC_I386=$cc_i386" >> $config_host_mak | echo "CC_I386=$cc_i386" >> $config_host_mak | ||||||
| @@ -3148,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 | ||||||
| @@ -3310,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 | ||||||
| @@ -3530,7 +3654,7 @@ DIRS="$DIRS roms/seabios roms/vgabios" | |||||||
| DIRS="$DIRS fsdev ui" | DIRS="$DIRS fsdev ui" | ||||||
| DIRS="$DIRS qapi" | DIRS="$DIRS qapi" | ||||||
| DIRS="$DIRS qga" | DIRS="$DIRS qga" | ||||||
| FILES="Makefile tests/Makefile" | FILES="Makefile tests/Makefile qdict-test-data.txt" | ||||||
| FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit" | FILES="$FILES tests/cris/Makefile tests/cris/.gdbinit" | ||||||
| FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps" | FILES="$FILES pc-bios/optionrom/Makefile pc-bios/keymaps" | ||||||
| FILES="$FILES pc-bios/spapr-rtas/Makefile" | FILES="$FILES pc-bios/spapr-rtas/Makefile" | ||||||
|   | |||||||
| @@ -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
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								cpus.c
									
									
									
									
									
								
							| @@ -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
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								cpus.h
									
									
									
									
									
								
							| @@ -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); | ||||||
|   | |||||||
| @@ -809,9 +809,6 @@ int main(int argc, char **argv) | |||||||
|             usage(); |             usage(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     if (optind >= argc) |  | ||||||
|         usage(); |  | ||||||
|     filename = argv[optind]; |  | ||||||
|  |  | ||||||
|     /* init debug */ |     /* init debug */ | ||||||
|     cpu_set_log_filename(log_file); |     cpu_set_log_filename(log_file); | ||||||
| @@ -830,6 +827,11 @@ int main(int argc, char **argv) | |||||||
|         cpu_set_log(mask); |         cpu_set_log(mask); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (optind >= argc) { | ||||||
|  |         usage(); | ||||||
|  |     } | ||||||
|  |     filename = argv[optind]; | ||||||
|  |  | ||||||
|     /* Zero out regs */ |     /* Zero out regs */ | ||||||
|     memset(regs, 0, sizeof(struct target_pt_regs)); |     memset(regs, 0, sizeof(struct target_pt_regs)); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										19
									
								
								exec.c
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								exec.c
									
									
									
									
									
								
							| @@ -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); | ||||||
| @@ -4121,6 +4136,8 @@ 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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|  |  | ||||||
|     { |     { | ||||||
|   | |||||||
							
								
								
									
										18
									
								
								hppa.ld
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								hppa.ld
									
									
									
									
									
								
							| @@ -75,36 +75,34 @@ SECTIONS | |||||||
|   .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } |   .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) } | ||||||
|   .PARISC.unwind   : { *(.PARISC.unwind) } |   .PARISC.unwind   : { *(.PARISC.unwind) } | ||||||
|   .eh_frame_hdr : { *(.eh_frame_hdr) } |   .eh_frame_hdr : { *(.eh_frame_hdr) } | ||||||
|   .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) } |  | ||||||
|   .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } |  | ||||||
|   /* Adjust the address for the data segment.  We want to adjust up to |   /* Adjust the address for the data segment.  We want to adjust up to | ||||||
|      the same address within the page on the next page up.  */ |      the same address within the page on the next page up.  */ | ||||||
|   . = ALIGN(0x10000) + (. & (0x10000 - 1)); |   . = ALIGN(0x10000) + (. & (0x10000 - 1)); | ||||||
|   /* Exception handling  */ |   /* Exception handling  */ | ||||||
|   .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) } |   .eh_frame       : { KEEP (*(.eh_frame)) } | ||||||
|   .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } |   .gcc_except_table   : { *(.gcc_except_table .gcc_except_table.*) } | ||||||
|   /* Thread Local Storage sections  */ |   /* Thread Local Storage sections  */ | ||||||
|   .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) } |   .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) } | ||||||
|   .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } |   .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } | ||||||
|   .preinit_array     : |   .preinit_array     : | ||||||
|   { |   { | ||||||
|     PROVIDE_HIDDEN (__preinit_array_start = .); |     PROVIDE (__preinit_array_start = .); | ||||||
|     KEEP (*(.preinit_array)) |     KEEP (*(.preinit_array)) | ||||||
|     PROVIDE_HIDDEN (__preinit_array_end = .); |     PROVIDE (__preinit_array_end = .); | ||||||
|   } |   } | ||||||
|   .init_array     : |   .init_array     : | ||||||
|   { |   { | ||||||
|      PROVIDE_HIDDEN (__init_array_start = .); |      PROVIDE (__init_array_start = .); | ||||||
|      KEEP (*(SORT(.init_array.*))) |      KEEP (*(SORT(.init_array.*))) | ||||||
|      KEEP (*(.init_array)) |      KEEP (*(.init_array)) | ||||||
|      PROVIDE_HIDDEN (__init_array_end = .); |      PROVIDE (__init_array_end = .); | ||||||
|   } |   } | ||||||
|   .fini_array     : |   .fini_array     : | ||||||
|   { |   { | ||||||
|     PROVIDE_HIDDEN (__fini_array_start = .); |     PROVIDE (__fini_array_start = .); | ||||||
|     KEEP (*(.fini_array)) |     KEEP (*(.fini_array)) | ||||||
|     KEEP (*(SORT(.fini_array.*))) |     KEEP (*(SORT(.fini_array.*))) | ||||||
|     PROVIDE_HIDDEN (__fini_array_end = .); |     PROVIDE (__fini_array_end = .); | ||||||
|   } |   } | ||||||
|   .ctors          : |   .ctors          : | ||||||
|   { |   { | ||||||
|   | |||||||
| @@ -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; | ||||||
|   | |||||||
							
								
								
									
										116
									
								
								hw/apic.c
									
									
									
									
									
								
							
							
						
						
									
										116
									
								
								hw/apic.c
									
									
									
									
									
								
							| @@ -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,6 +303,9 @@ void cpu_set_apic_base(DeviceState *d, uint64_t val) | |||||||
|  |  | ||||||
|     if (!s) |     if (!s) | ||||||
|         return; |         return; | ||||||
|  |     if (kvm_enabled() && kvm_irqchip_in_kernel()) | ||||||
|  |         s->apicbase = val; | ||||||
|  |     else | ||||||
|         s->apicbase = (val & 0xfffff000) | |         s->apicbase = (val & 0xfffff000) | | ||||||
|             (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE)); |             (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE)); | ||||||
|     /* if disabled, cannot be enabled again */ |     /* if disabled, cannot be enabled again */ | ||||||
| @@ -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) | ||||||
| { | { | ||||||
|   | |||||||
| @@ -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); | ||||||
|   | |||||||
| @@ -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
									
								
							
							
						
						
									
										1909
									
								
								hw/device-assignment.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										120
									
								
								hw/device-assignment.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								hw/device-assignment.h
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										123
									
								
								hw/extboot.c
									
									
									
									
									
										Normal 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, §ors); | ||||||
|  | 	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); | ||||||
|  | } | ||||||
							
								
								
									
										51
									
								
								hw/fdc.c
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								hw/fdc.c
									
									
									
									
									
								
							| @@ -36,7 +36,6 @@ | |||||||
| #include "qdev-addr.h" | #include "qdev-addr.h" | ||||||
| #include "blockdev.h" | #include "blockdev.h" | ||||||
| #include "sysemu.h" | #include "sysemu.h" | ||||||
| #include "block_int.h" |  | ||||||
|  |  | ||||||
| /********************************************************/ | /********************************************************/ | ||||||
| /* debug Floppy devices */ | /* debug Floppy devices */ | ||||||
| @@ -83,7 +82,6 @@ typedef struct FDrive { | |||||||
|     uint8_t max_track;        /* Nb of tracks           */ |     uint8_t max_track;        /* Nb of tracks           */ | ||||||
|     uint16_t bps;             /* Bytes per sector       */ |     uint16_t bps;             /* Bytes per sector       */ | ||||||
|     uint8_t ro;               /* Is read-only           */ |     uint8_t ro;               /* Is read-only           */ | ||||||
|     uint8_t media_changed;    /* Is media changed       */ |  | ||||||
| } FDrive; | } FDrive; | ||||||
|  |  | ||||||
| static void fd_init(FDrive *drv) | static void fd_init(FDrive *drv) | ||||||
| @@ -535,63 +533,16 @@ static CPUWriteMemoryFunc * const fdctrl_mem_write_strict[3] = { | |||||||
|     NULL, |     NULL, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static void fdrive_media_changed_pre_save(void *opaque) |  | ||||||
| { |  | ||||||
|     FDrive *drive = opaque; |  | ||||||
|  |  | ||||||
|     drive->media_changed = drive->bs->media_changed; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static int fdrive_media_changed_post_load(void *opaque, int version_id) |  | ||||||
| { |  | ||||||
|     FDrive *drive = opaque; |  | ||||||
|  |  | ||||||
|     if (drive->bs != NULL) { |  | ||||||
|         drive->bs->media_changed = drive->media_changed; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /* User ejected the floppy when drive->bs == NULL */ |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static bool fdrive_media_changed_needed(void *opaque) |  | ||||||
| { |  | ||||||
|     FDrive *drive = opaque; |  | ||||||
|  |  | ||||||
|     return (drive->bs != NULL && drive->bs->media_changed != 1); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static const VMStateDescription vmstate_fdrive_media_changed = { |  | ||||||
|     .name = "fdrive/media_changed", |  | ||||||
|     .version_id = 1, |  | ||||||
|     .minimum_version_id = 1, |  | ||||||
|     .minimum_version_id_old = 1, |  | ||||||
|     .pre_save = fdrive_media_changed_pre_save, |  | ||||||
|     .post_load = fdrive_media_changed_post_load, |  | ||||||
|     .fields      = (VMStateField[]) { |  | ||||||
|         VMSTATE_UINT8(media_changed, FDrive), |  | ||||||
|         VMSTATE_END_OF_LIST() |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| static const VMStateDescription vmstate_fdrive = { | static const VMStateDescription vmstate_fdrive = { | ||||||
|     .name = "fdrive", |     .name = "fdrive", | ||||||
|     .version_id = 1, |     .version_id = 1, | ||||||
|     .minimum_version_id = 1, |     .minimum_version_id = 1, | ||||||
|     .minimum_version_id_old = 1, |     .minimum_version_id_old = 1, | ||||||
|     .fields      = (VMStateField[]) { |     .fields      = (VMStateField []) { | ||||||
|         VMSTATE_UINT8(head, FDrive), |         VMSTATE_UINT8(head, FDrive), | ||||||
|         VMSTATE_UINT8(track, FDrive), |         VMSTATE_UINT8(track, FDrive), | ||||||
|         VMSTATE_UINT8(sect, FDrive), |         VMSTATE_UINT8(sect, FDrive), | ||||||
|         VMSTATE_END_OF_LIST() |         VMSTATE_END_OF_LIST() | ||||||
|     }, |  | ||||||
|     .subsections = (VMStateSubsection[]) { |  | ||||||
|         { |  | ||||||
|             .vmsd = &vmstate_fdrive_media_changed, |  | ||||||
|             .needed = &fdrive_media_changed_needed, |  | ||||||
|         } , { |  | ||||||
|             /* empty */ |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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
									
								
							
							
						
						
									
										115
									
								
								hw/i8254-kvm.c
									
									
									
									
									
										Normal 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; | ||||||
|  | } | ||||||
							
								
								
									
										146
									
								
								hw/i8254.c
									
									
									
									
									
								
							
							
						
						
									
										146
									
								
								hw/i8254.c
									
									
									
									
									
								
							| @@ -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]; | ||||||
|  |  | ||||||
|  |     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); |             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
									
								
							
							
						
						
									
										75
									
								
								hw/i8254.h
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										145
									
								
								hw/i8259.c
									
									
									
									
									
								
							
							
						
						
									
										145
									
								
								hw/i8259.c
									
									
									
									
									
								
							| @@ -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 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										66
									
								
								hw/ioapic.c
									
									
									
									
									
								
							
							
						
						
									
										66
									
								
								hw/ioapic.c
									
									
									
									
									
								
							| @@ -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
									
								
							
							
						
						
									
										707
									
								
								hw/ipf.c
									
									
									
									
									
										Normal 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, §ors); | ||||||
|  |     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, §ors); | ||||||
|  |                 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); | ||||||
|  | } | ||||||
| @@ -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]; | ||||||
|   | |||||||
| @@ -310,10 +310,12 @@ static int milkymist_softusb_init(SysBusDevice *dev) | |||||||
|     usb_bus_new(&s->usbbus, &softusb_bus_ops, NULL); |     usb_bus_new(&s->usbbus, &softusb_bus_ops, NULL); | ||||||
|  |  | ||||||
|     /* our two ports */ |     /* our two ports */ | ||||||
|  |     /* FIXME: claim to support full speed devices. qemu mouse and keyboard | ||||||
|  |      * report themselves as full speed devices. */ | ||||||
|     usb_register_port(&s->usbbus, &s->usbport[0], NULL, 0, &softusb_ops, |     usb_register_port(&s->usbbus, &s->usbport[0], NULL, 0, &softusb_ops, | ||||||
|             USB_SPEED_MASK_LOW); |             USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); | ||||||
|     usb_register_port(&s->usbbus, &s->usbport[1], NULL, 1, &softusb_ops, |     usb_register_port(&s->usbbus, &s->usbport[1], NULL, 1, &softusb_ops, | ||||||
|             USB_SPEED_MASK_LOW); |             USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); | ||||||
|  |  | ||||||
|     /* and finally create an usb keyboard */ |     /* and finally create an usb keyboard */ | ||||||
|     s->usbdev = usb_create_simple(&s->usbbus, "usb-kbd"); |     s->usbdev = usb_create_simple(&s->usbbus, "usb-kbd"); | ||||||
|   | |||||||
							
								
								
									
										131
									
								
								hw/msi.c
									
									
									
									
									
								
							
							
						
						
									
										131
									
								
								hw/msi.c
									
									
									
									
									
								
							| @@ -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); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								hw/msi.h
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								hw/msi.h
									
									
									
									
									
								
							| @@ -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) | ||||||
| { | { | ||||||
|   | |||||||
							
								
								
									
										221
									
								
								hw/msix.c
									
									
									
									
									
								
							
							
						
						
									
										221
									
								
								hw/msix.c
									
									
									
									
									
								
							| @@ -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,6 +133,12 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries, | |||||||
| { | { | ||||||
|     int config_offset; |     int config_offset; | ||||||
|     uint8_t *config; |     uint8_t *config; | ||||||
|  |  | ||||||
|  |     pdev->msix_bar_size = bar_size; | ||||||
|  |  | ||||||
|  |     config_offset = pci_find_capability(pdev, PCI_CAP_ID_MSIX); | ||||||
|  |  | ||||||
|  |     if (!config_offset) { | ||||||
|         uint32_t new_size; |         uint32_t new_size; | ||||||
|  |  | ||||||
|         if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) |         if (nentries < 1 || nentries > PCI_MSIX_FLAGS_QSIZE + 1) | ||||||
| @@ -75,6 +169,7 @@ static int msix_add_config(struct PCIDevice *pdev, unsigned short nentries, | |||||||
|         /* Pending bits on top of that */ |         /* Pending bits on top of that */ | ||||||
|         pci_set_long(config + PCI_MSIX_PBA, (bar_size + MSIX_PAGE_PENDING) | |         pci_set_long(config + PCI_MSIX_PBA, (bar_size + MSIX_PAGE_PENDING) | | ||||||
|                      bar_nr); |                      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; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -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
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								hw/pc.c
									
									
									
									
									
								
							| @@ -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
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								hw/pc.h
									
									
									
									
									
								
							| @@ -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 | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								hw/pc_piix.c
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								hw/pc_piix.c
									
									
									
									
									
								
							| @@ -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(); | ||||||
|  |         if (!(kvm_enabled() && kvm_irqchip_in_kernel())) { | ||||||
|             i8259 = i8259_init(cpu_irq[0]); |             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); | ||||||
|     } |     } | ||||||
|  |     if (!(kvm_enabled() && kvm_irqchip_in_kernel())) { | ||||||
|         isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24); |         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
									
									
									
									
									
								
							
							
						
						
									
										140
									
								
								hw/pci.c
									
									
									
									
									
								
							| @@ -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) | ||||||
|   | |||||||
							
								
								
									
										35
									
								
								hw/pci.h
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								hw/pci.h
									
									
									
									
									
								
							| @@ -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); | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
							
								
								
									
										51
									
								
								hw/pcspk.c
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								hw/pcspk.c
									
									
									
									
									
								
							| @@ -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) | ||||||
|   | |||||||
| @@ -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
									
								
							
							
						
						
									
										140
									
								
								hw/testdev.c
									
									
									
									
									
										Normal 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) | ||||||
							
								
								
									
										3
									
								
								hw/vga.c
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								hw/vga.c
									
									
									
									
									
								
							| @@ -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: | ||||||
|   | |||||||
| @@ -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" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,7 +1,9 @@ | |||||||
| /* | /* | ||||||
|  * Virtio Block Device |  * Virtio Balloon Device | ||||||
|  * |  * | ||||||
|  * Copyright IBM, Corp. 2008 |  * Copyright IBM, Corp. 2008 | ||||||
|  |  * Copyright (C) 2011 Red Hat, Inc. | ||||||
|  |  * Copyright (C) 2011 Amit Shah <amit.shah@redhat.com> | ||||||
|  * |  * | ||||||
|  * Authors: |  * Authors: | ||||||
|  *  Anthony Liguori   <aliguori@us.ibm.com> |  *  Anthony Liguori   <aliguori@us.ibm.com> | ||||||
| @@ -43,6 +45,7 @@ typedef struct VirtIOBalloon | |||||||
|     size_t stats_vq_offset; |     size_t stats_vq_offset; | ||||||
|     MonitorCompletion *stats_callback; |     MonitorCompletion *stats_callback; | ||||||
|     void *stats_opaque_callback_data; |     void *stats_opaque_callback_data; | ||||||
|  |     DeviceState *qdev; | ||||||
| } VirtIOBalloon; | } VirtIOBalloon; | ||||||
|  |  | ||||||
| static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev) | static VirtIOBalloon *to_virtio_balloon(VirtIODevice *vdev) | ||||||
| @@ -199,18 +202,11 @@ static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f) | |||||||
|     return f; |     return f; | ||||||
| } | } | ||||||
|  |  | ||||||
| static void virtio_balloon_to_target(void *opaque, ram_addr_t target, | static void virtio_balloon_stat(void *opaque, MonitorCompletion cb, | ||||||
|                                      MonitorCompletion cb, void *cb_data) |                                 void *cb_data) | ||||||
| { | { | ||||||
|     VirtIOBalloon *dev = opaque; |     VirtIOBalloon *dev = opaque; | ||||||
|  |  | ||||||
|     if (target > ram_size) |  | ||||||
|         target = ram_size; |  | ||||||
|  |  | ||||||
|     if (target) { |  | ||||||
|         dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT; |  | ||||||
|         virtio_notify_config(&dev->vdev); |  | ||||||
|     } else { |  | ||||||
|     /* For now, only allow one request at a time.  This restriction can be |     /* For now, only allow one request at a time.  This restriction can be | ||||||
|      * removed later by queueing callback and data pairs. |      * removed later by queueing callback and data pairs. | ||||||
|      */ |      */ | ||||||
| @@ -219,16 +215,31 @@ static void virtio_balloon_to_target(void *opaque, ram_addr_t target, | |||||||
|     } |     } | ||||||
|     dev->stats_callback = cb; |     dev->stats_callback = cb; | ||||||
|     dev->stats_opaque_callback_data = cb_data; |     dev->stats_opaque_callback_data = cb_data; | ||||||
|         if (ENABLE_GUEST_STATS && (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ))) { |  | ||||||
|  |     if (ENABLE_GUEST_STATS | ||||||
|  |         && (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ))) { | ||||||
|         virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset); |         virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset); | ||||||
|         virtio_notify(&dev->vdev, dev->svq); |         virtio_notify(&dev->vdev, dev->svq); | ||||||
|         } else { |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /* Stats are not supported.  Clear out any stale values that might |     /* Stats are not supported.  Clear out any stale values that might | ||||||
|      * have been set by a more featureful guest kernel. |      * have been set by a more featureful guest kernel. | ||||||
|      */ |      */ | ||||||
|     reset_stats(dev); |     reset_stats(dev); | ||||||
|     complete_stats_request(dev); |     complete_stats_request(dev); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void virtio_balloon_to_target(void *opaque, ram_addr_t target) | ||||||
|  | { | ||||||
|  |     VirtIOBalloon *dev = opaque; | ||||||
|  |  | ||||||
|  |     if (target > ram_size) { | ||||||
|  |         target = ram_size; | ||||||
|     } |     } | ||||||
|  |     if (target) { | ||||||
|  |         dev->num_pages = (ram_size - target) >> VIRTIO_BALLOON_PFN_SHIFT; | ||||||
|  |         virtio_notify_config(&dev->vdev); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -259,6 +270,7 @@ static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id) | |||||||
| VirtIODevice *virtio_balloon_init(DeviceState *dev) | VirtIODevice *virtio_balloon_init(DeviceState *dev) | ||||||
| { | { | ||||||
|     VirtIOBalloon *s; |     VirtIOBalloon *s; | ||||||
|  |     int ret; | ||||||
|  |  | ||||||
|     s = (VirtIOBalloon *)virtio_common_init("virtio-balloon", |     s = (VirtIOBalloon *)virtio_common_init("virtio-balloon", | ||||||
|                                             VIRTIO_ID_BALLOON, |                                             VIRTIO_ID_BALLOON, | ||||||
| @@ -268,15 +280,29 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev) | |||||||
|     s->vdev.set_config = virtio_balloon_set_config; |     s->vdev.set_config = virtio_balloon_set_config; | ||||||
|     s->vdev.get_features = virtio_balloon_get_features; |     s->vdev.get_features = virtio_balloon_get_features; | ||||||
|  |  | ||||||
|  |     ret = qemu_add_balloon_handler(virtio_balloon_to_target, | ||||||
|  |                                    virtio_balloon_stat, s); | ||||||
|  |     if (ret < 0) { | ||||||
|  |         virtio_cleanup(&s->vdev); | ||||||
|  |         return NULL; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     s->ivq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output); |     s->ivq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output); | ||||||
|     s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output); |     s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output); | ||||||
|     s->svq = virtio_add_queue(&s->vdev, 128, virtio_balloon_receive_stats); |     s->svq = virtio_add_queue(&s->vdev, 128, virtio_balloon_receive_stats); | ||||||
|  |  | ||||||
|     reset_stats(s); |     reset_stats(s); | ||||||
|     qemu_add_balloon_handler(virtio_balloon_to_target, s); |  | ||||||
|  |  | ||||||
|  |     s->qdev = dev; | ||||||
|     register_savevm(dev, "virtio-balloon", -1, 1, |     register_savevm(dev, "virtio-balloon", -1, 1, | ||||||
|                     virtio_balloon_save, virtio_balloon_load, s); |                     virtio_balloon_save, virtio_balloon_load, s); | ||||||
|  |  | ||||||
|     return &s->vdev; |     return &s->vdev; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void virtio_balloon_exit(VirtIODevice *vdev) | ||||||
|  | { | ||||||
|  |     VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev); | ||||||
|  |     unregister_savevm(s->qdev, "virtio-balloon", s); | ||||||
|  |     virtio_cleanup(vdev); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -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; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -788,10 +864,22 @@ static int virtio_balloon_init_pci(PCIDevice *pci_dev) | |||||||
|     VirtIODevice *vdev; |     VirtIODevice *vdev; | ||||||
|  |  | ||||||
|     vdev = virtio_balloon_init(&pci_dev->qdev); |     vdev = virtio_balloon_init(&pci_dev->qdev); | ||||||
|  |     if (!vdev) { | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|     virtio_init_pci(proxy, vdev); |     virtio_init_pci(proxy, vdev); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static int virtio_balloon_exit_pci(PCIDevice *pci_dev) | ||||||
|  | { | ||||||
|  |     VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); | ||||||
|  |  | ||||||
|  |     virtio_pci_stop_ioeventfd(proxy); | ||||||
|  |     virtio_balloon_exit(proxy->vdev); | ||||||
|  |     return virtio_exit_pci(pci_dev); | ||||||
|  | } | ||||||
|  |  | ||||||
| static PCIDeviceInfo virtio_info[] = { | static PCIDeviceInfo virtio_info[] = { | ||||||
|     { |     { | ||||||
|         .qdev.name = "virtio-blk-pci", |         .qdev.name = "virtio-blk-pci", | ||||||
| @@ -866,7 +954,7 @@ static PCIDeviceInfo virtio_info[] = { | |||||||
|         .qdev.alias = "virtio-balloon", |         .qdev.alias = "virtio-balloon", | ||||||
|         .qdev.size = sizeof(VirtIOPCIProxy), |         .qdev.size = sizeof(VirtIOPCIProxy), | ||||||
|         .init      = virtio_balloon_init_pci, |         .init      = virtio_balloon_init_pci, | ||||||
|         .exit      = virtio_exit_pci, |         .exit      = virtio_balloon_exit_pci, | ||||||
|         .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, |         .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, | ||||||
|         .device_id = PCI_DEVICE_ID_VIRTIO_BALLOON, |         .device_id = PCI_DEVICE_ID_VIRTIO_BALLOON, | ||||||
|         .revision  = VIRTIO_PCI_ABI_VERSION, |         .revision  = VIRTIO_PCI_ABI_VERSION, | ||||||
|   | |||||||
| @@ -213,6 +213,7 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf); | |||||||
| void virtio_net_exit(VirtIODevice *vdev); | void virtio_net_exit(VirtIODevice *vdev); | ||||||
| void virtio_blk_exit(VirtIODevice *vdev); | void virtio_blk_exit(VirtIODevice *vdev); | ||||||
| void virtio_serial_exit(VirtIODevice *vdev); | void virtio_serial_exit(VirtIODevice *vdev); | ||||||
|  | void virtio_balloon_exit(VirtIODevice *vdev); | ||||||
|  |  | ||||||
| #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \ | #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \ | ||||||
| 	DEFINE_PROP_BIT("indirect_desc", _state, _field, \ | 	DEFINE_PROP_BIT("indirect_desc", _state, _field, \ | ||||||
|   | |||||||
							
								
								
									
										8
									
								
								i386.ld
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								i386.ld
									
									
									
									
									
								
							| @@ -42,16 +42,16 @@ SECTIONS | |||||||
|   .rel.plt      : |   .rel.plt      : | ||||||
|   { |   { | ||||||
|     *(.rel.plt) |     *(.rel.plt) | ||||||
|     PROVIDE_HIDDEN (__rel_iplt_start = .); |     PROVIDE (__rel_iplt_start = .); | ||||||
|     *(.rel.iplt) |     *(.rel.iplt) | ||||||
|     PROVIDE_HIDDEN (__rel_iplt_end = .); |     PROVIDE (__rel_iplt_end = .); | ||||||
|   } |   } | ||||||
|   .rela.plt       : |   .rela.plt       : | ||||||
|   { |   { | ||||||
|     *(.rela.plt) |     *(.rela.plt) | ||||||
|     PROVIDE_HIDDEN (__rela_iplt_start = .); |     PROVIDE (__rela_iplt_start = .); | ||||||
|     *(.rela.iplt) |     *(.rela.iplt) | ||||||
|     PROVIDE_HIDDEN (__rela_iplt_end = .); |     PROVIDE (__rela_iplt_end = .); | ||||||
|   } |   } | ||||||
|   .init          : { *(.init)	} =0x47ff041f |   .init          : { *(.init)	} =0x47ff041f | ||||||
|   .text      : |   .text      : | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								ia64.ld
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								ia64.ld
									
									
									
									
									
								
							| @@ -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
									
								
							
							
						
						
									
										150
									
								
								ia64intrin.h
									
									
									
									
									
										Normal 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 */ | ||||||
							
								
								
									
										51
									
								
								kvm-all.c
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								kvm-all.c
									
									
									
									
									
								
							| @@ -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" | ||||||
|   | |||||||
							
								
								
									
										51
									
								
								kvm-stub.c
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								kvm-stub.c
									
									
									
									
									
								
							| @@ -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
									
								
							
							
						
						
									
										380
									
								
								kvm-tpr-opt.c
									
									
									
									
									
										Normal 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
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								kvm.h
									
									
									
									
									
								
							| @@ -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
									
								
							
							
						
						
									
										66
									
								
								kvm/.gitignore
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										125
									
								
								kvm/Makefile
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										142
									
								
								kvm/configure
									
									
									
									
										vendored
									
									
										Executable 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
									
								
							
							
						
						
									
										41
									
								
								kvm/extboot/Makefile
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										6
									
								
								kvm/extboot/STATUS
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										79
									
								
								kvm/extboot/signrom.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										264
									
								
								kvm/include/ia64/asm/kvm.h
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										31
									
								
								kvm/include/ia64/asm/kvm_para.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								kvm/include/ia64/asm/kvm_para.h
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										2
									
								
								kvm/include/linux/compiler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								kvm/include/linux/compiler.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | /* dummy file */ | ||||||
|  |  | ||||||
							
								
								
									
										43
									
								
								kvm/include/linux/config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								kvm/include/linux/config.h
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										784
									
								
								kvm/include/linux/kvm.h
									
									
									
									
									
										Normal 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 */ | ||||||
							
								
								
									
										41
									
								
								kvm/include/linux/kvm_para.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								kvm/include/linux/kvm_para.h
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										130
									
								
								kvm/include/linux/vhost.h
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										62
									
								
								kvm/include/powerpc/asm/kvm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								kvm/include/powerpc/asm/kvm.h
									
									
									
									
									
										Normal 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 */ | ||||||
							
								
								
									
										37
									
								
								kvm/include/powerpc/asm/kvm_para.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								kvm/include/powerpc/asm/kvm_para.h
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										324
									
								
								kvm/include/x86/asm/kvm.h
									
									
									
									
									
										Normal 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 */ | ||||||
							
								
								
									
										149
									
								
								kvm/include/x86/asm/kvm_para.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								kvm/include/x86/asm/kvm_para.h
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										139
									
								
								kvm/kvm.spec
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										469
									
								
								kvm/kvm_stat
									
									
									
									
									
										Executable 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
									
								
							
							
						
						
									
										19
									
								
								kvm/libfdt/Makefile
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										3
									
								
								kvm/libfdt/README
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										194
									
								
								kvm/libfdt/fdt.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										60
									
								
								kvm/libfdt/fdt.h
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										476
									
								
								kvm/libfdt/fdt_ro.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										467
									
								
								kvm/libfdt/fdt_rw.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										96
									
								
								kvm/libfdt/fdt_strerror.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										258
									
								
								kvm/libfdt/fdt_sw.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										144
									
								
								kvm/libfdt/fdt_wip.c
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										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
									
								
							
							
						
						
									
										22
									
								
								kvm/libfdt/libfdt_env.h
									
									
									
									
									
										Normal 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 */ | ||||||
							
								
								
									
										96
									
								
								kvm/libfdt/libfdt_internal.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								kvm/libfdt/libfdt_internal.h
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										54
									
								
								kvm/libkvm/Makefile
									
									
									
									
									
										Normal 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 | ||||||
							
								
								
									
										6
									
								
								kvm/libkvm/config-i386.mak
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								kvm/libkvm/config-i386.mak
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  |  | ||||||
|  | LIBDIR := /lib | ||||||
|  | CFLAGS += -m32 | ||||||
|  | CFLAGS += -D__i386__ | ||||||
|  |  | ||||||
|  | libkvm-$(ARCH)-objs := libkvm-x86.o | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user