uq/master: Introduce basic irqchip support
v2 cover uq/master: Introduce basic irqchip support
This is v2, addressing the feedback comments provided so far, namely:
- dropped #include <> conversions
- do not abort() on reserved memory region accesses but only warn once
- use memory_region_init_io in memory_region_init_reservation
Patch 1 of this series has meanwhile been posted for direct upstream inclusion, see http://thread.gmane.org/gmane.comp.emulators.qemu/127308.
I'm keeping it to easy testing, but it should likely not go via uq/master. The same may apply to other patches too, e.g. 10.
--- original series description ---
Some weeks back I posted my MSI rework for qemu-kvm that shall once help integrating those bits into upstream. After that I wondered how a rewritten in-kernel irqchip model could look like and make use of this. But then I realized that there is actually no technical need to role out a first version of kvm irqchips that already support MSI. As the MSI thing will likely take a few more iterations, I now decided to rush forward with basic kvm irqchip for QEMU upstream. Here we go.
My idea was always to create proper alternatives to the existing user space device models while keeping the vmstates 100% compatible. I think I succeeded in this, tests worked fine so far. The kvm and the user space models now have a common core where they share logic and specific code modules where they differ. Also, I moved all kvm devices into hw/kvm.
The in-kernel irqchip support can be controlled via a machine property (-machine ...,kernel_irqchip=on), in contrast to qemu-kvm's dedicated command line switch. This series keeps the support off by default because we still lack the MSI bits as I explained. Also, in-kernel PIT is not yet implemented and TPR patching/VAPIC (for Windows guests).
The merge story would basically look similar to what we did before with the clean-room reimplementation of kvm for QEMU: Merge into upstream, merge back into qemu-kvm, disabling the new bits for now, then gradually switching over to the new services, specifically once they are feature-equivalent. Of course, I will support these steps as usual.
So, feedback and review welcome!
Jan Kiszka (16):
msi: Generalize msix_supported to msi_supported
kvm: Move kvmclock into hw/kvm folder
apic: Stop timer on reset
apic: Factor out core for KVM reuse
apic: Open-code timer save/restore
i8259: Factor out core for KVM reuse
ioapic: Convert to memory API
ioapic: Reject non-dword accesses to IOWIN register
ioapic: Factor out core for KVM reuse
memory: Introduce memory_region_init_reservation
kvm: Introduce core services for in-kernel irqchip support
kvm: x86: Establish IRQ0 override control
kvm: x86: Add user space part for in-kernel APIC
kvm: x86: Add user space part for in-kernel i8259
kvm: x86: Add user space part for in-kernel IOAPIC
kvm: Arm in-kernel irqchip support
Makefile.objs | 2 +-
Makefile.target | 6 +-
configure | 1 +
hw/apic.c | 288 ++++------------------------------------
hw/apic_common.c | 262 ++++++++++++++++++++++++++++++++++++
hw/apic_internal.h | 111 +++++++++++++++
hw/i8259.c | 78 +-----------
hw/i8259_common.c | 103 ++++++++++++++
hw/i8259_internal.h | 67 +++++++++
hw/ioapic.c | 136 +++----------------
hw/ioapic_common.c | 89 ++++++++++++
hw/ioapic_internal.h | 94 +++++++++++++
hw/kvm/apic.c | 147 ++++++++++++++++++++
hw/{kvmclock.c => kvm/clock.c} | 4 +-
hw/{kvmclock.h => kvm/clock.h} | 0
hw/kvm/i8259.c | 154 +++++++++++++++++++++
hw/kvm/ioapic.c | 120 +++++++++++++++++
hw/msi.c | 8 +
hw/msi.h | 2 +
hw/msix.c | 9 +-
hw/msix.h | 2 -
hw/pc.c | 20 ++-
hw/pc.h | 1 +
hw/pc_piix.c | 67 +++++++++-
kvm-all.c | 154 +++++++++++++++++++++
kvm-stub.c | 5 +
kvm.h | 13 ++
memory.c | 36 +++++
memory.h | 16 +++
qemu-config.c | 4 +
qemu-options.hx | 5 +-
sysemu.h | 1 -
target-i386/kvm.c | 19 +++
trace-events | 2 +-
vl.c | 1 -
35 files changed, 1547 insertions(+), 480 deletions(-)
create mode 100644 hw/apic_common.c
create mode 100644 hw/apic_internal.h
create mode 100644 hw/i8259_common.c
create mode 100644 hw/i8259_internal.h
create mode 100644 hw/ioapic_common.c
create mode 100644 hw/ioapic_internal.h
create mode 100644 hw/kvm/apic.c
rename hw/{kvmclock.c => kvm/clock.c} (98%)
rename hw/{kvmclock.h => kvm/clock.h} (100%)
create mode 100644 hw/kvm/i8259.c
create mode 100644 hw/kvm/ioapic.cSignature · 1 line
1.7.3.4
PATCH v2 1/16 msi: Generalize msix_supported to msi_supported
From: Jan Kiszka <[email protected]>
Rename msix_supported to msi_supported and control MSI and MSI-X activation this way. That was likely to original intention for this flag, but MSI support came after MSI-X.
--- hw/msi.c | 8 ++++++++ hw/msi.h | 2 ++ hw/msix.c | 9 ++++----- hw/msix.h | 2 -- hw/pc.c | 4 ++-- 5 files changed, 16 insertions(+), 9 deletions(-)
hw/msi.c +8 -0
@@ -36,6 +36,9 @@#define PCI_MSI_VECTORS_MAX 32 +/* Flag for interrupt controller to declare MSI/MSI-X support */ +bool msi_supported; +/* If we get rid of cap allocator, we won't need this. */ static inline uint8_t msi_cap_sizeof (uint16_t flags) {
@@ -116,6 +119,11 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,uint16_t flags;uint8_t cap_size;int config_offset; + +if (!msi_supported) { +return -ENOTSUP ; + } + MSI_DEV_PRINTF(dev, "init offset: 0x%"PRIx8" vector: %"PRId8 " 64bit %d mask %d\n",
hw/msi.h +2 -0
@@ -24,6 +24,8 @@#include "qemu-common.h" #include "pci.h" +extern bool msi_supported; +bool msi_enabled (const PCIDevice *dev);int msi_init (struct PCIDevice *dev,uint8_t offset,unsigned int nr_vectors,bool msi64bit,bool msi_per_vector_mask);
hw/msix.c +4 -5
@@ -12,6 +12,7 @@*/ #include "hw.h" +#include "msi.h" #include "msix.h" #include "pci.h" #include "range.h"
@@ -32,9 +33,6 @@#define MSIX_MAX_ENTRIES 32 -/* Flag for interrupt controller to declare MSI-X support */ -int msix_supported; -/* 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 * and fill MSI-X capability in the config space.
@@ -212,10 +210,11 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries, unsigned bar_nr, unsigned bar_size) { int ret; +/* Nothing to do if MSI is not supported by interrupt controller */ -if (!msix_supported) +if (!msi_supported) {return -ENOTSUP ; - + }if (nentries >MSIX_MAX_ENTRIES )return -EINVAL ;
hw/msix.h +0 -2
@@ -29,6 +29,4 @@ void msix_notify(PCIDevice *dev, unsigned vector);void msix_reset (PCIDevice *dev); -extern int msix_supported; -#endif
hw/pc.c +2 -2
@@ -36,7 +36,7 @@#include "elf.h" #include "multiboot.h" #include "mc146818rtc.h" -#include "msix.h" +#include "msi.h" #include "sysbus.h" #include "sysemu.h" #include "blockdev.h"
@@ -896,7 +896,7 @@ static DeviceState *apic_init(void *env, uint8_t apic_id) apic_mapped =1 ; } - msix_supported =1 ; + msi_supported = true;return dev; }
Signature · 1 line
1.7.3.4
PATCH v2 2/16 kvm: Move kvmclock into hw/kvm folder
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
More KVM-specific devices will come, so let's start with moving the kvmclock into a dedicated folder.
---
Makefile.target | 4 ++--
configure | 1 +
hw/{kvmclock.c => kvm/clock.c} | 4 ++--
hw/{kvmclock.h => kvm/clock.h} | 0
hw/pc_piix.c | 2 +-
5 files changed, 6 insertions(+), 5 deletions(-)
rename hw/{kvmclock.c => kvm/clock.c} (98%)
rename hw/{kvmclock.h => kvm/clock.h} (100%)Makefile.target +2 -2
@@ -231,7 +231,7 @@ obj-i386-y += vmport.o obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o obj-i386-y += debugcon.o multiboot.o obj-i386-y += pc_piix.o -obj-i386-$(CONFIG_KVM) += kvmclock.o +obj-i386-$(CONFIG_KVM) += kvm/clock.o obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o # shared objects
@@ -421,7 +421,7 @@ qmp-commands-old.h: $(SRC_PATH)/qmp-commands.hx clean: rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o - rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o + rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o kvm/*.o rm -f hmp-commands.h qmp-commands-old.h gdbstub-xml.c ifdef CONFIG_TRACE_SYSTEMTAP rm -f *.stp
configure +1 -0
@@ -3220,6 +3220,7 @@ mkdir -p $target_dir/fpu mkdir -p $target_dir/tcg mkdir -p $target_dir/ide mkdir -p $target_dir/9pfs +mkdir -p $target_dir/kvm if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" -o "$target" = "arm-bsd-user" -o "$target" = "armeb-bsd-user" ; then mkdir -p $target_dir/nwfpe fi
hw/kvm/clock.c renamed from hw/kvmclock.c +2 -2
@@ -13,9 +13,9 @@#include "qemu-common.h" #include "sysemu.h" -#include "sysbus.h" #include "kvm.h" -#include "kvmclock.h" +#include "hw/sysbus.h" +#include "hw/kvm/clock.h" #include <linux/kvm.h> #include <linux/kvm_para.h>
hw/kvm/clock.h renamed from hw/kvmclock.h +0 -0
hw/pc_piix.c +1 -1
@@ -34,7 +34,7 @@#include "boards.h" #include "ide.h" #include "kvm.h" -#include "kvmclock.h" +#include "kvm/clock.h" #include "sysemu.h" #include "sysbus.h" #include "arch_init.h"
Signature · 1 line
1.7.3.4
PATCH v2 3/16 apic: Stop timer on reset
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
All LVTs are masked on reset, so the timer becomes ineffective. Letting it tick nevertheless is harmless, but will at least create a spurious trace event.
--- hw/apic.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
hw/apic.c +2 -0
@@ -528,6 +528,8 @@ void apic_init_reset(DeviceState *d) s->initial_count_load_time =0 ; s->next_time =0 ; s->wait_for_sipi =1 ; + +qemu_del_timer (s->timer); }static void apic_startup (APICState *s,int vector_num)
Signature · 1 line
1.7.3.4
PATCH v2 4/16 apic: Factor out core for KVM reuse
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
The KVM in-kernel APIC model will reuse parts of the user space model, namely the vmstate, reset handling, IRQ coalescing tracker, some init steps and the base and tpr set/get routines. For the latter, we also prepare set callbacks as KVM will override those.
--- Makefile.target | 2 +- hw/apic.c | 260 +++------------------------------------------------- hw/apic_common.c | 215 +++++++++++++++++++++++++++++++++++++++++++ hw/apic_internal.h | 108 ++++++++++++++++++++++ trace-events | 2 +- 5 files changed, 339 insertions(+), 248 deletions(-) create mode 100644 hw/apic_common.c create mode 100644 hw/apic_internal.h
Makefile.target +1 -1
@@ -226,7 +226,7 @@ obj-$(CONFIG_IVSHMEM) += ivshmem.o # Hardware support obj-i386-y += vga.o obj-i386-y += mc146818rtc.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_common.o apic.o ioapic.o piix_pci.o obj-i386-y += vmport.o obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o obj-i386-y += debugcon.o multiboot.o
hw/apic.c +14 -246
335 lines not on this page · raw message
hw/apic_common.c new file +215 -0
215 lines not on this page · raw message
hw/apic_internal.h new file +108 -0
108 lines not on this page · raw message
trace-events +1 -1
@@ -97,7 +97,7 @@ apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x" # coalescing apic_reset_irq_delivered(int apic_irq_delivered) "old coalescing %d" apic_get_irq_delivered(int apic_irq_delivered) "returning coalescing %d" -apic_set_irq(int apic_irq_delivered) "coalescing %d" +apic_set_irq_delivered(int apic_irq_delivered) "coalescing %d" # hw/cs4231.c cs4231_mem_readl_dreg(uint32_t reg, uint32_t ret) "read dreg %d: 0x%02x"
Signature · 1 line
1.7.3.4
PATCH v2 5/16 apic: Open-code timer save/restore
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
To enable migration between accelerated and non-accelerated APIC models, we will need to handle the timer saving and restoring specially and can no longer rely on the automatics of VMSTATE_TIMER. Specifically, accelerated model will not start any QEMUTimer.
This patch therefore factors out the generic bits into apic_next_timer and introduces a post-load callback that can be implemented differently by both models.
--- hw/apic.c | 30 ++++++++++++------------------ hw/apic_common.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- hw/apic_internal.h | 3 +++ 3 files changed, 64 insertions(+), 20 deletions(-)
hw/apic.c +12 -18
@@ -516,25 +516,9 @@ static uint32_t apic_get_current_count(APICState *s)static void apic_timer_update (APICState *s,int64_t current_time) { -int64_t next_time, d; - -if (!(s->lvt[APIC_LVT_TIMER ] &APIC_LVT_MASKED )) { - d = (current_time - s->initial_count_load_time) >> - s->count_shift; -if (s->lvt[APIC_LVT_TIMER ] &APIC_LVT_TIMER_PERIODIC ) { -if (!s->initial_count) - goto no_timer; - d = ((d / ((uint64_t )s->initial_count +1 )) +1 ) * ((uint64_t )s->initial_count +1 ); - }else { -if (d >= s->initial_count) - goto no_timer; - d = (uint64_t )s->initial_count +1 ; - } - next_time = s->initial_count_load_time + (d << s->count_shift); -qemu_mod_timer (s->timer, next_time); - s->next_time = next_time; +if (apic_next_timer (s, current_time)) { +qemu_mod_timer (s->timer, s->next_time); }else { - no_timer:qemu_del_timer (s->timer); } }
@@ -756,6 +740,15 @@ static const MemoryRegionOps apic_io_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +static void apic_post_load (APICState *s) +{ +if (s->timer_expiry !=-1 ) { +qemu_mod_timer (s->timer, s->timer_expiry); + }else { +qemu_del_timer (s->timer); + } +} +static int apic_init (SysBusDevice *dev) {APICState *s =FROM_SYSBUS (APICState, dev);
@@ -772,6 +765,7 @@ static int apic_init(SysBusDevice *dev) s->timer =qemu_new_timer_ns (vm_clock, apic_timer, s); s->set_base = apic_set_base; s->set_tpr = apic_set_tpr; + s->post_load = apic_post_load; local_apics[s->idx] = s;return 0 ; }
hw/apic_common.c +49 -2
81 lines not on this page · raw message
hw/apic_internal.h +3 -0
@@ -92,17 +92,20 @@ struct APICState {int64_t next_time;int idx;QEMUTimer *timer; +int64_t timer_expiry;int sipi_vector;int wait_for_sipi;void (*set_base)(APICState *s,uint64_t val);void (*set_tpr)(APICState *s,uint8_t val); + void (*post_load)(APICState *s); };extern const VMStateDescription vmstate_apic;int apic_init_common (APICState *s);void apic_reset (DeviceState *d); +bool apic_next_timer (APICState *s,int64_t current_time);void apic_set_irq_delivered (int delivered);#endif /* !QEMU_APIC_INTERNAL_H */
Signature · 1 line
1.7.3.4
PATCH v2 6/16 i8259: Factor out core for KVM reuse
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
Analogously to the APIC, we will reuse some parts of the user space i8259 model for KVM. In this case it is the PicState, vmstate description, a reset core and some init bits.
--- Makefile.objs | 2 +- hw/i8259.c | 78 +------------------------------------- hw/i8259_common.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++ hw/i8259_internal.h | 67 +++++++++++++++++++++++++++++++++ 4 files changed, 174 insertions(+), 76 deletions(-) create mode 100644 hw/i8259_common.c create mode 100644 hw/i8259_internal.h
Makefile.objs +1 -1
@@ -220,7 +220,7 @@ hw-obj-$(CONFIG_APPLESMC) += applesmc.o hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o ccid-card-passthru.o hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o hw-obj-$(CONFIG_USB_REDIR) += usb-redir.o -hw-obj-$(CONFIG_I8259) += i8259.o +hw-obj-$(CONFIG_I8259) += i8259_common.o i8259.o # PPC devices hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o
hw/i8259.c +3 -75
112 lines not on this page · raw message
hw/i8259_common.c new file +103 -0
103 lines not on this page · raw message
hw/i8259_internal.h new file +67 -0
67 lines not on this page · raw message
Signature · 1 line
1.7.3.4
PATCH v2 7/16 ioapic: Convert to memory API
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
This maintains the old imprecise access size handling.
--- hw/ioapic.c | 28 +++++++++++----------------- 1 files changed, 11 insertions(+), 17 deletions(-)
hw/ioapic.c +11 -17
@@ -86,6 +86,7 @@ typedef struct IOAPICState IOAPICState;struct IOAPICState {SysBusDevice busdev; +MemoryRegion io_memory;uint8_t id;uint8_t ioregsel;uint32_t irr;
@@ -195,7 +196,8 @@ void ioapic_eoi_broadcast(int vector) } } -static uint32_t ioapic_mem_readl (void *opaque,target_phys_addr_t addr) +static uint64_t +ioapic_mem_read (void *opaque,target_phys_addr_t addr,unsigned int size) {IOAPICState *s = opaque;int index;
@@ -234,7 +236,8 @@ static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr) }static void -ioapic_mem_writel (void *opaque,target_phys_addr_t addr,uint32_t val) +ioapic_mem_write (void *opaque,target_phys_addr_t addr,uint64_t val, +unsigned int size) {IOAPICState *s = opaque;int index;
@@ -309,32 +312,23 @@ static void ioapic_reset(DeviceState *d) } } -static CPUReadMemoryFunc *const ioapic_mem_read[3 ] = { - ioapic_mem_readl, - ioapic_mem_readl, - ioapic_mem_readl, -}; - -static CPUWriteMemoryFunc *const ioapic_mem_write[3 ] = { - ioapic_mem_writel, - ioapic_mem_writel, - ioapic_mem_writel, +static const MemoryRegionOps ioapic_io_ops = { + .read = ioapic_mem_read, + .write = ioapic_mem_write, + .endianness =DEVICE_NATIVE_ENDIAN , };static int ioapic_init1 (SysBusDevice *dev) {IOAPICState *s =FROM_SYSBUS (IOAPICState, dev); -int io_memory;static int ioapic_no;if (ioapic_no >=MAX_IOAPICS ) {return -1 ; } - io_memory =cpu_register_io_memory (ioapic_mem_read, - ioapic_mem_write, s, -DEVICE_NATIVE_ENDIAN ); -sysbus_init_mmio (dev,0x1000 , io_memory); +memory_region_init_io (&s->io_memory, &ioapic_io_ops, s,"ioapic" ,0x1000 ); +sysbus_init_mmio_region (dev, &s->io_memory);qdev_init_gpio_in (&dev->qdev, ioapic_set_irq,IOAPIC_NUM_PINS );
Signature · 1 line
1.7.3.4
PATCH v2 8/16 ioapic: Reject non-dword accesses to IOWIN register
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
Aligns the model with the spec.
--- hw/ioapic.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-)
hw/ioapic.c +6 -0
@@ -208,6 +208,9 @@ ioapic_mem_read(void *opaque, target_phys_addr_t addr, unsigned int size) val = s->ioregsel;break ;case IOAPIC_IOWIN : +if (size !=4 ) { +break ; + }switch (s->ioregsel) {case IOAPIC_REG_ID : val = s->id <<IOAPIC_ID_SHIFT ;
@@ -247,6 +250,9 @@ ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val, s->ioregsel = val;break ;case IOAPIC_IOWIN : +if (size !=4 ) { +break ; + }DPRINTF ("write: %08x = %08x\n" , s->ioregsel, val);switch (s->ioregsel) {case IOAPIC_REG_ID :
Signature · 1 line
1.7.3.4
PATCH v2 9/16 ioapic: Factor out core for KVM reuse
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
KVM will share the IOAPICState, the vmstate, the reset logic and certain init parts with the user space model.
--- Makefile.target | 2 +- hw/ioapic.c | 108 ++++--------------------------------------------- hw/ioapic_common.c | 89 +++++++++++++++++++++++++++++++++++++++++ hw/ioapic_internal.h | 93 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 192 insertions(+), 100 deletions(-) create mode 100644 hw/ioapic_common.c create mode 100644 hw/ioapic_internal.h
Makefile.target +1 -1
@@ -226,7 +226,7 @@ obj-$(CONFIG_IVSHMEM) += ivshmem.o # Hardware support obj-i386-y += vga.o obj-i386-y += mc146818rtc.o pc.o -obj-i386-y += cirrus_vga.o sga.o apic_common.o apic.o ioapic.o piix_pci.o +obj-i386-y += cirrus_vga.o sga.o apic_common.o apic.o ioapic_common.o ioapic.o piix_pci.o obj-i386-y += vmport.o obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o obj-i386-y += debugcon.o multiboot.o
hw/ioapic.c +9 -99
142 lines not on this page · raw message
hw/ioapic_common.c new file +89 -0
89 lines not on this page · raw message
hw/ioapic_internal.h new file +93 -0
93 lines not on this page · raw message
Signature · 1 line
1.7.3.4
PATCH v2 10/16 memory: Introduce memory_region_init_reservation
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
Introduce a memory region type that can reserve I/O space. Such regions are useful for modeling I/O that is only handled outside of QEMU, i.e. in the context of an accelerator like KVM.
Any access to such a region from QEMU is a bug, but could theoretically be triggered by guest code (DMA to reserved region). So only warning about such events once, then ignore them.
--- memory.c | 36 ++++++++++++++++++++++++++++++++++++ memory.h | 16 ++++++++++++++++ 2 files changed, 52 insertions(+), 0 deletions(-)
memory.c +36 -0
@@ -1003,6 +1003,42 @@ void memory_region_init_rom_device(MemoryRegion *mr, mr->backend_registered = true; } +static uint64_t invalid_read (void *opaque,target_phys_addr_t addr, +unsigned size) +{ +MemoryRegion *mr = opaque; + +if (!mr->warning_printed) { +fprintf (stderr,"Invalid read from memory region %s\n" , mr->name); + mr->warning_printed = true; + } +return -1U ; +} + +static void invalid_write (void *opaque,target_phys_addr_t addr,uint64_t data, +unsigned size) +{ +MemoryRegion *mr = opaque; + +if (!mr->warning_printed) { +fprintf (stderr,"Invalid write to memory region %s\n" , mr->name); + mr->warning_printed = true; + } +} + +static const MemoryRegionOps reservation_ops = { + .read = invalid_read, + .write = invalid_write, + .endianness =DEVICE_NATIVE_ENDIAN , +}; + +void memory_region_init_reservation (MemoryRegion *mr, +const char *name, +uint64_t size) +{ +memory_region_init_io (mr, &reservation_ops, mr, name, size); +} +void memory_region_destroy (MemoryRegion *mr) {assert (QTAILQ_EMPTY (&mr->subregions));
memory.h +16 -0
@@ -115,6 +115,7 @@ struct MemoryRegion {bool terminates;bool readable;bool readonly;/* For RAM regions */ +bool warning_printed;/* For reservations */ MemoryRegion *alias;target_phys_addr_t alias_offset;unsigned priority;
@@ -242,6 +243,21 @@ void memory_region_init_rom_device(MemoryRegion *mr, uint64_t size);/** +* memory_region_init_reservation: Initialize a memory region that reserves +* I/O space. +* +* A reservation region primariy serves debugging purposes. It claims I/O +* space that is not supposed to be handled by QEMU itself. Any access via +* the memory API will cause an abort(). +* +* @mr: the #MemoryRegion to be initialized +* @name: used for debugging; not visible to the user or ABI +* @size: size of the region. +*/ +void memory_region_init_reservation (MemoryRegion *mr, +const char *name, +uint64_t size); +/** * memory_region_destroy: Destroy a memory region and relaim all resources. * * @mr: the region to be destroyed. May not currently be a subregion
Signature · 1 line
1.7.3.4
PATCH v2 11/16 kvm: Introduce core services for in-kernel irqchip support
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
Add the basic infrastructure to active in-kernel irqchip support, inject interrupts into these models, and maintain IRQ routes.
Routing is optional and depends on the host arch supporting KVM_CAP_IRQ_ROUTING. When it's not available on x86, we looe the HPET as we can't route GSI0 to IOAPIC pin 2.
In-kernel irqchip support will once be controlled by the machine property 'kernel_irqchip', but this is not yet wired up.
--- kvm-all.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++ kvm.h | 8 +++ target-i386/kvm.c | 11 ++++ 3 files changed, 168 insertions(+), 0 deletions(-)
kvm-all.c +149 -0
@@ -76,6 +76,13 @@ struct KVMStateint pit_in_kernel;int xsave, xcrs;int many_ioeventfds; +int irqchip_inject_ioctl; +#ifdef KVM_CAP_IRQ_ROUTING +struct kvm_irq_routing *irq_routes; +int nr_allocated_irq_routes; +uint32_t *used_gsi_bitmap; +unsigned int max_gsi; +#endif };KVMState *kvm_state;
@@ -692,6 +699,138 @@ static void kvm_handle_interrupt(CPUState *env, int mask) } } +int kvm_irqchip_set_irq (KVMState *s,int irq,int level) +{ +struct kvm_irq_level event; +int ret; + +assert (s->irqchip_in_kernel); + + event.level = level; + event.irq = irq; + ret =kvm_vm_ioctl (s, s->irqchip_inject_ioctl, &event); +if (ret <0 ) { +perror ("kvm_set_irqchip_line" ); +abort (); + } + +return (s->irqchip_inject_ioctl ==KVM_IRQ_LINE ) ?1 : event.status; +} + +#ifdef KVM_CAP_IRQ_ROUTING +static void set_gsi (KVMState *s,unsigned int gsi) +{ +assert (gsi < s->max_gsi); + + s->used_gsi_bitmap[gsi /32 ] |=1U << (gsi %32 ); +} + +static void kvm_init_irq_routing (KVMState *s) +{ +int gsi_count; + + gsi_count =kvm_check_extension (s,KVM_CAP_IRQ_ROUTING ); +if (gsi_count >0 ) { +unsigned int gsi_bits, i; + +/* Round up so we can search ints using ffs */ + gsi_bits = (gsi_count +31 ) /32 ; + s->used_gsi_bitmap =g_malloc0 (gsi_bits /8 ); + s->max_gsi = gsi_bits; + +/* Mark any over-allocated bits as already in use */ +for (i = gsi_count; i < gsi_bits; i++) { +set_gsi (s, i); + } + } + + s->irq_routes =g_malloc0 (sizeof (*s->irq_routes)); + s->nr_allocated_irq_routes =0 ; + +kvm_arch_init_irq_routing (s); +} + +static void kvm_add_routing_entry (KVMState *s, +struct kvm_irq_routing_entry *entry) +{ +struct kvm_irq_routing_entry *new; +int n, size; + +if (s->irq_routes->nr == s->nr_allocated_irq_routes) { + n = s->nr_allocated_irq_routes *2 ; +if (n <64 ) { + n =64 ; + } + size =sizeof (struct kvm_irq_routing ); + size += n *sizeof (*new); + s->irq_routes =g_realloc (s->irq_routes, size); + s->nr_allocated_irq_routes = n; + } + n = s->irq_routes->nr++; + new = &s->irq_routes->entries[n]; +memset (new,0 ,sizeof (*new)); + new->gsi = entry->gsi; + new->type = entry->type; + new->flags = entry->flags; + new->u = entry->u; + +set_gsi (s, entry->gsi); +} + +void kvm_irqchip_add_route (KVMState *s,int irq,int irqchip,int pin) +{ +struct kvm_irq_routing_entry e; + + e.gsi = irq; + e.type =KVM_IRQ_ROUTING_IRQCHIP ; + e.flags =0 ; + e.u.irqchip.irqchip = irqchip; + e.u.irqchip.pin = pin; +kvm_add_routing_entry (s, &e); +} + +int kvm_irqchip_commit_routes (KVMState *s) +{ + s->irq_routes->flags =0 ; +return kvm_vm_ioctl (s,KVM_SET_GSI_ROUTING , s->irq_routes); +} + +#else /* !KVM_CAP_IRQ_ROUTING */ + +static void kvm_init_irq_routing (KVMState *s) +{ +} +#endif /* !KVM_CAP_IRQ_ROUTING */ + +static int kvm_irqchip_create (KVMState *s) +{ +QemuOptsList *list =qemu_find_opts ("machine" ); +int ret; + +if (QTAILQ_EMPTY (&list->head) || + !qemu_opt_get_bool (QTAILQ_FIRST (&list->head), +"kernel_irqchip" , false) || + !kvm_check_extension (s,KVM_CAP_IRQCHIP )) { +return 0 ; + } + + ret =kvm_vm_ioctl (s,KVM_CREATE_IRQCHIP ); +if (ret <0 ) { +fprintf (stderr,"Create kernel irqchip failed\n" ); +return ret; + } + + s->irqchip_inject_ioctl =KVM_IRQ_LINE ; +if (kvm_check_extension (s,KVM_CAP_IRQ_INJECT_STATUS )) { + s->irqchip_inject_ioctl =KVM_IRQ_LINE_STATUS ; + } + s->irqchip_in_kernel =1 ; + +kvm_init_irq_routing (s); + +return 0 ; +} +int kvm_init (void ) { static const char upgrade_note[] =
@@ -786,6 +925,11 @@ int kvm_init(void) goto err; } + ret =kvm_irqchip_create (s); +if (ret <0 ) { + goto err; + } + kvm_state = s;cpu_register_phys_memory_client (&kvm_cpu_phys_memory_client);
@@ -1111,6 +1255,11 @@ int kvm_has_many_ioeventfds(void)return kvm_state->many_ioeventfds; } +int kvm_has_gsi_routing (void ) +{ +return kvm_check_extension (kvm_state,KVM_CAP_IRQ_ROUTING ); +} +void kvm_setup_guest_memory (void *start,size_t size) {if (!kvm_has_sync_mmu ()) {
kvm.h +8 -0
@@ -51,6 +51,7 @@ int kvm_has_debugregs(void);int kvm_has_xsave (void );int kvm_has_xcrs (void );int kvm_has_many_ioeventfds (void ); +int kvm_has_gsi_routing (void );#ifdef NEED_CPU_H int kvm_init_vcpu (CPUState *env);
@@ -124,6 +125,13 @@ void kvm_arch_reset_vcpu(CPUState *env);int kvm_arch_on_sigbus_vcpu (CPUState *env,int code,void *addr);int kvm_arch_on_sigbus (int code,void *addr); +void kvm_arch_init_irq_routing (KVMState *s); + +int kvm_irqchip_set_irq (KVMState *s,int irq,int level); + +void kvm_irqchip_add_route (KVMState *s,int gsi,int irqchip,int pin); +int kvm_irqchip_commit_routes (KVMState *s); +struct kvm_guest_debug ;struct kvm_debug_exit_arch ;
target-i386/kvm.c +11 -0
@@ -1864,3 +1864,14 @@ bool kvm_arch_stop_on_emulation_error(CPUState *env)return !(env->cr[0 ] &CR0_PE_MASK ) || ((env->segs[R_CS ].selector &3 ) !=3 ); } + +void kvm_arch_init_irq_routing (KVMState *s) +{ +if (!kvm_check_extension (s,KVM_CAP_IRQ_ROUTING )) { +/* If kernel can't do irq routing, interrupt source +* override 0->2 cannot be set up as required by HPET. +* So we have to disable it. +*/ + no_hpet =1 ; + } +}
Signature · 1 line
1.7.3.4
PATCH v2 12/16 kvm: x86: Establish IRQ0 override control
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
KVM is forced to disable the IRQ0 override when we run with in-kernel irqchip but without IRQ routing support of the kernel. Set the fwcfg value correspondingly. This aligns us with qemu-kvm.
--- hw/pc.c | 3 ++- kvm-all.c | 5 +++++ kvm-stub.c | 5 +++++ kvm.h | 2 ++ sysemu.h | 1 - vl.c | 1 - 6 files changed, 14 insertions(+), 3 deletions(-)
hw/pc.c +2 -1
@@ -39,6 +39,7 @@#include "msi.h" #include "sysbus.h" #include "sysemu.h" +#include "kvm.h" #include "blockdev.h" #include "ui/qemu-spice.h" #include "memory.h"
@@ -609,7 +610,7 @@ static void *bochs_bios_init(void)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, 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);if (smbios_table)
kvm-all.c +5 -0
@@ -1260,6 +1260,11 @@ int kvm_has_gsi_routing(void)return kvm_check_extension (kvm_state,KVM_CAP_IRQ_ROUTING ); } +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) {if (!kvm_has_sync_mmu ()) {
kvm-stub.c +5 -0
@@ -78,6 +78,11 @@ int kvm_has_many_ioeventfds(void)return 0 ; } +int kvm_allows_irq0_override (void ) +{ +return 1 ; +} +void kvm_setup_guest_memory (void *start,size_t size) { }
kvm.h +2 -0
@@ -53,6 +53,8 @@ int kvm_has_xcrs(void);int kvm_has_many_ioeventfds (void );int kvm_has_gsi_routing (void ); +int kvm_allows_irq0_override (void ); +#ifdef NEED_CPU_H int kvm_init_vcpu (CPUState *env);
sysemu.h +0 -1
@@ -102,7 +102,6 @@ extern int vga_interface_type;extern int graphic_width;extern int graphic_height;extern int graphic_depth; -extern uint8_t irq0override;extern DisplayType display_type;extern const char *keyboard_layout;extern int win2k_install_hack;
vl.c +0 -1
@@ -218,7 +218,6 @@ int no_reboot = 0;int no_shutdown =0 ;int cursor_hide =1 ;int graphic_rotate =0 ; -uint8_t irq0override =1 ;const char *watchdog;QEMUOptionRom option_rom[MAX_OPTION_ROMS ];int nb_option_roms;
Signature · 1 line
1.7.3.4
PATCH v2 13/16 kvm: x86: Add user space part for in-kernel APIC
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
This introduces the alternative APIC model 'kvm-apic' which makes use of KVM's in-kernel device model. MSI is not yet supported, so we disable this when the in-kernel model is in use.
--- Makefile.target | 2 +- hw/kvm/apic.c | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pc.c | 15 ++++-- kvm.h | 3 + target-i386/kvm.c | 8 +++ 5 files changed, 169 insertions(+), 6 deletions(-) create mode 100644 hw/kvm/apic.c
Makefile.target +1 -1
@@ -231,7 +231,7 @@ obj-i386-y += vmport.o obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o obj-i386-y += debugcon.o multiboot.o obj-i386-y += pc_piix.o -obj-i386-$(CONFIG_KVM) += kvm/clock.o +obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o # shared objects
hw/kvm/apic.c new file +147 -0
147 lines not on this page · raw message
hw/pc.c +10 -5
@@ -879,25 +879,30 @@ DeviceState *cpu_get_current_apic(void)static DeviceState *apic_init (void *env,uint8_t apic_id) {DeviceState *dev; -SysBusDevice *d;static int apic_mapped; - dev =qdev_create (NULL ,"apic" ); +if (kvm_enabled () &&kvm_irqchip_in_kernel ()) { + dev =qdev_create (NULL ,"kvm-apic" ); + }else { + dev =qdev_create (NULL ,"apic" ); + }qdev_prop_set_uint8 (dev,"id" , apic_id);qdev_prop_set_ptr (dev,"cpu_env" , env);qdev_init_nofail (dev); - d =sysbus_from_qdev (dev);/* XXX: mapping more APICs at the same memory location */ if (apic_mapped ==0 ) {/* NOTE: the APIC is directly connected to the CPU - it is not on the global memory bus. */ /* XXX: what if the base changes? */ -sysbus_mmio_map (d,0 ,MSI_ADDR_BASE ); +sysbus_mmio_map (sysbus_from_qdev (dev),0 ,MSI_ADDR_BASE ); apic_mapped =1 ; } - msi_supported = true; +/* KVM does not support MSI yet. */ +if (!kvm_enabled () || !kvm_irqchip_in_kernel ()) { + msi_supported = true; + }return dev; }
kvm.h +3 -0
@@ -134,6 +134,9 @@ int kvm_irqchip_set_irq(KVMState *s, int irq, int level);void kvm_irqchip_add_route (KVMState *s,int gsi,int irqchip,int pin);int kvm_irqchip_commit_routes (KVMState *s); +int kvm_put_apic (CPUState *env); +int kvm_get_apic (CPUState *env); +struct kvm_guest_debug ;struct kvm_debug_exit_arch ;
target-i386/kvm.c +8 -0
@@ -1435,6 +1435,10 @@ int kvm_arch_put_registers(CPUState *env, int level)if (ret <0 ) {return ret; } + ret =kvm_put_apic (env); +if (ret <0 ) { +return ret; + } } ret =kvm_put_vcpu_events (env, level);if (ret <0 ) {
@@ -1482,6 +1486,10 @@ int kvm_arch_get_registers(CPUState *env)if (ret <0 ) {return ret; } + ret =kvm_get_apic (env); +if (ret <0 ) { +return ret; + } ret =kvm_get_vcpu_events (env);if (ret <0 ) {return ret;
Signature · 1 line
1.7.3.4
PATCH v2 14/16 kvm: x86: Add user space part for in-kernel i8259
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
Introduce the alternative 'kvm-i8259' device model that exploits KVM in-kernel acceleration.
The PIIX3 initialization code is furthermore extended by KVM specific IRQ route setup. Moreover, GSI injection differs in KVM mode from the user space model. As we can dispatch ISA-range IRQs to both IOAPIC and PIC inside the kernel, we do not need to inject them separately. This is reflected by a KVM-specific GSI handler.
--- Makefile.target | 2 +- hw/kvm/i8259.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pc.h | 1 + hw/pc_piix.c | 50 ++++++++++++++++-- 4 files changed, 202 insertions(+), 5 deletions(-) create mode 100644 hw/kvm/i8259.c
Makefile.target +1 -1
@@ -231,7 +231,7 @@ obj-i386-y += vmport.o obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o obj-i386-y += debugcon.o multiboot.o obj-i386-y += pc_piix.o -obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o +obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o # shared objects
hw/kvm/i8259.c new file +154 -0
154 lines not on this page · raw message
hw/pc.h +1 -0
@@ -63,6 +63,7 @@ bool parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,typedef struct PicState PicState ;extern PicState *isa_pic;qemu_irq *i8259_init (qemu_irq parent_irq); +qemu_irq *kvm_i8259_init (void );int pic_read_irq (PicState *s);int pic_get_output (PicState *s);void pic_info (Monitor *mon);
hw/pc_piix.c +46 -4
70 lines not on this page · raw message
Signature · 1 line
1.7.3.4
PATCH v2 15/16 kvm: x86: Add user space part for in-kernel IOAPIC
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
This introduces the KVM-accelerated IOAPIC model 'kvm-ioapic' and extends the IRQ routing setup by the 0->2 redirection when needed.
The kvm-ioapic model has a property that allows to define its GSI base for injecting interrupts into the kernel model. This will allow to disentangle PIC and IOAPIC pins for chipsets that support more sophisticated IRQ routes than the PIIX3. So far the base is kept at 0, i.e. PIC and IOAPIC share pins 0..15.
--- Makefile.target | 2 +- hw/ioapic_internal.h | 1 + hw/kvm/ioapic.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++ hw/pc_piix.c | 15 ++++++- 4 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 hw/kvm/ioapic.c
Makefile.target +1 -1
@@ -231,7 +231,7 @@ obj-i386-y += vmport.o obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o obj-i386-y += debugcon.o multiboot.o obj-i386-y += pc_piix.o -obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o +obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o # shared objects
hw/ioapic_internal.h +1 -0
@@ -83,6 +83,7 @@ struct IOAPICState {void (*pre_save)(IOAPICState *s);void (*post_load)(IOAPICState *s); +uint32_t kvm_gsi_base; };extern const VMStateDescription vmstate_ioapic;
hw/kvm/ioapic.c new file +120 -0
120 lines not on this page · raw message
hw/pc_piix.c +14 -1
@@ -68,6 +68,15 @@ static void kvm_piix3_setup_irq_routing(bool pci_enabled)for (i =8 ; i <16 ; ++i) {kvm_irqchip_add_route (s, i,KVM_IRQCHIP_PIC_SLAVE , i -8 ); } +if (pci_enabled) { +for (i =0 ; i <24 ; ++i) { +if (i ==0 ) { +kvm_irqchip_add_route (s, i,KVM_IRQCHIP_IOAPIC ,2 ); + }else if (i !=2 ) { +kvm_irqchip_add_route (s, i,KVM_IRQCHIP_IOAPIC , i); + } + } + } ret =kvm_irqchip_commit_routes (s);if (ret <0 ) {hw_error ("KVM IRQ routing setup failed" );
@@ -93,7 +102,11 @@ static void ioapic_init(GSIState *gsi_state)SysBusDevice *d;unsigned int i; - dev =qdev_create (NULL ,"ioapic" ); +if (kvm_enabled () &&kvm_irqchip_in_kernel ()) { + dev =qdev_create (NULL ,"kvm-ioapic" ); + }else { + dev =qdev_create (NULL ,"ioapic" ); + }qdev_init_nofail (dev); d =sysbus_from_qdev (dev);sysbus_mmio_map (d,0 ,0xfec00000 );
Signature · 1 line
1.7.3.4
PATCH v2 16/16 kvm: Arm in-kernel irqchip support
In reply to Jan KiszkaFrom: Jan Kiszka <[email protected]>
Make the basic in-kernel irqchip support selectable via -machine ...,kernel_irqchip=on. Leave it off by default until it can fully replace user space models.
--- qemu-config.c | 4 ++++ qemu-options.hx | 5 ++++- 2 files changed, 8 insertions(+), 1 deletions(-)
qemu-config.c +4 -0
@@ -483,6 +483,10 @@ static QemuOptsList qemu_machine_opts = { .name = "accel", .type = QEMU_OPT_STRING, .help = "accelerator list", + }, { + .name = "kernel_irqchip", + .type = QEMU_OPT_BOOL, + .help = "use KVM in-kernel irqchip", }, {/* End of list */ } },
qemu-options.hx +4 -1
@@ -31,7 +31,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \ "-machine [type=]name[,prop[=value][,...]]\n" " selects emulated machine (-machine ? for list)\n" " property accel=accel1[:accel2[:...]] selects accelerator\n" - " supported accelerators are kvm, xen, tcg (default: tcg)\n", + " supported accelerators are kvm, xen, tcg (default: tcg)\n" + " kernel_irqchip=on|off controls accelerated irqchip support\n", QEMU_ARCH_ALL) STEXI @item -machine [type=]@var{name}[,prop=@var{value}[,...]]
@@ -44,6 +45,8 @@ This is used to enable an accelerator. Depending on the target architecture, kvm, xen, or tcg can be available. By default, tcg is used. If there is more than one accelerator specified, the next one is used if the previous one fails to initialize. +@item kernel_irqchip=on|off +Enables in-kernel irqchip support for the chosen accelerator when available. @end table ETEXI
Signature · 1 line
1.7.3.4