Re: [PATCH 2/4] kvmtool: ARM: allow level interrupts in device tree
Hi, On 11/12/14 17:15, Will Deacon wrote: On Thu, Dec 11, 2014 at 04:30:33PM +, Andre Przywara wrote: Currently we describe every interrupt for each device in the FDT as being edge triggered. Add a parameter to the irq property generation to allow devices to specify their interrupts as level triggered if needed. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- tools/kvm/arm/fdt.c|6 +++--- tools/kvm/hw/serial.c |5 +++-- tools/kvm/include/kvm/ioport.h |4 +++- tools/kvm/ioport.c |6 -- tools/kvm/virtio/mmio.c|5 +++-- 5 files changed, 16 insertions(+), 10 deletions(-) [...] @@ -71,7 +72,8 @@ static void generate_ioport_fdt_node(void *fdt, static void generate_ioport_fdt_node(void *fdt, struct device_header *dev_hdr, void (*generate_irq_prop)(void *fdt, - u8 irq)) + u8 irq, + u32 irq_type)) { die(Unable to generate device tree nodes without libfdt\n); } diff --git a/tools/kvm/virtio/mmio.c b/tools/kvm/virtio/mmio.c index 3a2bd62..28b0651 100644 --- a/tools/kvm/virtio/mmio.c +++ b/tools/kvm/virtio/mmio.c @@ -233,7 +233,8 @@ static void virtio_mmio_mmio_callback(struct kvm_cpu *vcpu, static void generate_virtio_mmio_fdt_node(void *fdt, struct device_header *dev_hdr, void (*generate_irq_prop)(void *fdt, -u8 irq)) +u8 irq, +u32 type)) { char dev_name[DEVICE_NAME_MAX_LEN]; struct virtio_mmio *vmmio = container_of(dev_hdr, @@ -250,7 +251,7 @@ static void generate_virtio_mmio_fdt_node(void *fdt, _FDT(fdt_begin_node(fdt, dev_name)); _FDT(fdt_property_string(fdt, compatible, virtio,mmio)); _FDT(fdt_property(fdt, reg, reg_prop, sizeof(reg_prop))); -generate_irq_prop(fdt, vmmio-irq); +generate_irq_prop(fdt, vmmio-irq, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI); This is a GIC-specific #define in arch-agnostic code. I think we should have a new enum type for describing edge and level interrupts, then just use that instead. Right, good point. I dug a bit in the kernel source, and actually those values behind the defines are not GIC specific, but are generic IRQ FDT values (used by other architectures as well). Even the GIC driver source uses these defines, it's just the GICv3 binding doc that speaks of those specific numbers. So if you don't mind, I will remove the GIC_FDT_IRQ_FLAGS_{LEVEL,EDGE} defines from kvmtool's headers and use the generic defines from the kernel in one of the fdt headers. Cheers, Andre. -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/4] kvmtool: remove warning about bzImage on non-x86 architectures
Among the architectures supported by kvmtool, only x86 defines a bzImage format. So we shouldn't bother users of other architectures with a message about something that cannot work. Make the bzImage check dependent on compiling for x86. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- tools/kvm/kvm.c |5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/kvm/kvm.c b/tools/kvm/kvm.c index e1b9f6c..21817c3 100644 --- a/tools/kvm/kvm.c +++ b/tools/kvm/kvm.c @@ -380,12 +380,15 @@ bool kvm__load_kernel(struct kvm *kvm, const char *kernel_filename, die(%s is not an initrd, initrd_filename); } +#ifdef CONFIG_X86 ret = load_bzimage(kvm, fd_kernel, fd_initrd, kernel_cmdline); if (ret) goto found_kernel; - pr_warning(%s is not a bzImage. Trying to load it as a flat binary..., kernel_filename); + pr_warning(%s is not a bzImage. Trying to load it as an ELF or flat binary..., + kernel_filename); +#endif ret = load_elf_binary(kvm, fd_kernel, fd_initrd, kernel_cmdline); -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/4] kvmtool: ARM: allow level interrupts in device tree
Currently we describe every interrupt for each device in the FDT as being edge triggered. Add a parameter to the irq property generation to allow devices to specify their interrupts as level triggered if needed. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- tools/kvm/arm/fdt.c|6 +++--- tools/kvm/hw/serial.c |5 +++-- tools/kvm/include/kvm/ioport.h |4 +++- tools/kvm/ioport.c |6 -- tools/kvm/virtio/mmio.c|5 +++-- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/tools/kvm/arm/fdt.c b/tools/kvm/arm/fdt.c index 4a33846..918d89f 100644 --- a/tools/kvm/arm/fdt.c +++ b/tools/kvm/arm/fdt.c @@ -74,12 +74,12 @@ static void generate_cpu_nodes(void *fdt, struct kvm *kvm) _FDT(fdt_end_node(fdt)); } -static void generate_irq_prop(void *fdt, u8 irq) +static void generate_irq_prop(void *fdt, u8 irq, u32 irq_type) { u32 irq_prop[] = { cpu_to_fdt32(GIC_FDT_IRQ_TYPE_SPI), cpu_to_fdt32(irq - GIC_SPI_IRQ_BASE), - cpu_to_fdt32(GIC_FDT_IRQ_FLAGS_EDGE_LO_HI), + cpu_to_fdt32(irq_type) }; _FDT(fdt_property(fdt, interrupts, irq_prop, sizeof(irq_prop))); @@ -127,7 +127,7 @@ static int setup_fdt(struct kvm *kvm) void *fdt_dest = guest_flat_to_host(kvm, kvm-arch.dtb_guest_start); void (*generate_mmio_fdt_nodes)(void *, struct device_header *, - void (*)(void *, u8)); + void (*)(void *, u8, u32)); void (*generate_cpu_peripheral_fdt_nodes)(void *, struct kvm *, u32) = kvm-cpus[0]-generate_fdt_nodes; diff --git a/tools/kvm/hw/serial.c b/tools/kvm/hw/serial.c index 60147de..266863b 100644 --- a/tools/kvm/hw/serial.c +++ b/tools/kvm/hw/serial.c @@ -369,7 +369,8 @@ static bool serial8250_in(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, #define DEVICE_NAME_MAX_LEN 32 static void serial8250_generate_fdt_node(struct ioport *ioport, void *fdt, void (*generate_irq_prop)(void *fdt, - u8 irq)) + u8 irq, + u32 type)) { char dev_name[DEVICE_NAME_MAX_LEN]; struct serial8250_device *dev = ioport-priv; @@ -384,7 +385,7 @@ static void serial8250_generate_fdt_node(struct ioport *ioport, void *fdt, _FDT(fdt_begin_node(fdt, dev_name)); _FDT(fdt_property_string(fdt, compatible, ns16550a)); _FDT(fdt_property(fdt, reg, reg_prop, sizeof(reg_prop))); - generate_irq_prop(fdt, dev-irq); + generate_irq_prop(fdt, dev-irq, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI); _FDT(fdt_property_cell(fdt, clock-frequency, 1843200)); _FDT(fdt_end_node(fdt)); } diff --git a/tools/kvm/include/kvm/ioport.h b/tools/kvm/include/kvm/ioport.h index 18da47c..ffd938d 100644 --- a/tools/kvm/include/kvm/ioport.h +++ b/tools/kvm/include/kvm/ioport.h @@ -31,7 +31,9 @@ struct ioport_operations { bool (*io_in)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size); bool (*io_out)(struct ioport *ioport, struct kvm_cpu *vcpu, u16 port, void *data, int size); void (*generate_fdt_node)(struct ioport *ioport, void *fdt, - void (*generate_irq_prop)(void *fdt, u8 irq)); + void (*generate_irq_prop)(void *fdt, + u8 irq, + u32 irq_type)); }; void ioport__setup_arch(struct kvm *kvm); diff --git a/tools/kvm/ioport.c b/tools/kvm/ioport.c index 5bfb7e2..b507cab 100644 --- a/tools/kvm/ioport.c +++ b/tools/kvm/ioport.c @@ -59,7 +59,8 @@ static void ioport_remove(struct rb_root *root, struct ioport *data) static void generate_ioport_fdt_node(void *fdt, struct device_header *dev_hdr, void (*generate_irq_prop)(void *fdt, - u8 irq)) + u8 irq, + u32 irq_type)) { struct ioport *ioport = container_of(dev_hdr, struct ioport, dev_hdr); struct ioport_operations *ops = ioport-ops; @@ -71,7 +72,8 @@ static void generate_ioport_fdt_node(void *fdt, static void generate_ioport_fdt_node(void *fdt, struct device_header *dev_hdr, void (*generate_irq_prop)(void *fdt, - u8 irq
[PATCH 3/4] kvmtool: ARM: advertise 8250 IRQs as level-triggered
Both the 16550/8250 UART emulation in kvmtool as well as all the drivers and DTBs for real hardware use level triggered interrupts. But the device tree currently describes them as being edge triggered, which can lead to hangs in guests. Use the new IRQ type parameter to properly describe the interrupts. This goes along the lines of a similar QEMU patch: http://git.qemu.org/?p=qemu.git;a=commitdiff;h=0be969a2d974971628fc4ed95834d22ecf0fd497 Signed-off-by: Andre Przywara andre.przyw...@arm.com --- tools/kvm/hw/serial.c |2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/kvm/hw/serial.c b/tools/kvm/hw/serial.c index 266863b..f223802 100644 --- a/tools/kvm/hw/serial.c +++ b/tools/kvm/hw/serial.c @@ -385,7 +385,7 @@ static void serial8250_generate_fdt_node(struct ioport *ioport, void *fdt, _FDT(fdt_begin_node(fdt, dev_name)); _FDT(fdt_property_string(fdt, compatible, ns16550a)); _FDT(fdt_property(fdt, reg, reg_prop, sizeof(reg_prop))); - generate_irq_prop(fdt, dev-irq, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI); + generate_irq_prop(fdt, dev-irq, GIC_FDT_IRQ_FLAGS_LEVEL_HI); _FDT(fdt_property_cell(fdt, clock-frequency, 1843200)); _FDT(fdt_end_node(fdt)); } -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/4] kvmtool: ARM: fix initrd functionality
lkvm -i is currently broken on ARM/ARM64. We should not try to convert smaller-than-4GB addresses into 64-bit big endian and then stuff them into u32 variables if we expect to read anything other than 0 out of it. Adjust the type to u64 to write the proper address in BE format into the /chosen node (and also match the address size we formely posted) and let Linux thus read the right values. This fixes initrd functionality for ARM and ARM64 guests. Signed-off-by: Andre Przywara andre.przyw...@arm.com Acked-by: Marc Zyngier marc.zyng...@arm.com --- tools/kvm/arm/fdt.c |4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/kvm/arm/fdt.c b/tools/kvm/arm/fdt.c index 5626931..4a33846 100644 --- a/tools/kvm/arm/fdt.c +++ b/tools/kvm/arm/fdt.c @@ -149,8 +149,8 @@ static int setup_fdt(struct kvm *kvm) /* Initrd */ if (kvm-arch.initrd_size != 0) { - u32 ird_st_prop = cpu_to_fdt64(kvm-arch.initrd_guest_start); - u32 ird_end_prop = cpu_to_fdt64(kvm-arch.initrd_guest_start + + u64 ird_st_prop = cpu_to_fdt64(kvm-arch.initrd_guest_start); + u64 ird_end_prop = cpu_to_fdt64(kvm-arch.initrd_guest_start + kvm-arch.initrd_size); _FDT(fdt_property(fdt, linux,initrd-start, -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/4] kvmtool: ARM: fixing initrd, serial IRQs and bzImage message
Hi, dumping a part of my kvmtool patch queue here. Patch 1 (fixing initrd for ARM) was already on the list, but hasn't been merged yet. Patch 2 and 3 let kvmtool describe the 8250 serial IRQs as level triggered and fix a stability problem. Patch 4 is an easy fix for a message that annoys me every time ;-) Cheers, Andre. Andre Przywara (4): kvmtool: ARM: fix initrd functionality kvmtool: ARM: allow level interrupts in device tree kvmtool: ARM: advertise 8250 IRQs as level-triggered kvmtool: remove warning about bzImage on non-x86 architectures tools/kvm/arm/fdt.c| 10 +- tools/kvm/hw/serial.c |5 +++-- tools/kvm/include/kvm/ioport.h |4 +++- tools/kvm/ioport.c |6 -- tools/kvm/kvm.c|5 - tools/kvm/virtio/mmio.c|5 +++-- 6 files changed, 22 insertions(+), 13 deletions(-) -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] arm/arm64: vgic: Remove unreachable irq_clear_pending
Hej Christoffer, On 24/11/14 09:41, Christoffer Dall wrote: When 'injecting' an edge-triggered interrupt with a falling edge we shouldn't clear the pending state on the distributor. In fact, we don't, because the check in vgic_validate_injection would prevent us from ever reaching this bit of code. Remove the unreachable snippet. Signed-off-by: Christoffer Dall christoffer.d...@linaro.org Acked-by: Andre Przywara andre.przyw...@arm.com I agree on this. Would it make sense to rewrite this function a bit to make it more clearer what happens? I find the nesting of the if-statements counter-intuitive: I'd prefer to first differentiate between level and edge triggered and then only check the actual level in the level-triggered branch. Not sure if it's worth the fuss, though. Cheers, Andre. --- virt/kvm/arm/vgic.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 3aaca49..f45cf16 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -1643,8 +1643,6 @@ static bool vgic_update_irq_pending(struct kvm *kvm, int cpuid, vgic_dist_irq_clear_level(vcpu, irq_num); if (!vgic_dist_irq_soft_pend(vcpu, irq_num)) vgic_dist_irq_clear_pending(vcpu, irq_num); - } else { - vgic_dist_irq_clear_pending(vcpu, irq_num); } } -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4 0/3] irqfd support for arm/arm64
Hi, On 24/11/14 10:10, Eric Auger wrote: On 11/24/2014 10:47 AM, Christoffer Dall wrote: On Sun, Nov 23, 2014 at 06:56:57PM +0100, Eric Auger wrote: This patch series enables irqfd on arm and arm64. Irqfd framework enables to inject a virtual IRQ into a guest upon an eventfd trigger. User-side uses KVM_IRQFD VM ioctl to provide KVM with a kvm_irqfd struct that associates a VM, an eventfd, a virtual IRQ number (aka. the gsi). When an actor signals the eventfd (typically a VFIO platform driver), the kvm irqfd subsystem injects the gsi into the VM. Resamplefd also is supported for level sensitive interrupts, ie. the user can provide another eventfd that is triggered when the completion of the virtual IRQ (gsi) is detected by the GIC. The gsi must correspond to a shared peripheral interrupt (SPI), ie the GIC interrupt ID is gsi + 32. The rationale behind not supporting PPI irqfd injection is that any device using a PPI would be a private-to-the-CPU device (timer for instance), so its state would have to be context-switched along with the VCPU and would require in-kernel wiring anyhow. It is not a relevant use case for irqfds. this patch enables CONFIG_HAVE_KVM_EVENTFD and CONFIG_HAVE_KVM_IRQFD. No IRQ routing table is used, enabling to remove CONFIG_HAVE_KVM_IRQCHIP can be found at git://git.linaro.org/people/eric.auger/linux.git on branch irqfd_integ_v8 This work was tested with Calxeda Midway xgmac main interrupt with qemu-system-arm and QEMU VFIO platform device. Also irqfd was proven functional on several vhost-net prototypes. v3 - v4: - rebase on 3.18rc5 - vgic dynamic instantiation brought new challenges: handling of irqfd injection when vgic is not ready - unset of CONFIG_HAVE_KVM_IRQCHIP in a separate patch - add arm64 enable - vgic.c style modifications according to Christoffer comments There also seems to be a different split of the patches here? Hi Christoffer, yes I added arm64b support and moved CONFIG_HAVE_KVM_IRQCHIP removal in a separate patch. We've probably also reached the point where you need to start rebasing on Andre's GICv3 patches, which I expect will go in first. the patch applies without conflict on Andre's series. Yes, I can confirm this. I also manually checked the patches to spot any fallouts due to the vgic.c file split, but Eric's patches are not affected by this. Cheers, Andre. BR Eric Thanks, -Christoffer ___ kvmarm mailing list kvm...@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH 1/4] ARM: KVM: on unhandled IO mem abort, route the call to the KVM MMIO bus
Hi Nikolay, On 13/11/14 11:37, Marc Zyngier wrote: [fixing Andre's email address] On 13/11/14 11:20, Christoffer Dall wrote: On Thu, Nov 13, 2014 at 12:45:42PM +0200, Nikolay Nikolaev wrote: [...] Going through the vgic_handle_mmio we see that it will require large refactoring: - there are 15 MMIO ranges for the vgic now - each should be registered as a separate device - the handler of each range should be split into read and write - all handlers take 'struct kvm_exit_mmio', and pass it to 'vgic_reg_access', 'mmio_data_read' and 'mmio_data_read' To sum up - if we do this refactoring of vgic's MMIO handling + kvm_io_bus_ API getting 'vcpu argument we'll get a 'much' cleaner vgic code and as a bonus we'll get 'ioeventfd' capabilities. We have 3 questions: - is the kvm_io_bus_ getting 'vcpu' argument acceptable for the other architectures too? - is this huge vgic MMIO handling redesign acceptable/desired (it touches a lot of code)? - is there a way that ioeventfd is accepted leaving vgic.c in it's current state? Not sure how the latter question is relevant to this, but check with Andre who recently looked at this as well and decided that for GICv3 the only sane thing was to remove that comment for the gic. @Andre - what's your experience with the GICv3 and MMIO handling, anything specific? I don't recall the details of what you were trying to accomplish here (it's been 8 months or so) but the surely the vgic handling code should *somehow* be integrated into the handle_kernel_mmio (like Paolo suggested), unless you come back and tell me that that would involve a complete rewrite of the vgic code. I'm experimenting now - it's not exactly rewrite of whole vgic code, but it will touch a lot of it - all MMIO access handlers and the supporting functions. We're ready to spend the effort. My question is - is this acceptable? I certainly appreciate the offer to do this work, but it's hard to say at this point if it is worth it. What I was trying to say above is that Andre looked at this, and came to the conclusion that it is not worth it. Marc, what are your thoughts? Same here, I rely on Andre's view that it was not very useful. Now, it would be good to see a mock-up of the patches and find out: Seconded, can you send a pointer to the VGIC rework patches mentioned? - if it is a major improvement for the general quality of the code - if that allow us to *delete* a lot of code (if it is just churn, I'm not really interested) - if it helps or hinders further developments that are currently in the pipeline Andre, can you please share your findings? I don't remember the specifics of the discussion we had a few months ago... 1) Given the date in the reply I sense that your patches are from March this year or earlier. So this is based on VGIC code from March, which predates Marc's vgic_dyn changes that just went in 3.18-rc1? His patches introduced another member to struct mmio_range to check validity of accesses with a reduced number of SPIs supported (.bits_per_irq). So is this covered in your rework? 2) - there are 15 MMIO ranges for the vgic now - each should be Well, the GICv3 emulation adds 41 new ranges. Not sure if this still fits. registered as a separate device I found this fact a show-stopper when looking at this a month ago. Somehow it feels wrong to register a bunch of pseudo-devices. I could go with registering a small number of regions (one distributor, two redistributor regions for instance), but not handling every single of the 41 + 15 register groups as a device. Also I wasn't sure if we had to expose some of the vGIC structures to the other KVM code layers. But I am open to any suggestions (as long as they go in _after_ my vGICv3 series ;-) - so looking forward to some repo to see how it looks like. Cheers, Andre. -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH 1/4] ARM: KVM: on unhandled IO mem abort, route the call to the KVM MMIO bus
Hi Nikolay, On 13/11/14 12:29, Nikolay Nikolaev wrote: On Thu, Nov 13, 2014 at 1:52 PM, Andre Przywara andre.przyw...@arm.com wrote: Hi Nikolay, On 13/11/14 11:37, Marc Zyngier wrote: [fixing Andre's email address] On 13/11/14 11:20, Christoffer Dall wrote: On Thu, Nov 13, 2014 at 12:45:42PM +0200, Nikolay Nikolaev wrote: [...] Going through the vgic_handle_mmio we see that it will require large refactoring: - there are 15 MMIO ranges for the vgic now - each should be registered as a separate device - the handler of each range should be split into read and write - all handlers take 'struct kvm_exit_mmio', and pass it to 'vgic_reg_access', 'mmio_data_read' and 'mmio_data_read' To sum up - if we do this refactoring of vgic's MMIO handling + kvm_io_bus_ API getting 'vcpu argument we'll get a 'much' cleaner vgic code and as a bonus we'll get 'ioeventfd' capabilities. We have 3 questions: - is the kvm_io_bus_ getting 'vcpu' argument acceptable for the other architectures too? - is this huge vgic MMIO handling redesign acceptable/desired (it touches a lot of code)? - is there a way that ioeventfd is accepted leaving vgic.c in it's current state? Not sure how the latter question is relevant to this, but check with Andre who recently looked at this as well and decided that for GICv3 the only sane thing was to remove that comment for the gic. @Andre - what's your experience with the GICv3 and MMIO handling, anything specific? I don't recall the details of what you were trying to accomplish here (it's been 8 months or so) but the surely the vgic handling code should *somehow* be integrated into the handle_kernel_mmio (like Paolo suggested), unless you come back and tell me that that would involve a complete rewrite of the vgic code. I'm experimenting now - it's not exactly rewrite of whole vgic code, but it will touch a lot of it - all MMIO access handlers and the supporting functions. We're ready to spend the effort. My question is - is this acceptable? I certainly appreciate the offer to do this work, but it's hard to say at this point if it is worth it. What I was trying to say above is that Andre looked at this, and came to the conclusion that it is not worth it. Marc, what are your thoughts? Same here, I rely on Andre's view that it was not very useful. Now, it would be good to see a mock-up of the patches and find out: Seconded, can you send a pointer to the VGIC rework patches mentioned? They are still in WiP state - not exactly working. I'm still exploring what the status is. Our major target is having ioeventfd suport in ARM. For this we need to support kvm_io_bus_ mechanisms for MMIO access (cause ioevent fd device is registered this way). Then this subject of integrating vgic with the kvm_io_bus_ APIs came up. My personal opinion - they should be able to coexist in peace. - if it is a major improvement for the general quality of the code - if that allow us to *delete* a lot of code (if it is just churn, I'm not really interested) - if it helps or hinders further developments that are currently in the pipeline Andre, can you please share your findings? I don't remember the specifics of the discussion we had a few months ago... 1) Given the date in the reply I sense that your patches are from March this year or earlier. So this is based on VGIC code from March, which predates Marc's vgic_dyn changes that just went in 3.18-rc1? His patches introduced another member to struct mmio_range to check validity of accesses with a reduced number of SPIs supported (.bits_per_irq). So is this covered in your rework? Still no (rebased to 3.17) - didn't see it, but should not be an issue. 2) - there are 15 MMIO ranges for the vgic now - each should be Well, the GICv3 emulation adds 41 new ranges. Not sure if this still fits. registered as a separate device I found this fact a show-stopper when looking at this a month ago. Somehow it feels wrong to register a bunch of pseudo-devices. I could go with registering a small number of regions (one distributor, two redistributor regions for instance), but not handling every single of the 41 + 15 register groups as a device. Do you sense performance issues, or just it's not right? Just not right, since they are no 15 devices for a GICv2 emulation. Maybe kvm_io_bus_ needs some extesion to hanlde a device with multiple regions? Well, maybe a simple rename could fix this, but I am not sure it still fits then. I am just afraid we end up with quite some code duplication in each handler function. Also if we needed to split-up read and write this ends up with much more code. Currently this is cleverly handled in one function without looking messy (great job, Marc, btw!) Also handling private GICv3 interrupts is no longer done via a single MMIO offset banked by the accessing (v)CPU, but by per-CPU MMIO regions. Would we need to register separate devices for each VCPU
Re: [RFC PATCH 1/4] ARM: KVM: on unhandled IO mem abort, route the call to the KVM MMIO bus
On 13/11/14 15:02, Nikolay Nikolaev wrote: On Thu, Nov 13, 2014 at 4:23 PM, Eric Auger eric.au...@linaro.org wrote: On 11/13/2014 03:16 PM, Eric Auger wrote: On 11/13/2014 11:45 AM, Nikolay Nikolaev wrote: On Mon, Nov 10, 2014 at 6:27 PM, Christoffer Dall christoffer.d...@linaro.org wrote: On Mon, Nov 10, 2014 at 05:09:07PM +0200, Nikolay Nikolaev wrote: Hello, On Fri, Mar 28, 2014 at 9:09 PM, Christoffer Dall christoffer.d...@linaro.org wrote: On Thu, Mar 13, 2014 at 04:57:26PM +0100, Antonios Motakis wrote: On an unhandled IO memory abort, use the kvm_io_bus_* API in order to handle the MMIO access through any registered read/write callbacks. This is a dependency for eventfd support (ioeventfd and irqfd). However, accesses to the VGIC are still left implemented independently, since the kvm_io_bus_* API doesn't pass the VCPU pointer doing the access. Signed-off-by: Antonios Motakis a.mota...@virtualopensystems.com Signed-off-by: Nikolay Nikolaev n.nikol...@virtualopensystems.com --- arch/arm/kvm/mmio.c | 32 virt/kvm/arm/vgic.c | 5 - 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c index 4cb5a93..1d17831 100644 --- a/arch/arm/kvm/mmio.c +++ b/arch/arm/kvm/mmio.c @@ -162,6 +162,35 @@ static int decode_hsr(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, return 0; } +/** + * kvm_handle_mmio - handle an in-kernel MMIO access + * @vcpu:pointer to the vcpu performing the access + * @run: pointer to the kvm_run structure + * @mmio:pointer to the data describing the access + * + * returns true if the MMIO access has been performed in kernel space, + * and false if it needs to be emulated in user space. + */ +static bool handle_kernel_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, + struct kvm_exit_mmio *mmio) +{ + int ret; + if (mmio-is_write) { + ret = kvm_io_bus_write(vcpu-kvm, KVM_MMIO_BUS, mmio-phys_addr, + mmio-len, mmio-data); + + } else { + ret = kvm_io_bus_read(vcpu-kvm, KVM_MMIO_BUS, mmio-phys_addr, + mmio-len, mmio-data); + } + if (!ret) { + kvm_prepare_mmio(run, mmio); + kvm_handle_mmio_return(vcpu, run); + } + + return !ret; +} + int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, phys_addr_t fault_ipa) { @@ -200,6 +229,9 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, if (vgic_handle_mmio(vcpu, run, mmio)) return 1; + if (handle_kernel_mmio(vcpu, run, mmio)) + return 1; + We're reconsidering ioeventfds patchseries and we tried to evaluate what you suggested here. this special-casing of the vgic is now really terrible. Is there anything holding you back from doing the necessary restructure of the kvm_bus_io_*() API instead? Restructuring the kvm_io_bus_ API is not a big thing (we actually did it), but is not directly related to the these patches. Of course it can be justified if we do it in the context of removing vgic_handle_mmio and leaving only handle_kernel_mmio. That would allow us to get rid of the ugly Fix it! in the vgic driver as well. Going through the vgic_handle_mmio we see that it will require large refactoring: - there are 15 MMIO ranges for the vgic now - each should be registered as a separate device Re-correcting Andre's address, sorry: Hi Nikolay, Andre, what does mandate to register 15 devices? Isn't possible to register a single kvm_io_device covering the whole distributor range [base, base + KVM_VGIC_V2_DIST_SIZE] (current code) and in associated kvm_io_device_ops read/write locate the addressed range and do the same as what is done in current vgic_handle_mmio? Isn't it done that way for Well, then we'll actually get slower mmio processing. Instead of calling vgic_handle_mmio in io_mem_abort, we'll be calling kvm_io_bus_write. This just adds another level of translation (i.e. find the kvm_io_ device) and the underlying vgic code will remain almost the same. Agreed. That was one possibility I came around also, but I think it defeats the purpose of the rework, which is mostly to get rid of the GIC's private MMIO dispatching code, right? But honestly I would happily sacrifice performance for easier VGIC code - especially if one thinks about security for instance. Though I think that another memory reference doesn't really matter in this context ;-) the ioapic? what do I miss? I looked quickly in the ioapic code, and if I get it right there are no ranges' like what we have with the GIC. They have this regselect/regwindow concept and they seem to have much less registers to handle. GIC seems a lot more complex in terms of MMIO interface. Right, that was my impression, too. IOAPIC isn't really comparable to the GIC in
Re: [PATCH v2 03/15] arm/arm64: KVM: refactor vgic_handle_mmio() function
Hi Christoffer, On 15/10/14 17:25, Christoffer Dall wrote: On Thu, Aug 21, 2014 at 02:06:44PM +0100, Andre Przywara wrote: Currently we only need to deal with one MMIO region for the GIC emulation, but we soon need to extend this. Refactor the existing code to allow easier addition of different ranges without code duplication. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- virt/kvm/arm/vgic.c | 72 --- 1 file changed, 51 insertions(+), 21 deletions(-) diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index bba8692..3b6f78d 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -925,37 +925,28 @@ static bool vgic_validate_access(const struct vgic_dist *dist, return true; } -/** - * vgic_handle_mmio - handle an in-kernel MMIO access +/* + * vgic_handle_mmio_range - handle an in-kernel MMIO access * @vcpu: pointer to the vcpu performing the access * @run:pointer to the kvm_run structure * @mmio: pointer to the data describing the access + * @ranges: pointer to the register defining structure + * @mmio_base: base address for this mapping * - * returns true if the MMIO access has been performed in kernel space, - * and false if it needs to be emulated in user space. + * returns true if the MMIO access could be performed */ -bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, - struct kvm_exit_mmio *mmio) +static bool vgic_handle_mmio_range(struct kvm_vcpu *vcpu, struct kvm_run *run, +struct kvm_exit_mmio *mmio, +const struct mmio_range *ranges, +unsigned long mmio_base) now when we're chopping this up and about to add more logic based on our struct mmio_range, I think we should really consider getting rid of that comment abou the kvm_bus_io_*() API or actually use that API. So I did some research in this area. The API is meant to separate devices on a bus, so we would still need the structure to tell the single registers apart. The users of kvm_io_bus do this all in one switch/case, which would mean a step back in our case. Also we need more members than just base and length. So though I didn't try it, I guess it wouldn't be a win for us, I am not even sure it would produce less code. So I am more looking at removing the comment. { const struct mmio_range *range; struct vgic_dist *dist = vcpu-kvm-arch.vgic; -unsigned long base = dist-vgic_dist_base; bool updated_state; unsigned long offset; -if (!irqchip_in_kernel(vcpu-kvm) || -mmio-phys_addr base || -(mmio-phys_addr + mmio-len) (base + KVM_VGIC_V2_DIST_SIZE)) -return false; - -/* We don't support ldrd / strd or ldm / stm to the emulated vgic */ -if (mmio-len 4) { -kvm_inject_dabt(vcpu, mmio-phys_addr); -return true; -} - -offset = mmio-phys_addr - base; -range = find_matching_range(vgic_dist_ranges, mmio, offset); +offset = mmio-phys_addr - mmio_base; +range = find_matching_range(ranges, mmio, offset); if (unlikely(!range || !range-handle_mmio)) { pr_warn(Unhandled access %d %08llx %d\n, mmio-is_write, mmio-phys_addr, mmio-len); @@ -963,7 +954,7 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, } spin_lock(vcpu-kvm-arch.vgic.lock); -offset = mmio-phys_addr - range-base - base; +offset -= range-base; if (vgic_validate_access(dist, range, offset)) { updated_state = range-handle_mmio(vcpu, mmio, offset); } else { @@ -981,6 +972,45 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, return true; } +#define IS_IN_RANGE(addr, alen, base, len) \ +(((addr) = (base)) (((addr) + (alen)) ((base) + (len that should be = ((base) + (len)) right? Indeed, thanks for spotting. that's a lot of parenthesis, how about creating a static inline instead? you could also rename alen to access_len Will fix this. Cheers, Andre. + +static bool vgic_v2_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, +struct kvm_exit_mmio *mmio) +{ +unsigned long base = vcpu-kvm-arch.vgic.vgic_dist_base; + +if (!IS_IN_RANGE(mmio-phys_addr, mmio-len, base, + KVM_VGIC_V2_DIST_SIZE)) +return false; + +/* GICv2 does not support accesses wider than 32 bits */ +if (mmio-len 4) { +kvm_inject_dabt(vcpu, mmio-phys_addr); +return true; +} + +return vgic_handle_mmio_range(vcpu, run, mmio, vgic_dist_ranges, base); +} + +/** + * vgic_handle_mmio - handle an in-kernel MMIO access for the GIC emulation + * @vcpu: pointer to the vcpu performing the access + * @run: pointer to the kvm_run structure + * @mmio: pointer
Re: [PATCH v2 04/15] arm/arm64: KVM: wrap 64 bit MMIO accesses with two 32 bit ones
Hi Christoffer, On 15/10/14 17:26, Christoffer Dall wrote: On Thu, Aug 21, 2014 at 02:06:45PM +0100, Andre Przywara wrote: Some GICv3 registers can and will be accessed as 64 bit registers. Currently the register handling code can only deal with 32 bit accesses, so we do two consecutive calls to cover this. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- virt/kvm/arm/vgic.c | 48 +--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 3b6f78d..bef9aa0 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -926,6 +926,48 @@ static bool vgic_validate_access(const struct vgic_dist *dist, } /* + * Call the respective handler function for the given range. + * We split up any 64 bit accesses into two consecutive 32 bit + * handler calls and merge the result afterwards. + */ +static bool call_range_handler(struct kvm_vcpu *vcpu, + struct kvm_exit_mmio *mmio, + unsigned long offset, + const struct mmio_range *range) +{ +u32 *data32 = (void *)mmio-data; +struct kvm_exit_mmio mmio32; +bool ret; + +if (likely(mmio-len = 4)) +return range-handle_mmio(vcpu, mmio, offset); + +/* + * We assume that any access greater than 4 bytes is actually Is this an assumption or something that will always hold true at this point in the code? If the former, which situations could it not hold and what would happen? If the latter, we should just state that. I wasn't so sure about this at the time of writing ;-) So I see how one can read/write 1, 2, 4, 8 bytes and multiples of 4 or 8 bytes with ldm/ldp. For the latter we don't have syndrome support, so I take it we don't care about this. So if nobody sees other supported operand sizes when doing MMIO, I will rephrase the above comment to be more strict. + * 8 bytes long, caused by a 64-bit access + */ + +mmio32.len = 4; +mmio32.is_write = mmio-is_write; + +mmio32.phys_addr = mmio-phys_addr + 4; +if (mmio-is_write) +*(u32 *)mmio32.data = data32[1]; +ret = range-handle_mmio(vcpu, mmio32, offset + 4); +if (!mmio-is_write) +data32[1] = *(u32 *)mmio32.data; + +mmio32.phys_addr = mmio-phys_addr; +if (mmio-is_write) +*(u32 *)mmio32.data = data32[0]; +ret |= range-handle_mmio(vcpu, mmio32, offset); +if (!mmio-is_write) +data32[0] = *(u32 *)mmio32.data; won't this break on a BE system? Mmh, I remember having this discussed with Marc before. But I see that it looks suspicious. This whole endianess thing is even more confusing since the GIC is always LE and the guest as well as KVM already do swapping. So I rewrote the above function to avoid explicit endianess assumptions, but am still struggling to get it tested successfully on a bi-endian setup. As I don't want to hold back the newer patches any longer, I will try to debug this next week, meanwhile not stating bi-endianness is supported for the new series. Cheers, Andre. + +return ret; +} + +/* * vgic_handle_mmio_range - handle an in-kernel MMIO access * @vcpu: pointer to the vcpu performing the access * @run:pointer to the kvm_run structure @@ -956,10 +998,10 @@ static bool vgic_handle_mmio_range(struct kvm_vcpu *vcpu, struct kvm_run *run, spin_lock(vcpu-kvm-arch.vgic.lock); offset -= range-base; if (vgic_validate_access(dist, range, offset)) { -updated_state = range-handle_mmio(vcpu, mmio, offset); +updated_state = call_range_handler(vcpu, mmio, offset, range); } else { -vgic_reg_access(mmio, NULL, offset, -ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED); +if (!mmio-is_write) +memset(mmio-data, 0, mmio-len); updated_state = false; } spin_unlock(vcpu-kvm-arch.vgic.lock); -- 1.7.9.5 Thanks, -Christoffer -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 05/15] arm/arm64: KVM: introduce per-VM ops
Hi Christoffer, On 15/10/14 17:27, Christoffer Dall wrote: On Thu, Aug 21, 2014 at 02:06:46PM +0100, Andre Przywara wrote: Currently we only have one virtual GIC model supported, so all guests use the same emulation code. With the addition of another model we end up with different guests using potentially different vGIC models, so we have to split up some functions to be per VM. Introduce a vgic_vm_ops struct to hold function pointers for those functions that are different and provide the necessary code to initialize them. This includes functions that depend on the emulated GIC model only and functions that depend on the combination of host and guest GIC. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- include/kvm/arm_vgic.h | 18 -- virt/kvm/arm/vgic-v2.c | 17 +++-- virt/kvm/arm/vgic-v3.c | 16 +++-- virt/kvm/arm/vgic.c| 92 +++- 4 files changed, 113 insertions(+), 30 deletions(-) diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 4feac9a..7e7c99e 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -99,8 +99,6 @@ struct vgic_vmcr { }; struct vgic_ops { - struct vgic_lr (*get_lr)(const struct kvm_vcpu *, int); - void(*set_lr)(struct kvm_vcpu *, int, struct vgic_lr); void(*sync_lr_elrsr)(struct kvm_vcpu *, int, struct vgic_lr); u64 (*get_elrsr)(const struct kvm_vcpu *vcpu); u64 (*get_eisr)(const struct kvm_vcpu *vcpu); @@ -123,6 +121,17 @@ struct vgic_params { unsigned intmaint_irq; /* Virtual control interface base address */ void __iomem*vctrl_base; + bool (*init_emul)(struct kvm *kvm, int type); +}; + +struct vgic_vm_ops { + struct vgic_lr (*get_lr)(const struct kvm_vcpu *, int); + void(*set_lr)(struct kvm_vcpu *, int, struct vgic_lr); + bool(*handle_mmio)(struct kvm_vcpu *, struct kvm_run *, +struct kvm_exit_mmio *); + bool(*queue_sgi)(struct kvm_vcpu *vcpu, int irq); + void(*unqueue_sgi)(struct kvm_vcpu *vcpu, int irq, int source); + int (*vgic_init)(struct kvm *kvm, const struct vgic_params *params); }; struct vgic_dist { @@ -131,6 +140,9 @@ struct vgic_dist { boolin_kernel; boolready; + /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */ + u32 vgic_model; + int nr_cpus; int nr_irqs; @@ -168,6 +180,8 @@ struct vgic_dist { /* Bitmap indicating which CPU has something pending */ unsigned long irq_pending_on_cpu; + + struct vgic_vm_ops vm_ops; #endif }; diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c index 01124ef..90947c6 100644 --- a/virt/kvm/arm/vgic-v2.c +++ b/virt/kvm/arm/vgic-v2.c @@ -161,8 +161,6 @@ static void vgic_v2_enable(struct kvm_vcpu *vcpu) } static const struct vgic_ops vgic_v2_ops = { - .get_lr = vgic_v2_get_lr, - .set_lr = vgic_v2_set_lr, .sync_lr_elrsr = vgic_v2_sync_lr_elrsr, .get_elrsr = vgic_v2_get_elrsr, .get_eisr = vgic_v2_get_eisr, @@ -176,6 +174,20 @@ static const struct vgic_ops vgic_v2_ops = { static struct vgic_params vgic_v2_params; +static bool vgic_v2_init_emul(struct kvm *kvm, int type) +{ + struct vgic_vm_ops *vm_ops = kvm-arch.vgic.vm_ops; + + switch (type) { + case KVM_DEV_TYPE_ARM_VGIC_V2: + vm_ops-get_lr = vgic_v2_get_lr; + vm_ops-set_lr = vgic_v2_set_lr; + return true; + } + + return false; +} + /** * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT * @node:pointer to the DT node @@ -214,6 +226,7 @@ int vgic_v2_probe(struct device_node *vgic_node, ret = -ENOMEM; goto out; } + vgic-init_emul = vgic_v2_init_emul; this feels overly complicated, can't each host-support function just export this function and we call it directly from the vgic creation code? That or just keep the host-specific functions the way they are and handle the split within these functions? Bah, I'm not sure, this patch is just terrible to review... Perhaps it's because we're doing some combination of introducing infrastructure and also changing random bits and naming to be version-specific. OK, I split up the patch to do one thing at a time. This is now 2 bigger and 2 smaller patches in the new series, and it looks more review-friendly, I hope. vgic-nr_lr = readl_relaxed(vgic-vctrl_base + GICH_VTR); vgic-nr_lr = (vgic-nr_lr 0x3f) + 1; diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c index 1c2c8ee..a38339e 100644 --- a/virt/kvm/arm/vgic-v3.c +++ b/virt/kvm/arm/vgic-v3.c
Re: [PATCH v2 01/15] arm/arm64: KVM: rework MPIDR assignment and add accessors
Hi Christoffer, On 15/10/14 17:25, Christoffer Dall wrote: On Thu, Aug 21, 2014 at 02:06:42PM +0100, Andre Przywara wrote: The virtual MPIDR registers (containing topology information) for the guest are currently mapped linearily to the vcpu_id. Improve this mapping for arm64 by using three levels to not artificially limit the number of vCPUs. Also add an accessor to later allow easier access to a vCPU with a given MPIDR. Use this new accessor in the PSCI emulation. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm/include/asm/kvm_emulate.h |2 +- arch/arm/include/asm/kvm_host.h |2 ++ arch/arm/kvm/arm.c | 15 +++ arch/arm/kvm/psci.c | 15 --- arch/arm64/include/asm/kvm_emulate.h |3 ++- arch/arm64/include/asm/kvm_host.h|2 ++ arch/arm64/kvm/sys_regs.c| 11 +-- 7 files changed, 35 insertions(+), 15 deletions(-) diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h index 69b7469..18e45f7 100644 --- a/arch/arm/include/asm/kvm_emulate.h +++ b/arch/arm/include/asm/kvm_emulate.h @@ -159,7 +159,7 @@ static inline u32 kvm_vcpu_hvc_get_imm(struct kvm_vcpu *vcpu) static inline unsigned long kvm_vcpu_get_mpidr(struct kvm_vcpu *vcpu) { -return vcpu-arch.cp15[c0_MPIDR]; +return vcpu-arch.cp15[c0_MPIDR] MPIDR_HWID_BITMASK; why? Because of the two current users one did that masking afterwards and the second does not care (applies an ever stricter mask). All the subsequent users in the GICv3 emulation also do this, so I deemed it useful to have the masking in here. For KVM purposes I guess we only are interested in the affinity bits. I can rename the function to make this more obvious if you like. Cheers, Andre. } static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 6dfb404..cf99ad0 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -233,4 +233,6 @@ static inline void vgic_arch_setup(const struct vgic_params *vgic) int kvm_perf_init(void); int kvm_perf_teardown(void); +struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr); + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 7d5065e..addb990 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -990,6 +990,21 @@ static void check_kvm_target_cpu(void *ret) *(int *)ret = kvm_target_cpu(); } +struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr) +{ +unsigned long c_mpidr; +struct kvm_vcpu *vcpu; +int i; + +mpidr = MPIDR_HWID_BITMASK; +kvm_for_each_vcpu(i, vcpu, kvm) { +c_mpidr = kvm_vcpu_get_mpidr(vcpu); +if (c_mpidr == mpidr) +return vcpu; +} +return NULL; +} + /** * Initialize Hyp-mode and memory mappings on all CPUs. */ diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index 09cf377..49f0992 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c @@ -21,6 +21,7 @@ #include asm/cputype.h #include asm/kvm_emulate.h #include asm/kvm_psci.h +#include asm/kvm_host.h /* * This is an implementation of the Power State Coordination Interface @@ -65,25 +66,17 @@ static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu) static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) { struct kvm *kvm = source_vcpu-kvm; -struct kvm_vcpu *vcpu = NULL, *tmp; +struct kvm_vcpu *vcpu = NULL; wait_queue_head_t *wq; unsigned long cpu_id; unsigned long context_id; -unsigned long mpidr; phys_addr_t target_pc; -int i; -cpu_id = *vcpu_reg(source_vcpu, 1); +cpu_id = *vcpu_reg(source_vcpu, 1) MPIDR_HWID_BITMASK; if (vcpu_mode_is_32bit(source_vcpu)) cpu_id = ~((u32) 0); -kvm_for_each_vcpu(i, tmp, kvm) { -mpidr = kvm_vcpu_get_mpidr(tmp); -if ((mpidr MPIDR_HWID_BITMASK) == (cpu_id MPIDR_HWID_BITMASK)) { -vcpu = tmp; -break; -} -} +vcpu = kvm_mpidr_to_vcpu(kvm, cpu_id); /* * Make sure the caller requested a valid CPU and that the CPU is diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index fdc3e21..4b8d636 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -27,6 +27,7 @@ #include asm/kvm_arm.h #include asm/kvm_mmio.h #include asm/ptrace.h +#include asm/cputype.h unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num); unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu); @@ -179,7 +180,7 @@ static inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu) static inline unsigned long
Re: [PATCH v2 06/15] arm/arm64: KVM: make the maximum number of vCPUs a per-VM value
On 15/10/14 17:27, Christoffer Dall wrote: On Thu, Aug 21, 2014 at 02:06:47PM +0100, Andre Przywara wrote: Currently the maximum number of vCPUs supported is a global value limited by the used GIC model. GICv3 will lift this limit, but we still need to observe it for guests using GICv2. So the maximum number of vCPUs is per-VM value, depending on the GIC model the guest uses. Store and check the value in struct kvm_arch, but keep it down to 8 for now. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm/include/asm/kvm_host.h |1 + arch/arm/kvm/arm.c|6 ++ arch/arm64/include/asm/kvm_host.h |3 +++ virt/kvm/arm/vgic-v2.c|5 + virt/kvm/arm/vgic-v3.c|6 ++ 5 files changed, 21 insertions(+) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index cf99ad0..0638419 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -67,6 +67,7 @@ struct kvm_arch { /* Interrupt controller */ struct vgic_distvgic; +int max_vcpus; }; #define KVM_NR_MEM_OBJS 40 diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 157e1b6..190f05f 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -142,6 +142,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) /* Mark the initial VMID generation invalid */ kvm-arch.vmid_gen = 0; +kvm-arch.max_vcpus = CONFIG_KVM_ARM_MAX_VCPUS; return ret; out_free_stage2_pgd: @@ -223,6 +224,11 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) int err; struct kvm_vcpu *vcpu; +if (id = kvm-arch.max_vcpus) { +err = -EINVAL; +goto out; +} + vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); if (!vcpu) { err = -ENOMEM; diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 017fbae..a325161 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -58,6 +58,9 @@ struct kvm_arch { /* VTTBR value associated with above pgd and vmid */ u64vttbr; +/* The maximum number of vCPUs depends on the used GIC model */ +int max_vcpus; + /* Interrupt controller */ struct vgic_distvgic; diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c index 90947c6..c7362ff 100644 --- a/virt/kvm/arm/vgic-v2.c +++ b/virt/kvm/arm/vgic-v2.c @@ -177,11 +177,16 @@ static struct vgic_params vgic_v2_params; static bool vgic_v2_init_emul(struct kvm *kvm, int type) { struct vgic_vm_ops *vm_ops = kvm-arch.vgic.vm_ops; +int nr_vcpus; switch (type) { case KVM_DEV_TYPE_ARM_VGIC_V2: +nr_vcpus = atomic_read(kvm-online_vcpus); +if (nr_vcpus 8) +return false; vm_ops-get_lr = vgic_v2_get_lr; vm_ops-set_lr = vgic_v2_set_lr; +kvm-arch.max_vcpus = 8; return true; } diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c index a38339e..86e8b99 100644 --- a/virt/kvm/arm/vgic-v3.c +++ b/virt/kvm/arm/vgic-v3.c @@ -171,11 +171,17 @@ static const struct vgic_ops vgic_v3_ops = { static bool vgic_v3_init_emul_compat(struct kvm *kvm, int type) { struct vgic_vm_ops *vm_ops = kvm-arch.vgic.vm_ops; +int nr_vcpus; switch (type) { case KVM_DEV_TYPE_ARM_VGIC_V2: +nr_vcpus = atomic_read(kvm-online_vcpus); +if (nr_vcpus 8) +return false; + I have a feeling we could be seeing this error a bit, could we dedicate an error code for the purpose or print a ratelimited warning or something? Did the latter. To be found in an inbox near you very soon. Cheers, Andre. vm_ops-get_lr = vgic_v3_get_lr; vm_ops-set_lr = vgic_v3_set_lr; +kvm-arch.max_vcpus = 8; return true; } return false; -- 1.7.9.5 Thanks, -Christoffer -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 00/15] KVM GICv3 emulation
On 08/10/14 05:08, wanghaibin wrote: On 2014/8/21 21:06, Andre Przywara wrote: GICv3 is the ARM generic interrupt controller designed to overcome some limits of the prevalent GICv2. Most notably it lifts the 8-CPU limit. Though with recent patches from Marc there is support for hosts to use a GICv3, the CPU limitation still applies to KVM guests, since the current code emulates a GICv2 only. Also, GICv2 backward compatibility being optional in GICv3, a number of systems won't be able to run GICv2 guests. This patch series provides code to emulate a GICv3 distributor and redistributor for any KVM guest. It requires a GICv3 in the host to work. With those patches one can run guests efficiently on any GICv3 host. It has the following features: - Affinity routing (support for up to 255 VCPUs, more possible) Hi, Andre, in struct vgic_dist { /* Bitmap indicating which CPU has something pending */ unsigned long irq_pending_on_cpu; } the irq_pending_on_cpu parameter type just **unsigned long**. See the vgic_update_state func: void vgic_update_state(struct kvm *kvm) { ... kvm_for_each_vcpu(c, vcpu, kvm) { if (compute_pending_for_cpu(vcpu)) { pr_debug(CPU%d has pending interrupts\n, c); set_bit(c, dist-irq_pending_on_cpu); } } } Maybe when the VCPU id greater than 64, and has pending irq, After calculated, here: set_bit(c, dist-irq_pending_on_cpu); must be wrong. Isn't it ? Indeed, thanks for spotting this. Marc has found this already some weeks ago and the fix is already in the latest branches[1][2]. Once -rc1 is out I will need to respin my patches anyway. Cheers, Andre. [1] https://git.kernel.org/cgit/linux/kernel/git/maz/arm-platforms.git/log/?h=kvm-arm64/vgic-dyn [2] https://git.kernel.org/cgit/linux/kernel/git/kvmarm/kvmarm.git/log/?h=next - System registers (as opposed to MMIO access) - No ITS - No priority support (as the GICv2 emulation) - No save / restore support so far (will be added soon) The first 11 patches actually refactor the current VGIC code to make room for a different VGIC model to be dropped in with Patch 12/15. The remaining patches connect the new model to the kernel backend and the userland facing code. The series goes on top of v3.17-rc1 and Marc's vgic-dyn series[2]. The necessary patches for kvmtool to enable the guest's GICv3 have been posted here before [3], an updated version will follow as soon as the kvmtools tree has been updated. There was some testing on the fast model with some I/O and interrupt affinity shuffling in a Linux guest with a varying number of VCPUs as well as some testing on a Juno board (GICv2 only, to spot regressions). Please review and test. I would be grateful for people to test for GICv2 regressions also (so on a GICv2 host with current kvmtool/qemu), as there is quite some refactoring on that front. Much of the code was inspired by MarcZ, also kudos to him for doing the rather painful rebase on top of v3.17-rc1. Cheers, Andre. [1] https://lists.cs.columbia.edu/pipermail/kvmarm/2014-June/010060.html [2] https://git.kernel.org/cgit/linux/kernel/git/maz/arm-platforms.git/log/?h=kvm-arm64/vgic-dyn [3] https://lists.cs.columbia.edu/pipermail/kvmarm/2014-June/010086.html Changes v1 ... v2: * rebase to v3.17-rc1, caused quite some changes to the init code * new 9/15 patch to make 10/15 smaller * fix wrongly ordered cp15 register trap entry (MarcZ) * fix SGI broadcast (thanks to wanghaibin for spotting) * fix broken bailout path in kvm_vgic_create (wanghaibin) * check return value of init_emulation_ops() (wanghaibin) * fix return value check in vgic_[sg]et_attr() * add header inclusion guards * remove double definition of VCPU_NOT_ALLOCATED * some code move-around * whitespace fixes Andre Przywara (15): arm/arm64: KVM: rework MPIDR assignment and add accessors arm/arm64: KVM: pass down user space provided GIC type into vGIC code arm/arm64: KVM: refactor vgic_handle_mmio() function arm/arm64: KVM: wrap 64 bit MMIO accesses with two 32 bit ones arm/arm64: KVM: introduce per-VM ops arm/arm64: KVM: make the maximum number of vCPUs a per-VM value arm/arm64: KVM: make the value of ICC_SRE_EL1 a per-VM variable arm/arm64: KVM: refactor MMIO accessors arm/arm64: KVM: refactor/wrap vgic_set/get_attr() arm/arm64: KVM: split GICv2 specific emulation code from vgic.c arm/arm64: KVM: add opaque private pointer to MMIO accessors arm/arm64: KVM: add virtual GICv3 distributor emulation arm/arm64: KVM: add SGI system register trapping arm/arm64: KVM: enable kernel side of GICv3 emulation arm/arm64: KVM: allow userland to request a virtual GICv3 arch/arm
Re: [PATCH v5 0/4] kvmtool: ARM/ARM64: Misc updates
Hi Anup, On 01/10/14 11:34, Anup Patel wrote: This patchset updates KVMTOOL to use some of the features supported by Linux-3.16 KVM ARM/ARM64, such as: 1. Target CPU == Host using KVM_ARM_PREFERRED_TARGET vm ioctl 2. Target CPU type Potenza for using KVMTOOL on X-Gene 3. PSCI v0.2 support for Aarch32 and Aarch64 guest 4. System event exit reason Thanks for the quick respin. Looks fine now for me. For the whole v5 series: Reviewed-by: Andre Przywara andre.przyw...@arm.com Cheers, Andre. Changes since v4: - Avoid using magic '0' target for kvm arm generic target - Added comment for why we need Potenza target in KVMTOOL Changes since v3: - Add generic targets for aarch32 and aarch64 which are used by KVMTOOL when target type returned by KVM_ARM_PREFERRED_TARGET vm ioctl is not known to KVMTOOL - Print more info when handling system reset event Changes since v2: - Use target type returned by KVM_ARM_PREFERRED_TARGET vm ioctl for VCPU init such that we don't need to update KVMTOOL for every new host hardware - Simplify DTB generation for PSCI node Changes since v1: - Drop the patch to fix compile error for aarch64 - Fallback to old method of trying all target types if KVM_ARM_PREFERRED_TARGET vm ioctl fails - Print more info when handling KVM_EXIT_SYSTEM_EVENT Anup Patel (4): kvmtool: ARM: Use KVM_ARM_PREFERRED_TARGET vm ioctl to determine target cpu kvmtool: ARM64: Add target type potenza for aarch64 kvmtool: Handle exit reason KVM_EXIT_SYSTEM_EVENT kvmtool: ARM/ARM64: Provide PSCI-0.2 to guest when KVM supports it tools/kvm/arm/aarch32/arm-cpu.c |8 +++ tools/kvm/arm/aarch64/arm-cpu.c | 23 - tools/kvm/arm/fdt.c | 51 +-- tools/kvm/arm/include/arm-common/kvm-cpu-arch.h |2 + tools/kvm/arm/kvm-cpu.c | 61 +++ tools/kvm/kvm-cpu.c | 21 6 files changed, 149 insertions(+), 17 deletions(-) -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH] arm/arm64: KVM: Fix BE accesses to GICv2 EISR and ELRSR regs
Hi Christoffer, On 28/09/14 15:04, Christoffer Dall wrote: The EIRSR and ELRSR registers are 32-bit registers on GICv2, and we store these as an array of two such registers on the vgic vcpu struct. However, we access them as a single 64-bit value or as a bitmap pointer in the generic vgic code, which breaks BE support. Instead, store them as u64 values on the vgic structure and do the word-swapping in the assembly code, which already handles the byte order for BE systems. I am wondering if that approach isn't too involved. EISR and ELRSR are 32-bit registers, and AFAIK the GIC is always LE on the hardware side. So by claiming we have a 64bit register we introduce too much hassle, right? Wouldn't it be better to just fix the registers shortly before we actually use them? With my limited endianess experience: Wouldn't this patch solve the EISR part (copy pasted, so for eyes only ;-) @@ -92,13 +89,10 @@ static u64 vgic_v2_get_eisr(const struct kvm_vcpu *vcpu) { u64 val; -#if BITS_PER_LONG == 64 - val = vcpu-arch.vgic_cpu.vgic_v2.vgic_eisr[1]; + val = le32_to_cpu(vcpu-arch.vgic_cpu.vgic_v2.vgic_eisr[1]); val = 32; - val |= vcpu-arch.vgic_cpu.vgic_v2.vgic_eisr[0]; -#else - val = *(u64 *)vcpu-arch.vgic_cpu.vgic_v2.vgic_eisr; -#endif + val |= le32_to_cpu(vcpu-arch.vgic_cpu.vgic_v2.vgic_eisr[0]); + return val; } (BTW: Wasn't that 64 bit optimization path the wrong way round here?) Please bear with me if this is complete nonsense, could well twisted my mind once too much ;-) Still thinking about a clever solution for that strange sync_elrsr() thing ... Cheers, Andre. Signed-off-by: Christoffer Dall christoffer.d...@linaro.org --- I don't have a working BE configuration, so sending this out as an *UNTESTED on BE* RFC in hoping that someone with a working setup can give it a test for me (Will tells me Virtio is broken with kvmtool no BE hosts though), and to avoid someone else also doing this work. arch/arm/kvm/interrupts_head.S | 7 +++ arch/arm64/kvm/vgic-v2-switch.S | 12 include/kvm/arm_vgic.h | 4 ++-- virt/kvm/arm/vgic-v2.c | 24 +++- virt/kvm/arm/vgic.c | 18 -- 5 files changed, 36 insertions(+), 29 deletions(-) diff --git a/arch/arm/kvm/interrupts_head.S b/arch/arm/kvm/interrupts_head.S index 98c8c5b..14d4883 100644 --- a/arch/arm/kvm/interrupts_head.S +++ b/arch/arm/kvm/interrupts_head.S @@ -433,10 +433,17 @@ ARM_BE8(rev r10, r10) str r3, [r11, #VGIC_V2_CPU_HCR] str r4, [r11, #VGIC_V2_CPU_VMCR] str r5, [r11, #VGIC_V2_CPU_MISR] +#ifdef CONFIG_CPU_ENDIAN_BE8 + str r6, [r11, #(VGIC_V2_CPU_EISR + 4)] + str r7, [r11, #VGIC_V2_CPU_EISR] + str r8, [r11, #(VGIC_V2_CPU_ELRSR + 4)] + str r9, [r11, #VGIC_V2_CPU_ELRSR] +#else str r6, [r11, #VGIC_V2_CPU_EISR] str r7, [r11, #(VGIC_V2_CPU_EISR + 4)] str r8, [r11, #VGIC_V2_CPU_ELRSR] str r9, [r11, #(VGIC_V2_CPU_ELRSR + 4)] +#endif str r10, [r11, #VGIC_V2_CPU_APR] /* Clear GICH_HCR */ diff --git a/arch/arm64/kvm/vgic-v2-switch.S b/arch/arm64/kvm/vgic-v2-switch.S index ae21177..f002fe1 100644 --- a/arch/arm64/kvm/vgic-v2-switch.S +++ b/arch/arm64/kvm/vgic-v2-switch.S @@ -67,10 +67,14 @@ CPU_BE( rev w11, w11 ) str w4, [x3, #VGIC_V2_CPU_HCR] str w5, [x3, #VGIC_V2_CPU_VMCR] str w6, [x3, #VGIC_V2_CPU_MISR] - str w7, [x3, #VGIC_V2_CPU_EISR] - str w8, [x3, #(VGIC_V2_CPU_EISR + 4)] - str w9, [x3, #VGIC_V2_CPU_ELRSR] - str w10, [x3, #(VGIC_V2_CPU_ELRSR + 4)] +CPU_LE( str w7, [x3, #VGIC_V2_CPU_EISR] ) +CPU_LE( str w8, [x3, #(VGIC_V2_CPU_EISR + 4)] ) +CPU_LE( str w9, [x3, #VGIC_V2_CPU_ELRSR] ) +CPU_LE( str w10, [x3, #(VGIC_V2_CPU_ELRSR + 4)] ) +CPU_BE( str w7, [x3, #(VGIC_V2_CPU_EISR + 4)] ) +CPU_BE( str w8, [x3, #VGIC_V2_CPU_EISR] ) +CPU_BE( str w9, [x3, #(VGIC_V2_CPU_ELRSR + 4)] ) +CPU_BE( str w10, [x3, #VGIC_V2_CPU_ELRSR] ) str w11, [x3, #VGIC_V2_CPU_APR] /* Clear GICH_HCR */ diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 35b0c12..c66dc9ed 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -168,8 +168,8 @@ struct vgic_v2_cpu_if { u32 vgic_hcr; u32 vgic_vmcr; u32 vgic_misr; /* Saved only */ - u32 vgic_eisr[2]; /* Saved only */ - u32 vgic_elrsr[2]; /* Saved only */ + u64 vgic_eisr; /* Saved only */ + u64 vgic_elrsr; /* Saved only */ u32 vgic_apr; u32 vgic_lr[VGIC_V2_MAX_LRS]; }; diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c index
Re: [PATCH v4 1/4] kvmtool: ARM: Use KVM_ARM_PREFERRED_TARGET vm ioctl to determine target cpu
Hi Anup, thanks for the re-spin and sorry for the delay. Looks better now, some minor comments below. On 19/09/14 00:57, Anup Patel wrote: Instead, of trying out each and every target type we should use KVM_ARM_PREFERRED_TARGET vm ioctl to determine target type for KVM ARM/ARM64. If KVM_ARM_PREFERRED_TARGET vm ioctl fails then we fallback to old method of trying all known target types. If KVM_ARM_PREFERRED_TARGET vm ioctl succeeds but the returned target type is not known to KVMTOOL then we forcefully init VCPU with target type returned by KVM_ARM_PREFERRED_TARGET vm ioctl. Signed-off-by: Pranavkumar Sawargaonkar pranavku...@linaro.org Signed-off-by: Anup Patel anup.pa...@linaro.org --- tools/kvm/arm/aarch32/arm-cpu.c |9 ++- tools/kvm/arm/aarch64/arm-cpu.c | 10 ++-- tools/kvm/arm/kvm-cpu.c | 52 ++- 3 files changed, 57 insertions(+), 14 deletions(-) diff --git a/tools/kvm/arm/aarch32/arm-cpu.c b/tools/kvm/arm/aarch32/arm-cpu.c index 71b98fe..0d2ff11 100644 --- a/tools/kvm/arm/aarch32/arm-cpu.c +++ b/tools/kvm/arm/aarch32/arm-cpu.c @@ -22,6 +22,12 @@ static int arm_cpu__vcpu_init(struct kvm_cpu *vcpu) return 0; } +static struct kvm_arm_target target_generic_v7 = { + .id = UINT_MAX, + .compatible = arm,arm-v7, + .init = arm_cpu__vcpu_init, +}; + static struct kvm_arm_target target_cortex_a15 = { .id = KVM_ARM_TARGET_CORTEX_A15, .compatible = arm,cortex-a15, @@ -36,7 +42,8 @@ static struct kvm_arm_target target_cortex_a7 = { static int arm_cpu__core_init(struct kvm *kvm) { - return (kvm_cpu__register_kvm_arm_target(target_cortex_a15) || + return (kvm_cpu__register_kvm_arm_target(target_generic_v7) || + kvm_cpu__register_kvm_arm_target(target_cortex_a15) || kvm_cpu__register_kvm_arm_target(target_cortex_a7)); } I wonder if you could avoid the registration of this target and instead reference it later directly (instead of using a magic 0 index)? This way you wouldn't need to care about avoiding accidental .id matches with the UINT_MAX above. core_init(arm_cpu__core_init); diff --git a/tools/kvm/arm/aarch64/arm-cpu.c b/tools/kvm/arm/aarch64/arm-cpu.c index ce5ea2f..9ee3da3 100644 --- a/tools/kvm/arm/aarch64/arm-cpu.c +++ b/tools/kvm/arm/aarch64/arm-cpu.c @@ -16,13 +16,18 @@ static void generate_fdt_nodes(void *fdt, struct kvm *kvm, u32 gic_phandle) timer__generate_fdt_nodes(fdt, kvm, timer_interrupts); } - static int arm_cpu__vcpu_init(struct kvm_cpu *vcpu) { vcpu-generate_fdt_nodes = generate_fdt_nodes; return 0; } +static struct kvm_arm_target target_generic_v8 = { + .id = UINT_MAX, + .compatible = arm,arm-v8, + .init = arm_cpu__vcpu_init, +}; + static struct kvm_arm_target target_aem_v8 = { .id = KVM_ARM_TARGET_AEM_V8, .compatible = arm,arm-v8, @@ -43,7 +48,8 @@ static struct kvm_arm_target target_cortex_a57 = { static int arm_cpu__core_init(struct kvm *kvm) { - return (kvm_cpu__register_kvm_arm_target(target_aem_v8) || + return (kvm_cpu__register_kvm_arm_target(target_generic_v8) || + kvm_cpu__register_kvm_arm_target(target_aem_v8) || kvm_cpu__register_kvm_arm_target(target_foundation_v8) || kvm_cpu__register_kvm_arm_target(target_cortex_a57)); } (same thing like for v7 here) diff --git a/tools/kvm/arm/kvm-cpu.c b/tools/kvm/arm/kvm-cpu.c index aeaa4cf..6de5344 100644 --- a/tools/kvm/arm/kvm-cpu.c +++ b/tools/kvm/arm/kvm-cpu.c @@ -13,7 +13,7 @@ int kvm_cpu__get_debug_fd(void) return debug_fd; } -static struct kvm_arm_target *kvm_arm_targets[KVM_ARM_NUM_TARGETS]; +static struct kvm_arm_target *kvm_arm_targets[KVM_ARM_NUM_TARGETS+1]; w/s issue int kvm_cpu__register_kvm_arm_target(struct kvm_arm_target *target) { unsigned int i = 0; @@ -33,7 +33,8 @@ struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id) struct kvm_arm_target *target; struct kvm_cpu *vcpu; int coalesced_offset, mmap_size, err = -1; - unsigned int i; + unsigned int i, target_type; + struct kvm_vcpu_init preferred_init; struct kvm_vcpu_init vcpu_init = { .features = ARM_VCPU_FEATURE_FLAGS(kvm, cpu_id) }; @@ -55,19 +56,47 @@ struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id) if (vcpu-kvm_run == MAP_FAILED) die(unable to mmap vcpu fd); - /* Find an appropriate target CPU type. */ - for (i = 0; i ARRAY_SIZE(kvm_arm_targets); ++i) { - if (!kvm_arm_targets[i]) - continue; - target = kvm_arm_targets[i]; - vcpu_init.target = target-id; + /* + * If preferred target ioctl successful then use
Re: [PATCH v4 4/4] kvmtool: ARM/ARM64: Provide PSCI-0.2 to guest when KVM supports it
Hi Anup, this looks good now, only one minor formatting thing below. On 19/09/14 00:57, Anup Patel wrote: If in-kernel KVM support PSCI-0.2 emulation then we should set KVM_ARM_VCPU_PSCI_0_2 feature for each guest VCPU and also provide arm,psci-0.2,arm,psci as PSCI compatible string. This patch updates kvm_cpu__arch_init() and setup_fdt() as per above. Signed-off-by: Pranavkumar Sawargaonkar pranavku...@linaro.org Signed-off-by: Anup Patel anup.pa...@linaro.org --- tools/kvm/arm/fdt.c | 52 ++- tools/kvm/arm/kvm-cpu.c |5 + 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/tools/kvm/arm/fdt.c b/tools/kvm/arm/fdt.c index 186a718..a15450e 100644 --- a/tools/kvm/arm/fdt.c +++ b/tools/kvm/arm/fdt.c @@ -13,6 +13,7 @@ #include linux/byteorder.h #include linux/kernel.h #include linux/sizes.h +#include linux/psci.h static char kern_cmdline[COMMAND_LINE_SIZE]; @@ -84,6 +85,34 @@ static void generate_irq_prop(void *fdt, u8 irq) _FDT(fdt_property(fdt, interrupts, irq_prop, sizeof(irq_prop))); } +struct psci_fns { + u32 cpu_suspend; + u32 cpu_off; + u32 cpu_on; + u32 migrate; +}; + +static struct psci_fns psci_0_1_fns = { + .cpu_suspend = KVM_PSCI_FN_CPU_SUSPEND, + .cpu_off = KVM_PSCI_FN_CPU_OFF, + .cpu_on = KVM_PSCI_FN_CPU_ON, + .migrate = KVM_PSCI_FN_MIGRATE, +}; + +static struct psci_fns psci_0_2_aarch32_fns = { + .cpu_suspend = PSCI_0_2_FN_CPU_SUSPEND, + .cpu_off = PSCI_0_2_FN_CPU_OFF, + .cpu_on = PSCI_0_2_FN_CPU_ON, + .migrate = PSCI_0_2_FN_MIGRATE, +}; + +static struct psci_fns psci_0_2_aarch64_fns = { + .cpu_suspend = PSCI_0_2_FN64_CPU_SUSPEND, + .cpu_off = PSCI_0_2_FN_CPU_OFF, + .cpu_on = PSCI_0_2_FN64_CPU_ON, + .migrate = PSCI_0_2_FN64_MIGRATE, +}; + static int setup_fdt(struct kvm *kvm) { struct device_header *dev_hdr; @@ -93,6 +122,7 @@ static int setup_fdt(struct kvm *kvm) cpu_to_fdt64(kvm-arch.memory_guest_start), cpu_to_fdt64(kvm-ram_size), }; + struct psci_fns *fns; void *fdt = staging_fdt; void *fdt_dest = guest_flat_to_host(kvm, kvm-arch.dtb_guest_start); @@ -162,12 +192,24 @@ static int setup_fdt(struct kvm *kvm) /* PSCI firmware */ _FDT(fdt_begin_node(fdt, psci)); - _FDT(fdt_property_string(fdt, compatible, arm,psci)); + if (kvm__supports_extension(kvm, KVM_CAP_ARM_PSCI_0_2)) { + const char compatible[] = arm,psci-0.2\0arm,psci; + _FDT(fdt_property(fdt, compatible, + compatible, sizeof(compatible))); + if (kvm-cfg.arch.aarch32_guest) { + fns = psci_0_2_aarch32_fns; + } else { + fns = psci_0_2_aarch64_fns; + } You can remove the braces here. Given that you fix that: Reviewed-by: Andre Przywara andre.przyw...@arm.com Thanks! Andre + } else { + _FDT(fdt_property_string(fdt, compatible, arm,psci)); + fns = psci_0_1_fns; + } _FDT(fdt_property_string(fdt, method, hvc)); - _FDT(fdt_property_cell(fdt, cpu_suspend, KVM_PSCI_FN_CPU_SUSPEND)); - _FDT(fdt_property_cell(fdt, cpu_off, KVM_PSCI_FN_CPU_OFF)); - _FDT(fdt_property_cell(fdt, cpu_on, KVM_PSCI_FN_CPU_ON)); - _FDT(fdt_property_cell(fdt, migrate, KVM_PSCI_FN_MIGRATE)); + _FDT(fdt_property_cell(fdt, cpu_suspend, fns-cpu_suspend)); + _FDT(fdt_property_cell(fdt, cpu_off, fns-cpu_off)); + _FDT(fdt_property_cell(fdt, cpu_on, fns-cpu_on)); + _FDT(fdt_property_cell(fdt, migrate, fns-migrate)); _FDT(fdt_end_node(fdt)); /* Finalise. */ diff --git a/tools/kvm/arm/kvm-cpu.c b/tools/kvm/arm/kvm-cpu.c index 6de5344..219de16 100644 --- a/tools/kvm/arm/kvm-cpu.c +++ b/tools/kvm/arm/kvm-cpu.c @@ -56,6 +56,11 @@ struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id) if (vcpu-kvm_run == MAP_FAILED) die(unable to mmap vcpu fd); + /* Set KVM_ARM_VCPU_PSCI_0_2 if available */ + if (kvm__supports_extension(kvm, KVM_CAP_ARM_PSCI_0_2)) { + vcpu_init.features[0] |= (1UL KVM_ARM_VCPU_PSCI_0_2); + } + /* * If preferred target ioctl successful then use preferred target * else try each and every target type. -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4 3/4] kvmtool: Handle exit reason KVM_EXIT_SYSTEM_EVENT
On 19/09/14 00:57, Anup Patel wrote: The KVM_EXIT_SYSTEM_EVENT exit reason was added to define architecture independent system-wide events for a Guest. Currently, it is used by in-kernel PSCI-0.2 emulation of KVM ARM/ARM64 to inform user space about PSCI SYSTEM_OFF or PSCI SYSTEM_RESET request. For now, we simply treat all system-wide guest events as shutdown request in KVMTOOL. Signed-off-by: Pranavkumar Sawargaonkar pranavku...@linaro.org Signed-off-by: Anup Patel anup.pa...@linaro.org --- tools/kvm/kvm-cpu.c | 21 + 1 file changed, 21 insertions(+) diff --git a/tools/kvm/kvm-cpu.c b/tools/kvm/kvm-cpu.c index ee0a8ec..5180039 100644 --- a/tools/kvm/kvm-cpu.c +++ b/tools/kvm/kvm-cpu.c @@ -160,6 +160,27 @@ int kvm_cpu__start(struct kvm_cpu *cpu) goto exit_kvm; case KVM_EXIT_SHUTDOWN: goto exit_kvm; + case KVM_EXIT_SYSTEM_EVENT: + /* + * Print the type of system event and + * treat all system events as shutdown request. + */ + switch (cpu-kvm_run-system_event.type) { + case KVM_SYSTEM_EVENT_SHUTDOWN: + printf( # Info: shutdown system event\n); + goto exit_kvm; + case KVM_SYSTEM_EVENT_RESET: + printf( # Info: reset system event\n); + printf( # Info: KVMTOOL does not support VM reset\n); + printf( # Info: please re-launch the VM manually\n); + goto exit_kvm; + default: + printf( # Warning: unknown system event type=%d\n, +cpu-kvm_run-system_event.type); + printf( # Info: exiting KVMTOOL\n); + goto exit_kvm; + }; + break; default: { bool ret; Looks good to me. Reviewed-by: Andre Przywara andre.przyw...@arm.com Cheers, Andre. -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4 2/4] kvmtool: ARM64: Add target type potenza for aarch64
On 19/09/14 00:57, Anup Patel wrote: The VCPU target type KVM_ARM_TARGET_XGENE_POTENZA is available in latest Linux-3.16-rcX or higher hence register aarch64 target type for it. This patch enables us to run KVMTOOL on X-Gene Potenza host. I still don't like the addition of another CPU, but for the sake of running older kernels (which seems to have a use-case in your case) I am OK with this. Maybe it's worth adding a comment which states that this list is closed and just provided to support older kernels? So that other SoCs don't get funny ideas... ;-) Cheers, Andre. Signed-off-by: Pranavkumar Sawargaonkar pranavku...@linaro.org Signed-off-by: Anup Patel anup.pa...@linaro.org --- tools/kvm/arm/aarch64/arm-cpu.c |9 - 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/kvm/arm/aarch64/arm-cpu.c b/tools/kvm/arm/aarch64/arm-cpu.c index 9ee3da3..51a1e2f 100644 --- a/tools/kvm/arm/aarch64/arm-cpu.c +++ b/tools/kvm/arm/aarch64/arm-cpu.c @@ -46,11 +46,18 @@ static struct kvm_arm_target target_cortex_a57 = { .init = arm_cpu__vcpu_init, }; +static struct kvm_arm_target target_potenza = { + .id = KVM_ARM_TARGET_XGENE_POTENZA, + .compatible = arm,arm-v8, + .init = arm_cpu__vcpu_init, +}; + static int arm_cpu__core_init(struct kvm *kvm) { return (kvm_cpu__register_kvm_arm_target(target_generic_v8) || kvm_cpu__register_kvm_arm_target(target_aem_v8) || kvm_cpu__register_kvm_arm_target(target_foundation_v8) || - kvm_cpu__register_kvm_arm_target(target_cortex_a57)); + kvm_cpu__register_kvm_arm_target(target_cortex_a57) || + kvm_cpu__register_kvm_arm_target(target_potenza)); } core_init(arm_cpu__core_init); -- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you. ARM Limited, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England Wales, Company No: 2557590 ARM Holdings plc, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England Wales, Company No: 2548782 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] kvmtool/arm{,64}: fix ARM initrd functionality
lkvm -i is currently broken on ARM/ARM64. We should not try to convert smaller-than-4GB addresses into 64-bit big endian and then stuff them into u32 variables if we expect to read anything other than 0 out of it. Adjust the type to u64 to write the proper address in BE format into the /chosen node (and also match the address size we formely posted) and let Linux thus read the right values. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- tools/kvm/arm/fdt.c |4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/kvm/arm/fdt.c b/tools/kvm/arm/fdt.c index 186a718..1a76b07c 100644 --- a/tools/kvm/arm/fdt.c +++ b/tools/kvm/arm/fdt.c @@ -119,8 +119,8 @@ static int setup_fdt(struct kvm *kvm) /* Initrd */ if (kvm-arch.initrd_size != 0) { - u32 ird_st_prop = cpu_to_fdt64(kvm-arch.initrd_guest_start); - u32 ird_end_prop = cpu_to_fdt64(kvm-arch.initrd_guest_start + + u64 ird_st_prop = cpu_to_fdt64(kvm-arch.initrd_guest_start); + u64 ird_end_prop = cpu_to_fdt64(kvm-arch.initrd_guest_start + kvm-arch.initrd_size); _FDT(fdt_property(fdt, linux,initrd-start, -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 1/4] kvmtool: ARM: Use KVM_ARM_PREFERRED_TARGET vm ioctl to determine target cpu
Hi Anup, On 08/09/14 09:17, Anup Patel wrote: Instead, of trying out each and every target type we should use KVM_ARM_PREFERRED_TARGET vm ioctl to determine target type for KVM ARM/ARM64. If KVM_ARM_PREFERRED_TARGET vm ioctl fails then we fallback to old method of trying all known target types. If KVM_ARM_PREFERRED_TARGET vm ioctl succeeds but the returned target type is not known to KVMTOOL then we forcefully init VCPU with target type returned by KVM_ARM_PREFERRED_TARGET vm ioctl. Signed-off-by: Pranavkumar Sawargaonkar pranavku...@linaro.org Signed-off-by: Anup Patel anup.pa...@linaro.org --- tools/kvm/arm/kvm-cpu.c | 52 +-- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/tools/kvm/arm/kvm-cpu.c b/tools/kvm/arm/kvm-cpu.c index aeaa4cf..ba7a762 100644 --- a/tools/kvm/arm/kvm-cpu.c +++ b/tools/kvm/arm/kvm-cpu.c @@ -33,7 +33,8 @@ struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id) struct kvm_arm_target *target; struct kvm_cpu *vcpu; int coalesced_offset, mmap_size, err = -1; - unsigned int i; + unsigned int i, target_type; + struct kvm_vcpu_init preferred_init; struct kvm_vcpu_init vcpu_init = { .features = ARM_VCPU_FEATURE_FLAGS(kvm, cpu_id) }; @@ -55,19 +56,47 @@ struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id) if (vcpu-kvm_run == MAP_FAILED) die(unable to mmap vcpu fd); - /* Find an appropriate target CPU type. */ - for (i = 0; i ARRAY_SIZE(kvm_arm_targets); ++i) { - if (!kvm_arm_targets[i]) - continue; - target = kvm_arm_targets[i]; - vcpu_init.target = target-id; - err = ioctl(vcpu-vcpu_fd, KVM_ARM_VCPU_INIT, vcpu_init); - if (!err) - break; + /* + * If preferred target ioctl successful then use preferred target + * else try each and every target type. + */ + err = ioctl(kvm-vm_fd, KVM_ARM_PREFERRED_TARGET, preferred_init); + if (!err) { + /* Match preferred target CPU type. */ + target = NULL; + for (i = 0; i ARRAY_SIZE(kvm_arm_targets); ++i) { + if (!kvm_arm_targets[i]) + continue; + if (kvm_arm_targets[i]-id == preferred_init.target) { + target = kvm_arm_targets[i]; + target_type = kvm_arm_targets[i]-id; + break; + } + } + if (!target) { + target = kvm_arm_targets[0]; I think you missed the part of the patch which adds the now magic zero member of kvm_arm_targets[]. A simple static initializer should work. + target_type = preferred_init.target; Can't you move that out of the loop, in front of it actually? Then you can get rid of the line above setting the target_type also, since you always use the same value now, regardless whether you found that CPU in the list or not. + } + } else { + /* Find an appropriate target CPU type. */ + for (i = 0; i ARRAY_SIZE(kvm_arm_targets); ++i) { + if (!kvm_arm_targets[i]) + continue; + target = kvm_arm_targets[i]; + target_type = target-id; + vcpu_init.target = target_type; + err = ioctl(vcpu-vcpu_fd, KVM_ARM_VCPU_INIT, vcpu_init); + if (!err) + break; + } + if (err) + die(Unable to find matching target); } + vcpu_init.target = target_type; + err = ioctl(vcpu-vcpu_fd, KVM_ARM_VCPU_INIT, vcpu_init); You should do this only in the if-branch above, since you (try to) call KVM_ARM_VCPU_INIT already in the else branch before. Otherwise in the latter case you would do it twice. Regards, Andre. if (err || target-init(vcpu)) - die(Unable to initialise ARM vcpu); + die(Unable to initialise vcpu); coalesced_offset = ioctl(kvm-sys_fd, KVM_CHECK_EXTENSION, KVM_CAP_COALESCED_MMIO); @@ -81,6 +110,7 @@ struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id) vcpu-cpu_type = target-id; vcpu-cpu_compatible= target-compatible; vcpu-is_running= true; + return vcpu; } -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 2/4] kvmtool: ARM64: Add target type potenza for aarch64
Anup, On 08/09/14 09:17, Anup Patel wrote: The VCPU target type KVM_ARM_TARGET_XGENE_POTENZA is available in latest Linux-3.16-rcX or higher hence register aarch64 target type for it. This patch enables us to run KVMTOOL on X-Gene Potenza host. Why do you need this still if the previous patch got rid of the need for naming each and every CPU in kvmtool? Do you care about kernels older than 3.12? I wouldn't bother so much since you'd need a much newer kvmtool anyway. Can you consider dropping this patch then? I'd rather avoid adding CPUs to this list needlessly from now on. Regards, Andre. Signed-off-by: Pranavkumar Sawargaonkar pranavku...@linaro.org Signed-off-by: Anup Patel anup.pa...@linaro.org --- tools/kvm/arm/aarch64/arm-cpu.c |9 - 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/kvm/arm/aarch64/arm-cpu.c b/tools/kvm/arm/aarch64/arm-cpu.c index ce5ea2f..ce526e3 100644 --- a/tools/kvm/arm/aarch64/arm-cpu.c +++ b/tools/kvm/arm/aarch64/arm-cpu.c @@ -41,10 +41,17 @@ static struct kvm_arm_target target_cortex_a57 = { .init = arm_cpu__vcpu_init, }; +static struct kvm_arm_target target_potenza = { + .id = KVM_ARM_TARGET_XGENE_POTENZA, + .compatible = arm,arm-v8, + .init = arm_cpu__vcpu_init, +}; + static int arm_cpu__core_init(struct kvm *kvm) { return (kvm_cpu__register_kvm_arm_target(target_aem_v8) || kvm_cpu__register_kvm_arm_target(target_foundation_v8) || - kvm_cpu__register_kvm_arm_target(target_cortex_a57)); + kvm_cpu__register_kvm_arm_target(target_cortex_a57) || + kvm_cpu__register_kvm_arm_target(target_potenza)); } core_init(arm_cpu__core_init); -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 3/4] kvmtool: Handle exit reason KVM_EXIT_SYSTEM_EVENT
On 08/09/14 09:17, Anup Patel wrote: The KVM_EXIT_SYSTEM_EVENT exit reason was added to define architecture independent system-wide events for a Guest. Currently, it is used by in-kernel PSCI-0.2 emulation of KVM ARM/ARM64 to inform user space about PSCI SYSTEM_OFF or PSCI SYSTEM_RESET request. For now, we simply treat all system-wide guest events as shutdown request in KVMTOOL. Is that really a good idea to default to exit_kvm? I find a shutdown a rather drastic default. Also I'd like to see RESET not easily mapped to shutdown. If the user resets the box explicitly, it's probably expected to come up again (to load an updated kernel or proceed with an install). So what about a more explicit message like: ... please restart the VM until we gain proper reboot support in kvmtool? Regards, Andre. Signed-off-by: Pranavkumar Sawargaonkar pranavku...@linaro.org Signed-off-by: Anup Patel anup.pa...@linaro.org --- tools/kvm/kvm-cpu.c | 19 +++ 1 file changed, 19 insertions(+) diff --git a/tools/kvm/kvm-cpu.c b/tools/kvm/kvm-cpu.c index ee0a8ec..6d01192 100644 --- a/tools/kvm/kvm-cpu.c +++ b/tools/kvm/kvm-cpu.c @@ -160,6 +160,25 @@ int kvm_cpu__start(struct kvm_cpu *cpu) goto exit_kvm; case KVM_EXIT_SHUTDOWN: goto exit_kvm; + case KVM_EXIT_SYSTEM_EVENT: + /* + * Print the type of system event and + * treat all system events as shutdown request. + */ + switch (cpu-kvm_run-system_event.type) { + case KVM_SYSTEM_EVENT_SHUTDOWN: + printf( # Info: shutdown system event\n); + break; + case KVM_SYSTEM_EVENT_RESET: + printf( # Info: reset system event\n); + break; + default: + printf( # Warning: unknown system event type=%d\n, +cpu-kvm_run-system_event.type); + break; + }; + printf( # Info: exiting KVMTOOL\n); + goto exit_kvm; default: { bool ret; -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 12/15] arm/arm64: KVM: add virtual GICv3 distributor emulation
Hi wanghaibin, On 05/09/14 04:28, wanghaibin wrote: On 2014/8/21 21:06, Andre Przywara wrote: +void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg) +{ +struct kvm *kvm = vcpu-kvm; +struct kvm_vcpu *c_vcpu; +struct vgic_dist *dist = kvm-arch.vgic; +u16 target_cpus; +u64 mpidr, mpidr_h, mpidr_l; +int sgi, mode, c, vcpu_id; +int updated = 0; + +vcpu_id = vcpu-vcpu_id; + +sgi = (reg 24) 0xf; +mode = (reg 40) 0x1; +target_cpus = reg 0x; +mpidr = ((reg 48) 0xff) MPIDR_LEVEL_SHIFT(3); +mpidr |= ((reg 32) 0xff) MPIDR_LEVEL_SHIFT(2); +mpidr |= ((reg 16) 0xff) MPIDR_LEVEL_SHIFT(1); +mpidr = ~MPIDR_LEVEL_MASK; + +/* + * We take the dist lock here, because we come from the sysregs + * code path and not from MMIO (where this is already done) + */ +spin_lock(dist-lock); +kvm_for_each_vcpu(c, c_vcpu, kvm) { Hi, Andre, there is a suggestion. Move the +if (target_cpus == 0) +break; code, out the kvm_for_each_vcpu loop, Like : if (!mode target_cpus == 0) /* the judgement do not need judge in kvm_for_each_vcpu loop */ return; I am not so much concerned about someone actually sending a SGI to no-one, but the code is there to stop the loop after the only CPU has been serviced. ... spin_lock(dist-lock); kvm_for_each_vcpu(c, c_vcpu, kvm) { +if (mode c == vcpu_id) /* not to myself */ +continue; +if (!mode) { +mpidr_h = kvm_vcpu_get_mpidr(c_vcpu); +mpidr_l = MPIDR_AFFINITY_LEVEL(mpidr_h, 0); +mpidr_h = ~MPIDR_LEVEL_MASK; +if (mpidr != mpidr_h) +continue; +if (!(target_cpus BIT(mpidr_l))) +continue; +target_cpus = ~BIT(mpidr_l); Here the CPU bit is removed from target_cpus. The idea is that most of the time we trigger a SGI for a single CPU only, so there is no need to further iterate through all VCPUs once we found the first and only one. That's why I check target_cpus inside the loop. Regards, Andre. +} +/* Flag the SGI as pending */ +vgic_dist_irq_set(c_vcpu, sgi); +updated = 1; +kvm_debug(SGI%d from CPU%d to CPU%d\n, sgi, vcpu_id, c); +} +if (updated) +vgic_update_state(vcpu-kvm); +spin_unlock(dist-lock); +if (updated) +vgic_kick_vcpus(vcpu-kvm); +} + + -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 1/4] kvmtool: ARM: Use KVM_ARM_PREFERRED_TARGET vm ioctl to determine target cpu
(resent, that was the wrong account before ...) Hi Anup, On 26/08/14 10:22, Anup Patel wrote: Instead, of trying out each and every target type we should use KVM_ARM_PREFERRED_TARGET vm ioctl to determine target type for KVM ARM/ARM64. If KVM_ARM_PREFERRED_TARGET vm ioctl fails then we fallback to old method of trying all known target types. So as the algorithm currently works, it does not give us much improvement over the current behaviour. We still need to list each supported MPIDR both in kvmtool and in the kernel. Looking more closely at the code, beside the target id we only need the kvm_target_arm[] list for the compatible string and the init() function. The latter is (currently) the same for all supported type, so we could use that as a standard fallback function. The compatible string seems to be completely ignored by the ARM64 kernel, so we could as well pass arm,armv8 all the time. In ARM(32) kernels we seem to not make any real use of it for CPUs which we care for (with virtualisation extensions). So what about the following: We keep the list as it is, but not extend it for future CPUs, expect those in need for a special compatible string or a specific init function. Instead we rely on PREFFERED_TARGET for all current and upcoming CPUs (meaning unsupported CPUs must use a 3.12 kernel or higher). If PREFERRED_TARGET works, we scan the list anyway (to find CPUs needing special treatment), but on failure of finding something in the list we just go ahead: - with the target ID the kernel returned, - an arm,armv8 compatible string (for arm64, not sure about arm) and - call the standard kvmtool init function This should relief us from the burden of adding each supported CPU to kvmtool. Does that make sense of am I missing something? I will hack something up to prove that it works. Also there is now a race on big.LITTLE systems: if the PREFERRED_TARGET ioctl is executed on one cluster, while the KVM_ARM_VCPU_INIT call is done on another core with a different MPIDR, then the kernel will refuse to init the CPU. I don't know of a good solution for this (except the sledgehammer pinning with sched_setaffinity to the current core, which is racy, too, but should at least work somehow ;-) Any ideas? Signed-off-by: Pranavkumar Sawargaonkar pranavku...@linaro.org Signed-off-by: Anup Patel anup.pa...@linaro.org --- tools/kvm/arm/kvm-cpu.c | 46 +++--- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/tools/kvm/arm/kvm-cpu.c b/tools/kvm/arm/kvm-cpu.c index aeaa4cf..c010e9c 100644 --- a/tools/kvm/arm/kvm-cpu.c +++ b/tools/kvm/arm/kvm-cpu.c @@ -34,6 +34,7 @@ struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id) struct kvm_cpu *vcpu; int coalesced_offset, mmap_size, err = -1; unsigned int i; + struct kvm_vcpu_init preferred_init; struct kvm_vcpu_init vcpu_init = { .features = ARM_VCPU_FEATURE_FLAGS(kvm, cpu_id) }; @@ -55,20 +56,42 @@ struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id) if (vcpu-kvm_run == MAP_FAILED) die(unable to mmap vcpu fd); - /* Find an appropriate target CPU type. */ - for (i = 0; i ARRAY_SIZE(kvm_arm_targets); ++i) { - if (!kvm_arm_targets[i]) - continue; - target = kvm_arm_targets[i]; - vcpu_init.target = target-id; + /* + * If preferred target ioctl successful then use preferred target + * else try each and every target type. + */ + err = ioctl(kvm-vm_fd, KVM_ARM_PREFERRED_TARGET, preferred_init); + if (!err) { + /* Match preferred target CPU type. */ + target = NULL; + for (i = 0; i ARRAY_SIZE(kvm_arm_targets); ++i) { + if (!kvm_arm_targets[i]) + continue; + if (kvm_arm_targets[i]-id == preferred_init.target) { + target = kvm_arm_targets[i]; + break; + } + } + + vcpu_init.target = preferred_init.target; err = ioctl(vcpu-vcpu_fd, KVM_ARM_VCPU_INIT, vcpu_init); - if (!err) - break; + if (err || target-init(vcpu)) + die(Unable to initialise vcpu for preferred target); So that segfaults if the CPU is not in kvmtools list (as target is still NULL). In the current implementation we should bail out (but better use the algorithm described above). Also these two line can be moved outside of the loop and joined with the last two lines from the else clause ... + } else { + /* Find an appropriate target CPU type. */ + for (i = 0; i ARRAY_SIZE(kvm_arm_targets); ++i) { + if (!kvm_arm_targets[i]) + continue; +
Re: [PATCH v2 4/4] kvmtool: ARM/ARM64: Provide PSCI-0.2 to guest when KVM supports it
Hi Anup, On 26/08/14 10:22, Anup Patel wrote: If in-kernel KVM support PSCI-0.2 emulation then we should set KVM_ARM_VCPU_PSCI_0_2 feature for each guest VCPU and also provide arm,psci-0.2,arm,psci as PSCI compatible string. This patch updates kvm_cpu__arch_init() and setup_fdt() as per above. Signed-off-by: Pranavkumar Sawargaonkar pranavku...@linaro.org Signed-off-by: Anup Patel anup.pa...@linaro.org --- tools/kvm/arm/fdt.c | 39 +-- tools/kvm/arm/kvm-cpu.c |5 + 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/tools/kvm/arm/fdt.c b/tools/kvm/arm/fdt.c index 186a718..93849cf2 100644 --- a/tools/kvm/arm/fdt.c +++ b/tools/kvm/arm/fdt.c @@ -13,6 +13,7 @@ #include linux/byteorder.h #include linux/kernel.h #include linux/sizes.h +#include linux/psci.h static char kern_cmdline[COMMAND_LINE_SIZE]; @@ -162,12 +163,38 @@ static int setup_fdt(struct kvm *kvm) /* PSCI firmware */ _FDT(fdt_begin_node(fdt, psci)); - _FDT(fdt_property_string(fdt, compatible, arm,psci)); - _FDT(fdt_property_string(fdt, method, hvc)); - _FDT(fdt_property_cell(fdt, cpu_suspend, KVM_PSCI_FN_CPU_SUSPEND)); - _FDT(fdt_property_cell(fdt, cpu_off, KVM_PSCI_FN_CPU_OFF)); - _FDT(fdt_property_cell(fdt, cpu_on, KVM_PSCI_FN_CPU_ON)); - _FDT(fdt_property_cell(fdt, migrate, KVM_PSCI_FN_MIGRATE)); + if (kvm__supports_extension(kvm, KVM_CAP_ARM_PSCI_0_2)) { + const char compatible[] = arm,psci-0.2\0arm,psci; + _FDT(fdt_property(fdt, compatible, + compatible, sizeof(compatible))); + _FDT(fdt_property_string(fdt, method, hvc)); + if (kvm-cfg.arch.aarch32_guest) { + _FDT(fdt_property_cell(fdt, cpu_suspend, + PSCI_0_2_FN_CPU_SUSPEND)); + _FDT(fdt_property_cell(fdt, cpu_off, + PSCI_0_2_FN_CPU_OFF)); + _FDT(fdt_property_cell(fdt, cpu_on, + PSCI_0_2_FN_CPU_ON)); + _FDT(fdt_property_cell(fdt, migrate, + PSCI_0_2_FN_MIGRATE)); + } else { + _FDT(fdt_property_cell(fdt, cpu_suspend, + PSCI_0_2_FN64_CPU_SUSPEND)); + _FDT(fdt_property_cell(fdt, cpu_off, + PSCI_0_2_FN_CPU_OFF)); + _FDT(fdt_property_cell(fdt, cpu_on, + PSCI_0_2_FN64_CPU_ON)); + _FDT(fdt_property_cell(fdt, migrate, + PSCI_0_2_FN64_MIGRATE)); + } + } else { + _FDT(fdt_property_string(fdt, compatible, arm,psci)); + _FDT(fdt_property_string(fdt, method, hvc)); + _FDT(fdt_property_cell(fdt, cpu_suspend, KVM_PSCI_FN_CPU_SUSPEND)); + _FDT(fdt_property_cell(fdt, cpu_off, KVM_PSCI_FN_CPU_OFF)); + _FDT(fdt_property_cell(fdt, cpu_on, KVM_PSCI_FN_CPU_ON)); + _FDT(fdt_property_cell(fdt, migrate, KVM_PSCI_FN_MIGRATE)); + } I guess this could be simplified much by defining three arrays with the respective function IDs and setting a pointer to the right one here. Then there would still be only one set of _FDT() calls, which reference this pointer. Like: uint32_t *psci_fn_ids; ... if (KVM_CAP_ARM_PSCI_0_2) { if (aarch32_guest) psci_fn_ids = psci_0_2_fn_ids; else psci_fn_ids = psci_0_2_fn64_ids; } else psci_fn_ids = psci_0_1_fn_ids; _FDT(fdt_property_cell(fdt, cpu_suspend, psci_fn_ids[0])); _FDT(fdt_property_cell(fdt, cpu_off, psci_fn_ids[1])); ... Also I wonder if we actually need those different IDs. The binding doc says that Linux' PSCI 0.2 code ignores them altogether, only using them if the arm,psci branch of the compatible string is actually used (on kernels not supporting PSCI 0.2) So can't we just always pass the PSCI 0.1 numbers in here? That would restrict this whole patch to just changing the compatible string, right? Regards, Andre. _FDT(fdt_end_node(fdt)); /* Finalise. */ diff --git a/tools/kvm/arm/kvm-cpu.c b/tools/kvm/arm/kvm-cpu.c index c010e9c..0637e9a 100644 --- a/tools/kvm/arm/kvm-cpu.c +++ b/tools/kvm/arm/kvm-cpu.c @@ -56,6 +56,11 @@ struct kvm_cpu *kvm_cpu__arch_init(struct kvm *kvm, unsigned long cpu_id) if (vcpu-kvm_run == MAP_FAILED) die(unable to mmap vcpu fd); + /* Set KVM_ARM_VCPU_PSCI_0_2 if available */ + if (kvm__supports_extension(kvm, KVM_CAP_ARM_PSCI_0_2)) { + vcpu_init.features[0] |= (1UL KVM_ARM_VCPU_PSCI_0_2); + } + /* * If preferred
Re: [PATCH v2 1/4] kvmtool: ARM: Use KVM_ARM_PREFERRED_TARGET vm ioctl to determine target cpu
On 29/08/14 17:17, Will Deacon wrote: On Fri, Aug 29, 2014 at 10:10:52AM +0100, Andre Przywara wrote: (resent, that was the wrong account before ...) Aha, and now your true identity has been revealed to all! Nice try Andre... or should I say, Rienhard? Psst, don't give Google funny ideas about this (now very secret) relationship ;-) Cheers, Andre R P. -- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you. ARM Limited, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England Wales, Company No: 2557590 ARM Holdings plc, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England Wales, Company No: 2548782 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 06/15] arm/arm64: KVM: make the maximum number of vCPUs a per-VM value
Currently the maximum number of vCPUs supported is a global value limited by the used GIC model. GICv3 will lift this limit, but we still need to observe it for guests using GICv2. So the maximum number of vCPUs is per-VM value, depending on the GIC model the guest uses. Store and check the value in struct kvm_arch, but keep it down to 8 for now. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm/include/asm/kvm_host.h |1 + arch/arm/kvm/arm.c|6 ++ arch/arm64/include/asm/kvm_host.h |3 +++ virt/kvm/arm/vgic-v2.c|5 + virt/kvm/arm/vgic-v3.c|6 ++ 5 files changed, 21 insertions(+) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index cf99ad0..0638419 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -67,6 +67,7 @@ struct kvm_arch { /* Interrupt controller */ struct vgic_distvgic; + int max_vcpus; }; #define KVM_NR_MEM_OBJS 40 diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 157e1b6..190f05f 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -142,6 +142,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) /* Mark the initial VMID generation invalid */ kvm-arch.vmid_gen = 0; + kvm-arch.max_vcpus = CONFIG_KVM_ARM_MAX_VCPUS; return ret; out_free_stage2_pgd: @@ -223,6 +224,11 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) int err; struct kvm_vcpu *vcpu; + if (id = kvm-arch.max_vcpus) { + err = -EINVAL; + goto out; + } + vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); if (!vcpu) { err = -ENOMEM; diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 017fbae..a325161 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -58,6 +58,9 @@ struct kvm_arch { /* VTTBR value associated with above pgd and vmid */ u64vttbr; + /* The maximum number of vCPUs depends on the used GIC model */ + int max_vcpus; + /* Interrupt controller */ struct vgic_distvgic; diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c index 90947c6..c7362ff 100644 --- a/virt/kvm/arm/vgic-v2.c +++ b/virt/kvm/arm/vgic-v2.c @@ -177,11 +177,16 @@ static struct vgic_params vgic_v2_params; static bool vgic_v2_init_emul(struct kvm *kvm, int type) { struct vgic_vm_ops *vm_ops = kvm-arch.vgic.vm_ops; + int nr_vcpus; switch (type) { case KVM_DEV_TYPE_ARM_VGIC_V2: + nr_vcpus = atomic_read(kvm-online_vcpus); + if (nr_vcpus 8) + return false; vm_ops-get_lr = vgic_v2_get_lr; vm_ops-set_lr = vgic_v2_set_lr; + kvm-arch.max_vcpus = 8; return true; } diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c index a38339e..86e8b99 100644 --- a/virt/kvm/arm/vgic-v3.c +++ b/virt/kvm/arm/vgic-v3.c @@ -171,11 +171,17 @@ static const struct vgic_ops vgic_v3_ops = { static bool vgic_v3_init_emul_compat(struct kvm *kvm, int type) { struct vgic_vm_ops *vm_ops = kvm-arch.vgic.vm_ops; + int nr_vcpus; switch (type) { case KVM_DEV_TYPE_ARM_VGIC_V2: + nr_vcpus = atomic_read(kvm-online_vcpus); + if (nr_vcpus 8) + return false; + vm_ops-get_lr = vgic_v3_get_lr; vm_ops-set_lr = vgic_v3_set_lr; + kvm-arch.max_vcpus = 8; return true; } return false; -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 12/15] arm/arm64: KVM: add virtual GICv3 distributor emulation
With everything separated and prepared, we implement a model of a GICv3 distributor and redistributors by using the existing framework to provide handler functions for each register group. Currently we limit the emulation to a model enforcing a single security state, with SRE==1 (forcing system register access) and ARE==1 (allowing more than 8 VCPUs). We share some of functions provided for GICv2 emulation, but take the different ways of addressing (v)CPUs into account. Save and restore is currently not implemented. Similar to the split-off GICv2 specific code, the new emulation code goes into a new file (vgic-v3-emul.c). Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm64/kvm/Makefile|1 + include/kvm/arm_vgic.h | 11 +- include/linux/irqchip/arm-gic-v3.h | 26 ++ include/linux/kvm_host.h |1 + include/uapi/linux/kvm.h |1 + virt/kvm/arm/vgic-v3-emul.c| 896 virt/kvm/arm/vgic.c| 11 +- virt/kvm/arm/vgic.h|3 + virt/kvm/kvm_main.c|3 + 9 files changed, 950 insertions(+), 3 deletions(-) create mode 100644 virt/kvm/arm/vgic-v3-emul.c diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile index d957353..4e6e09e 100644 --- a/arch/arm64/kvm/Makefile +++ b/arch/arm64/kvm/Makefile @@ -24,5 +24,6 @@ kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2-emul.o kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v2-switch.o kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v3.o +kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v3-emul.o kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v3-switch.o kvm-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 8aa8482..3b164ee 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -151,7 +151,11 @@ struct vgic_dist { /* Distributor and vcpu interface mapping in the guest */ phys_addr_t vgic_dist_base; - phys_addr_t vgic_cpu_base; + /* GICv2 and GICv3 use different mapped register blocks */ + union { + phys_addr_t vgic_cpu_base; + phys_addr_t vgic_redist_base; + }; /* Distributor enabled */ u32 enabled; @@ -176,6 +180,10 @@ struct vgic_dist { /* Target CPU for each IRQ */ u8 *irq_spi_cpu; + + /* Target MPIDR for each IRQ (needed for GICv3 IROUTERn) only */ + u32 *irq_spi_mpidr; + struct vgic_bitmap *irq_spi_target; /* Bitmap indicating which CPU has something pending */ @@ -253,6 +261,7 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu); void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu); int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num, bool level); +void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg); int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu); bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, struct kvm_exit_mmio *mmio); diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 03a4ea3..6a649bc 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -33,6 +33,7 @@ #define GICD_SETSPI_SR 0x0050 #define GICD_CLRSPI_SR 0x0058 #define GICD_SEIR 0x0068 +#define GICD_IGROUPR 0x0080 #define GICD_ISENABLER 0x0100 #define GICD_ICENABLER 0x0180 #define GICD_ISPENDR 0x0200 @@ -41,14 +42,31 @@ #define GICD_ICACTIVER 0x0380 #define GICD_IPRIORITYR0x0400 #define GICD_ICFGR 0x0C00 +#define GICD_IGRPMODR 0x0D00 +#define GICD_NSACR 0x0E00 #define GICD_IROUTER 0x6000 +#define GICD_IDREGS0xFFD0 #define GICD_PIDR2 0xFFE8 +/* + * Non-ARE distributor registers, needed to provide the RES0 + * semantics for KVM's emulated GICv3 + */ +#define GICD_ITARGETSR 0x0800 +#define GICD_SGIR 0x0F00 +#define GICD_CPENDSGIR 0x0F10 +#define GICD_SPENDSGIR 0x0F20 + + #define GICD_CTLR_RWP (1U 31) +#define GICD_CTLR_DS (1U 6) #define GICD_CTLR_ARE_NS (1U 4) #define GICD_CTLR_ENABLE_G1A (1U 1) #define GICD_CTLR_ENABLE_G1(1U 0) +#define GICD_TYPER_LPIS(1U 17) +#define GICD_TYPER_MBIS(1U 16) + #define GICD_IROUTER_SPI_MODE_ONE (0U 31) #define GICD_IROUTER_SPI_MODE_ANY (1U 31) @@ -56,6 +74,8 @@ #define
[PATCH v2 14/15] arm/arm64: KVM: enable kernel side of GICv3 emulation
With all the necessary GICv3 emulation code in place, we can now connect the code to the GICv3 backend in the kernel. The LR register handling is different depending on the emulated GIC model, so provide different implementations for each. Also allow non-v2-compatible GICv3 implementations (which don't provide MMIO regions for the virtual CPU interface in the DT), but restrict those hosts to use GICv3 guests only. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- virt/kvm/arm/vgic-v3.c | 168 +++- virt/kvm/arm/vgic.c|2 + 2 files changed, 127 insertions(+), 43 deletions(-) diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c index 8af8037..c4e2f13 100644 --- a/virt/kvm/arm/vgic-v3.c +++ b/virt/kvm/arm/vgic-v3.c @@ -34,6 +34,7 @@ #define GICH_LR_VIRTUALID (0x3ffUL 0) #define GICH_LR_PHYSID_CPUID_SHIFT (10) #define GICH_LR_PHYSID_CPUID (7UL GICH_LR_PHYSID_CPUID_SHIFT) +#define ICH_LR_VIRTUALID_MASK (BIT_ULL(32) - 1) /* * LRs are stored in reverse order in memory. make sure we index them @@ -43,7 +44,35 @@ static u32 ich_vtr_el2; -static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr) +static u64 sync_lr_val(u8 state) +{ + u64 lr_val = 0; + + if (state LR_STATE_PENDING) + lr_val |= ICH_LR_PENDING_BIT; + if (state LR_STATE_ACTIVE) + lr_val |= ICH_LR_ACTIVE_BIT; + if (state LR_EOI_INT) + lr_val |= ICH_LR_EOI; + + return lr_val; +} + +static u8 sync_lr_state(u64 lr_val) +{ + u8 state = 0; + + if (lr_val ICH_LR_PENDING_BIT) + state |= LR_STATE_PENDING; + if (lr_val ICH_LR_ACTIVE_BIT) + state |= LR_STATE_ACTIVE; + if (lr_val ICH_LR_EOI) + state |= LR_EOI_INT; + + return state; +} + +static struct vgic_lr vgic_v2_on_v3_get_lr(const struct kvm_vcpu *vcpu, int lr) { struct vgic_lr lr_desc; u64 val = vcpu-arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)]; @@ -53,30 +82,53 @@ static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr) lr_desc.source = (val GICH_LR_PHYSID_CPUID_SHIFT) 0x7; else lr_desc.source = 0; - lr_desc.state = 0; + lr_desc.state = sync_lr_state(val); - if (val ICH_LR_PENDING_BIT) - lr_desc.state |= LR_STATE_PENDING; - if (val ICH_LR_ACTIVE_BIT) - lr_desc.state |= LR_STATE_ACTIVE; - if (val ICH_LR_EOI) - lr_desc.state |= LR_EOI_INT; + return lr_desc; +} + +static struct vgic_lr vgic_v3_on_v3_get_lr(const struct kvm_vcpu *vcpu, int lr) +{ + struct vgic_lr lr_desc; + u64 val = vcpu-arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)]; + + lr_desc.irq = val ICH_LR_VIRTUALID_MASK; + lr_desc.source = 0; + lr_desc.state = sync_lr_state(val); return lr_desc; } -static void vgic_v3_set_lr(struct kvm_vcpu *vcpu, int lr, - struct vgic_lr lr_desc) +static void vgic_v3_on_v3_set_lr(struct kvm_vcpu *vcpu, int lr, +struct vgic_lr lr_desc) { - u64 lr_val = (((u32)lr_desc.source GICH_LR_PHYSID_CPUID_SHIFT) | - lr_desc.irq); + u64 lr_val; - if (lr_desc.state LR_STATE_PENDING) - lr_val |= ICH_LR_PENDING_BIT; - if (lr_desc.state LR_STATE_ACTIVE) - lr_val |= ICH_LR_ACTIVE_BIT; - if (lr_desc.state LR_EOI_INT) - lr_val |= ICH_LR_EOI; + lr_val = lr_desc.irq; + + /* +* currently all guest IRQs are Group1, as Group0 would result +* in a FIQ in the guest, which it wouldn't expect. +* Eventually we want to make this configurable, so we may revisit +* this in the future. +*/ + lr_val |= ICH_LR_GROUP; + + lr_val |= sync_lr_val(lr_desc.state); + + vcpu-arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)] = lr_val; +} + +static void vgic_v2_on_v3_set_lr(struct kvm_vcpu *vcpu, int lr, +struct vgic_lr lr_desc) +{ + u64 lr_val; + + lr_val = lr_desc.irq; + + lr_val |= (u32)lr_desc.source GICH_LR_PHYSID_CPUID_SHIFT; + + lr_val |= sync_lr_val(lr_desc.state); vcpu-arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)] = lr_val; } @@ -145,9 +197,8 @@ static void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp) static void vgic_v3_enable(struct kvm_vcpu *vcpu) { - struct vgic_v3_cpu_if *vgic_v3; + struct vgic_v3_cpu_if *vgic_v3 = vcpu-arch.vgic_cpu.vgic_v3; - vgic_v3 = vcpu-arch.vgic_cpu.vgic_v3; /* * By forcing VMCR to zero, the GIC will restore the binary * points to their reset values. Anything else resets to zero @@ -155,7 +206,14 @@ static void vgic_v3_enable(struct kvm_vcpu *vcpu) */ vgic_v3-vgic_vmcr
[PATCH v2 08/15] arm/arm64: KVM: refactor MMIO accessors
The MMIO accessors for GICD_I[CS]ENABLER, GICD_I[CS]PENDR and GICD_ICFGR behave very similiar in GICv3, although the way the affected vCPU is determined differs. Factor out a generic, backend-facing implementation and use small wrappers in the current GICv2 emulation to ease code sharing later. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- virt/kvm/arm/vgic.c | 93 --- 1 file changed, 52 insertions(+), 41 deletions(-) diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 5e0bc24..e8f92b2 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -418,35 +418,54 @@ static bool handle_mmio_raz_wi(struct kvm_vcpu *vcpu, return false; } -static bool handle_mmio_set_enable_reg(struct kvm_vcpu *vcpu, - struct kvm_exit_mmio *mmio, - phys_addr_t offset) +static bool vgic_handle_enable_reg(struct kvm *kvm, struct kvm_exit_mmio *mmio, + phys_addr_t offset, int vcpu_id, int access) { - u32 *reg = vgic_bitmap_get_reg(vcpu-kvm-arch.vgic.irq_enabled, - vcpu-vcpu_id, offset); - vgic_reg_access(mmio, reg, offset, - ACCESS_READ_VALUE | ACCESS_WRITE_SETBIT); + u32 *reg; + int mode = ACCESS_READ_VALUE | access; + struct kvm_vcpu *target_vcpu = kvm_get_vcpu(kvm, vcpu_id); + + reg = vgic_bitmap_get_reg(kvm-arch.vgic.irq_enabled, vcpu_id, offset); + vgic_reg_access(mmio, reg, offset, mode); if (mmio-is_write) { - vgic_update_state(vcpu-kvm); + if (access ACCESS_WRITE_CLEARBIT) { + if (offset 4) /* Force SGI enabled */ + *reg |= 0x; + vgic_retire_disabled_irqs(target_vcpu); + } + vgic_update_state(kvm); return true; } return false; } +static bool handle_mmio_set_enable_reg(struct kvm_vcpu *vcpu, + struct kvm_exit_mmio *mmio, + phys_addr_t offset) +{ + return vgic_handle_enable_reg(vcpu-kvm, mmio, offset, + vcpu-vcpu_id, ACCESS_WRITE_SETBIT); +} + static bool handle_mmio_clear_enable_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, phys_addr_t offset) { - u32 *reg = vgic_bitmap_get_reg(vcpu-kvm-arch.vgic.irq_enabled, - vcpu-vcpu_id, offset); - vgic_reg_access(mmio, reg, offset, - ACCESS_READ_VALUE | ACCESS_WRITE_CLEARBIT); + return vgic_handle_enable_reg(vcpu-kvm, mmio, offset, + vcpu-vcpu_id, ACCESS_WRITE_CLEARBIT); +} + +static bool vgic_handle_pending_reg(struct kvm *kvm, struct kvm_exit_mmio *mmio, + phys_addr_t offset, int vcpu_id, int access) +{ + u32 *reg; + int mode = ACCESS_READ_VALUE | access; + + reg = vgic_bitmap_get_reg(kvm-arch.vgic.irq_state, vcpu_id, offset); + vgic_reg_access(mmio, reg, offset, mode); if (mmio-is_write) { - if (offset 4) /* Force SGI enabled */ - *reg |= 0x; - vgic_retire_disabled_irqs(vcpu); - vgic_update_state(vcpu-kvm); + vgic_update_state(kvm); return true; } @@ -457,31 +476,16 @@ static bool handle_mmio_set_pending_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, phys_addr_t offset) { - u32 *reg = vgic_bitmap_get_reg(vcpu-kvm-arch.vgic.irq_state, - vcpu-vcpu_id, offset); - vgic_reg_access(mmio, reg, offset, - ACCESS_READ_VALUE | ACCESS_WRITE_SETBIT); - if (mmio-is_write) { - vgic_update_state(vcpu-kvm); - return true; - } - - return false; + return vgic_handle_pending_reg(vcpu-kvm, mmio, offset, + vcpu-vcpu_id, ACCESS_WRITE_SETBIT); } static bool handle_mmio_clear_pending_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, phys_addr_t offset) { - u32 *reg = vgic_bitmap_get_reg(vcpu-kvm-arch.vgic.irq_state, - vcpu-vcpu_id, offset); - vgic_reg_access(mmio, reg, offset, - ACCESS_READ_VALUE | ACCESS_WRITE_CLEARBIT); - if (mmio-is_write) { - vgic_update_state(vcpu-kvm); - return true; - } - + return vgic_handle_pending_reg(vcpu-kvm, mmio, offset, + vcpu
[PATCH v2 15/15] arm/arm64: KVM: allow userland to request a virtual GICv3
With everything in place we allow userland to request the kernel using a virtual GICv3 in the guest, which finally lifts the 8 vCPU limit for a guest. Also we provide the necessary support for guests setting the memory addresses for the virtual distributor and redistributors. This requires some userland code to make use of that feature and explicitly ask for a virtual GICv3. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm64/include/uapi/asm/kvm.h |7 ++ include/kvm/arm_vgic.h|4 ++-- virt/kvm/arm/vgic-v3-emul.c |3 +++ virt/kvm/arm/vgic.c | 46 ++--- 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 5513de4..9a62081 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -77,6 +77,13 @@ struct kvm_regs { #define KVM_VGIC_V2_DIST_SIZE 0x1000 #define KVM_VGIC_V2_CPU_SIZE 0x2000 +/* Supported VGICv3 address types */ +#define KVM_VGIC_V3_ADDR_TYPE_DIST 2 +#define KVM_VGIC_V3_ADDR_TYPE_REDIST 3 + +#define KVM_VGIC_V3_DIST_SIZE SZ_64K +#define KVM_VGIC_V3_REDIST_SIZE(2 * SZ_64K) + #define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ #define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */ #define KVM_ARM_VCPU_PSCI_0_2 2 /* CPU uses PSCI v0.2 */ diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 3b164ee..82e00a5 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -35,8 +35,8 @@ #define VGIC_MAX_IRQS 1024 /* Sanity checks... */ -#if (KVM_MAX_VCPUS 8) -#error Invalid number of CPU interfaces +#if (KVM_MAX_VCPUS 255) +#error Too many KVM VCPUs, the VGIC only supports up to 255 VCPUs for now #endif #if (VGIC_NR_IRQS_LEGACY 31) diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c index ac5c5ee..d4d9fe4 100644 --- a/virt/kvm/arm/vgic-v3-emul.c +++ b/virt/kvm/arm/vgic-v3-emul.c @@ -874,6 +874,9 @@ static int vgic_v3_has_attr(struct kvm_device *dev, case KVM_VGIC_V2_ADDR_TYPE_DIST: case KVM_VGIC_V2_ADDR_TYPE_CPU: return -ENXIO; + case KVM_VGIC_V3_ADDR_TYPE_DIST: + case KVM_VGIC_V3_ADDR_TYPE_REDIST: + return 0; } break; case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index b1bcb6d..f13ab4e 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -1567,7 +1567,7 @@ static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr, /** * kvm_vgic_addr - set or get vgic VM base addresses * @kvm: pointer to the vm struct - * @type: the VGIC addr type, one of KVM_VGIC_V2_ADDR_TYPE_XXX + * @type: the VGIC addr type, one of KVM_VGIC_V[23]_ADDR_TYPE_XXX * @addr: pointer to address value * @write: if true set the address in the VM address space, if false read the * address @@ -1581,29 +1581,49 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write) { int r = 0; struct vgic_dist *vgic = kvm-arch.vgic; + int type_needed; + phys_addr_t *addr_ptr, block_size; mutex_lock(kvm-lock); switch (type) { case KVM_VGIC_V2_ADDR_TYPE_DIST: - if (write) { - r = vgic_ioaddr_assign(kvm, vgic-vgic_dist_base, - *addr, KVM_VGIC_V2_DIST_SIZE); - } else { - *addr = vgic-vgic_dist_base; - } + type_needed = KVM_DEV_TYPE_ARM_VGIC_V2; + addr_ptr = vgic-vgic_dist_base; + block_size = KVM_VGIC_V2_DIST_SIZE; break; case KVM_VGIC_V2_ADDR_TYPE_CPU: - if (write) { - r = vgic_ioaddr_assign(kvm, vgic-vgic_cpu_base, - *addr, KVM_VGIC_V2_CPU_SIZE); - } else { - *addr = vgic-vgic_cpu_base; - } + type_needed = KVM_DEV_TYPE_ARM_VGIC_V2; + addr_ptr = vgic-vgic_cpu_base; + block_size = KVM_VGIC_V2_CPU_SIZE; break; +#ifdef CONFIG_ARM_GIC_V3 + case KVM_VGIC_V3_ADDR_TYPE_DIST: + type_needed = KVM_DEV_TYPE_ARM_VGIC_V3; + addr_ptr = vgic-vgic_dist_base; + block_size = KVM_VGIC_V3_DIST_SIZE; + break; + case KVM_VGIC_V3_ADDR_TYPE_REDIST: + type_needed = KVM_DEV_TYPE_ARM_VGIC_V3; + addr_ptr = vgic-vgic_redist_base; + block_size = KVM_VGIC_V3_REDIST_SIZE; + break; +#endif default: r = -ENODEV; + goto out; } + if (vgic-vgic_model
[PATCH v2 04/15] arm/arm64: KVM: wrap 64 bit MMIO accesses with two 32 bit ones
Some GICv3 registers can and will be accessed as 64 bit registers. Currently the register handling code can only deal with 32 bit accesses, so we do two consecutive calls to cover this. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- virt/kvm/arm/vgic.c | 48 +--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 3b6f78d..bef9aa0 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -926,6 +926,48 @@ static bool vgic_validate_access(const struct vgic_dist *dist, } /* + * Call the respective handler function for the given range. + * We split up any 64 bit accesses into two consecutive 32 bit + * handler calls and merge the result afterwards. + */ +static bool call_range_handler(struct kvm_vcpu *vcpu, + struct kvm_exit_mmio *mmio, + unsigned long offset, + const struct mmio_range *range) +{ + u32 *data32 = (void *)mmio-data; + struct kvm_exit_mmio mmio32; + bool ret; + + if (likely(mmio-len = 4)) + return range-handle_mmio(vcpu, mmio, offset); + + /* +* We assume that any access greater than 4 bytes is actually +* 8 bytes long, caused by a 64-bit access +*/ + + mmio32.len = 4; + mmio32.is_write = mmio-is_write; + + mmio32.phys_addr = mmio-phys_addr + 4; + if (mmio-is_write) + *(u32 *)mmio32.data = data32[1]; + ret = range-handle_mmio(vcpu, mmio32, offset + 4); + if (!mmio-is_write) + data32[1] = *(u32 *)mmio32.data; + + mmio32.phys_addr = mmio-phys_addr; + if (mmio-is_write) + *(u32 *)mmio32.data = data32[0]; + ret |= range-handle_mmio(vcpu, mmio32, offset); + if (!mmio-is_write) + data32[0] = *(u32 *)mmio32.data; + + return ret; +} + +/* * vgic_handle_mmio_range - handle an in-kernel MMIO access * @vcpu: pointer to the vcpu performing the access * @run: pointer to the kvm_run structure @@ -956,10 +998,10 @@ static bool vgic_handle_mmio_range(struct kvm_vcpu *vcpu, struct kvm_run *run, spin_lock(vcpu-kvm-arch.vgic.lock); offset -= range-base; if (vgic_validate_access(dist, range, offset)) { - updated_state = range-handle_mmio(vcpu, mmio, offset); + updated_state = call_range_handler(vcpu, mmio, offset, range); } else { - vgic_reg_access(mmio, NULL, offset, - ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED); + if (!mmio-is_write) + memset(mmio-data, 0, mmio-len); updated_state = false; } spin_unlock(vcpu-kvm-arch.vgic.lock); -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 10/15] arm/arm64: KVM: split GICv2 specific emulation code from vgic.c
vgic.c is currently a mixture of generic vGIC emulation code and functions specific to emulating a GICv2. To ease the addition of GICv3, split off strictly v2 specific parts into a new file vgic-v2-emul.c. A new header file vgic.h is introduced to allow separation and later sharing of functions. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- As the diff isn't always obvious here (and to aid eventual rebases), here is a list of high-level changes done to the code: * added new file to respective arm/arm64 Makefiles * moved definitions and prototypes from vgic.c to vgic.h: - VGIC_ADDR_UNDEF - ACCESS_{READ,WRITE}_* - vgic_update_state() - vgic_kick_vcpus() - vgic_get_vmcr() - vgic_set_vmcr() - struct mmio_range {} - IS_IN_RANGE() macro * removed static keyword and exported prototype in vgic.h: - vgic_bitmap_get_reg() - vgic_bitmap_set_irq_val() - vgic_bitmap_get_shared_map() - vgic_bytemap_get_reg() - vgic_dist_irq_set() - vgic_dist_irq_clear() - vgic_cpu_irq_clear() - vgic_reg_access() - handle_mmio_raz_wi() - vgic_handle_enable_reg() - vgic_handle_pending_reg() - vgic_handle_cfg_reg() - vgic_unqueue_irqs() - find_matching_range() (renamed to vgic_* to avoid namespace clutter) - vgic_handle_mmio_range() - vgic_update_state() - vgic_get_vmcr() - vgic_set_vmcr() - vgic_queue_irq() - vgic_kick_vcpus() - vgic_init_maps() - vgic_has_attr_regs() - vgic_set_common_attr() - vgic_get_common_attr() - vgic_destroy() - vgic_create() * moved functions to vgic.h (static inline): - mmio_data_read() - mmio_data_write() * moved GICv2 specific functions to vgic-v2-emul.c: - handle_mmio_misc() - handle_mmio_set_enable_reg() - handle_mmio_clear_enable_reg() - handle_mmio_set_pending_reg() - handle_mmio_clear_pending_reg() - handle_mmio_priority_reg() - vgic_get_target_reg() - vgic_set_target_reg() - handle_mmio_target_reg() - handle_mmio_cfg_reg() - handle_mmio_sgi_reg() - vgic_v2_unqueue_sgi() - read_set_clear_sgi_pend_reg() - write_set_clear_sgi_pend_reg() - handle_mmio_sgi_set() - handle_mmio_sgi_clear() - vgic_v2_handle_mmio() - vgic_get_sgi_sources() - vgic_dispatch_sgi() - vgic_v2_queue_sgi() - vgic_v2_init() - handle_cpu_mmio_misc() - handle_mmio_abpr() - handle_cpu_mmio_ident() - vgic_attr_regs_access() - vgic_has_attr() (renamed to vgic_v2_has_attr()) - vgic_set_attr() (renamed to vgic_v2_set_attr()) - vgic_get_attr() (renamed to vgic_v2_get_attr()) - struct mmio_range vgic_dist_ranges[] - struct mmio_range vgic_cpu_ranges[] - struct kvm_device_ops kvm_arm_vgic_v2_ops {} * moved content of init_emulation_ops() into separate function in vgic-v2-emul.c --- arch/arm/kvm/Makefile |1 + arch/arm64/kvm/Makefile |1 + virt/kvm/arm/vgic-v2-emul.c | 796 +++ virt/kvm/arm/vgic.c | 870 ++- virt/kvm/arm/vgic.h | 122 ++ 5 files changed, 960 insertions(+), 830 deletions(-) create mode 100644 virt/kvm/arm/vgic-v2-emul.c create mode 100644 virt/kvm/arm/vgic.h diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile index f7057ed..443b8be 100644 --- a/arch/arm/kvm/Makefile +++ b/arch/arm/kvm/Makefile @@ -22,4 +22,5 @@ obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o +obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2-emul.o obj-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile index 32a0961..d957353 100644 --- a/arch/arm64/kvm/Makefile +++ b/arch/arm64/kvm/Makefile @@ -21,6 +21,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += guest.o reset.o sys_regs.o sys_regs_generic_v8.o kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o +kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2-emul.o kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v2-switch.o kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v3.o kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v3-switch.o diff --git a/virt/kvm/arm/vgic-v2-emul.c b/virt/kvm/arm/vgic-v2-emul.c new file mode 100644 index 000..a6bfd75 --- /dev/null +++ b/virt/kvm/arm/vgic-v2-emul.c @@ -0,0 +1,796 @@ +/* + * Contains GICv2 specific emulation code, was in vgic.c before. + * + * Copyright (C) 2012 ARM Ltd. + * Author: Marc Zyngier marc.zyng...@arm.com + * + * 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
[PATCH v2 01/15] arm/arm64: KVM: rework MPIDR assignment and add accessors
The virtual MPIDR registers (containing topology information) for the guest are currently mapped linearily to the vcpu_id. Improve this mapping for arm64 by using three levels to not artificially limit the number of vCPUs. Also add an accessor to later allow easier access to a vCPU with a given MPIDR. Use this new accessor in the PSCI emulation. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm/include/asm/kvm_emulate.h |2 +- arch/arm/include/asm/kvm_host.h |2 ++ arch/arm/kvm/arm.c | 15 +++ arch/arm/kvm/psci.c | 15 --- arch/arm64/include/asm/kvm_emulate.h |3 ++- arch/arm64/include/asm/kvm_host.h|2 ++ arch/arm64/kvm/sys_regs.c| 11 +-- 7 files changed, 35 insertions(+), 15 deletions(-) diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h index 69b7469..18e45f7 100644 --- a/arch/arm/include/asm/kvm_emulate.h +++ b/arch/arm/include/asm/kvm_emulate.h @@ -159,7 +159,7 @@ static inline u32 kvm_vcpu_hvc_get_imm(struct kvm_vcpu *vcpu) static inline unsigned long kvm_vcpu_get_mpidr(struct kvm_vcpu *vcpu) { - return vcpu-arch.cp15[c0_MPIDR]; + return vcpu-arch.cp15[c0_MPIDR] MPIDR_HWID_BITMASK; } static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 6dfb404..cf99ad0 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -233,4 +233,6 @@ static inline void vgic_arch_setup(const struct vgic_params *vgic) int kvm_perf_init(void); int kvm_perf_teardown(void); +struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr); + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 7d5065e..addb990 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -990,6 +990,21 @@ static void check_kvm_target_cpu(void *ret) *(int *)ret = kvm_target_cpu(); } +struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr) +{ + unsigned long c_mpidr; + struct kvm_vcpu *vcpu; + int i; + + mpidr = MPIDR_HWID_BITMASK; + kvm_for_each_vcpu(i, vcpu, kvm) { + c_mpidr = kvm_vcpu_get_mpidr(vcpu); + if (c_mpidr == mpidr) + return vcpu; + } + return NULL; +} + /** * Initialize Hyp-mode and memory mappings on all CPUs. */ diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index 09cf377..49f0992 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c @@ -21,6 +21,7 @@ #include asm/cputype.h #include asm/kvm_emulate.h #include asm/kvm_psci.h +#include asm/kvm_host.h /* * This is an implementation of the Power State Coordination Interface @@ -65,25 +66,17 @@ static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu) static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) { struct kvm *kvm = source_vcpu-kvm; - struct kvm_vcpu *vcpu = NULL, *tmp; + struct kvm_vcpu *vcpu = NULL; wait_queue_head_t *wq; unsigned long cpu_id; unsigned long context_id; - unsigned long mpidr; phys_addr_t target_pc; - int i; - cpu_id = *vcpu_reg(source_vcpu, 1); + cpu_id = *vcpu_reg(source_vcpu, 1) MPIDR_HWID_BITMASK; if (vcpu_mode_is_32bit(source_vcpu)) cpu_id = ~((u32) 0); - kvm_for_each_vcpu(i, tmp, kvm) { - mpidr = kvm_vcpu_get_mpidr(tmp); - if ((mpidr MPIDR_HWID_BITMASK) == (cpu_id MPIDR_HWID_BITMASK)) { - vcpu = tmp; - break; - } - } + vcpu = kvm_mpidr_to_vcpu(kvm, cpu_id); /* * Make sure the caller requested a valid CPU and that the CPU is diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index fdc3e21..4b8d636 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -27,6 +27,7 @@ #include asm/kvm_arm.h #include asm/kvm_mmio.h #include asm/ptrace.h +#include asm/cputype.h unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num); unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu); @@ -179,7 +180,7 @@ static inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu) static inline unsigned long kvm_vcpu_get_mpidr(struct kvm_vcpu *vcpu) { - return vcpu_sys_reg(vcpu, MPIDR_EL1); + return vcpu_sys_reg(vcpu, MPIDR_EL1) MPIDR_HWID_BITMASK; } static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index e10c45a..017fbae 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -244,4 +244,6 @@ static inline void vgic_arch_setup(const struct vgic_params *vgic) } } +struct kvm_vcpu *kvm_mpidr_to_vcpu
[PATCH v2 07/15] arm/arm64: KVM: make the value of ICC_SRE_EL1 a per-VM variable
ICC_SRE_EL1 is a system register allowing msr/mrs accesses to the GIC CPU interface for EL1 (guests). Currently we force it to 0, but for proper GICv3 support we have to allow guests to use it (depending on their selected virtual GIC model). So add ICC_SRE_EL1 to the list of saved/restored registers on a world switch, but actually disallow a guest to change it by only restoring a fixed, once-initialized value. This value depends on the GIC model userland has chosen for a guest. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm64/kernel/asm-offsets.c |1 + arch/arm64/kvm/vgic-v3-switch.S | 14 +- include/kvm/arm_vgic.h |1 + virt/kvm/arm/vgic-v3.c |9 +++-- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 9a9fce0..9d34486 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -140,6 +140,7 @@ int main(void) DEFINE(VGIC_V2_CPU_ELRSR,offsetof(struct vgic_cpu, vgic_v2.vgic_elrsr)); DEFINE(VGIC_V2_CPU_APR, offsetof(struct vgic_cpu, vgic_v2.vgic_apr)); DEFINE(VGIC_V2_CPU_LR, offsetof(struct vgic_cpu, vgic_v2.vgic_lr)); + DEFINE(VGIC_V3_CPU_SRE, offsetof(struct vgic_cpu, vgic_v3.vgic_sre)); DEFINE(VGIC_V3_CPU_HCR, offsetof(struct vgic_cpu, vgic_v3.vgic_hcr)); DEFINE(VGIC_V3_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v3.vgic_vmcr)); DEFINE(VGIC_V3_CPU_MISR, offsetof(struct vgic_cpu, vgic_v3.vgic_misr)); diff --git a/arch/arm64/kvm/vgic-v3-switch.S b/arch/arm64/kvm/vgic-v3-switch.S index d160469..617a012 100644 --- a/arch/arm64/kvm/vgic-v3-switch.S +++ b/arch/arm64/kvm/vgic-v3-switch.S @@ -148,17 +148,18 @@ * x0: Register pointing to VCPU struct */ .macro restore_vgic_v3_state - // Disable SRE_EL1 access. Necessary, otherwise - // ICH_VMCR_EL2.VFIQEn becomes one, and FIQ happens... - msr_s ICC_SRE_EL1, xzr - isb - // Compute the address of struct vgic_cpu add x3, x0, #VCPU_VGIC_CPU // Restore all interesting registers ldr w4, [x3, #VGIC_V3_CPU_HCR] ldr w5, [x3, #VGIC_V3_CPU_VMCR] + ldr w25, [x3, #VGIC_V3_CPU_SRE] + + msr_s ICC_SRE_EL1, x25 + + // make sure SRE is valid before writing the other registers + isb msr_s ICH_HCR_EL2, x4 msr_s ICH_VMCR_EL2, x5 @@ -244,9 +245,12 @@ dsb sy // Prevent the guest from touching the GIC system registers + // if SRE isn't enabled for GICv3 emulation + cbnzx25, 1f mrs_s x5, ICC_SRE_EL2 and x5, x5, #~ICC_SRE_EL2_ENABLE msr_s ICC_SRE_EL2, x5 +1: .endm ENTRY(__save_vgic_v3_state) diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 7e7c99e..8aa8482 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -199,6 +199,7 @@ struct vgic_v3_cpu_if { #ifdef CONFIG_ARM_GIC_V3 u32 vgic_hcr; u32 vgic_vmcr; + u32 vgic_sre; /* Restored only, change ignored */ u32 vgic_misr; /* Saved only */ u32 vgic_eisr; /* Saved only */ u32 vgic_elrsr; /* Saved only */ diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c index 86e8b99..8af8037 100644 --- a/virt/kvm/arm/vgic-v3.c +++ b/virt/kvm/arm/vgic-v3.c @@ -145,15 +145,20 @@ static void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp) static void vgic_v3_enable(struct kvm_vcpu *vcpu) { + struct vgic_v3_cpu_if *vgic_v3; + + vgic_v3 = vcpu-arch.vgic_cpu.vgic_v3; /* * By forcing VMCR to zero, the GIC will restore the binary * points to their reset values. Anything else resets to zero * anyway. */ - vcpu-arch.vgic_cpu.vgic_v3.vgic_vmcr = 0; + vgic_v3-vgic_vmcr = 0; + + vgic_v3-vgic_sre = 0; /* Get the show on the road... */ - vcpu-arch.vgic_cpu.vgic_v3.vgic_hcr = ICH_HCR_EN; + vgic_v3-vgic_hcr = ICH_HCR_EN; } static const struct vgic_ops vgic_v3_ops = { -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 05/15] arm/arm64: KVM: introduce per-VM ops
Currently we only have one virtual GIC model supported, so all guests use the same emulation code. With the addition of another model we end up with different guests using potentially different vGIC models, so we have to split up some functions to be per VM. Introduce a vgic_vm_ops struct to hold function pointers for those functions that are different and provide the necessary code to initialize them. This includes functions that depend on the emulated GIC model only and functions that depend on the combination of host and guest GIC. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- include/kvm/arm_vgic.h | 18 -- virt/kvm/arm/vgic-v2.c | 17 +++-- virt/kvm/arm/vgic-v3.c | 16 +++-- virt/kvm/arm/vgic.c| 92 +++- 4 files changed, 113 insertions(+), 30 deletions(-) diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 4feac9a..7e7c99e 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -99,8 +99,6 @@ struct vgic_vmcr { }; struct vgic_ops { - struct vgic_lr (*get_lr)(const struct kvm_vcpu *, int); - void(*set_lr)(struct kvm_vcpu *, int, struct vgic_lr); void(*sync_lr_elrsr)(struct kvm_vcpu *, int, struct vgic_lr); u64 (*get_elrsr)(const struct kvm_vcpu *vcpu); u64 (*get_eisr)(const struct kvm_vcpu *vcpu); @@ -123,6 +121,17 @@ struct vgic_params { unsigned intmaint_irq; /* Virtual control interface base address */ void __iomem*vctrl_base; + bool (*init_emul)(struct kvm *kvm, int type); +}; + +struct vgic_vm_ops { + struct vgic_lr (*get_lr)(const struct kvm_vcpu *, int); + void(*set_lr)(struct kvm_vcpu *, int, struct vgic_lr); + bool(*handle_mmio)(struct kvm_vcpu *, struct kvm_run *, + struct kvm_exit_mmio *); + bool(*queue_sgi)(struct kvm_vcpu *vcpu, int irq); + void(*unqueue_sgi)(struct kvm_vcpu *vcpu, int irq, int source); + int (*vgic_init)(struct kvm *kvm, const struct vgic_params *params); }; struct vgic_dist { @@ -131,6 +140,9 @@ struct vgic_dist { boolin_kernel; boolready; + /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */ + u32 vgic_model; + int nr_cpus; int nr_irqs; @@ -168,6 +180,8 @@ struct vgic_dist { /* Bitmap indicating which CPU has something pending */ unsigned long irq_pending_on_cpu; + + struct vgic_vm_ops vm_ops; #endif }; diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c index 01124ef..90947c6 100644 --- a/virt/kvm/arm/vgic-v2.c +++ b/virt/kvm/arm/vgic-v2.c @@ -161,8 +161,6 @@ static void vgic_v2_enable(struct kvm_vcpu *vcpu) } static const struct vgic_ops vgic_v2_ops = { - .get_lr = vgic_v2_get_lr, - .set_lr = vgic_v2_set_lr, .sync_lr_elrsr = vgic_v2_sync_lr_elrsr, .get_elrsr = vgic_v2_get_elrsr, .get_eisr = vgic_v2_get_eisr, @@ -176,6 +174,20 @@ static const struct vgic_ops vgic_v2_ops = { static struct vgic_params vgic_v2_params; +static bool vgic_v2_init_emul(struct kvm *kvm, int type) +{ + struct vgic_vm_ops *vm_ops = kvm-arch.vgic.vm_ops; + + switch (type) { + case KVM_DEV_TYPE_ARM_VGIC_V2: + vm_ops-get_lr = vgic_v2_get_lr; + vm_ops-set_lr = vgic_v2_set_lr; + return true; + } + + return false; +} + /** * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT * @node: pointer to the DT node @@ -214,6 +226,7 @@ int vgic_v2_probe(struct device_node *vgic_node, ret = -ENOMEM; goto out; } + vgic-init_emul = vgic_v2_init_emul; vgic-nr_lr = readl_relaxed(vgic-vctrl_base + GICH_VTR); vgic-nr_lr = (vgic-nr_lr 0x3f) + 1; diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c index 1c2c8ee..a38339e 100644 --- a/virt/kvm/arm/vgic-v3.c +++ b/virt/kvm/arm/vgic-v3.c @@ -157,8 +157,6 @@ static void vgic_v3_enable(struct kvm_vcpu *vcpu) } static const struct vgic_ops vgic_v3_ops = { - .get_lr = vgic_v3_get_lr, - .set_lr = vgic_v3_set_lr, .sync_lr_elrsr = vgic_v3_sync_lr_elrsr, .get_elrsr = vgic_v3_get_elrsr, .get_eisr = vgic_v3_get_eisr, @@ -170,6 +168,19 @@ static const struct vgic_ops vgic_v3_ops = { .enable = vgic_v3_enable, }; +static bool vgic_v3_init_emul_compat(struct kvm *kvm, int type) +{ + struct vgic_vm_ops *vm_ops = kvm-arch.vgic.vm_ops; + + switch (type) { + case KVM_DEV_TYPE_ARM_VGIC_V2: + vm_ops-get_lr = vgic_v3_get_lr
[PATCH v2 13/15] arm/arm64: KVM: add SGI system register trapping
While the injection of a (virtual) inter-processor interrupt (SGI) on a GICv2 works by writing to a MMIO register, GICv3 uses system registers to trigger them. Trap the appropriate registers both on ARM and ARM64 machines and call the SGI handler function in the vGICv3 emulation code. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm/kvm/coproc.c | 19 +++ arch/arm64/kvm/sys_regs.c | 26 ++ virt/kvm/arm/vgic-v3-emul.c |2 +- 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c index 37a0fe1..1cd049f 100644 --- a/arch/arm/kvm/coproc.c +++ b/arch/arm/kvm/coproc.c @@ -230,6 +230,22 @@ done: return true; } +static bool access_gic_sgi(struct kvm_vcpu *vcpu, + const struct coproc_params *p, + const struct coproc_reg *r) +{ + u64 val; + + if (!p-is_write) + return read_from_write_only(vcpu, p); + + val = *vcpu_reg(vcpu, p-Rt1); + val |= (u64)*vcpu_reg(vcpu, p-Rt2) 32; + vgic_v3_dispatch_sgi(vcpu, val); + + return true; +} + /* * Generic accessor for VM registers. Only called as long as HCR_TVM * is set. @@ -401,6 +417,9 @@ static const struct coproc_reg cp15_regs[] = { { CRn(10), CRm( 3), Op1( 0), Op2( 1), is32, access_vm_reg, reset_unknown, c10_AMAIR1}, + /* ICC_SGI1R */ + { CRm64(12), Op1( 0), is64, access_gic_sgi}, + /* VBAR: swapped by interrupt.S. */ { CRn(12), CRm( 0), Op1( 0), Op2( 0), is32, NULL, reset_val, c12_VBAR, 0x }, diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index a79538a..befbcfd 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -165,6 +165,27 @@ static bool access_sctlr(struct kvm_vcpu *vcpu, return true; } +/* + * Trapping on the GICv3 SGI system register. + * Forward the request to the VGIC emulation. + * The cp15_64 code makes sure this automatically works + * for both AArch64 and AArch32 accesses. + */ +static bool access_gic_sgi(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + u64 val; + + if (!p-is_write) + return read_from_write_only(vcpu, p); + + val = *vcpu_reg(vcpu, p-Rt); + vgic_v3_dispatch_sgi(vcpu, val); + + return true; +} + static bool trap_raz_wi(struct kvm_vcpu *vcpu, const struct sys_reg_params *p, const struct sys_reg_desc *r) @@ -431,6 +452,9 @@ static const struct sys_reg_desc sys_reg_descs[] = { /* VBAR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b), Op2(0b000), NULL, reset_val, VBAR_EL1, 0 }, + /* ICC_SGI1R_EL1 */ + { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1011), Op2(0b101), + access_gic_sgi }, /* CONTEXTIDR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b), Op2(0b001), access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 }, @@ -659,6 +683,8 @@ static const struct sys_reg_desc cp14_64_regs[] = { * register). */ static const struct sys_reg_desc cp15_regs[] = { + { Op1( 0), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, + { Op1( 0), CRn( 1), CRm( 0), Op2( 0), access_sctlr, NULL, c1_SCTLR }, { Op1( 0), CRn( 2), CRm( 0), Op2( 0), access_vm_reg, NULL, c2_TTBR0 }, { Op1( 0), CRn( 2), CRm( 0), Op2( 1), access_vm_reg, NULL, c2_TTBR1 }, diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c index 82ca1b5..ac5c5ee 100644 --- a/virt/kvm/arm/vgic-v3-emul.c +++ b/virt/kvm/arm/vgic-v3-emul.c @@ -802,7 +802,7 @@ void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg) */ spin_lock(dist-lock); kvm_for_each_vcpu(c, c_vcpu, kvm) { - if (target_cpus == 0) + if (!mode target_cpus == 0) break; if (mode c == vcpu_id) /* not to myself */ continue; -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 11/15] arm/arm64: KVM: add opaque private pointer to MMIO accessors
For a GICv2 there is always only one (v)CPU involved: the one that does the access. On a GICv3 the access to a CPU redistributor is memory-mapped, but not banked, so the (v)CPU affected is determined by looking at the MMIO address region being accessed. To allow passing the affected CPU into the accessors, extend them to take an opaque private pointer parameter. For the current GICv2 emulation we ignore it and simply pass NULL on the call. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- virt/kvm/arm/vgic-v2-emul.c | 41 - virt/kvm/arm/vgic.c | 15 --- virt/kvm/arm/vgic.h |7 --- 3 files changed, 36 insertions(+), 27 deletions(-) diff --git a/virt/kvm/arm/vgic-v2-emul.c b/virt/kvm/arm/vgic-v2-emul.c index a6bfd75..a913060 100644 --- a/virt/kvm/arm/vgic-v2-emul.c +++ b/virt/kvm/arm/vgic-v2-emul.c @@ -41,7 +41,8 @@ static u8 *vgic_get_sgi_sources(struct vgic_dist *dist, int vcpu_id, int sgi) } static bool handle_mmio_misc(struct kvm_vcpu *vcpu, -struct kvm_exit_mmio *mmio, phys_addr_t offset) +struct kvm_exit_mmio *mmio, phys_addr_t offset, +void *private) { u32 reg; u32 word_offset = offset 3; @@ -77,7 +78,7 @@ static bool handle_mmio_misc(struct kvm_vcpu *vcpu, static bool handle_mmio_set_enable_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, - phys_addr_t offset) + phys_addr_t offset, void *private) { return vgic_handle_enable_reg(vcpu-kvm, mmio, offset, vcpu-vcpu_id, ACCESS_WRITE_SETBIT); @@ -85,7 +86,7 @@ static bool handle_mmio_set_enable_reg(struct kvm_vcpu *vcpu, static bool handle_mmio_clear_enable_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, -phys_addr_t offset) +phys_addr_t offset, void *private) { return vgic_handle_enable_reg(vcpu-kvm, mmio, offset, vcpu-vcpu_id, ACCESS_WRITE_CLEARBIT); @@ -93,7 +94,7 @@ static bool handle_mmio_clear_enable_reg(struct kvm_vcpu *vcpu, static bool handle_mmio_set_pending_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, - phys_addr_t offset) + phys_addr_t offset, void *private) { return vgic_handle_pending_reg(vcpu-kvm, mmio, offset, vcpu-vcpu_id, ACCESS_WRITE_SETBIT); @@ -101,7 +102,7 @@ static bool handle_mmio_set_pending_reg(struct kvm_vcpu *vcpu, static bool handle_mmio_clear_pending_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, - phys_addr_t offset) + phys_addr_t offset, void *private) { return vgic_handle_pending_reg(vcpu-kvm, mmio, offset, vcpu-vcpu_id, ACCESS_WRITE_CLEARBIT); @@ -109,7 +110,7 @@ static bool handle_mmio_clear_pending_reg(struct kvm_vcpu *vcpu, static bool handle_mmio_priority_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, -phys_addr_t offset) +phys_addr_t offset, void *private) { u32 *reg = vgic_bytemap_get_reg(vcpu-kvm-arch.vgic.irq_priority, vcpu-vcpu_id, offset); @@ -168,7 +169,7 @@ static void vgic_set_target_reg(struct kvm *kvm, u32 val, int irq) static bool handle_mmio_target_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, - phys_addr_t offset) + phys_addr_t offset, void *private) { u32 reg; @@ -198,7 +199,8 @@ static bool handle_mmio_target_reg(struct kvm_vcpu *vcpu, } static bool handle_mmio_cfg_reg(struct kvm_vcpu *vcpu, - struct kvm_exit_mmio *mmio, phys_addr_t offset) + struct kvm_exit_mmio *mmio, phys_addr_t offset, + void *private) { u32 *reg; @@ -209,7 +211,8 @@ static bool handle_mmio_cfg_reg(struct kvm_vcpu *vcpu, } static bool handle_mmio_sgi_reg(struct kvm_vcpu *vcpu, - struct kvm_exit_mmio *mmio, phys_addr_t offset) + struct kvm_exit_mmio *mmio, phys_addr_t offset, + void *private) { u32 reg; @@ -285,7 +288,7 @@ static bool write_set_clear_sgi_pend_reg(struct kvm_vcpu *vcpu, static bool handle_mmio_sgi_set(struct kvm_vcpu *vcpu
[PATCH v2 02/15] arm/arm64: KVM: pass down user space provided GIC type into vGIC code
With the introduction of a second emulated GIC model we need to let userspace specify the GIC model to use for each VM. Pass the userspace provided value down into the vGIC code to differentiate later. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm/kvm/arm.c |2 +- include/kvm/arm_vgic.h |4 ++-- virt/kvm/arm/vgic.c|4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index addb990..157e1b6 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -767,7 +767,7 @@ long kvm_arch_vm_ioctl(struct file *filp, switch (ioctl) { case KVM_CREATE_IRQCHIP: { if (vgic_present) - return kvm_vgic_create(kvm); + return kvm_vgic_create(kvm, KVM_DEV_TYPE_ARM_VGIC_V2); else return -ENXIO; } diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index f5788cf..4feac9a 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -231,7 +231,7 @@ struct kvm_exit_mmio; int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write); int kvm_vgic_hyp_init(void); int kvm_vgic_init(struct kvm *kvm); -int kvm_vgic_create(struct kvm *kvm); +int kvm_vgic_create(struct kvm *kvm, u32 type); void kvm_vgic_destroy(struct kvm *kvm); void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu); void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu); @@ -282,7 +282,7 @@ static inline int kvm_vgic_init(struct kvm *kvm) return 0; } -static inline int kvm_vgic_create(struct kvm *kvm) +static inline int kvm_vgic_create(struct kvm *kvm, u32 type) { return 0; } diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index b3e5ee2..bba8692 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -1864,7 +1864,7 @@ out: return ret; } -int kvm_vgic_create(struct kvm *kvm) +int kvm_vgic_create(struct kvm *kvm, u32 type) { int i, vcpu_lock_idx = -1, ret = 0; struct kvm_vcpu *vcpu; @@ -2320,7 +2320,7 @@ static void vgic_destroy(struct kvm_device *dev) static int vgic_create(struct kvm_device *dev, u32 type) { - return kvm_vgic_create(dev-kvm); + return kvm_vgic_create(dev-kvm, type); } struct kvm_device_ops kvm_arm_vgic_v2_ops = { -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 00/15] KVM GICv3 emulation
This is an updated version of the GICv3 guest emulation series. Compared to v1[1] it has been rebased on v3.17-rc1 (with quite some conflict resolutions done by MarcZ) and contains minor fixes (partially triggered by comments on the list, partially due to code review caused by the rebase). Also there is a new patch (09/15) with some refactoring to make the big split patch (10/15) smaller. This big patch contains now an elaborate commit message to detail the code move, as the diff isn't always obvious here. This part should be considered for removal from the patch on committing it. A git repo hosting all these patches lives in the kvm-gicv3/v2 branch of: http://www.linux-arm.org/git?p=linux-ap.git - GICv3 is the ARM generic interrupt controller designed to overcome some limits of the prevalent GICv2. Most notably it lifts the 8-CPU limit. Though with recent patches from Marc there is support for hosts to use a GICv3, the CPU limitation still applies to KVM guests, since the current code emulates a GICv2 only. Also, GICv2 backward compatibility being optional in GICv3, a number of systems won't be able to run GICv2 guests. This patch series provides code to emulate a GICv3 distributor and redistributor for any KVM guest. It requires a GICv3 in the host to work. With those patches one can run guests efficiently on any GICv3 host. It has the following features: - Affinity routing (support for up to 255 VCPUs, more possible) - System registers (as opposed to MMIO access) - No ITS - No priority support (as the GICv2 emulation) - No save / restore support so far (will be added soon) The first 11 patches actually refactor the current VGIC code to make room for a different VGIC model to be dropped in with Patch 12/15. The remaining patches connect the new model to the kernel backend and the userland facing code. The series goes on top of v3.17-rc1 and Marc's vgic-dyn series[2]. The necessary patches for kvmtool to enable the guest's GICv3 have been posted here before [3], an updated version will follow as soon as the kvmtools tree has been updated. There was some testing on the fast model with some I/O and interrupt affinity shuffling in a Linux guest with a varying number of VCPUs as well as some testing on a Juno board (GICv2 only, to spot regressions). Please review and test. I would be grateful for people to test for GICv2 regressions also (so on a GICv2 host with current kvmtool/qemu), as there is quite some refactoring on that front. Much of the code was inspired by MarcZ, also kudos to him for doing the rather painful rebase on top of v3.17-rc1. Cheers, Andre. [1] https://lists.cs.columbia.edu/pipermail/kvmarm/2014-June/010060.html [2] https://git.kernel.org/cgit/linux/kernel/git/maz/arm-platforms.git/log/?h=kvm-arm64/vgic-dyn [3] https://lists.cs.columbia.edu/pipermail/kvmarm/2014-June/010086.html Changes v1 ... v2: * rebase to v3.17-rc1, caused quite some changes to the init code * new 9/15 patch to make 10/15 smaller * fix wrongly ordered cp15 register trap entry (MarcZ) * fix SGI broadcast (thanks to wanghaibin for spotting) * fix broken bailout path in kvm_vgic_create (wanghaibin) * check return value of init_emulation_ops() (wanghaibin) * fix return value check in vgic_[sg]et_attr() * add header inclusion guards * remove double definition of VCPU_NOT_ALLOCATED * some code move-around * whitespace fixes Andre Przywara (15): arm/arm64: KVM: rework MPIDR assignment and add accessors arm/arm64: KVM: pass down user space provided GIC type into vGIC code arm/arm64: KVM: refactor vgic_handle_mmio() function arm/arm64: KVM: wrap 64 bit MMIO accesses with two 32 bit ones arm/arm64: KVM: introduce per-VM ops arm/arm64: KVM: make the maximum number of vCPUs a per-VM value arm/arm64: KVM: make the value of ICC_SRE_EL1 a per-VM variable arm/arm64: KVM: refactor MMIO accessors arm/arm64: KVM: refactor/wrap vgic_set/get_attr() arm/arm64: KVM: split GICv2 specific emulation code from vgic.c arm/arm64: KVM: add opaque private pointer to MMIO accessors arm/arm64: KVM: add virtual GICv3 distributor emulation arm/arm64: KVM: add SGI system register trapping arm/arm64: KVM: enable kernel side of GICv3 emulation arm/arm64: KVM: allow userland to request a virtual GICv3 arch/arm/include/asm/kvm_emulate.h |2 +- arch/arm/include/asm/kvm_host.h |3 + arch/arm/kvm/Makefile|1 + arch/arm/kvm/arm.c | 23 +- arch/arm/kvm/coproc.c| 19 + arch/arm/kvm/psci.c | 15 +- arch/arm64/include/asm/kvm_emulate.h |3 +- arch/arm64/include/asm/kvm_host.h|5 + arch/arm64/include/uapi/asm/kvm.h|7 + arch/arm64/kernel/asm-offsets.c |1 + arch/arm64/kvm/Makefile |2 + arch/arm64/kvm/sys_regs.c| 37 +- arch/arm64/kvm/vgic-v3-switch.S | 14 +- include/kvm/arm_vgic.h | 38 +- include/linux/irqchip/arm-gic-v3.h | 26
[PATCH v2 03/15] arm/arm64: KVM: refactor vgic_handle_mmio() function
Currently we only need to deal with one MMIO region for the GIC emulation, but we soon need to extend this. Refactor the existing code to allow easier addition of different ranges without code duplication. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- virt/kvm/arm/vgic.c | 72 --- 1 file changed, 51 insertions(+), 21 deletions(-) diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index bba8692..3b6f78d 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -925,37 +925,28 @@ static bool vgic_validate_access(const struct vgic_dist *dist, return true; } -/** - * vgic_handle_mmio - handle an in-kernel MMIO access +/* + * vgic_handle_mmio_range - handle an in-kernel MMIO access * @vcpu: pointer to the vcpu performing the access * @run: pointer to the kvm_run structure * @mmio: pointer to the data describing the access + * @ranges:pointer to the register defining structure + * @mmio_base: base address for this mapping * - * returns true if the MMIO access has been performed in kernel space, - * and false if it needs to be emulated in user space. + * returns true if the MMIO access could be performed */ -bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, - struct kvm_exit_mmio *mmio) +static bool vgic_handle_mmio_range(struct kvm_vcpu *vcpu, struct kvm_run *run, + struct kvm_exit_mmio *mmio, + const struct mmio_range *ranges, + unsigned long mmio_base) { const struct mmio_range *range; struct vgic_dist *dist = vcpu-kvm-arch.vgic; - unsigned long base = dist-vgic_dist_base; bool updated_state; unsigned long offset; - if (!irqchip_in_kernel(vcpu-kvm) || - mmio-phys_addr base || - (mmio-phys_addr + mmio-len) (base + KVM_VGIC_V2_DIST_SIZE)) - return false; - - /* We don't support ldrd / strd or ldm / stm to the emulated vgic */ - if (mmio-len 4) { - kvm_inject_dabt(vcpu, mmio-phys_addr); - return true; - } - - offset = mmio-phys_addr - base; - range = find_matching_range(vgic_dist_ranges, mmio, offset); + offset = mmio-phys_addr - mmio_base; + range = find_matching_range(ranges, mmio, offset); if (unlikely(!range || !range-handle_mmio)) { pr_warn(Unhandled access %d %08llx %d\n, mmio-is_write, mmio-phys_addr, mmio-len); @@ -963,7 +954,7 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, } spin_lock(vcpu-kvm-arch.vgic.lock); - offset = mmio-phys_addr - range-base - base; + offset -= range-base; if (vgic_validate_access(dist, range, offset)) { updated_state = range-handle_mmio(vcpu, mmio, offset); } else { @@ -981,6 +972,45 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, return true; } +#define IS_IN_RANGE(addr, alen, base, len) \ + (((addr) = (base)) (((addr) + (alen)) ((base) + (len + +static bool vgic_v2_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, + struct kvm_exit_mmio *mmio) +{ + unsigned long base = vcpu-kvm-arch.vgic.vgic_dist_base; + + if (!IS_IN_RANGE(mmio-phys_addr, mmio-len, base, +KVM_VGIC_V2_DIST_SIZE)) + return false; + + /* GICv2 does not support accesses wider than 32 bits */ + if (mmio-len 4) { + kvm_inject_dabt(vcpu, mmio-phys_addr); + return true; + } + + return vgic_handle_mmio_range(vcpu, run, mmio, vgic_dist_ranges, base); +} + +/** + * vgic_handle_mmio - handle an in-kernel MMIO access for the GIC emulation + * @vcpu: pointer to the vcpu performing the access + * @run: pointer to the kvm_run structure + * @mmio: pointer to the data describing the access + * + * returns true if the MMIO access has been performed in kernel space, + * and false if it needs to be emulated in user space. + */ +bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, + struct kvm_exit_mmio *mmio) +{ + if (!irqchip_in_kernel(vcpu-kvm)) + return false; + + return vgic_v2_handle_mmio(vcpu, run, mmio); +} + static u8 *vgic_get_sgi_sources(struct vgic_dist *dist, int vcpu_id, int sgi) { return dist-irq_sgi_sources + vcpu_id * VGIC_NR_SGIS + sgi; -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 09/15] arm/arm64: KVM: refactor/wrap vgic_set/get_attr()
vgic_set_attr() and vgic_get_attr() contain both code specific for the emulated GIC as well as code for the userland facing, generic part of the GIC. Split the guest GIC facing code of from the generic part to allow easier splitting later. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- virt/kvm/arm/vgic.c | 79 +++ 1 file changed, 54 insertions(+), 25 deletions(-) diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index e8f92b2..3386557 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -2301,7 +2301,8 @@ out: return ret; } -static int vgic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) +static int vgic_set_common_attr(struct kvm_device *dev, + struct kvm_device_attr *attr) { int r; @@ -2317,17 +2318,6 @@ static int vgic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) r = kvm_vgic_addr(dev-kvm, type, addr, true); return (r == -ENODEV) ? -ENXIO : r; } - - case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: - case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: { - u32 __user *uaddr = (u32 __user *)(long)attr-addr; - u32 reg; - - if (get_user(reg, uaddr)) - return -EFAULT; - - return vgic_attr_regs_access(dev, attr, reg, true); - } case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: { u32 __user *uaddr = (u32 __user *)(long)attr-addr; u32 val; @@ -2356,7 +2346,33 @@ static int vgic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) return -ENXIO; } -static int vgic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) +static int vgic_set_attr(struct kvm_device *dev, struct kvm_device_attr *attr) +{ + int ret; + + ret = vgic_set_common_attr(dev, attr); + if (ret != -ENXIO) + return ret; + + switch (attr-group) { + case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: + case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: { + u32 __user *uaddr = (u32 __user *)(long)attr-addr; + u32 reg; + + if (get_user(reg, uaddr)) + return -EFAULT; + + return vgic_attr_regs_access(dev, attr, reg, true); + } + + } + + return -ENXIO; +} + +static int vgic_get_common_attr(struct kvm_device *dev, + struct kvm_device_attr *attr) { int r = -ENXIO; @@ -2374,18 +2390,6 @@ static int vgic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) return -EFAULT; break; } - - case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: - case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: { - u32 __user *uaddr = (u32 __user *)(long)attr-addr; - u32 reg = 0; - - r = vgic_attr_regs_access(dev, attr, reg, false); - if (r) - return r; - r = put_user(reg, uaddr); - break; - } case KVM_DEV_ARM_VGIC_GRP_NR_IRQS: { u32 __user *uaddr = (u32 __user *)(long)attr-addr; r = put_user(dev-kvm-arch.vgic.nr_irqs, uaddr); @@ -2403,6 +2407,31 @@ static int vgic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) return r; } +static int vgic_get_attr(struct kvm_device *dev, struct kvm_device_attr *attr) +{ + int ret; + + ret = vgic_get_common_attr(dev, attr); + if (ret != -ENXIO) + return ret; + + switch (attr-group) { + case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: + case KVM_DEV_ARM_VGIC_GRP_CPU_REGS: { + u32 __user *uaddr = (u32 __user *)(long)attr-addr; + u32 reg = 0; + + ret = vgic_attr_regs_access(dev, attr, reg, false); + if (ret) + return ret; + return put_user(reg, uaddr); + } + + } + + return -ENXIO; +} + static int vgic_has_attr_regs(const struct mmio_range *ranges, phys_addr_t offset) { -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 00/14] KVM GICv3 emulation
On 20/06/14 02:39, Chalamarla, Tirumalesh wrote: Hi Tirumalesh, Is there a public repo where we can get this patches from easily. Indeed, many thanks to Marc who hosts now my patches on his kernel.org repo. Simply checkout the gicv3/kvm-guest branch from git://git.kernel.org/pub/scm/linux/kernel/git/maz/arm-platforms.git to get all of GICv3 host, vgic-dyn and the GICv3 guest emualation stuff at once. Regards, Andre. From: kvmarm-boun...@lists.cs.columbia.edu kvmarm-boun...@lists.cs.columbia.edu on behalf of Andre Przywara andre.przyw...@arm.com Sent: Thursday, June 19, 2014 3:15 PM To: linux-arm-ker...@lists.infradead.org; kvm...@lists.cs.columbia.edu; kvm@vger.kernel.org Cc: christoffer.d...@linaro.org Subject: [PATCH 00/14] KVM GICv3 emulation GICv3 is the ARM generic interrupt controller designed to overcome some limits of the prevalent GICv2. Most notably it lifts the 8-CPU limit. Though with recent patches from Marc there is support for hosts to use a GICv3, the CPU limitation still applies to KVM guests, since the current code emulates a GICv2 only. Also, GICv2 backward compatibility being optional in GICv3, a number of systems won't be able to run GICv2 guests. This patch series provides code to emulate a GICv3 distributor and redistributor for any KVM guest. It requires a GICv3 in the host to work. With those patches one can run guests efficiently on any GICv3 host. It has the following features: - Affinity routing (support for up to 255 VCPUs, more possible) - System registers (as opposed to MMIO access) - No ITS - No priority support (as the GICv2 emulation) - No save / restore support so far (will be added soon) The first 10 patches actually refactor the current VGIC code to make room for a different VGIC model to be dropped in with Patch 11/14. The remaining patches connect the new model to the kernel backend and the userland facing code. The series goes on top of both Marc's GICv3 host support series as well as his vgic-dyn patches. The necessary patches for kvmtool to enable the guest's GICv3 will be posted here as well. There was some testing on the fast model with some I/O and interrupt affinity shuffling in a Linux guest with a varying number of VCPUs. Please review and test. I would be grateful for people to test for GICv2 regressions also (so on a GICv2 host with current kvmtool/qemu), as there is quite some refactoring on that front. Much of the code was inspired by Marc, so send all praises to him (while I take the blame). Cheers, Andre. Andre Przywara (14): arm/arm64: KVM: rework MPIDR assignment and add accessors arm/arm64: KVM: pass down user space provided GIC type into vGIC code arm/arm64: KVM: refactor vgic_handle_mmio() function arm/arm64: KVM: wrap 64 bit MMIO accesses with two 32 bit ones arm/arm64: KVM: introduce per-VM ops arm/arm64: KVM: make the maximum number of vCPUs a per-VM value arm/arm64: KVM: make the value of ICC_SRE_EL1 a per-VM variable arm/arm64: KVM: refactor MMIO accessors arm/arm64: KVM: split GICv2 specific emulation code from vgic.c arm/arm64: KVM: add opaque private pointer to MMIO accessors arm/arm64: KVM: add virtual GICv3 distributor emulation arm/arm64: KVM: add SGI system register trapping arm/arm64: KVM: enable kernel side of GICv3 emulation arm/arm64: KVM: allow userland to request a virtual GICv3 arch/arm/include/asm/kvm_emulate.h |2 +- arch/arm/include/asm/kvm_host.h |3 + arch/arm/kvm/Makefile|1 + arch/arm/kvm/arm.c | 23 +- arch/arm/kvm/coproc.c| 19 + arch/arm/kvm/psci.c | 15 +- arch/arm64/include/asm/kvm_emulate.h |3 +- arch/arm64/include/asm/kvm_host.h|5 + arch/arm64/include/uapi/asm/kvm.h|7 + arch/arm64/kernel/asm-offsets.c |1 + arch/arm64/kvm/Makefile |2 + arch/arm64/kvm/sys_regs.c| 37 +- arch/arm64/kvm/vgic-v3-switch.S | 14 +- include/kvm/arm_vgic.h | 38 +- include/linux/irqchip/arm-gic-v3.h | 26 + include/linux/kvm_host.h |1 + include/uapi/linux/kvm.h |1 + virt/kvm/arm/vgic-v2-emul.c | 802 +++ virt/kvm/arm/vgic-v2.c | 22 +- virt/kvm/arm/vgic-v3-emul.c | 898 ++ virt/kvm/arm/vgic-v3.c | 157 +- virt/kvm/arm/vgic.c | 1017 +++--- virt/kvm/arm/vgic.h | 117 virt/kvm/kvm_main.c |3 + 24 files changed, 2346 insertions(+), 868 deletions(-) create mode 100644 virt/kvm/arm/vgic-v2-emul.c create mode 100644 virt/kvm/arm/vgic-v3-emul.c create mode 100644 virt/kvm/arm/vgic.h -- 1.7.9.5 ___ kvmarm mailing
Re: [PATCH 04/14] arm/arm64: KVM: wrap 64 bit MMIO accesses with two 32 bit ones
On 19/06/14 22:15, Chalamarla, Tirumalesh wrote: -Original Message- From: kvmarm-boun...@lists.cs.columbia.edu [mailto:kvmarm-boun...@lists.cs.columbia.edu] On Behalf Of Andre Przywara Sent: Thursday, June 19, 2014 2:46 AM To: linux-arm-ker...@lists.infradead.org; kvm...@lists.cs.columbia.edu; kvm@vger.kernel.org Cc: christoffer.d...@linaro.org Subject: [PATCH 04/14] arm/arm64: KVM: wrap 64 bit MMIO accesses with two 32 bit ones Some GICv3 registers can and will be accessed as 64 bit registers. Currently the register handling code can only deal with 32 bit accesses, so we do two consecutive calls to cover this. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- virt/kvm/arm/vgic.c | 48 +--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 4c6b212..b3cf4c7 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -906,6 +906,48 @@ static bool vgic_validate_access(const struct vgic_dist *dist, } /* + * Call the respective handler function for the given range. + * We split up any 64 bit accesses into two consecutive 32 bit + * handler calls and merge the result afterwards. + */ +static bool call_range_handler(struct kvm_vcpu *vcpu, +struct kvm_exit_mmio *mmio, +unsigned long offset, +const struct mmio_range *range) { + u32 *data32 = (void *)mmio-data; + struct kvm_exit_mmio mmio32; + bool ret; + + if (likely(mmio-len = 4)) + return range-handle_mmio(vcpu, mmio, offset); + + /* + * We assume that any access greater than 4 bytes is actually + * 8 bytes long, caused by a 64-bit access + */ + + mmio32.len = 4; + mmio32.is_write = mmio-is_write; + + mmio32.phys_addr = mmio-phys_addr + 4; + if (mmio-is_write) + *(u32 *)mmio32.data = data32[1]; + ret = range-handle_mmio(vcpu, mmio32, offset + 4); + if (!mmio-is_write) + data32[1] = *(u32 *)mmio32.data; + + mmio32.phys_addr = mmio-phys_addr; + if (mmio-is_write) + *(u32 *)mmio32.data = data32[0]; + ret |= range-handle_mmio(vcpu, mmio32, offset); + if (!mmio-is_write) + data32[0] = *(u32 *)mmio32.data; + + return ret; +} Any reason to use two 32 bits instead of one 64 bit. AArch32 on ARMv8 may be. For the registers we care about right now we get along with this split. And it seems to be less intrusive. I have a patch to support native 64-bit accesses, but it needs some more work. If there is high demand for it, I can post it (but Marc didn't like the first version so much ;-) ) Regards, Andre. + +/* * vgic_handle_mmio_range - handle an in-kernel MMIO access * @vcpu:pointer to the vcpu performing the access * @run: pointer to the kvm_run structure @@ -936,10 +978,10 @@ static bool vgic_handle_mmio_range(struct kvm_vcpu *vcpu, struct kvm_run *run, spin_lock(vcpu-kvm-arch.vgic.lock); offset -= range-base; if (vgic_validate_access(dist, range, offset)) { - updated_state = range-handle_mmio(vcpu, mmio, offset); + updated_state = call_range_handler(vcpu, mmio, offset, range); } else { - vgic_reg_access(mmio, NULL, offset, - ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED); + if (!mmio-is_write) + memset(mmio-data, 0, mmio-len); What is the use of this memset. updated_state = false; } spin_unlock(vcpu-kvm-arch.vgic.lock); -- 1.7.9.5 ___ kvmarm mailing list kvm...@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm -- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you. ARM Limited, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England Wales, Company No: 2557590 ARM Holdings plc, Registered office 110 Fulbourn Road, Cambridge CB1 9NJ, Registered in England Wales, Company No: 2548782 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 13/14] arm/arm64: KVM: enable kernel side of GICv3 emulation
On 19/06/14 22:43, Chalamarla, Tirumalesh wrote: -Original Message- From: kvmarm-boun...@lists.cs.columbia.edu [mailto:kvmarm-boun...@lists.cs.columbia.edu] On Behalf Of Andre Przywara Sent: Thursday, June 19, 2014 2:46 AM To: linux-arm-ker...@lists.infradead.org; kvm...@lists.cs.columbia.edu; kvm@vger.kernel.org Cc: christoffer.d...@linaro.org Subject: [PATCH 13/14] arm/arm64: KVM: enable kernel side of GICv3 emulation With all the necessary GICv3 emulation code in place, we can now connect the code to the GICv3 backend in the kernel. The LR register handling is different depending on the emulated GIC model, so provide different implementations for each. Also allow non-v2-compatible GICv3 implementations (which don't provide MMIO regions for the virtual CPU interface in the DT), but restrict those hosts to use GICv3 guests only. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- virt/kvm/arm/vgic-v3.c | 138 ++-- virt/kvm/arm/vgic.c|2 + 2 files changed, 112 insertions(+), 28 deletions(-) diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c index 7d9c85e..d26d12f 100644 --- a/virt/kvm/arm/vgic-v3.c +++ b/virt/kvm/arm/vgic-v3.c @@ -34,6 +34,7 @@ #define GICH_LR_VIRTUALID(0x3ffUL 0) #define GICH_LR_PHYSID_CPUID_SHIFT (10) #define GICH_LR_PHYSID_CPUID (7UL GICH_LR_PHYSID_CPUID_SHIFT) +#define ICH_LR_VIRTUALID_MASK(BIT_ULL(32) - 1) /* * LRs are stored in reverse order in memory. make sure we index them @@ -43,7 +44,35 @@ static u32 ich_vtr_el2; -static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr) +static u64 sync_lr_val(u8 state) +{ + u64 lr_val = 0; + + if (state LR_STATE_PENDING) + lr_val |= ICH_LR_PENDING_BIT; + if (state LR_STATE_ACTIVE) + lr_val |= ICH_LR_ACTIVE_BIT; + if (state LR_EOI_INT) + lr_val |= ICH_LR_EOI; + + return lr_val; +} + +static u8 sync_lr_state(u64 lr_val) +{ + u8 state = 0; + + if (lr_val ICH_LR_PENDING_BIT) + state |= LR_STATE_PENDING; + if (lr_val ICH_LR_ACTIVE_BIT) + state |= LR_STATE_ACTIVE; + if (lr_val ICH_LR_EOI) + state |= LR_EOI_INT; + + return state; +} + +static struct vgic_lr vgic_v2_on_v3_get_lr(const struct kvm_vcpu *vcpu, +int lr) { struct vgic_lr lr_desc; u64 val = vcpu-arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)]; @@ -53,30 +82,53 @@ static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr) lr_desc.source = (val GICH_LR_PHYSID_CPUID_SHIFT) 0x7; else lr_desc.source = 0; - lr_desc.state = 0; + lr_desc.state = sync_lr_state(val); - if (val ICH_LR_PENDING_BIT) - lr_desc.state |= LR_STATE_PENDING; - if (val ICH_LR_ACTIVE_BIT) - lr_desc.state |= LR_STATE_ACTIVE; - if (val ICH_LR_EOI) - lr_desc.state |= LR_EOI_INT; + return lr_desc; +} + +static struct vgic_lr vgic_v3_on_v3_get_lr(const struct kvm_vcpu *vcpu, +int lr) { + struct vgic_lr lr_desc; + u64 val = vcpu-arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)]; + + lr_desc.irq = val ICH_LR_VIRTUALID_MASK; + lr_desc.source = 0; + lr_desc.state = sync_lr_state(val); return lr_desc; } -static void vgic_v3_set_lr(struct kvm_vcpu *vcpu, int lr, -struct vgic_lr lr_desc) +static void vgic_v3_on_v3_set_lr(struct kvm_vcpu *vcpu, int lr, + struct vgic_lr lr_desc) { - u64 lr_val = (((u32)lr_desc.source GICH_LR_PHYSID_CPUID_SHIFT) | - lr_desc.irq); + u64 lr_val; - if (lr_desc.state LR_STATE_PENDING) - lr_val |= ICH_LR_PENDING_BIT; - if (lr_desc.state LR_STATE_ACTIVE) - lr_val |= ICH_LR_ACTIVE_BIT; - if (lr_desc.state LR_EOI_INT) - lr_val |= ICH_LR_EOI; + lr_val = lr_desc.irq; + + /* + * currently all guest IRQs are Group1, as Group0 would result + * in a FIQ in the guest, which it wouldn't expect. + * Eventually we want to make this configurable, so we may revisit + * this in the future. + */ + lr_val |= ICH_LR_GROUP; + + lr_val |= sync_lr_val(lr_desc.state); + + vcpu-arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)] = lr_val; } + +static void vgic_v2_on_v3_set_lr(struct kvm_vcpu *vcpu, int lr, + struct vgic_lr lr_desc) +{ + u64 lr_val; + + lr_val = lr_desc.irq; + + lr_val |= (u32)lr_desc.source GICH_LR_PHYSID_CPUID_SHIFT; + + lr_val |= sync_lr_val(lr_desc.state); vcpu-arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)] = lr_val; } @@ -145,9 +197,8 @@ static void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp) static void
[PATCH 07/14] arm/arm64: KVM: make the value of ICC_SRE_EL1 a per-VM variable
ICC_SRE_EL1 is a system register allowing msr/mrs accesses to the GIC CPU interface for EL1 (guests). Currently we force it to 0, but for proper GICv3 support we have to allow guests to use it (depending on their selected virtual GIC model). So add ICC_SRE_EL1 to the list of saved/restored registers on a world switch, but actually disallow a guest to change it by only restoring a fixed, once-initialized value. This value depends on the GIC model userland has chosen for a guest. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm64/kernel/asm-offsets.c |1 + arch/arm64/kvm/vgic-v3-switch.S | 14 +- include/kvm/arm_vgic.h |1 + virt/kvm/arm/vgic-v3.c |9 +++-- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index e74654c..0f24b21 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -139,6 +139,7 @@ int main(void) DEFINE(VGIC_V2_CPU_ELRSR,offsetof(struct vgic_cpu, vgic_v2.vgic_elrsr)); DEFINE(VGIC_V2_CPU_APR, offsetof(struct vgic_cpu, vgic_v2.vgic_apr)); DEFINE(VGIC_V2_CPU_LR, offsetof(struct vgic_cpu, vgic_v2.vgic_lr)); + DEFINE(VGIC_V3_CPU_SRE, offsetof(struct vgic_cpu, vgic_v3.vgic_sre)); DEFINE(VGIC_V3_CPU_HCR, offsetof(struct vgic_cpu, vgic_v3.vgic_hcr)); DEFINE(VGIC_V3_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v3.vgic_vmcr)); DEFINE(VGIC_V3_CPU_MISR, offsetof(struct vgic_cpu, vgic_v3.vgic_misr)); diff --git a/arch/arm64/kvm/vgic-v3-switch.S b/arch/arm64/kvm/vgic-v3-switch.S index 4ede9d8..c0cfd16 100644 --- a/arch/arm64/kvm/vgic-v3-switch.S +++ b/arch/arm64/kvm/vgic-v3-switch.S @@ -148,17 +148,18 @@ * x0: Register pointing to VCPU struct */ .macro restore_vgic_v3_state - // Disable SRE_EL1 access. Necessary, otherwise - // ICH_VMCR_EL2.VFIQEn becomes one, and FIQ happens... - msr ICC_SRE_EL1, xzr - isb - // Compute the address of struct vgic_cpu add x3, x0, #VCPU_VGIC_CPU // Restore all interesting registers ldr w4, [x3, #VGIC_V3_CPU_HCR] ldr w5, [x3, #VGIC_V3_CPU_VMCR] + ldr w25, [x3, #VGIC_V3_CPU_SRE] + + msr ICC_SRE_EL1, x25 + + // make sure SRE is valid before writing the other registers + isb msr ICH_HCR_EL2, x4 msr ICH_VMCR_EL2, x5 @@ -243,9 +244,12 @@ dsb sy // Prevent the guest from touching the GIC system registers + // if SRE isn't enabled for GICv3 emulation + cbnzx25, 1f mrs x5, ICC_SRE_EL2 and x5, x5, #~ICC_SRE_EL2_ENABLE msr ICC_SRE_EL2, x5 +1: .endm ENTRY(__save_vgic_v3_state) diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 7e7c99e..8aa8482 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -199,6 +199,7 @@ struct vgic_v3_cpu_if { #ifdef CONFIG_ARM_GIC_V3 u32 vgic_hcr; u32 vgic_vmcr; + u32 vgic_sre; /* Restored only, change ignored */ u32 vgic_misr; /* Saved only */ u32 vgic_eisr; /* Saved only */ u32 vgic_elrsr; /* Saved only */ diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c index 40d6817..7d9c85e 100644 --- a/virt/kvm/arm/vgic-v3.c +++ b/virt/kvm/arm/vgic-v3.c @@ -145,15 +145,20 @@ static void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp) static void vgic_v3_enable(struct kvm_vcpu *vcpu) { + struct vgic_v3_cpu_if *vgic_v3; + + vgic_v3 = vcpu-arch.vgic_cpu.vgic_v3; /* * By forcing VMCR to zero, the GIC will restore the binary * points to their reset values. Anything else resets to zero * anyway. */ - vcpu-arch.vgic_cpu.vgic_v3.vgic_vmcr = 0; + vgic_v3-vgic_vmcr = 0; + + vgic_v3-vgic_sre = 0; /* Get the show on the road... */ - vcpu-arch.vgic_cpu.vgic_v3.vgic_hcr = ICH_HCR_EN; + vgic_v3-vgic_hcr = ICH_HCR_EN; } static const struct vgic_ops vgic_v3_ops = { -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 12/14] arm/arm64: KVM: add SGI system register trapping
While the injection of a (virtual) inter-processor interrupt (SGI) on a GICv2 works by writing to a MMIO register, GICv3 uses system registers to trigger them. Trap the appropriate registers both on ARM and ARM64 machines and call the SGI handler function in the vGICv3 emulation code. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm/kvm/coproc.c | 19 +++ arch/arm64/kvm/sys_regs.c | 26 ++ 2 files changed, 45 insertions(+) diff --git a/arch/arm/kvm/coproc.c b/arch/arm/kvm/coproc.c index c58a351..4adadb7 100644 --- a/arch/arm/kvm/coproc.c +++ b/arch/arm/kvm/coproc.c @@ -205,6 +205,22 @@ done: return true; } +static bool access_gic_sgi(struct kvm_vcpu *vcpu, + const struct coproc_params *p, + const struct coproc_reg *r) +{ + u64 val; + + if (!p-is_write) + return read_from_write_only(vcpu, p); + + val = *vcpu_reg(vcpu, p-Rt1); + val |= (u64)*vcpu_reg(vcpu, p-Rt2) 32; + vgic_v3_dispatch_sgi(vcpu, val); + + return true; +} + /* * Generic accessor for VM registers. Only called as long as HCR_TVM * is set. @@ -376,6 +392,9 @@ static const struct coproc_reg cp15_regs[] = { { CRn(10), CRm( 3), Op1( 0), Op2( 1), is32, access_vm_reg, reset_unknown, c10_AMAIR1}, + /* ICC_SGI1R */ + { CRm64(12), Op1( 0), is64, access_gic_sgi}, + /* VBAR: swapped by interrupt.S. */ { CRn(12), CRm( 0), Op1( 0), Op2( 0), is32, NULL, reset_val, c12_VBAR, 0x }, diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index fa2273a..012f21a 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -164,6 +164,27 @@ static bool access_sctlr(struct kvm_vcpu *vcpu, } /* + * Trapping on the GICv3 SGI system register. + * Forward the request to the VGIC emulation. + * The cp15_64 code makes sure this automatically works + * for both AArch64 and AArch32 accesses. + */ +static bool access_gic_sgi(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + u64 val; + + if (!p-is_write) + return read_from_write_only(vcpu, p); + + val = *vcpu_reg(vcpu, p-Rt); + vgic_v3_dispatch_sgi(vcpu, val); + + return true; +} + +/* * We could trap ID_DFR0 and tell the guest we don't support performance * monitoring. Unfortunately the patch to make the kernel check ID_DFR0 was * NAKed, so it will read the PMCR anyway. @@ -282,6 +303,9 @@ static const struct sys_reg_desc sys_reg_descs[] = { /* VBAR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b), Op2(0b000), NULL, reset_val, VBAR_EL1, 0 }, + /* ICC_SGI1R_EL1 */ + { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1011), Op2(0b101), + access_gic_sgi }, /* CONTEXTIDR_EL1 */ { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b), Op2(0b001), access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 }, @@ -374,6 +398,8 @@ static const struct sys_reg_desc cp15_regs[] = { { Op1( 0), CRn( 6), CRm( 0), Op2( 0), access_vm_reg, NULL, c6_DFAR }, { Op1( 0), CRn( 6), CRm( 0), Op2( 2), access_vm_reg, NULL, c6_IFAR }, + { Op1( 0), CRn( 0), CRm(12), Op2( 0), access_gic_sgi }, + /* * DC{C,I,CI}SW operations: */ -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 11/14] arm/arm64: KVM: add virtual GICv3 distributor emulation
With everything separated and prepared, we implement a model of a GICv3 distributor and redistributors by using the existing framework to provide handler functions for each register group. Currently we limit the emulation to a model enforcing a single security state, with SRE==1 (forcing system register access) and ARE==1 (allowing more than 8 VCPUs). We share some of functions provided for GICv2 emulation, but take the different ways of addressing (v)CPUs into account. Save and restore is currently not implemented. Similar to the split-off GICv2 specific code, the new emulation code goes into a new file (vgic-v3-emul.c). Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm64/kvm/Makefile|1 + include/kvm/arm_vgic.h | 11 +- include/linux/irqchip/arm-gic-v3.h | 26 ++ include/linux/kvm_host.h |1 + include/uapi/linux/kvm.h |1 + virt/kvm/arm/vgic-v3-emul.c| 895 virt/kvm/arm/vgic.c| 11 +- virt/kvm/arm/vgic.h|3 + virt/kvm/kvm_main.c|3 + 9 files changed, 949 insertions(+), 3 deletions(-) create mode 100644 virt/kvm/arm/vgic-v3-emul.c diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile index f241db6..2fba3a5 100644 --- a/arch/arm64/kvm/Makefile +++ b/arch/arm64/kvm/Makefile @@ -21,6 +21,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += guest.o reset.o sys_regs.o sys_regs_generic_v8.o kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2-emul.o +kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v3-emul.o kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v2-switch.o kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v3.o diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 8aa8482..3b164ee 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -151,7 +151,11 @@ struct vgic_dist { /* Distributor and vcpu interface mapping in the guest */ phys_addr_t vgic_dist_base; - phys_addr_t vgic_cpu_base; + /* GICv2 and GICv3 use different mapped register blocks */ + union { + phys_addr_t vgic_cpu_base; + phys_addr_t vgic_redist_base; + }; /* Distributor enabled */ u32 enabled; @@ -176,6 +180,10 @@ struct vgic_dist { /* Target CPU for each IRQ */ u8 *irq_spi_cpu; + + /* Target MPIDR for each IRQ (needed for GICv3 IROUTERn) only */ + u32 *irq_spi_mpidr; + struct vgic_bitmap *irq_spi_target; /* Bitmap indicating which CPU has something pending */ @@ -253,6 +261,7 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu); void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu); int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num, bool level); +void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg); int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu); bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, struct kvm_exit_mmio *mmio); diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 9eac712..9f17e57 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -31,6 +31,7 @@ #define GICD_SETSPI_SR 0x0050 #define GICD_CLRSPI_SR 0x0058 #define GICD_SEIR 0x0068 +#define GICD_IGROUPR 0x0080 #define GICD_ISENABLER 0x0100 #define GICD_ICENABLER 0x0180 #define GICD_ISPENDR 0x0200 @@ -39,19 +40,38 @@ #define GICD_ICACTIVER 0x0380 #define GICD_IPRIORITYR0x0400 #define GICD_ICFGR 0x0C00 +#define GICD_IGRPMODR 0x0D00 +#define GICD_NSACR 0x0E00 #define GICD_IROUTER 0x6000 +#define GICD_IDREGS0xFFD0 #define GICD_PIDR2 0xFFE8 +/* + * Non-ARE distributor registers, needed to provide the RES0 + * semantics for KVM's emulated GICv3 + */ +#define GICD_ITARGETSR 0x0800 +#define GICD_SGIR 0x0F00 +#define GICD_CPENDSGIR 0x0F10 +#define GICD_SPENDSGIR 0x0F20 + + #define GICD_CTLR_RWP (1U 31) +#define GICD_CTLR_DS (1U 6) #define GICD_CTLR_ARE_NS (1U 4) #define GICD_CTLR_ENABLE_G1A (1U 1) #define GICD_CTLR_ENABLE_G1(1U 0) +#define GICD_TYPER_LPIS(1U 17) +#define GICD_TYPER_MBIS(1U 16) + #define GICD_IROUTER_SPI_MODE_ONE (0U 31) #define GICD_IROUTER_SPI_MODE_ANY (1U 31) #define
[PATCH 05/14] arm/arm64: KVM: introduce per-VM ops
Currently we only have one virtual GIC model supported, so all guests use the same emulation code. With the addition of another model we end up with different guests using potentially different vGIC models, so we have to split up some functions to be per VM. Introduce a vgic_vm_ops struct to hold function pointers for those functions that are different and provide the necessary code to initialize them. This includes functions that depend on the emulated GIC model only and functions that depend on the combination of host and guest GIC. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- include/kvm/arm_vgic.h | 18 +++- virt/kvm/arm/vgic-v2.c | 17 +++- virt/kvm/arm/vgic-v3.c | 16 ++- virt/kvm/arm/vgic.c| 109 +--- 4 files changed, 121 insertions(+), 39 deletions(-) diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 4feac9a..7e7c99e 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -99,8 +99,6 @@ struct vgic_vmcr { }; struct vgic_ops { - struct vgic_lr (*get_lr)(const struct kvm_vcpu *, int); - void(*set_lr)(struct kvm_vcpu *, int, struct vgic_lr); void(*sync_lr_elrsr)(struct kvm_vcpu *, int, struct vgic_lr); u64 (*get_elrsr)(const struct kvm_vcpu *vcpu); u64 (*get_eisr)(const struct kvm_vcpu *vcpu); @@ -123,6 +121,17 @@ struct vgic_params { unsigned intmaint_irq; /* Virtual control interface base address */ void __iomem*vctrl_base; + bool (*init_emul)(struct kvm *kvm, int type); +}; + +struct vgic_vm_ops { + struct vgic_lr (*get_lr)(const struct kvm_vcpu *, int); + void(*set_lr)(struct kvm_vcpu *, int, struct vgic_lr); + bool(*handle_mmio)(struct kvm_vcpu *, struct kvm_run *, + struct kvm_exit_mmio *); + bool(*queue_sgi)(struct kvm_vcpu *vcpu, int irq); + void(*unqueue_sgi)(struct kvm_vcpu *vcpu, int irq, int source); + int (*vgic_init)(struct kvm *kvm, const struct vgic_params *params); }; struct vgic_dist { @@ -131,6 +140,9 @@ struct vgic_dist { boolin_kernel; boolready; + /* vGIC model the kernel emulates for the guest (GICv2 or GICv3) */ + u32 vgic_model; + int nr_cpus; int nr_irqs; @@ -168,6 +180,8 @@ struct vgic_dist { /* Bitmap indicating which CPU has something pending */ unsigned long irq_pending_on_cpu; + + struct vgic_vm_ops vm_ops; #endif }; diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c index a55a9a4..f2c214a 100644 --- a/virt/kvm/arm/vgic-v2.c +++ b/virt/kvm/arm/vgic-v2.c @@ -148,8 +148,6 @@ static void vgic_v2_enable(struct kvm_vcpu *vcpu) } static const struct vgic_ops vgic_v2_ops = { - .get_lr = vgic_v2_get_lr, - .set_lr = vgic_v2_set_lr, .sync_lr_elrsr = vgic_v2_sync_lr_elrsr, .get_elrsr = vgic_v2_get_elrsr, .get_eisr = vgic_v2_get_eisr, @@ -163,6 +161,20 @@ static const struct vgic_ops vgic_v2_ops = { static struct vgic_params vgic_v2_params; +static bool vgic_v2_init_emul(struct kvm *kvm, int type) +{ + struct vgic_vm_ops *vm_ops = kvm-arch.vgic.vm_ops; + + switch (type) { + case KVM_DEV_TYPE_ARM_VGIC_V2: + vm_ops-get_lr = vgic_v2_get_lr; + vm_ops-set_lr = vgic_v2_set_lr; + return true; + } + + return false; +} + /** * vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT * @node: pointer to the DT node @@ -201,6 +213,7 @@ int vgic_v2_probe(struct device_node *vgic_node, ret = -ENOMEM; goto out; } + vgic-init_emul = vgic_v2_init_emul; vgic-nr_lr = readl_relaxed(vgic-vctrl_base + GICH_VTR); vgic-nr_lr = (vgic-nr_lr 0x3f) + 1; diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c index f01d446..f42961c 100644 --- a/virt/kvm/arm/vgic-v3.c +++ b/virt/kvm/arm/vgic-v3.c @@ -157,8 +157,6 @@ static void vgic_v3_enable(struct kvm_vcpu *vcpu) } static const struct vgic_ops vgic_v3_ops = { - .get_lr = vgic_v3_get_lr, - .set_lr = vgic_v3_set_lr, .sync_lr_elrsr = vgic_v3_sync_lr_elrsr, .get_elrsr = vgic_v3_get_elrsr, .get_eisr = vgic_v3_get_eisr, @@ -170,6 +168,19 @@ static const struct vgic_ops vgic_v3_ops = { .enable = vgic_v3_enable, }; +static bool vgic_v3_init_emul_compat(struct kvm *kvm, int type) +{ + struct vgic_vm_ops *vm_ops = kvm-arch.vgic.vm_ops; + + switch (type) { + case KVM_DEV_TYPE_ARM_VGIC_V2: + vm_ops-get_lr = vgic_v3_get_lr
[PATCH 09/14] arm/arm64: KVM: split GICv2 specific emulation code from vgic.c
vgic.c is currently a mixture of generic vGIC emulation code and functions specific to emulating a GICv2. To ease the addition of GICv3, split off strictly v2 specific parts into a new file vgic-v2-emul.c. A new header file vgic.h is introduced to allow separation and later sharing of functions. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm/kvm/Makefile |1 + arch/arm64/kvm/Makefile |1 + virt/kvm/arm/vgic-v2-emul.c | 795 virt/kvm/arm/vgic.c | 856 +++ virt/kvm/arm/vgic.h | 113 ++ 5 files changed, 956 insertions(+), 810 deletions(-) create mode 100644 virt/kvm/arm/vgic-v2-emul.c create mode 100644 virt/kvm/arm/vgic.h diff --git a/arch/arm/kvm/Makefile b/arch/arm/kvm/Makefile index f7057ed..443b8be 100644 --- a/arch/arm/kvm/Makefile +++ b/arch/arm/kvm/Makefile @@ -22,4 +22,5 @@ obj-y += arm.o handle_exit.o guest.o mmu.o emulate.o reset.o obj-y += coproc.o coproc_a15.o coproc_a7.o mmio.o psci.o perf.o obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o +obj-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2-emul.o obj-$(CONFIG_KVM_ARM_TIMER) += $(KVM)/arm/arch_timer.o diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile index 32a0961..f241db6 100644 --- a/arch/arm64/kvm/Makefile +++ b/arch/arm64/kvm/Makefile @@ -20,6 +20,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o kvm-$(CONFIG_KVM_ARM_HOST) += guest.o reset.o sys_regs.o sys_regs_generic_v8.o kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic.o +kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2-emul.o kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v2.o kvm-$(CONFIG_KVM_ARM_VGIC) += vgic-v2-switch.o kvm-$(CONFIG_KVM_ARM_VGIC) += $(KVM)/arm/vgic-v3.o diff --git a/virt/kvm/arm/vgic-v2-emul.c b/virt/kvm/arm/vgic-v2-emul.c new file mode 100644 index 000..ba5f873 --- /dev/null +++ b/virt/kvm/arm/vgic-v2-emul.c @@ -0,0 +1,795 @@ +/* + * Contains GICv2 specific emulation code, was in vgic.c before. + * + * Copyright (C) 2012 ARM Ltd. + * Author: Marc Zyngier marc.zyng...@arm.com + * + * 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, see http://www.gnu.org/licenses/. + */ + +#include linux/cpu.h +#include linux/kvm.h +#include linux/kvm_host.h +#include linux/interrupt.h +#include linux/io.h +#include linux/uaccess.h + +#include linux/irqchip/arm-gic.h + +#include asm/kvm_emulate.h +#include asm/kvm_arm.h +#include asm/kvm_mmu.h + +#include vgic.h + +#define GICC_ARCH_VERSION_V20x2 + +static void vgic_dispatch_sgi(struct kvm_vcpu *vcpu, u32 reg); +static u8 *vgic_get_sgi_sources(struct vgic_dist *dist, int vcpu_id, int sgi) +{ + return dist-irq_sgi_sources + vcpu_id * VGIC_NR_SGIS + sgi; +} + +static bool handle_mmio_misc(struct kvm_vcpu *vcpu, +struct kvm_exit_mmio *mmio, phys_addr_t offset) +{ + u32 reg; + u32 word_offset = offset 3; + + switch (offset ~3) { + case 0: /* GICD_CTLR */ + reg = vcpu-kvm-arch.vgic.enabled; + vgic_reg_access(mmio, reg, word_offset, + ACCESS_READ_VALUE | ACCESS_WRITE_VALUE); + if (mmio-is_write) { + vcpu-kvm-arch.vgic.enabled = reg 1; + vgic_update_state(vcpu-kvm); + return true; + } + break; + + case 4: /* GICD_TYPER */ + reg = (atomic_read(vcpu-kvm-online_vcpus) - 1) 5; + reg |= (vcpu-kvm-arch.vgic.nr_irqs 5) - 1; + vgic_reg_access(mmio, reg, word_offset, + ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED); + break; + + case 8: /* GICD_IIDR */ + reg = (PRODUCT_ID_KVM 24) | (IMPLEMENTER_ARM 0); + vgic_reg_access(mmio, reg, word_offset, + ACCESS_READ_VALUE | ACCESS_WRITE_IGNORED); + break; + } + + return false; +} + +static bool handle_mmio_set_enable_reg(struct kvm_vcpu *vcpu, + struct kvm_exit_mmio *mmio, + phys_addr_t offset) +{ + return vgic_handle_enable_reg(vcpu-kvm, mmio, offset, + vcpu-vcpu_id, ACCESS_WRITE_SETBIT); +} + +static bool
[PATCH 03/14] arm/arm64: KVM: refactor vgic_handle_mmio() function
Currently we only need to deal with one MMIO region for the GIC emulation, but we soon need to extend this. Refactor the existing code to allow easier addition of different ranges without code duplication. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- virt/kvm/arm/vgic.c | 72 --- 1 file changed, 51 insertions(+), 21 deletions(-) diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 8f1daf2..4c6b212 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -905,37 +905,28 @@ static bool vgic_validate_access(const struct vgic_dist *dist, return true; } -/** - * vgic_handle_mmio - handle an in-kernel MMIO access +/* + * vgic_handle_mmio_range - handle an in-kernel MMIO access * @vcpu: pointer to the vcpu performing the access * @run: pointer to the kvm_run structure * @mmio: pointer to the data describing the access + * @ranges:pointer to the register defining structure + * @mmio_base: base address for this mapping * - * returns true if the MMIO access has been performed in kernel space, - * and false if it needs to be emulated in user space. + * returns true if the MMIO access could be performed */ -bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, - struct kvm_exit_mmio *mmio) +static bool vgic_handle_mmio_range(struct kvm_vcpu *vcpu, struct kvm_run *run, + struct kvm_exit_mmio *mmio, + const struct mmio_range *ranges, + unsigned long mmio_base) { const struct mmio_range *range; struct vgic_dist *dist = vcpu-kvm-arch.vgic; - unsigned long base = dist-vgic_dist_base; bool updated_state; unsigned long offset; - if (!irqchip_in_kernel(vcpu-kvm) || - mmio-phys_addr base || - (mmio-phys_addr + mmio-len) (base + KVM_VGIC_V2_DIST_SIZE)) - return false; - - /* We don't support ldrd / strd or ldm / stm to the emulated vgic */ - if (mmio-len 4) { - kvm_inject_dabt(vcpu, mmio-phys_addr); - return true; - } - - offset = mmio-phys_addr - base; - range = find_matching_range(vgic_dist_ranges, mmio, offset); + offset = mmio-phys_addr - mmio_base; + range = find_matching_range(ranges, mmio, offset); if (unlikely(!range || !range-handle_mmio)) { pr_warn(Unhandled access %d %08llx %d\n, mmio-is_write, mmio-phys_addr, mmio-len); @@ -943,7 +934,7 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, } spin_lock(vcpu-kvm-arch.vgic.lock); - offset = mmio-phys_addr - range-base - base; + offset -= range-base; if (vgic_validate_access(dist, range, offset)) { updated_state = range-handle_mmio(vcpu, mmio, offset); } else { @@ -961,6 +952,45 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, return true; } +#define IS_IN_RANGE(addr, alen, base, len) \ + (((addr) = (base)) (((addr) + (alen)) ((base) + (len + +static bool vgic_v2_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, + struct kvm_exit_mmio *mmio) +{ + unsigned long base = vcpu-kvm-arch.vgic.vgic_dist_base; + + if (!IS_IN_RANGE(mmio-phys_addr, mmio-len, base, +KVM_VGIC_V2_DIST_SIZE)) + return false; + + /* GICv2 does not support accesses wider than 32 bits */ + if (mmio-len 4) { + kvm_inject_dabt(vcpu, mmio-phys_addr); + return true; + } + + return vgic_handle_mmio_range(vcpu, run, mmio, vgic_dist_ranges, base); +} + +/** + * vgic_handle_mmio - handle an in-kernel MMIO access for the GIC emulation + * @vcpu: pointer to the vcpu performing the access + * @run: pointer to the kvm_run structure + * @mmio: pointer to the data describing the access + * + * returns true if the MMIO access has been performed in kernel space, + * and false if it needs to be emulated in user space. + */ +bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, + struct kvm_exit_mmio *mmio) +{ + if (!irqchip_in_kernel(vcpu-kvm)) + return false; + + return vgic_v2_handle_mmio(vcpu, run, mmio); +} + static u8 *vgic_get_sgi_sources(struct vgic_dist *dist, int vcpu_id, int sgi) { return dist-irq_sgi_sources + vcpu_id * VGIC_NR_SGIS + sgi; -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 02/14] arm/arm64: KVM: pass down user space provided GIC type into vGIC code
With the introduction of a second emulated GIC model we need to let userspace specify the GIC model to use for each VM. Pass the userspace provided value down into the vGIC code to differentiate later. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm/kvm/arm.c |2 +- include/kvm/arm_vgic.h |4 ++-- virt/kvm/arm/vgic.c|4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 9ffe962..fa37fa1 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -804,7 +804,7 @@ long kvm_arch_vm_ioctl(struct file *filp, switch (ioctl) { case KVM_CREATE_IRQCHIP: { if (vgic_present) - return kvm_vgic_create(kvm); + return kvm_vgic_create(kvm, KVM_DEV_TYPE_ARM_VGIC_V2); else return -ENXIO; } diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index f5788cf..4feac9a 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -231,7 +231,7 @@ struct kvm_exit_mmio; int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write); int kvm_vgic_hyp_init(void); int kvm_vgic_init(struct kvm *kvm); -int kvm_vgic_create(struct kvm *kvm); +int kvm_vgic_create(struct kvm *kvm, u32 type); void kvm_vgic_destroy(struct kvm *kvm); void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu); void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu); @@ -282,7 +282,7 @@ static inline int kvm_vgic_init(struct kvm *kvm) return 0; } -static inline int kvm_vgic_create(struct kvm *kvm) +static inline int kvm_vgic_create(struct kvm *kvm, u32 type) { return 0; } diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 68ac9c6..8f1daf2 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -1832,7 +1832,7 @@ out: return ret; } -int kvm_vgic_create(struct kvm *kvm) +int kvm_vgic_create(struct kvm *kvm, u32 type) { int i, vcpu_lock_idx = -1, ret = 0; struct kvm_vcpu *vcpu; @@ -2284,7 +2284,7 @@ static void vgic_destroy(struct kvm_device *dev) static int vgic_create(struct kvm_device *dev, u32 type) { - return kvm_vgic_create(dev-kvm); + return kvm_vgic_create(dev-kvm, type); } struct kvm_device_ops kvm_arm_vgic_v2_ops = { -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 06/14] arm/arm64: KVM: make the maximum number of vCPUs a per-VM value
Currently the maximum number of vCPUs supported is a global value limited by the used GIC model. GICv3 will lift this limit, but we still need to observe it for guests using GICv2. So the maximum number of vCPUs is per-VM value, depending on the GIC model the guest uses. Store and check the value in struct kvm_arch, but keep it down to 8 for now. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm/include/asm/kvm_host.h |1 + arch/arm/kvm/arm.c|6 ++ arch/arm64/include/asm/kvm_host.h |3 +++ virt/kvm/arm/vgic-v2.c|5 + virt/kvm/arm/vgic-v3.c|6 ++ 5 files changed, 21 insertions(+) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 8d30f05..49c07ea 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -67,6 +67,7 @@ struct kvm_arch { /* Interrupt controller */ struct vgic_distvgic; + int max_vcpus; }; #define KVM_NR_MEM_OBJS 40 diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index fa37fa1..a291e63 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -142,6 +142,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) /* Mark the initial VMID generation invalid */ kvm-arch.vmid_gen = 0; + kvm-arch.max_vcpus = CONFIG_KVM_ARM_MAX_VCPUS; return ret; out_free_stage2_pgd: @@ -260,6 +261,11 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) int err; struct kvm_vcpu *vcpu; + if (id = kvm-arch.max_vcpus) { + err = -EINVAL; + goto out; + } + vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); if (!vcpu) { err = -ENOMEM; diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 4c84250..eef63b1 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -58,6 +58,9 @@ struct kvm_arch { /* VTTBR value associated with above pgd and vmid */ u64vttbr; + /* The maximum number of vCPUs depends on the used GIC model */ + int max_vcpus; + /* Interrupt controller */ struct vgic_distvgic; diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c index f2c214a..4091078 100644 --- a/virt/kvm/arm/vgic-v2.c +++ b/virt/kvm/arm/vgic-v2.c @@ -164,11 +164,16 @@ static struct vgic_params vgic_v2_params; static bool vgic_v2_init_emul(struct kvm *kvm, int type) { struct vgic_vm_ops *vm_ops = kvm-arch.vgic.vm_ops; + int nr_vcpus; switch (type) { case KVM_DEV_TYPE_ARM_VGIC_V2: + nr_vcpus = atomic_read(kvm-online_vcpus); + if (nr_vcpus 8) + return false; vm_ops-get_lr = vgic_v2_get_lr; vm_ops-set_lr = vgic_v2_set_lr; + kvm-arch.max_vcpus = 8; return true; } diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c index f42961c..40d6817 100644 --- a/virt/kvm/arm/vgic-v3.c +++ b/virt/kvm/arm/vgic-v3.c @@ -171,11 +171,17 @@ static const struct vgic_ops vgic_v3_ops = { static bool vgic_v3_init_emul_compat(struct kvm *kvm, int type) { struct vgic_vm_ops *vm_ops = kvm-arch.vgic.vm_ops; + int nr_vcpus; switch (type) { case KVM_DEV_TYPE_ARM_VGIC_V2: + nr_vcpus = atomic_read(kvm-online_vcpus); + if (nr_vcpus 8) + return false; + vm_ops-get_lr = vgic_v3_get_lr; vm_ops-set_lr = vgic_v3_set_lr; + kvm-arch.max_vcpus = 8; return true; } return false; -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 08/14] arm/arm64: KVM: refactor MMIO accessors
The MMIO accessors for GICD_I[CS]ENABLER, GICD_I[CS]PENDR and GICD_ICFGR behave very similiar in GICv3, although the way the affected vCPU is determined differs. Factor out a generic, backend-facing implementation and use small wrappers in the current GICv2 emulation to ease code sharing later. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- virt/kvm/arm/vgic.c | 93 --- 1 file changed, 52 insertions(+), 41 deletions(-) diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 2de58b3..2a59dff 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -398,35 +398,54 @@ static bool handle_mmio_raz_wi(struct kvm_vcpu *vcpu, return false; } -static bool handle_mmio_set_enable_reg(struct kvm_vcpu *vcpu, - struct kvm_exit_mmio *mmio, - phys_addr_t offset) +static bool vgic_handle_enable_reg(struct kvm *kvm, struct kvm_exit_mmio *mmio, + phys_addr_t offset, int vcpu_id, int access) { - u32 *reg = vgic_bitmap_get_reg(vcpu-kvm-arch.vgic.irq_enabled, - vcpu-vcpu_id, offset); - vgic_reg_access(mmio, reg, offset, - ACCESS_READ_VALUE | ACCESS_WRITE_SETBIT); + u32 *reg; + int mode = ACCESS_READ_VALUE | access; + struct kvm_vcpu *target_vcpu = kvm_get_vcpu(kvm, vcpu_id); + + reg = vgic_bitmap_get_reg(kvm-arch.vgic.irq_enabled, vcpu_id, offset); + vgic_reg_access(mmio, reg, offset, mode); if (mmio-is_write) { - vgic_update_state(vcpu-kvm); + if (access ACCESS_WRITE_CLEARBIT) { + if (offset 4) /* Force SGI enabled */ + *reg |= 0x; + vgic_retire_disabled_irqs(target_vcpu); + } + vgic_update_state(kvm); return true; } return false; } +static bool handle_mmio_set_enable_reg(struct kvm_vcpu *vcpu, + struct kvm_exit_mmio *mmio, + phys_addr_t offset) +{ + return vgic_handle_enable_reg(vcpu-kvm, mmio, offset, + vcpu-vcpu_id, ACCESS_WRITE_SETBIT); +} + static bool handle_mmio_clear_enable_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, phys_addr_t offset) { - u32 *reg = vgic_bitmap_get_reg(vcpu-kvm-arch.vgic.irq_enabled, - vcpu-vcpu_id, offset); - vgic_reg_access(mmio, reg, offset, - ACCESS_READ_VALUE | ACCESS_WRITE_CLEARBIT); + return vgic_handle_enable_reg(vcpu-kvm, mmio, offset, + vcpu-vcpu_id, ACCESS_WRITE_CLEARBIT); +} + +static bool vgic_handle_pending_reg(struct kvm *kvm, struct kvm_exit_mmio *mmio, + phys_addr_t offset, int vcpu_id, int access) +{ + u32 *reg; + int mode = ACCESS_READ_VALUE | access; + + reg = vgic_bitmap_get_reg(kvm-arch.vgic.irq_state, vcpu_id, offset); + vgic_reg_access(mmio, reg, offset, mode); if (mmio-is_write) { - if (offset 4) /* Force SGI enabled */ - *reg |= 0x; - vgic_retire_disabled_irqs(vcpu); - vgic_update_state(vcpu-kvm); + vgic_update_state(kvm); return true; } @@ -437,31 +456,16 @@ static bool handle_mmio_set_pending_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, phys_addr_t offset) { - u32 *reg = vgic_bitmap_get_reg(vcpu-kvm-arch.vgic.irq_state, - vcpu-vcpu_id, offset); - vgic_reg_access(mmio, reg, offset, - ACCESS_READ_VALUE | ACCESS_WRITE_SETBIT); - if (mmio-is_write) { - vgic_update_state(vcpu-kvm); - return true; - } - - return false; + return vgic_handle_pending_reg(vcpu-kvm, mmio, offset, + vcpu-vcpu_id, ACCESS_WRITE_SETBIT); } static bool handle_mmio_clear_pending_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, phys_addr_t offset) { - u32 *reg = vgic_bitmap_get_reg(vcpu-kvm-arch.vgic.irq_state, - vcpu-vcpu_id, offset); - vgic_reg_access(mmio, reg, offset, - ACCESS_READ_VALUE | ACCESS_WRITE_CLEARBIT); - if (mmio-is_write) { - vgic_update_state(vcpu-kvm); - return true; - } - + return vgic_handle_pending_reg(vcpu-kvm, mmio, offset, + vcpu
[PATCH 14/14] arm/arm64: KVM: allow userland to request a virtual GICv3
With everything in place we allow userland to request the kernel using a virtual GICv3 in the guest, which finally lifts the 8 vCPU limit for a guest. Also we provide the necessary support for guests setting the memory addresses for the virtual distributor and redistributors. This requires some userland code to make use of that feature and explicitly ask for a virtual GICv3. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm64/include/uapi/asm/kvm.h |7 ++ include/kvm/arm_vgic.h|4 ++-- virt/kvm/arm/vgic-v3-emul.c |3 +++ virt/kvm/arm/vgic.c | 46 ++--- 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 5513de4..9a62081 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -77,6 +77,13 @@ struct kvm_regs { #define KVM_VGIC_V2_DIST_SIZE 0x1000 #define KVM_VGIC_V2_CPU_SIZE 0x2000 +/* Supported VGICv3 address types */ +#define KVM_VGIC_V3_ADDR_TYPE_DIST 2 +#define KVM_VGIC_V3_ADDR_TYPE_REDIST 3 + +#define KVM_VGIC_V3_DIST_SIZE SZ_64K +#define KVM_VGIC_V3_REDIST_SIZE(2 * SZ_64K) + #define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ #define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */ #define KVM_ARM_VCPU_PSCI_0_2 2 /* CPU uses PSCI v0.2 */ diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 3b164ee..82e00a5 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -35,8 +35,8 @@ #define VGIC_MAX_IRQS 1024 /* Sanity checks... */ -#if (KVM_MAX_VCPUS 8) -#error Invalid number of CPU interfaces +#if (KVM_MAX_VCPUS 255) +#error Too many KVM VCPUs, the VGIC only supports up to 255 VCPUs for now #endif #if (VGIC_NR_IRQS_LEGACY 31) diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c index 68821fd..88c2cca 100644 --- a/virt/kvm/arm/vgic-v3-emul.c +++ b/virt/kvm/arm/vgic-v3-emul.c @@ -873,6 +873,9 @@ static int vgic_v3_has_attr(struct kvm_device *dev, case KVM_VGIC_V2_ADDR_TYPE_DIST: case KVM_VGIC_V2_ADDR_TYPE_CPU: return -ENXIO; + case KVM_VGIC_V3_ADDR_TYPE_DIST: + case KVM_VGIC_V3_ADDR_TYPE_REDIST: + return 0; } break; case KVM_DEV_ARM_VGIC_GRP_DIST_REGS: diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 8a584e0..e3c7189 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -1526,7 +1526,7 @@ static int vgic_ioaddr_assign(struct kvm *kvm, phys_addr_t *ioaddr, /** * kvm_vgic_addr - set or get vgic VM base addresses * @kvm: pointer to the vm struct - * @type: the VGIC addr type, one of KVM_VGIC_V2_ADDR_TYPE_XXX + * @type: the VGIC addr type, one of KVM_VGIC_V[23]_ADDR_TYPE_XXX * @addr: pointer to address value * @write: if true set the address in the VM address space, if false read the * address @@ -1540,29 +1540,49 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write) { int r = 0; struct vgic_dist *vgic = kvm-arch.vgic; + int type_needed; + phys_addr_t *addr_ptr, block_size; mutex_lock(kvm-lock); switch (type) { case KVM_VGIC_V2_ADDR_TYPE_DIST: - if (write) { - r = vgic_ioaddr_assign(kvm, vgic-vgic_dist_base, - *addr, KVM_VGIC_V2_DIST_SIZE); - } else { - *addr = vgic-vgic_dist_base; - } + type_needed = KVM_DEV_TYPE_ARM_VGIC_V2; + addr_ptr = vgic-vgic_dist_base; + block_size = KVM_VGIC_V2_DIST_SIZE; break; case KVM_VGIC_V2_ADDR_TYPE_CPU: - if (write) { - r = vgic_ioaddr_assign(kvm, vgic-vgic_cpu_base, - *addr, KVM_VGIC_V2_CPU_SIZE); - } else { - *addr = vgic-vgic_cpu_base; - } + type_needed = KVM_DEV_TYPE_ARM_VGIC_V2; + addr_ptr = vgic-vgic_cpu_base; + block_size = KVM_VGIC_V2_CPU_SIZE; break; +#ifdef CONFIG_ARM_GIC_V3 + case KVM_VGIC_V3_ADDR_TYPE_DIST: + type_needed = KVM_DEV_TYPE_ARM_VGIC_V3; + addr_ptr = vgic-vgic_dist_base; + block_size = KVM_VGIC_V3_DIST_SIZE; + break; + case KVM_VGIC_V3_ADDR_TYPE_REDIST: + type_needed = KVM_DEV_TYPE_ARM_VGIC_V3; + addr_ptr = vgic-vgic_redist_base; + block_size = KVM_VGIC_V3_REDIST_SIZE; + break; +#endif default: r = -ENODEV; + goto out; + } + + if (vgic-vgic_model
[PATCH 00/14] KVM GICv3 emulation
GICv3 is the ARM generic interrupt controller designed to overcome some limits of the prevalent GICv2. Most notably it lifts the 8-CPU limit. Though with recent patches from Marc there is support for hosts to use a GICv3, the CPU limitation still applies to KVM guests, since the current code emulates a GICv2 only. Also, GICv2 backward compatibility being optional in GICv3, a number of systems won't be able to run GICv2 guests. This patch series provides code to emulate a GICv3 distributor and redistributor for any KVM guest. It requires a GICv3 in the host to work. With those patches one can run guests efficiently on any GICv3 host. It has the following features: - Affinity routing (support for up to 255 VCPUs, more possible) - System registers (as opposed to MMIO access) - No ITS - No priority support (as the GICv2 emulation) - No save / restore support so far (will be added soon) The first 10 patches actually refactor the current VGIC code to make room for a different VGIC model to be dropped in with Patch 11/14. The remaining patches connect the new model to the kernel backend and the userland facing code. The series goes on top of both Marc's GICv3 host support series as well as his vgic-dyn patches. The necessary patches for kvmtool to enable the guest's GICv3 will be posted here as well. There was some testing on the fast model with some I/O and interrupt affinity shuffling in a Linux guest with a varying number of VCPUs. Please review and test. I would be grateful for people to test for GICv2 regressions also (so on a GICv2 host with current kvmtool/qemu), as there is quite some refactoring on that front. Much of the code was inspired by Marc, so send all praises to him (while I take the blame). Cheers, Andre. Andre Przywara (14): arm/arm64: KVM: rework MPIDR assignment and add accessors arm/arm64: KVM: pass down user space provided GIC type into vGIC code arm/arm64: KVM: refactor vgic_handle_mmio() function arm/arm64: KVM: wrap 64 bit MMIO accesses with two 32 bit ones arm/arm64: KVM: introduce per-VM ops arm/arm64: KVM: make the maximum number of vCPUs a per-VM value arm/arm64: KVM: make the value of ICC_SRE_EL1 a per-VM variable arm/arm64: KVM: refactor MMIO accessors arm/arm64: KVM: split GICv2 specific emulation code from vgic.c arm/arm64: KVM: add opaque private pointer to MMIO accessors arm/arm64: KVM: add virtual GICv3 distributor emulation arm/arm64: KVM: add SGI system register trapping arm/arm64: KVM: enable kernel side of GICv3 emulation arm/arm64: KVM: allow userland to request a virtual GICv3 arch/arm/include/asm/kvm_emulate.h |2 +- arch/arm/include/asm/kvm_host.h |3 + arch/arm/kvm/Makefile|1 + arch/arm/kvm/arm.c | 23 +- arch/arm/kvm/coproc.c| 19 + arch/arm/kvm/psci.c | 15 +- arch/arm64/include/asm/kvm_emulate.h |3 +- arch/arm64/include/asm/kvm_host.h|5 + arch/arm64/include/uapi/asm/kvm.h|7 + arch/arm64/kernel/asm-offsets.c |1 + arch/arm64/kvm/Makefile |2 + arch/arm64/kvm/sys_regs.c| 37 +- arch/arm64/kvm/vgic-v3-switch.S | 14 +- include/kvm/arm_vgic.h | 38 +- include/linux/irqchip/arm-gic-v3.h | 26 + include/linux/kvm_host.h |1 + include/uapi/linux/kvm.h |1 + virt/kvm/arm/vgic-v2-emul.c | 802 +++ virt/kvm/arm/vgic-v2.c | 22 +- virt/kvm/arm/vgic-v3-emul.c | 898 ++ virt/kvm/arm/vgic-v3.c | 157 +- virt/kvm/arm/vgic.c | 1017 +++--- virt/kvm/arm/vgic.h | 117 virt/kvm/kvm_main.c |3 + 24 files changed, 2346 insertions(+), 868 deletions(-) create mode 100644 virt/kvm/arm/vgic-v2-emul.c create mode 100644 virt/kvm/arm/vgic-v3-emul.c create mode 100644 virt/kvm/arm/vgic.h -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 10/14] arm/arm64: KVM: add opaque private pointer to MMIO accessors
For a GICv2 there is always only one (v)CPU involved: the one that does the access. On a GICv3 the access to a CPU redistributor is memory-mapped, but not banked, so the (v)CPU affected is determined by looking at the MMIO address region being accessed. To allow passing the affected CPU into the accessors, extend them to take an opaque private pointer parameter. For the current GICv2 emulation we ignore it and simply pass NULL on the call. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- virt/kvm/arm/vgic-v2-emul.c | 41 - virt/kvm/arm/vgic.c | 16 +--- virt/kvm/arm/vgic.h |7 --- 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/virt/kvm/arm/vgic-v2-emul.c b/virt/kvm/arm/vgic-v2-emul.c index ba5f873..30d5c4c 100644 --- a/virt/kvm/arm/vgic-v2-emul.c +++ b/virt/kvm/arm/vgic-v2-emul.c @@ -41,7 +41,8 @@ static u8 *vgic_get_sgi_sources(struct vgic_dist *dist, int vcpu_id, int sgi) } static bool handle_mmio_misc(struct kvm_vcpu *vcpu, -struct kvm_exit_mmio *mmio, phys_addr_t offset) +struct kvm_exit_mmio *mmio, phys_addr_t offset, +void *private) { u32 reg; u32 word_offset = offset 3; @@ -77,7 +78,7 @@ static bool handle_mmio_misc(struct kvm_vcpu *vcpu, static bool handle_mmio_set_enable_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, - phys_addr_t offset) + phys_addr_t offset, void *private) { return vgic_handle_enable_reg(vcpu-kvm, mmio, offset, vcpu-vcpu_id, ACCESS_WRITE_SETBIT); @@ -85,7 +86,7 @@ static bool handle_mmio_set_enable_reg(struct kvm_vcpu *vcpu, static bool handle_mmio_clear_enable_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, -phys_addr_t offset) +phys_addr_t offset, void *private) { return vgic_handle_enable_reg(vcpu-kvm, mmio, offset, vcpu-vcpu_id, ACCESS_WRITE_CLEARBIT); @@ -93,7 +94,7 @@ static bool handle_mmio_clear_enable_reg(struct kvm_vcpu *vcpu, static bool handle_mmio_set_pending_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, - phys_addr_t offset) + phys_addr_t offset, void *private) { return vgic_handle_pending_reg(vcpu-kvm, mmio, offset, vcpu-vcpu_id, ACCESS_WRITE_SETBIT); @@ -101,7 +102,7 @@ static bool handle_mmio_set_pending_reg(struct kvm_vcpu *vcpu, static bool handle_mmio_clear_pending_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, - phys_addr_t offset) + phys_addr_t offset, void *private) { return vgic_handle_pending_reg(vcpu-kvm, mmio, offset, vcpu-vcpu_id, ACCESS_WRITE_CLEARBIT); @@ -109,7 +110,7 @@ static bool handle_mmio_clear_pending_reg(struct kvm_vcpu *vcpu, static bool handle_mmio_priority_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, -phys_addr_t offset) +phys_addr_t offset, void *private) { u32 *reg; @@ -169,7 +170,7 @@ static void vgic_set_target_reg(struct kvm *kvm, u32 val, int irq) static bool handle_mmio_target_reg(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, - phys_addr_t offset) + phys_addr_t offset, void *private) { u32 reg; @@ -197,7 +198,8 @@ static bool handle_mmio_target_reg(struct kvm_vcpu *vcpu, } static bool handle_mmio_cfg_reg(struct kvm_vcpu *vcpu, - struct kvm_exit_mmio *mmio, phys_addr_t offset) + struct kvm_exit_mmio *mmio, phys_addr_t offset, + void *private) { u32 *reg; @@ -208,7 +210,8 @@ static bool handle_mmio_cfg_reg(struct kvm_vcpu *vcpu, } static bool handle_mmio_sgi_reg(struct kvm_vcpu *vcpu, - struct kvm_exit_mmio *mmio, phys_addr_t offset) + struct kvm_exit_mmio *mmio, phys_addr_t offset, + void *private) { u32 reg; vgic_reg_access(mmio, reg, offset, @@ -281,7 +284,7 @@ static bool write_set_clear_sgi_pend_reg(struct kvm_vcpu *vcpu, static bool handle_mmio_sgi_set(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio
[PATCH 13/14] arm/arm64: KVM: enable kernel side of GICv3 emulation
With all the necessary GICv3 emulation code in place, we can now connect the code to the GICv3 backend in the kernel. The LR register handling is different depending on the emulated GIC model, so provide different implementations for each. Also allow non-v2-compatible GICv3 implementations (which don't provide MMIO regions for the virtual CPU interface in the DT), but restrict those hosts to use GICv3 guests only. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- virt/kvm/arm/vgic-v3.c | 138 ++-- virt/kvm/arm/vgic.c|2 + 2 files changed, 112 insertions(+), 28 deletions(-) diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c index 7d9c85e..d26d12f 100644 --- a/virt/kvm/arm/vgic-v3.c +++ b/virt/kvm/arm/vgic-v3.c @@ -34,6 +34,7 @@ #define GICH_LR_VIRTUALID (0x3ffUL 0) #define GICH_LR_PHYSID_CPUID_SHIFT (10) #define GICH_LR_PHYSID_CPUID (7UL GICH_LR_PHYSID_CPUID_SHIFT) +#define ICH_LR_VIRTUALID_MASK (BIT_ULL(32) - 1) /* * LRs are stored in reverse order in memory. make sure we index them @@ -43,7 +44,35 @@ static u32 ich_vtr_el2; -static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr) +static u64 sync_lr_val(u8 state) +{ + u64 lr_val = 0; + + if (state LR_STATE_PENDING) + lr_val |= ICH_LR_PENDING_BIT; + if (state LR_STATE_ACTIVE) + lr_val |= ICH_LR_ACTIVE_BIT; + if (state LR_EOI_INT) + lr_val |= ICH_LR_EOI; + + return lr_val; +} + +static u8 sync_lr_state(u64 lr_val) +{ + u8 state = 0; + + if (lr_val ICH_LR_PENDING_BIT) + state |= LR_STATE_PENDING; + if (lr_val ICH_LR_ACTIVE_BIT) + state |= LR_STATE_ACTIVE; + if (lr_val ICH_LR_EOI) + state |= LR_EOI_INT; + + return state; +} + +static struct vgic_lr vgic_v2_on_v3_get_lr(const struct kvm_vcpu *vcpu, int lr) { struct vgic_lr lr_desc; u64 val = vcpu-arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)]; @@ -53,30 +82,53 @@ static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr) lr_desc.source = (val GICH_LR_PHYSID_CPUID_SHIFT) 0x7; else lr_desc.source = 0; - lr_desc.state = 0; + lr_desc.state = sync_lr_state(val); - if (val ICH_LR_PENDING_BIT) - lr_desc.state |= LR_STATE_PENDING; - if (val ICH_LR_ACTIVE_BIT) - lr_desc.state |= LR_STATE_ACTIVE; - if (val ICH_LR_EOI) - lr_desc.state |= LR_EOI_INT; + return lr_desc; +} + +static struct vgic_lr vgic_v3_on_v3_get_lr(const struct kvm_vcpu *vcpu, int lr) +{ + struct vgic_lr lr_desc; + u64 val = vcpu-arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)]; + + lr_desc.irq = val ICH_LR_VIRTUALID_MASK; + lr_desc.source = 0; + lr_desc.state = sync_lr_state(val); return lr_desc; } -static void vgic_v3_set_lr(struct kvm_vcpu *vcpu, int lr, - struct vgic_lr lr_desc) +static void vgic_v3_on_v3_set_lr(struct kvm_vcpu *vcpu, int lr, +struct vgic_lr lr_desc) { - u64 lr_val = (((u32)lr_desc.source GICH_LR_PHYSID_CPUID_SHIFT) | - lr_desc.irq); + u64 lr_val; - if (lr_desc.state LR_STATE_PENDING) - lr_val |= ICH_LR_PENDING_BIT; - if (lr_desc.state LR_STATE_ACTIVE) - lr_val |= ICH_LR_ACTIVE_BIT; - if (lr_desc.state LR_EOI_INT) - lr_val |= ICH_LR_EOI; + lr_val = lr_desc.irq; + + /* +* currently all guest IRQs are Group1, as Group0 would result +* in a FIQ in the guest, which it wouldn't expect. +* Eventually we want to make this configurable, so we may revisit +* this in the future. +*/ + lr_val |= ICH_LR_GROUP; + + lr_val |= sync_lr_val(lr_desc.state); + + vcpu-arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)] = lr_val; +} + +static void vgic_v2_on_v3_set_lr(struct kvm_vcpu *vcpu, int lr, +struct vgic_lr lr_desc) +{ + u64 lr_val; + + lr_val = lr_desc.irq; + + lr_val |= (u32)lr_desc.source GICH_LR_PHYSID_CPUID_SHIFT; + + lr_val |= sync_lr_val(lr_desc.state); vcpu-arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)] = lr_val; } @@ -145,9 +197,8 @@ static void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcrp) static void vgic_v3_enable(struct kvm_vcpu *vcpu) { - struct vgic_v3_cpu_if *vgic_v3; + struct vgic_v3_cpu_if *vgic_v3 = vcpu-arch.vgic_cpu.vgic_v3; - vgic_v3 = vcpu-arch.vgic_cpu.vgic_v3; /* * By forcing VMCR to zero, the GIC will restore the binary * points to their reset values. Anything else resets to zero @@ -155,7 +206,14 @@ static void vgic_v3_enable(struct kvm_vcpu *vcpu) */ vgic_v3-vgic_vmcr
[PATCH 04/14] arm/arm64: KVM: wrap 64 bit MMIO accesses with two 32 bit ones
Some GICv3 registers can and will be accessed as 64 bit registers. Currently the register handling code can only deal with 32 bit accesses, so we do two consecutive calls to cover this. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- virt/kvm/arm/vgic.c | 48 +--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 4c6b212..b3cf4c7 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -906,6 +906,48 @@ static bool vgic_validate_access(const struct vgic_dist *dist, } /* + * Call the respective handler function for the given range. + * We split up any 64 bit accesses into two consecutive 32 bit + * handler calls and merge the result afterwards. + */ +static bool call_range_handler(struct kvm_vcpu *vcpu, + struct kvm_exit_mmio *mmio, + unsigned long offset, + const struct mmio_range *range) +{ + u32 *data32 = (void *)mmio-data; + struct kvm_exit_mmio mmio32; + bool ret; + + if (likely(mmio-len = 4)) + return range-handle_mmio(vcpu, mmio, offset); + + /* +* We assume that any access greater than 4 bytes is actually +* 8 bytes long, caused by a 64-bit access +*/ + + mmio32.len = 4; + mmio32.is_write = mmio-is_write; + + mmio32.phys_addr = mmio-phys_addr + 4; + if (mmio-is_write) + *(u32 *)mmio32.data = data32[1]; + ret = range-handle_mmio(vcpu, mmio32, offset + 4); + if (!mmio-is_write) + data32[1] = *(u32 *)mmio32.data; + + mmio32.phys_addr = mmio-phys_addr; + if (mmio-is_write) + *(u32 *)mmio32.data = data32[0]; + ret |= range-handle_mmio(vcpu, mmio32, offset); + if (!mmio-is_write) + data32[0] = *(u32 *)mmio32.data; + + return ret; +} + +/* * vgic_handle_mmio_range - handle an in-kernel MMIO access * @vcpu: pointer to the vcpu performing the access * @run: pointer to the kvm_run structure @@ -936,10 +978,10 @@ static bool vgic_handle_mmio_range(struct kvm_vcpu *vcpu, struct kvm_run *run, spin_lock(vcpu-kvm-arch.vgic.lock); offset -= range-base; if (vgic_validate_access(dist, range, offset)) { - updated_state = range-handle_mmio(vcpu, mmio, offset); + updated_state = call_range_handler(vcpu, mmio, offset, range); } else { - vgic_reg_access(mmio, NULL, offset, - ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED); + if (!mmio-is_write) + memset(mmio-data, 0, mmio-len); updated_state = false; } spin_unlock(vcpu-kvm-arch.vgic.lock); -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 01/14] arm/arm64: KVM: rework MPIDR assignment and add accessors
The virtual MPIDR registers (containing topology information) for the guest are currently mapped linearily to the vcpu_id. Improve this mapping for arm64 by using three levels to not artificially limit the number of vCPUs. Also add an accessor to later allow easier access to a vCPU with a given MPIDR. Use this new accessor in the PSCI emulation. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm/include/asm/kvm_emulate.h |2 +- arch/arm/include/asm/kvm_host.h |2 ++ arch/arm/kvm/arm.c | 15 +++ arch/arm/kvm/psci.c | 15 --- arch/arm64/include/asm/kvm_emulate.h |3 ++- arch/arm64/include/asm/kvm_host.h|2 ++ arch/arm64/kvm/sys_regs.c| 11 +-- 7 files changed, 35 insertions(+), 15 deletions(-) diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h index 0fa90c9..6b528e4 100644 --- a/arch/arm/include/asm/kvm_emulate.h +++ b/arch/arm/include/asm/kvm_emulate.h @@ -159,7 +159,7 @@ static inline u32 kvm_vcpu_hvc_get_imm(struct kvm_vcpu *vcpu) static inline unsigned long kvm_vcpu_get_mpidr(struct kvm_vcpu *vcpu) { - return vcpu-arch.cp15[c0_MPIDR]; + return vcpu-arch.cp15[c0_MPIDR] MPIDR_HWID_BITMASK; } static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index d6d5227..8d30f05 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -236,4 +236,6 @@ int kvm_perf_teardown(void); u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid); int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value); +struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr); + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 9b3957d..9ffe962 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -1027,6 +1027,21 @@ static void check_kvm_target_cpu(void *ret) *(int *)ret = kvm_target_cpu(); } +struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr) +{ + unsigned long c_mpidr; + struct kvm_vcpu *vcpu; + int i; + + mpidr = MPIDR_HWID_BITMASK; + kvm_for_each_vcpu(i, vcpu, kvm) { + c_mpidr = kvm_vcpu_get_mpidr(vcpu); + if (c_mpidr == mpidr) + return vcpu; + } + return NULL; +} + /** * Initialize Hyp-mode and memory mappings on all CPUs. */ diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index 09cf377..49f0992 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c @@ -21,6 +21,7 @@ #include asm/cputype.h #include asm/kvm_emulate.h #include asm/kvm_psci.h +#include asm/kvm_host.h /* * This is an implementation of the Power State Coordination Interface @@ -65,25 +66,17 @@ static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu) static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) { struct kvm *kvm = source_vcpu-kvm; - struct kvm_vcpu *vcpu = NULL, *tmp; + struct kvm_vcpu *vcpu = NULL; wait_queue_head_t *wq; unsigned long cpu_id; unsigned long context_id; - unsigned long mpidr; phys_addr_t target_pc; - int i; - cpu_id = *vcpu_reg(source_vcpu, 1); + cpu_id = *vcpu_reg(source_vcpu, 1) MPIDR_HWID_BITMASK; if (vcpu_mode_is_32bit(source_vcpu)) cpu_id = ~((u32) 0); - kvm_for_each_vcpu(i, tmp, kvm) { - mpidr = kvm_vcpu_get_mpidr(tmp); - if ((mpidr MPIDR_HWID_BITMASK) == (cpu_id MPIDR_HWID_BITMASK)) { - vcpu = tmp; - break; - } - } + vcpu = kvm_mpidr_to_vcpu(kvm, cpu_id); /* * Make sure the caller requested a valid CPU and that the CPU is diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h index dd8ecfc..685ea1b 100644 --- a/arch/arm64/include/asm/kvm_emulate.h +++ b/arch/arm64/include/asm/kvm_emulate.h @@ -27,6 +27,7 @@ #include asm/kvm_arm.h #include asm/kvm_mmio.h #include asm/ptrace.h +#include asm/cputype.h unsigned long *vcpu_reg32(const struct kvm_vcpu *vcpu, u8 reg_num); unsigned long *vcpu_spsr32(const struct kvm_vcpu *vcpu); @@ -179,7 +180,7 @@ static inline u8 kvm_vcpu_trap_get_fault(const struct kvm_vcpu *vcpu) static inline unsigned long kvm_vcpu_get_mpidr(struct kvm_vcpu *vcpu) { - return vcpu_sys_reg(vcpu, MPIDR_EL1); + return vcpu_sys_reg(vcpu, MPIDR_EL1) MPIDR_HWID_BITMASK; } static inline void kvm_vcpu_set_be(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 4ae9213..4c84250 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -228,4 +228,6 @@ static inline void vgic_arch_setup(const struct vgic_params *vgic
[PATCH 3/4] kvmtool: add support for supplying GICv3 redistributor addresses
The code currently is assuming fixed sized memory regions for the distributor and CPU interface. GICv3 needs a dynamic allocation of it's redistributor region, since it's size depends on the number of vCPUs. Also add the necessary code to create a GICv3 IRQ chip instance. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- tools/kvm/arm/aarch64/include/kvm/kvm-arch.h |6 ++ tools/kvm/arm/gic.c | 29 -- tools/kvm/arm/include/arm-common/kvm-arch.h | 11 ++ tools/kvm/arm/kvm-cpu.c |4 +++- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/tools/kvm/arm/aarch64/include/kvm/kvm-arch.h b/tools/kvm/arm/aarch64/include/kvm/kvm-arch.h index 4925736..42d0fd6 100644 --- a/tools/kvm/arm/aarch64/include/kvm/kvm-arch.h +++ b/tools/kvm/arm/aarch64/include/kvm/kvm-arch.h @@ -3,6 +3,12 @@ #define ARM_GIC_DIST_SIZE 0x1 #define ARM_GIC_CPUI_SIZE 0x2 +/* + * On a GICv3 there must be one redistributor per vCPU. + * The value here is the size for one, we multiply this at runtime with + * the number of requested vCPUs to get the actual size. + */ +#define ARM_GIC_REDIST_SIZE0x2 #define ARM_KERN_OFFSET(kvm) ((kvm)-cfg.arch.aarch32_guest ? \ 0x8000 : \ diff --git a/tools/kvm/arm/gic.c b/tools/kvm/arm/gic.c index 770c6e7..5141868 100644 --- a/tools/kvm/arm/gic.c +++ b/tools/kvm/arm/gic.c @@ -11,6 +11,7 @@ static int irq_ids; static int gic_fd = -1; static u64 cpu_if_addr = ARM_GIC_CPUI_BASE; +static int nr_redists = 0; int gic__alloc_irqnum(void) { @@ -27,6 +28,7 @@ static int gic__create_device(struct kvm *kvm, u32 type) int err; u32 offset = 0; u64 dist_addr = ARM_GIC_DIST_BASE; + u64 redist_addr; struct kvm_create_device gic_device = { .type = type, }; @@ -41,9 +43,13 @@ static int gic__create_device(struct kvm *kvm, u32 type) }; struct kvm_device_attr dist_attr = { .group = KVM_DEV_ARM_VGIC_GRP_ADDR, - .attr = KVM_VGIC_V2_ADDR_TYPE_DIST, .addr = (u64)(unsigned long)dist_addr, }; + struct kvm_device_attr redist_attr = { + .group = KVM_DEV_ARM_VGIC_GRP_ADDR, + .attr = KVM_VGIC_V3_ADDR_TYPE_REDIST, + .addr = (u64)(unsigned long)redist_addr, + }; err = ioctl(kvm-vm_fd, KVM_CREATE_DEVICE, gic_device); if (err) @@ -64,13 +70,23 @@ static int gic__create_device(struct kvm *kvm, u32 type) err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, cpu_if_attr); if (err) return err; + dist_attr.attr = KVM_VGIC_V2_ADDR_TYPE_DIST; pr_info(creating GICv2 KVM device); break; + case KVM_DEV_TYPE_ARM_VGIC_V3: + dist_attr.attr = KVM_VGIC_V3_ADDR_TYPE_DIST; + redist_addr = dist_addr - nr_redists * ARM_GIC_REDIST_SIZE; + break; default: return -ENODEV; } err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, dist_attr); + if (err) + return err; + + if (type == KVM_DEV_TYPE_ARM_VGIC_V3) + err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, redist_attr); return err; } @@ -166,17 +182,26 @@ void gic__generate_fdt_nodes(void *fdt, u32 phandle, u32 type) u64 reg_prop[] = { cpu_to_fdt64(ARM_GIC_DIST_BASE), cpu_to_fdt64(ARM_GIC_DIST_SIZE), - cpu_to_fdt64(cpu_if_addr), cpu_to_fdt64(ARM_GIC_CPUI_SIZE), + 0, 0, /* to be filled */ }; switch (type) { case KVM_DEV_TYPE_ARM_VGIC_V2: compatible = arm,cortex-a15-gic; + reg_prop[2] = cpu_if_addr; + reg_prop[3] = ARM_GIC_CPUI_SIZE; pr_info(creating FDT for a GICv2); break; + case KVM_DEV_TYPE_ARM_VGIC_V3: + compatible = arm,gic-v3; + reg_prop[2] = ARM_GIC_DIST_BASE - nr_redists * ARM_GIC_REDIST_SIZE; + reg_prop[3] = ARM_GIC_REDIST_SIZE * nr_redists; + break; default: return; } + reg_prop[2] = cpu_to_fdt64(reg_prop[2]); + reg_prop[3] = cpu_to_fdt64(reg_prop[3]); _FDT(fdt_begin_node(fdt, intc)); _FDT(fdt_property_string(fdt, compatible, compatible)); diff --git a/tools/kvm/arm/include/arm-common/kvm-arch.h b/tools/kvm/arm/include/arm-common/kvm-arch.h index 72b204f..c7bfd9a 100644 --- a/tools/kvm/arm/include/arm-common/kvm-arch.h +++ b/tools/kvm/arm/include/arm-common/kvm-arch.h @@ -15,10 +15,8 @@ #define ARM_GIC_DIST_BASE (ARM_AXI_AREA - ARM_GIC_DIST_SIZE) #define ARM_GIC_CPUI_BASE (ARM_GIC_DIST_BASE - ARM_GIC_CPUI_SIZE) -#define ARM_GIC_SIZE
[PATCH 2/4] kvmtool: prepare for instantiating different IRQ chip devices
Extend the vGIC handling code to deal with different IRQ chip devices instead of hard-coding the GICv2 in. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- tools/kvm/arm/aarch64/arm-cpu.c|2 +- tools/kvm/arm/gic.c| 59 tools/kvm/arm/include/arm-common/gic.h |4 +-- tools/kvm/arm/kvm.c|2 +- tools/kvm/virtio/mmio.c|2 +- 5 files changed, 49 insertions(+), 20 deletions(-) diff --git a/tools/kvm/arm/aarch64/arm-cpu.c b/tools/kvm/arm/aarch64/arm-cpu.c index ce5ea2f..35771e0 100644 --- a/tools/kvm/arm/aarch64/arm-cpu.c +++ b/tools/kvm/arm/aarch64/arm-cpu.c @@ -12,7 +12,7 @@ static void generate_fdt_nodes(void *fdt, struct kvm *kvm, u32 gic_phandle) { int timer_interrupts[4] = {13, 14, 11, 10}; - gic__generate_fdt_nodes(fdt, gic_phandle); + gic__generate_fdt_nodes(fdt, gic_phandle, KVM_DEV_TYPE_ARM_VGIC_V2); timer__generate_fdt_nodes(fdt, kvm, timer_interrupts); } diff --git a/tools/kvm/arm/gic.c b/tools/kvm/arm/gic.c index c92deaa..770c6e7 100644 --- a/tools/kvm/arm/gic.c +++ b/tools/kvm/arm/gic.c @@ -22,13 +22,13 @@ int gic__alloc_irqnum(void) return irq; } -static int gic__create_device(struct kvm *kvm) +static int gic__create_device(struct kvm *kvm, u32 type) { int err; u32 offset = 0; u64 dist_addr = ARM_GIC_DIST_BASE; struct kvm_create_device gic_device = { - .type = KVM_DEV_TYPE_ARM_VGIC_V2, + .type = type, }; struct kvm_device_attr offset_attr = { .group = KVM_DEV_ARM_VGIC_GRP_ADDR_OFFSET, @@ -51,19 +51,28 @@ static int gic__create_device(struct kvm *kvm) gic_fd = gic_device.fd; - if (!ioctl(gic_fd, KVM_HAS_DEVICE_ATTR, offset_attr)) { - err = ioctl(gic_fd, KVM_GET_DEVICE_ATTR, offset_attr); + switch (type) { + case KVM_DEV_TYPE_ARM_VGIC_V2: + if (!ioctl(gic_fd, KVM_HAS_DEVICE_ATTR, offset_attr)) { + err = ioctl(gic_fd, KVM_GET_DEVICE_ATTR, offset_attr); + if (err) + return err; + } + + cpu_if_addr += offset; + + err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, cpu_if_attr); if (err) return err; + pr_info(creating GICv2 KVM device); + break; + default: + return -ENODEV; } - cpu_if_addr += offset; + err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, dist_attr); - err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, cpu_if_attr); - if (err) - return err; - - return ioctl(gic_fd, KVM_SET_DEVICE_ATTR, dist_attr); + return err; } static int gic__create_irqchip(struct kvm *kvm) @@ -94,7 +103,7 @@ static int gic__create_irqchip(struct kvm *kvm) return err; } -int gic__init_irqchip(struct kvm *kvm) +static int gicv2__init_irqchip(struct kvm *kvm) { int err; int psz; @@ -113,13 +122,22 @@ int gic__init_irqchip(struct kvm *kvm) } /* Try the new way first, and fallback on legacy method otherwise */ - err = gic__create_device(kvm); + err = gic__create_device(kvm, KVM_DEV_TYPE_ARM_VGIC_V2); if (err) err = gic__create_irqchip(kvm); return err; } +int gic__init_irqchip(struct kvm *kvm, u32 type) +{ + switch (type) { + case KVM_DEV_TYPE_ARM_VGIC_V2: + return gicv2__init_irqchip(kvm); + } + return -ENODEV; +} + static int gic__init_max_irq(struct kvm *kvm) { u32 nr_irqs = ALIGN(irq_ids, 32) + GIC_SPI_IRQ_BASE; @@ -142,15 +160,26 @@ static int gic__init_max_irq(struct kvm *kvm) } late_init(gic__init_max_irq) -void gic__generate_fdt_nodes(void *fdt, u32 phandle) +void gic__generate_fdt_nodes(void *fdt, u32 phandle, u32 type) { + const char *compatible; u64 reg_prop[] = { - cpu_to_fdt64(ARM_GIC_DIST_BASE), cpu_to_fdt64(ARM_GIC_DIST_SIZE), + cpu_to_fdt64(ARM_GIC_DIST_BASE), + cpu_to_fdt64(ARM_GIC_DIST_SIZE), cpu_to_fdt64(cpu_if_addr), cpu_to_fdt64(ARM_GIC_CPUI_SIZE), }; + switch (type) { + case KVM_DEV_TYPE_ARM_VGIC_V2: + compatible = arm,cortex-a15-gic; + pr_info(creating FDT for a GICv2); + break; + default: + return; + } + _FDT(fdt_begin_node(fdt, intc)); - _FDT(fdt_property_string(fdt, compatible, arm,cortex-a15-gic)); + _FDT(fdt_property_string(fdt, compatible, compatible)); _FDT(fdt_property_cell(fdt, #interrupt-cells, GIC_FDT_IRQ_NUM_CELLS)); _FDT(fdt_property(fdt, interrupt-controller, NULL, 0)); _FDT(fdt_property(fdt, reg, reg_prop, sizeof(reg_prop))); diff --git a/tools/kvm/arm/include/arm-common/gic.h b/tools
[PATCH 4/4] kvmtool: add command line parameter to instantiate a vGICv3
Add the command line parameter --gicv3 to request GICv3 emulation in the kernel. Connect that to the already existing GICv3 code. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- tools/kvm/arm/aarch64/arm-cpu.c|5 - .../kvm/arm/aarch64/include/kvm/kvm-config-arch.h |4 +++- tools/kvm/arm/gic.c| 17 + tools/kvm/arm/include/arm-common/kvm-config-arch.h |1 + tools/kvm/arm/kvm.c|4 +++- 5 files changed, 28 insertions(+), 3 deletions(-) diff --git a/tools/kvm/arm/aarch64/arm-cpu.c b/tools/kvm/arm/aarch64/arm-cpu.c index 35771e0..e3514ea 100644 --- a/tools/kvm/arm/aarch64/arm-cpu.c +++ b/tools/kvm/arm/aarch64/arm-cpu.c @@ -12,7 +12,10 @@ static void generate_fdt_nodes(void *fdt, struct kvm *kvm, u32 gic_phandle) { int timer_interrupts[4] = {13, 14, 11, 10}; - gic__generate_fdt_nodes(fdt, gic_phandle, KVM_DEV_TYPE_ARM_VGIC_V2); + gic__generate_fdt_nodes(fdt, gic_phandle, + kvm-cfg.arch.gicv3 ? + KVM_DEV_TYPE_ARM_VGIC_V3 : + KVM_DEV_TYPE_ARM_VGIC_V2); timer__generate_fdt_nodes(fdt, kvm, timer_interrupts); } diff --git a/tools/kvm/arm/aarch64/include/kvm/kvm-config-arch.h b/tools/kvm/arm/aarch64/include/kvm/kvm-config-arch.h index 89860ae..780a6d1 100644 --- a/tools/kvm/arm/aarch64/include/kvm/kvm-config-arch.h +++ b/tools/kvm/arm/aarch64/include/kvm/kvm-config-arch.h @@ -3,7 +3,9 @@ #define ARM_OPT_ARCH_RUN(cfg) \ OPT_BOOLEAN('\0', aarch32, (cfg)-aarch32_guest, \ - Run AArch32 guest), + Run AArch32 guest), \ + OPT_BOOLEAN('\0', gicv3, (cfg)-gicv3, \ + use a GICv3 interrupt controller in the guest), #include arm-common/kvm-config-arch.h diff --git a/tools/kvm/arm/gic.c b/tools/kvm/arm/gic.c index 5141868..15dc99d 100644 --- a/tools/kvm/arm/gic.c +++ b/tools/kvm/arm/gic.c @@ -76,6 +76,7 @@ static int gic__create_device(struct kvm *kvm, u32 type) case KVM_DEV_TYPE_ARM_VGIC_V3: dist_attr.attr = KVM_VGIC_V3_ADDR_TYPE_DIST; redist_addr = dist_addr - nr_redists * ARM_GIC_REDIST_SIZE; + pr_info(creating GICv3 KVM device); break; default: return -ENODEV; @@ -119,6 +120,17 @@ static int gic__create_irqchip(struct kvm *kvm) return err; } +static int gicv3__init_irqchip(struct kvm *kvm) +{ + if (kvm-nrcpus 255) { + pr_warning(%d CPUS greater than maximum of %d -- truncating\n, + kvm-nrcpus, 255); + kvm-nrcpus = 255; + } + + return gic__create_device(kvm, KVM_DEV_TYPE_ARM_VGIC_V3); +} + static int gicv2__init_irqchip(struct kvm *kvm) { int err; @@ -150,6 +162,9 @@ int gic__init_irqchip(struct kvm *kvm, u32 type) switch (type) { case KVM_DEV_TYPE_ARM_VGIC_V2: return gicv2__init_irqchip(kvm); + case KVM_DEV_TYPE_ARM_VGIC_V3: + nr_redists = kvm-cfg.nrcpus; + return gicv3__init_irqchip(kvm); } return -ENODEV; } @@ -196,6 +211,8 @@ void gic__generate_fdt_nodes(void *fdt, u32 phandle, u32 type) compatible = arm,gic-v3; reg_prop[2] = ARM_GIC_DIST_BASE - nr_redists * ARM_GIC_REDIST_SIZE; reg_prop[3] = ARM_GIC_REDIST_SIZE * nr_redists; + pr_info(creating FDT for a GICv3 with %d redistributors, + nr_redists); break; default: return; diff --git a/tools/kvm/arm/include/arm-common/kvm-config-arch.h b/tools/kvm/arm/include/arm-common/kvm-config-arch.h index f3baf39..088b012 100644 --- a/tools/kvm/arm/include/arm-common/kvm-config-arch.h +++ b/tools/kvm/arm/include/arm-common/kvm-config-arch.h @@ -7,6 +7,7 @@ struct kvm_config_arch { const char *dump_dtb_filename; unsigned int force_cntfrq; bool aarch32_guest; + bool gicv3; }; #define OPT_ARCH_RUN(pfx, cfg) \ diff --git a/tools/kvm/arm/kvm.c b/tools/kvm/arm/kvm.c index faf4702..3858170 100644 --- a/tools/kvm/arm/kvm.c +++ b/tools/kvm/arm/kvm.c @@ -80,6 +80,8 @@ void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size) MADV_MERGEABLE); /* Initialise the virtual GIC. */ - if (gic__init_irqchip(kvm, KVM_DEV_TYPE_ARM_VGIC_V2)) + if (gic__init_irqchip(kvm, kvm-cfg.arch.gicv3 ? + KVM_DEV_TYPE_ARM_VGIC_V3 : + KVM_DEV_TYPE_ARM_VGIC_V2)) die(Failed to initialise virtual GIC); } -- 1.7.9.5 -- To unsubscribe from this list: send
[PATCH 0/4] kvmtool: Add GICv3 emulation support
This is a first version of the kvmtool changes needed for GICv3 emulation. Allows testing of the GICv3 emulation code and allows creating guests with more than 8 VCPUs (given that in the host CONFIG_KVM_ARM_MAX_VCPUS and in the guest CONFIG_NR_CPUS have been raised accordingly). Use --gicv3 to create a GICv3 IRQ chip in the guest. This goes on top of Marc's kvmtool-vgic-dyn branch on kernel.org: https://git.kernel.org/cgit/linux/kernel/git/maz/arm-platforms.git/log/?h=kvm-arm64/kvmtool-vgic-dyn This is not meant for merging right now, as it eventually needs to be rebased on a more recent kvmtool version first. Cheers, Andre Andre Przywara (4): kvmtool: public header definitions from GICv3 emulation patch series kvmtool: prepare for instantiating different IRQ chip devices kvmtool: add support for supplying GICv3 redistributor addresses kvmtool: add command line parameter to instantiate a vGICv3 arch/arm64/include/uapi/asm/kvm.h |6 ++ include/uapi/linux/kvm.h |1 + tools/kvm/arm/aarch64/arm-cpu.c|5 +- tools/kvm/arm/aarch64/include/kvm/kvm-arch.h |6 ++ .../kvm/arm/aarch64/include/kvm/kvm-config-arch.h |4 +- tools/kvm/arm/gic.c| 101 +--- tools/kvm/arm/include/arm-common/gic.h |4 +- tools/kvm/arm/include/arm-common/kvm-arch.h| 11 ++- tools/kvm/arm/include/arm-common/kvm-config-arch.h |1 + tools/kvm/arm/kvm-cpu.c|4 +- tools/kvm/arm/kvm.c|4 +- tools/kvm/virtio/mmio.c|2 +- 12 files changed, 123 insertions(+), 26 deletions(-) -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/4] kvmtool: public header definitions from GICv3 emulation patch series
This pulls the necessary defines for the GICv3 constants from the Linux tree into kvmtool for now. Should be obsolete as soon as the vGICv3 patches are upstream and kvmtool is rebased on top of it. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- arch/arm64/include/uapi/asm/kvm.h |6 ++ include/uapi/linux/kvm.h |1 + 2 files changed, 7 insertions(+) diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index 0dc731d..2c26821 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -75,6 +75,12 @@ struct kvm_regs { #define KVM_VGIC_V2_DIST_SIZE 0x1000 #define KVM_VGIC_V2_CPU_SIZE 0x2000 +#define KVM_VGIC_V3_ADDR_TYPE_DIST 2 +#define KVM_VGIC_V3_ADDR_TYPE_REDIST 3 + +#define KVM_VGIC_V3_DIST_SIZE 0x1 +#define KVM_VGIC_V3_REDIST_SIZE0x2 + #define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */ #define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */ diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 932d7f2..3af4b60 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -855,6 +855,7 @@ struct kvm_device_attr { #define KVM_DEV_VFIO_GROUP_ADD 1 #define KVM_DEV_VFIO_GROUP_DEL 2 #define KVM_DEV_TYPE_ARM_VGIC_V2 5 +#define KVM_DEV_TYPE_ARM_VGIC_V3 7 /* * ioctls for VM fds -- 1.7.9.5 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5] ARM/KVM: save and restore generic timer registers
For migration to work we need to save (and later restore) the state of each core's virtual generic timer. Since this is per VCPU, we can use the [gs]et_one_reg ioctl and export the three needed registers (control, counter, compare value). Though they live in cp15 space, we don't use the existing list, since they need special accessor functions and the arch timer is optional. Signed-off-by: Andre Przywara andre.przyw...@linaro.org Signed-off-by: Christoffer Dall christoffer.d...@linaro.org --- Changes from v1: - move code out of coproc.c and into guest.c and arch_timer.c - present the registers with their native CP15 addresses, but without using space in the VCPU's cp15 array - do the user space copying in the accessor functions Changes from v2: - fix compilation without CONFIG_ARCH_TIMER - fix compilation for arm64 by defining the appropriate registers there - move userspace access out of arch_timer.c into coproc.c - Christoffer: removed whitespace in function declaration Changes from v3: - adapted Marc's SYSREG macro magic from kvmtool for nicer looking code Changes from v4: - remove ARM64-REG32 type, the ARM ARM defines no 32-bit system registers arch/arm/include/asm/kvm_host.h | 3 ++ arch/arm/include/uapi/asm/kvm.h | 20 + arch/arm/kvm/guest.c | 92 ++- arch/arm64/include/uapi/asm/kvm.h | 18 virt/kvm/arm/arch_timer.c | 34 +++ 5 files changed, 166 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 8a6f6db..098f7dd 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -225,4 +225,7 @@ static inline int kvm_arch_dev_ioctl_check_extension(long ext) int kvm_perf_init(void); int kvm_perf_teardown(void); +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid); +int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value); + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h index c498b60..835b867 100644 --- a/arch/arm/include/uapi/asm/kvm.h +++ b/arch/arm/include/uapi/asm/kvm.h @@ -119,6 +119,26 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_32_CRN_MASK0x7800 #define KVM_REG_ARM_32_CRN_SHIFT 11 +#define ARM_CP15_REG_SHIFT_MASK(x,n) \ + (((x) KVM_REG_ARM_ ## n ## _SHIFT) KVM_REG_ARM_ ## n ## _MASK) + +#define __ARM_CP15_REG(op1,crn,crm,op2) \ + (KVM_REG_ARM | (15 KVM_REG_ARM_COPROC_SHIFT) | \ + ARM_CP15_REG_SHIFT_MASK(op1, OPC1) | \ + ARM_CP15_REG_SHIFT_MASK(crn, 32_CRN) | \ + ARM_CP15_REG_SHIFT_MASK(crm, CRM) | \ + ARM_CP15_REG_SHIFT_MASK(op2, 32_OPC2)) + +#define ARM_CP15_REG32(...) (__ARM_CP15_REG(__VA_ARGS__) | KVM_REG_SIZE_U32) + +#define __ARM_CP15_REG64(op1,crm) \ + (__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64) +#define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__) + +#define KVM_REG_ARM_TIMER_CTL ARM_CP15_REG32(0, 14, 3, 1) +#define KVM_REG_ARM_TIMER_CNT ARM_CP15_REG64(1, 14) +#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14) + /* Normal registers are mapped as coprocessor 16. */ #define KVM_REG_ARM_CORE (0x0010 KVM_REG_ARM_COPROC_SHIFT) #define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4) diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c index 20f8d97..2786eae 100644 --- a/arch/arm/kvm/guest.c +++ b/arch/arm/kvm/guest.c @@ -109,6 +109,83 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) return -EINVAL; } +#ifndef CONFIG_KVM_ARM_TIMER + +#define NUM_TIMER_REGS 0 + +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) +{ + return 0; +} + +static bool is_timer_reg(u64 index) +{ + return false; +} + +int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value) +{ + return 0; +} + +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid) +{ + return 0; +} + +#else + +#define NUM_TIMER_REGS 3 + +static bool is_timer_reg(u64 index) +{ + switch (index) { + case KVM_REG_ARM_TIMER_CTL: + case KVM_REG_ARM_TIMER_CNT: + case KVM_REG_ARM_TIMER_CVAL: + return true; + } + return false; +} + +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) +{ + if (put_user(KVM_REG_ARM_TIMER_CTL, uindices)) + return -EFAULT; + uindices++; + if (put_user(KVM_REG_ARM_TIMER_CNT, uindices)) + return -EFAULT; + uindices++; + if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices)) + return -EFAULT; + + return 0; +} + +#endif + +static int set_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) +{ + void __user *uaddr = (void __user *)(long)reg-addr; + u64 val; + int ret; + + ret = copy_from_user(val, uaddr
Re: [PATCH v5] ARM/KVM: save and restore generic timer registers
On 12/13/2013 09:10 PM, Christoffer Dall wrote: On Fri, Dec 13, 2013 at 02:23:26PM +0100, Andre Przywara wrote: For migration to work we need to save (and later restore) the state of each core's virtual generic timer. Since this is per VCPU, we can use the [gs]et_one_reg ioctl and export the three needed registers (control, counter, compare value). Though they live in cp15 space, we don't use the existing list, since they need special accessor functions and the arch timer is optional. Signed-off-by: Andre Przywara andre.przyw...@linaro.org Signed-off-by: Christoffer Dall christoffer.d...@linaro.org --- Changes from v1: - move code out of coproc.c and into guest.c and arch_timer.c - present the registers with their native CP15 addresses, but without using space in the VCPU's cp15 array - do the user space copying in the accessor functions Changes from v2: - fix compilation without CONFIG_ARCH_TIMER - fix compilation for arm64 by defining the appropriate registers there - move userspace access out of arch_timer.c into coproc.c - Christoffer: removed whitespace in function declaration Changes from v3: - adapted Marc's SYSREG macro magic from kvmtool for nicer looking code Changes from v4: - remove ARM64-REG32 type, the ARM ARM defines no 32-bit system registers arch/arm/include/asm/kvm_host.h | 3 ++ arch/arm/include/uapi/asm/kvm.h | 20 + arch/arm/kvm/guest.c | 92 ++- arch/arm64/include/uapi/asm/kvm.h | 18 virt/kvm/arm/arch_timer.c | 34 +++ 5 files changed, 166 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 8a6f6db..098f7dd 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -225,4 +225,7 @@ static inline int kvm_arch_dev_ioctl_check_extension(long ext) int kvm_perf_init(void); int kvm_perf_teardown(void); +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid); +int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value); + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h index c498b60..835b867 100644 --- a/arch/arm/include/uapi/asm/kvm.h +++ b/arch/arm/include/uapi/asm/kvm.h @@ -119,6 +119,26 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_32_CRN_MASK 0x7800 #define KVM_REG_ARM_32_CRN_SHIFT 11 +#define ARM_CP15_REG_SHIFT_MASK(x,n) \ + (((x) KVM_REG_ARM_ ## n ## _SHIFT) KVM_REG_ARM_ ## n ## _MASK) + +#define __ARM_CP15_REG(op1,crn,crm,op2) \ + (KVM_REG_ARM | (15 KVM_REG_ARM_COPROC_SHIFT) | \ + ARM_CP15_REG_SHIFT_MASK(op1, OPC1) | \ + ARM_CP15_REG_SHIFT_MASK(crn, 32_CRN) | \ + ARM_CP15_REG_SHIFT_MASK(crm, CRM) | \ + ARM_CP15_REG_SHIFT_MASK(op2, 32_OPC2)) + +#define ARM_CP15_REG32(...) (__ARM_CP15_REG(__VA_ARGS__) | KVM_REG_SIZE_U32) + +#define __ARM_CP15_REG64(op1,crm) \ + (__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64) +#define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__) + +#define KVM_REG_ARM_TIMER_CTL ARM_CP15_REG32(0, 14, 3, 1) +#define KVM_REG_ARM_TIMER_CNT ARM_CP15_REG64(1, 14) +#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14) + /* Normal registers are mapped as coprocessor 16. */ #define KVM_REG_ARM_CORE (0x0010 KVM_REG_ARM_COPROC_SHIFT) #define KVM_REG_ARM_CORE_REG(name)(offsetof(struct kvm_regs, name) / 4) diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c index 20f8d97..2786eae 100644 --- a/arch/arm/kvm/guest.c +++ b/arch/arm/kvm/guest.c @@ -109,6 +109,83 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) return -EINVAL; } +#ifndef CONFIG_KVM_ARM_TIMER + +#define NUM_TIMER_REGS 0 + +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) +{ + return 0; +} + +static bool is_timer_reg(u64 index) +{ + return false; +} + +int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value) +{ + return 0; +} + +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid) +{ + return 0; +} + +#else + +#define NUM_TIMER_REGS 3 + +static bool is_timer_reg(u64 index) +{ + switch (index) { + case KVM_REG_ARM_TIMER_CTL: + case KVM_REG_ARM_TIMER_CNT: + case KVM_REG_ARM_TIMER_CVAL: + return true; + } + return false; +} + +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) +{ + if (put_user(KVM_REG_ARM_TIMER_CTL, uindices)) + return -EFAULT; + uindices++; + if (put_user(KVM_REG_ARM_TIMER_CNT, uindices)) + return -EFAULT; + uindices++; + if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices)) + return -EFAULT; + + return 0; +} + +#endif + +static int set_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) +{ + void __user *uaddr
Re: [PATCH v4] ARM/KVM: save and restore generic timer registers
On 12/12/2013 10:23 AM, Peter Maydell wrote: On 12 December 2013 02:28, Christoffer Dall christoffer.d...@linaro.org wrote: diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index a30035d..9565e6a 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -1889,9 +1889,12 @@ value in the kvm_regs structure seen as a 32bit array. arm64 CCSIDR registers are demultiplexed by CSSELR value: 0x6020 0011 00 csselr:8 -arm64 system registers have the following id bit patterns: +arm64 64-bit system registers have the following id bit patterns: 0x6030 0013 op0:2 op1:3 crn:4 crm:4 op2:3 +arm64 32-bit system registers have the following id bit patterns: + 0x6020 0013 op0:2 op1:3 crn:4 crm:4 op2:3 What does it mean to say that a system register for AArch64 is 32 bits given that MRS/MSR always operate on a 64 bit register? We have the distinction in AArch32 because the instructions (and whether the input/output is in one register or a register pair) are different, but I can't see the need for AArch64. But ARMv8 ARM still defines these registers as 32-bit: D8.5.14: CNTV_CTL_EL0 Attributes CNTV_CTL_EL0 is a 32-bit register. But indeed the MSR/MRS instruction references a Xt register, and the documentation does not seem to tell how this is handled, so I assume this is zero-extended. Would be great to have this clarified, though. Regards, Andre. (The code I've just written for QEMU to handle sysregs says they're all 64 bit...) thanks -- PMM -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4] ARM/KVM: save and restore generic timer registers
From: Andre Przywara andre.przyw...@calxeda.com For migration to work we need to save (and later restore) the state of each cores virtual generic timer. Since this is per VCPU, we can use the [gs]et_one_reg ioctl and export the three needed registers (control, counter, compare value). Though they live in cp15 space, we don't use the existing list, since they need special accessor functions and the arch timer is optional. Signed-off-by: Andre Przywara andre.przyw...@linaro.org Signed-off-by: Christoffer Dall christoffer.d...@linaro.org --- Changes from v1: - move code out of coproc.c and into guest.c and arch_timer.c - present the registers with their native CP15 addresses, but without using space in the VCPU's cp15 array - do the user space copying in the accessor functions Changes from v2: - fix compilation without CONFIG_ARCH_TIMER - fix compilation for arm64 by defining the appropriate registers there - move userspace access out of arch_timer.c into coproc.c - Christoffer: removed whitespace in function declaration Changes from v3: - adapted Marc's SYSREG macro magic from kvmtool for nicer looking code arch/arm/include/asm/kvm_host.h | 3 ++ arch/arm/include/uapi/asm/kvm.h | 20 + arch/arm/kvm/guest.c | 92 ++- arch/arm64/include/uapi/asm/kvm.h | 19 virt/kvm/arm/arch_timer.c | 34 +++ 5 files changed, 167 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 8a6f6db..098f7dd 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -225,4 +225,7 @@ static inline int kvm_arch_dev_ioctl_check_extension(long ext) int kvm_perf_init(void); int kvm_perf_teardown(void); +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid); +int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value); + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h index c498b60..835b867 100644 --- a/arch/arm/include/uapi/asm/kvm.h +++ b/arch/arm/include/uapi/asm/kvm.h @@ -119,6 +119,26 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_32_CRN_MASK0x7800 #define KVM_REG_ARM_32_CRN_SHIFT 11 +#define ARM_CP15_REG_SHIFT_MASK(x,n) \ + (((x) KVM_REG_ARM_ ## n ## _SHIFT) KVM_REG_ARM_ ## n ## _MASK) + +#define __ARM_CP15_REG(op1,crn,crm,op2) \ + (KVM_REG_ARM | (15 KVM_REG_ARM_COPROC_SHIFT) | \ + ARM_CP15_REG_SHIFT_MASK(op1, OPC1) | \ + ARM_CP15_REG_SHIFT_MASK(crn, 32_CRN) | \ + ARM_CP15_REG_SHIFT_MASK(crm, CRM) | \ + ARM_CP15_REG_SHIFT_MASK(op2, 32_OPC2)) + +#define ARM_CP15_REG32(...) (__ARM_CP15_REG(__VA_ARGS__) | KVM_REG_SIZE_U32) + +#define __ARM_CP15_REG64(op1,crm) \ + (__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64) +#define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__) + +#define KVM_REG_ARM_TIMER_CTL ARM_CP15_REG32(0, 14, 3, 1) +#define KVM_REG_ARM_TIMER_CNT ARM_CP15_REG64(1, 14) +#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14) + /* Normal registers are mapped as coprocessor 16. */ #define KVM_REG_ARM_CORE (0x0010 KVM_REG_ARM_COPROC_SHIFT) #define KVM_REG_ARM_CORE_REG(name) (offsetof(struct kvm_regs, name) / 4) diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c index 20f8d97..2786eae 100644 --- a/arch/arm/kvm/guest.c +++ b/arch/arm/kvm/guest.c @@ -109,6 +109,83 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) return -EINVAL; } +#ifndef CONFIG_KVM_ARM_TIMER + +#define NUM_TIMER_REGS 0 + +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) +{ + return 0; +} + +static bool is_timer_reg(u64 index) +{ + return false; +} + +int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value) +{ + return 0; +} + +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid) +{ + return 0; +} + +#else + +#define NUM_TIMER_REGS 3 + +static bool is_timer_reg(u64 index) +{ + switch (index) { + case KVM_REG_ARM_TIMER_CTL: + case KVM_REG_ARM_TIMER_CNT: + case KVM_REG_ARM_TIMER_CVAL: + return true; + } + return false; +} + +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) +{ + if (put_user(KVM_REG_ARM_TIMER_CTL, uindices)) + return -EFAULT; + uindices++; + if (put_user(KVM_REG_ARM_TIMER_CNT, uindices)) + return -EFAULT; + uindices++; + if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices)) + return -EFAULT; + + return 0; +} + +#endif + +static int set_timer_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) +{ + void __user *uaddr = (void __user *)(long)reg-addr; + u64 val; + int ret; + + ret = copy_from_user(val, uaddr, KVM_REG_SIZE(reg-id)); + if (ret != 0
Re: [PATCH v4] ARM/KVM: save and restore generic timer registers
On 12/10/2013 11:50 AM, Andre Przywara wrote: From: Andre Przywara andre.przyw...@calxeda.com Ooops, I managed to screw up the authorship :-( Can the committer please change this to: Andre Przywara andre.przyw...@linaro.org (as in the signed-off-by?) Thanks, Andre. For migration to work we need to save (and later restore) the state of each cores virtual generic timer. Since this is per VCPU, we can use the [gs]et_one_reg ioctl and export the three needed registers (control, counter, compare value). Though they live in cp15 space, we don't use the existing list, since they need special accessor functions and the arch timer is optional. Signed-off-by: Andre Przywara andre.przyw...@linaro.org Signed-off-by: Christoffer Dall christoffer.d...@linaro.org --- Changes from v1: - move code out of coproc.c and into guest.c and arch_timer.c - present the registers with their native CP15 addresses, but without using space in the VCPU's cp15 array - do the user space copying in the accessor functions Changes from v2: - fix compilation without CONFIG_ARCH_TIMER - fix compilation for arm64 by defining the appropriate registers there - move userspace access out of arch_timer.c into coproc.c - Christoffer: removed whitespace in function declaration Changes from v3: - adapted Marc's SYSREG macro magic from kvmtool for nicer looking code arch/arm/include/asm/kvm_host.h | 3 ++ arch/arm/include/uapi/asm/kvm.h | 20 + arch/arm/kvm/guest.c | 92 ++- arch/arm64/include/uapi/asm/kvm.h | 19 virt/kvm/arm/arch_timer.c | 34 +++ 5 files changed, 167 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 8a6f6db..098f7dd 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -225,4 +225,7 @@ static inline int kvm_arch_dev_ioctl_check_extension(long ext) int kvm_perf_init(void); int kvm_perf_teardown(void); +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *, u64 regid); +int kvm_arm_timer_set_reg(struct kvm_vcpu *, u64 regid, u64 value); + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h index c498b60..835b867 100644 --- a/arch/arm/include/uapi/asm/kvm.h +++ b/arch/arm/include/uapi/asm/kvm.h @@ -119,6 +119,26 @@ struct kvm_arch_memory_slot { #define KVM_REG_ARM_32_CRN_MASK 0x7800 #define KVM_REG_ARM_32_CRN_SHIFT 11 +#define ARM_CP15_REG_SHIFT_MASK(x,n) \ + (((x) KVM_REG_ARM_ ## n ## _SHIFT) KVM_REG_ARM_ ## n ## _MASK) + +#define __ARM_CP15_REG(op1,crn,crm,op2) \ + (KVM_REG_ARM | (15 KVM_REG_ARM_COPROC_SHIFT) | \ + ARM_CP15_REG_SHIFT_MASK(op1, OPC1) | \ + ARM_CP15_REG_SHIFT_MASK(crn, 32_CRN) | \ + ARM_CP15_REG_SHIFT_MASK(crm, CRM) | \ + ARM_CP15_REG_SHIFT_MASK(op2, 32_OPC2)) + +#define ARM_CP15_REG32(...) (__ARM_CP15_REG(__VA_ARGS__) | KVM_REG_SIZE_U32) + +#define __ARM_CP15_REG64(op1,crm) \ + (__ARM_CP15_REG(op1, 0, crm, 0) | KVM_REG_SIZE_U64) +#define ARM_CP15_REG64(...) __ARM_CP15_REG64(__VA_ARGS__) + +#define KVM_REG_ARM_TIMER_CTL ARM_CP15_REG32(0, 14, 3, 1) +#define KVM_REG_ARM_TIMER_CNT ARM_CP15_REG64(1, 14) +#define KVM_REG_ARM_TIMER_CVAL ARM_CP15_REG64(3, 14) + /* Normal registers are mapped as coprocessor 16. */ #define KVM_REG_ARM_CORE (0x0010 KVM_REG_ARM_COPROC_SHIFT) #define KVM_REG_ARM_CORE_REG(name)(offsetof(struct kvm_regs, name) / 4) diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c index 20f8d97..2786eae 100644 --- a/arch/arm/kvm/guest.c +++ b/arch/arm/kvm/guest.c @@ -109,6 +109,83 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) return -EINVAL; } +#ifndef CONFIG_KVM_ARM_TIMER + +#define NUM_TIMER_REGS 0 + +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) +{ + return 0; +} + +static bool is_timer_reg(u64 index) +{ + return false; +} + +int kvm_arm_timer_set_reg(struct kvm_vcpu *vcpu, u64 regid, u64 value) +{ + return 0; +} + +u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid) +{ + return 0; +} + +#else + +#define NUM_TIMER_REGS 3 + +static bool is_timer_reg(u64 index) +{ + switch (index) { + case KVM_REG_ARM_TIMER_CTL: + case KVM_REG_ARM_TIMER_CNT: + case KVM_REG_ARM_TIMER_CVAL: + return true; + } + return false; +} + +static int copy_timer_indices(struct kvm_vcpu *vcpu, u64 __user *uindices) +{ + if (put_user(KVM_REG_ARM_TIMER_CTL, uindices)) + return -EFAULT; + uindices++; + if (put_user(KVM_REG_ARM_TIMER_CNT, uindices)) + return -EFAULT; + uindices++; + if (put_user(KVM_REG_ARM_TIMER_CVAL, uindices)) + return -EFAULT; + + return 0; +} + +#endif + +static int set_timer_reg(struct
Re: [RFC PATCH] Emulate MOVBE
On Wed, 10 Apr 2013 01:46:02 +0200 Borislav Petkov b...@alien8.de wrote: Hi guys, so I was trying to repro tglx's bug in smpboot.c and for some reason, the most reliable way to trigger it was to boot an 32-bit atom smp guest in kvm (don't ask :)). The problem, however, was that atom wants MOVBE and qemu doesn't emulate it yet (except Richard's patches which I used in order to be able to actually even boot a guest). However, without hw acceleration, qemu is pretty slow, and waiting for an smp guest to boot in sw-only emulation is not fun. So, just for funsies, I decided to give the MOVBE emulation a try. Patch is below, 8 core smp atom guest boots fine and in 6-ish seconds with it. :-) I know, I know, it still needs cleaning up and proper rFLAGS handling but that is for later. For now, I'd very much like to hear whether this approach even makes sense and if so, what should be improved. Thanks, and thanks to Andre and Jörg for their help. Not-yet-signed-off-by: Borislav Petkov b...@suse.de You are missing an (hackish) older patch which enables the MOVBE CPUID bit even if the host does not have it (malformed due to cp): --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -273,7 +273,7 @@ static int do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, cpuid_mask(entry-ecx, 4); /* we support x2apic emulation even if host does not support * it since we emulate x2apic in software */ - entry-ecx |= F(X2APIC); + entry-ecx |= (F(X2APIC) | F(MOVBE)); break; /* function 2 entries are STATEFUL. That is, repeated cpuid commands * may return different values. This forces us to get_cpu() before -- diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index 15f960c06ff7..ae01c765cd77 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h @@ -281,6 +281,7 @@ struct x86_emulate_ctxt { /* decode cache */ u8 twobyte; + u8 thirdbyte; u8 b; u8 intercept; u8 lock_prefix; diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index a335cc6cde72..0ccff339359d 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -152,6 +152,7 @@ #define Avx ((u64)1 43) /* Advanced Vector Extensions */ #define Fastop ((u64)1 44) /* Use opcode::u.fastop */ #define NoWrite ((u64)1 45) /* No writeback */ +#define ThreeByte ((u64)1 46) /* Three byte opcodes 0F 38 and 0F 3A */ #define X2(x...) x, x #define X3(x...) X2(x), x @@ -3107,6 +3108,34 @@ static int em_mov(struct x86_emulate_ctxt *ctxt) return X86EMUL_CONTINUE; } +static int em_movbe(struct x86_emulate_ctxt *ctxt) +{ + char *valptr = ctxt-src.valptr; + + switch (ctxt-op_bytes) { + case 2: + *(u16 *)valptr = swab16(*(u16 *)valptr); + break; + case 4: + *(u32 *)valptr = swab32(*(u32 *)valptr); + + /* + * clear upper dword for 32-bit operand size in 64-bit mode. + */ + if (ctxt-mode == X86EMUL_MODE_PROT64) + *((u32 *)valptr + 1) = 0x0; + break; + case 8: + *(u64 *)valptr = swab64(*(u64 *)valptr); + break; + default: + return X86EMUL_PROPAGATE_FAULT; + } + + memcpy(ctxt-dst.valptr, ctxt-src.valptr, ctxt-op_bytes); + return X86EMUL_CONTINUE; +} + On 04/09/2013 05:03 PM, Borislav Petkov wrote: Note to self: this destroys the src operand but it shouldn't. Fix it tomorrow. What about this one? *(u16 *)(ctxt-dst.valptr) = swab16(*(u16 *)(ctxt-src.valptr)); Respective versions for the other operand sizes, of course, and drop the final memcpy. static int em_cr_write(struct x86_emulate_ctxt *ctxt) { if (ctxt-ops-set_cr(ctxt, ctxt-modrm_reg, ctxt-src.val)) @@ -3974,7 +4003,8 @@ static const struct opcode twobyte_table[256] = { I(ImplicitOps | VendorSpecific, em_sysenter), I(ImplicitOps | Priv | VendorSpecific, em_sysexit), N, N, - N, N, N, N, N, N, N, N, + I(ModRM | Mov | ThreeByte | VendorSpecific, em_movbe), + N, N, N, N, N, N, N, In a real world VendorSpecific should be replaced with something more meaningful. Depends on KVMs intention to emulate instructions, actually out of scope for a pure virtualizer. What is the opinion from the KVM folks on this? Shall we start to emulate instructions the host does not provide? In this particular case a relatively simple patch fixes a problem (starting Atom optimized kernels on non-Atom machines). (And if one can believe the AMD Fam16h SWOG [1], PS4^Wfuture AMD processors have MOVBE, so it's not even actually one CPU anymore). /* 0x40 - 0x4F */ X16(D(DstReg | SrcMem | ModRM | Mov)), /* 0x50 - 0x5F */ @@ -4323,6 +4353,15 @@ done_prefixes: }
Re: [RFC PATCH] Emulate MOVBE
On Wed, 10 Apr 2013 13:08:46 +0300 Gleb Natapov g...@redhat.com wrote: On Wed, Apr 10, 2013 at 11:29:42AM +0200, Andre Przywara wrote: In a real world VendorSpecific should be replaced with something more meaningful. Depends on KVMs intention to emulate instructions, actually out of scope for a pure virtualizer. Something like EmulateOnUD. Right. What is the opinion from the KVM folks on this? Shall we start to emulate instructions the host does not provide? In this particular case a relatively simple patch fixes a problem (starting Atom optimized kernels on non-Atom machines). We can add the emulation, but we should not start announcing the instruction availability to a guest if host cpu does not have it by default. This may trick a guest into thinking that movbe is the fastest way to do something when it is not. Good point. I'd also like to have a switch which enables this kind of non-standard behavior. Actually this should be requested by QEMU, right? So that a single guest can override the CPUID masking done by the kernel if it really really wants to. (And if one can believe the AMD Fam16h SWOG [1], PS4^Wfuture AMD processors have MOVBE, so it's not even actually one CPU anymore). If a host CPU has the instruction emulation is not needed unless the instruction is used for MMIO access. I meant to emulate such a CPU. -cpu ps4 ;-) Regards, Andre. -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Semantics of -cpu host (was Re: [Qemu-devel] [PATCH 2/2] Expose tsc deadline timer cpuid to guest)
On 05/07/2012 08:21 PM, Eduardo Habkost wrote: Andre? Are you able to help to answer the question below? Sorry for the delay, the easy answers first: I would like to clarify what's the expected behavior of -cpu host to be able to continue working on it. The purpose of -cpu host is to let guests use ISA features that the host CPU provides. Those would not need any KVM/QEMU intervention, because they work out of the box. Things like AES or SSE4.2, which are used by Linux and glibc, for instance. Users would expect those to be usable, and actually we only need to set the bits and are done. A second goal is to get rid of the awkward and artificial family/model/stepping settings and just let the guest see the actual CPU model. This has some strings attached, though, but other virtualization solution do it the same way and they can cope with it. A third thing currently not really addressed are the more informational bits like cache size and organization and TLB layout. Those are properties of the (core) CPU (except shared L3, cache maybe) and apply to guests as well. I don't see any reason why this should not be exposed to the guest. From the top of my head I don't know any prominent user (just glibc reading the cache size, but not really using it), but I guess there are applications which benefit from it. What clearly is not the intention of -cpu host is to provide access to every feature a certain CPU model provides. So things which require emulation or hypervisor intervention are not in the primary use case. That does not mean that they don't need to implemented, but that was not the purpose of -cpu host and they should be handled independently. Regards, Andre. I believe the code will need to be fixed on either case, but first we need to figure out what are the expectations/requirements, to know _which_ changes will be needed. On Tue, Apr 24, 2012 at 02:19:25PM -0300, Eduardo Habkost wrote: (CCing Andre Przywara, in case he can help to clarify what's the expected meaning of -cpu host) [...] I am not sure I understand what you are proposing. Let me explain the use case I am thinking about: - Feature FOO is of type (A) (e.g. just a new instruction set that doesn't require additional userspace support) - User has a Qemu vesion that doesn't know anything about feature FOO - User gets a new CPU that supports feature FOO - User gets a new kernel that supports feature FOO (i.e. has FOO in GET_SUPPORTED_CPUID) - User does _not_ upgrade Qemu. - User expects to get feature FOO enabled if using -cpu host, without upgrading Qemu. The problem here is: to support the above use-case, userspace need a probing mechanism that can differentiate _new_ (previously unknown) features that are in group (A) (safe to blindly enable) from features that are in group (B) (that can't be enabled without an userspace upgrade). In short, it becomes a problem if we consider the following case: - Feature BAR is of type (B) (it can't be enabled without extra userspace support) - User has a Qemu version that doesn't know anything about feature BAR - User gets a new CPU that supports feature BAR - User gets a new kernel that supports feature BAR (i.e. has BAR in GET_SUPPORTED_CPUID) - User does _not_ upgrade Qemu. - User simply shouldn't get feature BAR enabled, even if using -cpu host, otherwise Qemu would break. If userspace always limited itself to features it knows about, it would be really easy to implement the feature without any new probing mechanism from the kernel. But that's not how I think users expect -cpu host to work. Maybe I am wrong, I don't know. I am CCing Andre, who introduced the -cpu host feature, in case he can explain what's the expected semantics on the cases above. -- Andre Przywara AMD-Operating System Research Center (OSRC), Dresden, Germany -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: AMD SVM specification
On 02/27/2012 11:09 AM, Prateek Sharma wrote: Hello, I know this is not the right forum for this, but i am looking for the recent specification/documentation of the AMD NPT and SVM features. All i can find is the old pacifica document dating back to 2005, and only the NPT whitepaper. The technical SVM documentation is in the AMD64 Architecture Programmer's Manual (APM) Volume 2: http://support.amd.com/us/Processor_TechDocs/24593_APM_v2.pdf SVM is detailed in chapter 15, with appendix B C containing the needed bits for the data structures. Other chapters in this document contain details about paging, though this is mostly not AMD specific. Regards, Andre. The reason i seek this documentation is that i wish to modify some KVM code. Specifically, i am interested in how the hardware sets/resets the accessed/dirty bits of the guest/nested tables [https://lkml.org/lkml/2011/6/22/20] Any help will be appreciated. Prateek -- Andre Przywara AMD-Operating System Research Center (OSRC), Dresden, Germany -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: OpenBSD 5.0 kernel panic in AMD K10 cpu power state
On 11/10/2011 09:46 AM, Avi Kivity wrote: (re-adding cc) On 11/09/2011 09:35 PM, Walter Haidinger wrote: Am 09.11.2011 14:40, schrieb Avi Kivity: Actually, it looks like an OpenBSD bug. According to the AMD documentation: Well, the OpenBSD developers are very confident that is a bug in the KVM cpu emulation and _not_ in OpenBSD. Basically they say that [despite -cpu host], the emulated cpu does not look like a real, but _non-existant_ cpu. Virtualization should look like _existing_ hardware. That is true. But OpenBSD is not following the vendor's recommendation for how software should access the hardware. Since the list archive at http://marc.info/?l=openbsd-miscm=132077741910464w=2 lags a bit, I'm attaching some parts of the thread below: However, please remember it's OpenBSD, so the tone is, let's just say, rough. Less than expected, actually. The panic you hit is for an msr read, not a write. I'm aware those registers are read-only. The CPUID check isn't done, it matches on all family 10 and/or higher AMD processors. They're pretending to be an AMD K10 processor. On all real hardware I've tested this works fine. If you wish to be pedantic, patches are welcome. Avi, thanks for caring of that. The manual is clear here: no CPUID bit, no MSRs. Beside that the emulated ACPI tables probably also don't provide any info here, right? The fact that it runs: on all family 10 and/or higher AMD processors is just an empiric observation, not a law. You would be astonished what can be fused off... We had a similar discussion here with unconditional AMD Northbridge PCI accesses when detecting certain AMD CPU family/model/steppings in the Linux kernel already (...but every AMD CPU has a northbridge...) We (as virtualization guys) should not step back so easily here, especially if the spec is so clear. That spec argument should actually appeal to the OpenBSD guys, too. I got the impression that their design is, well, actually well designed. So they're actually open to adding the cpuid check. They sent me a patch as a workaround, which: The previous patch avoids touching the msr at all if ACPI indicates speed scaling is unavailable, this should prevent your panic. with -cpu host, OpenBSD dmesg showed the 1100T: cpu0: AMD Phenom(tm) II X6 1100T Processor (AuthenticAMD 686-class, 512KB L2 cache) 3.31 GHz cpu0: FPU,V86,DE,PSE,TSC,MSR,PAE,MCE,CX8,APIC,SEP,MTRR,PGE,MCA,CMOV,PAT,PSE36,CFLUSH,MMX,FXSR,SSE,SSE2,SSE3,CX16,POPCNT ... bios0: vendor Bochs version Bochs date 01/01/2007 bios0: Bochs Bochs They shouldn't be pretending to be AMD, especially if that emulation is very incompatible. but the bug is in the Linux KVM: They're pretending to be an AMD K10 processor. Exactly. What they are doing is wrong. They are pretending to be a AMD K10 processor _badly_, and then they think they can say oh, but you need to check all these other registers too. A machine with that setup has never physically existed. Is this all because I used -cpu host? -cpu host is not to blame, you could get the same result from other combinations of cpu model and family. I'll look at adding support for this MSR; should be simple. But in general processor features need to be qualified by cpuid, not by model. I guess emulating part of P-states will open up a can of worms. Beside the generic MSRs (0xC001006[1-3]) there are actual family specific ones which are selected by the CPUID family. So you would end up emulating them, too. I have a hard time to think about a strategy how to emulate this in general. So unless there is a real framework for dealing with P-state hints from the guest OS, I'd be reluctant with quick and dirty emulations. Thanks, Andre. -- Andre Przywara AMD-Operating System Research Center (OSRC), Dresden, Germany -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
unconditional CPUID propagation?
Hi, while looking through the code I found commit f79116867ec80ed5d1d10043a3fd9ac8afd182c1 (upstream QEMU: enable SMEP) which unconditionally propagates the bits from CPUID leaf 0x7 to the guest. Though there is the KVM module in the line, this currently whitelists three feature bits. Doesn't that break migration? The result of the CPUID instruction the guess issues only depends on the host and the KVM module's policy, not on the CPU model QEMU uses. So I guess migrating from a newer CPU to an older one breaks despite a rather conservative CPU model has been chosen intentionally by the user. The same is probably true for the VIA CPUID leaf. Is that considered OK now or is that a bug? Shall the new feature bits be made known to QEMU like the other ones on only enabled explicitly (+smep) or by -cpu host? I can make a patch for that if that is the right way to address this. Regards, Andre. -- Andre Przywara AMD-OSRC (Dresden) Tel: x29712 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] KVM: fix XSAVE bit scanning (now properly)
commit 123108f1c1aafd51d6a5c79cc04d7999dd88a930 tried to fix KVMs XSAVE valid feature scanning, but it was wrong. It was not considering the sparse nature of this bitfield, instead reading values from uninitialized members of the entries array. This patch now separates subleaf indicies from KVM's array indicies and fills the entry before querying it's value. This fixes AVX support in KVM guests. Signed-off-by: Andre Przywara andre.przyw...@amd.com --- arch/x86/kvm/x86.c |9 + 1 files changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 694538a..2a52e69 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2418,16 +2418,17 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, break; } case 0xd: { - int i; + int idx, i; entry-flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; - for (i = 1; *nent maxnent i 64; ++i) { - if (entry[i].eax == 0 || !supported_xcr0_bit(i)) + for (idx = 1, i = 1; *nent maxnent idx 64; ++idx) { + do_cpuid_1_ent(entry[i], function, idx); + if (entry[i].eax == 0 || !supported_xcr0_bit(idx)) continue; - do_cpuid_1_ent(entry[i], function, i); entry[i].flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; ++*nent; + ++i; } break; } -- 1.6.4 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] QEMU: Fix KVM XSAVE feature bit enumeration
When iterating through the XSAVE feature enumeration CPUID leaf (0xD) we should not stop at the first zero EAX, but instead keep scanning since there are gaps in the enumeration (ECX=1 for instance). This fixes the proper usage of AVX in KVM guests. Signed-off-by: Andre Przywara andre.przyw...@amd.com --- target-i386/kvm.c |4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index faedc6c..4a97f78 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -448,6 +448,8 @@ int kvm_arch_init_vcpu(CPUState *env) case 0xb: case 0xd: for (j = 0; ; j++) { +if (i == 0xd j == 64) +break; c-function = i; c-flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX; c-index = j; @@ -460,7 +462,7 @@ int kvm_arch_init_vcpu(CPUState *env) break; } if (i == 0xd c-eax == 0) { -break; +continue; } c = cpuid_data.entries[cpuid_i++]; } -- 1.6.4 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] KVM: Fix XSAVE feature bit enumeration
When iterating through the XSAVE feature enumeration CPUID leaf (0xD) we should not stop at the first zero EAX, but instead keep scanning since there are gaps in the enumeration (ECX=1 for instance). This fixes the proper usage of AVX in KVM guests. Signed-off-by: Andre Przywara andre.przyw...@amd.com --- target-i386/kvm.c |5 - 1 files changed, 4 insertions(+), 1 deletions(-) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index faedc6c..37a972f 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -448,6 +448,9 @@ int kvm_arch_init_vcpu(CPUState *env) case 0xb: case 0xd: for (j = 0; ; j++) { +if (i == 0xd j == 64) { +break; +} c-function = i; c-flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX; c-index = j; @@ -460,7 +463,7 @@ int kvm_arch_init_vcpu(CPUState *env) break; } if (i == 0xd c-eax == 0) { -break; +continue; } c = cpuid_data.entries[cpuid_i++]; } -- 1.6.4 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] kvm/x86: remove unneeded substitute search for missing CPUID entries
Avi Kivity wrote: On 03/30/2011 03:01 PM, Andre Przywara wrote: If KVM cannot find an exact match for a requested CPUID leaf, the code will try to find the closest match instead of simply confessing it's failure. The heuristic is on one hand wrong nowadays, since it does not take the KVM CPUID leaves (0x40xx) into account. On the other hand the callers of this function can all deal with the no-match situation. So lets remove this code, as it serves no purpose. This fixes a crash of newer Linux kernels as KVM guests on AMD Bulldozer CPUs, where bogus values were returned in response to a CPUID intercept. @@ -4959,12 +4959,6 @@ struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu, best = e; break; } - /* -* Both basic or both extended? -*/ - if (((e-function ^ function) 0x8000) == 0) - if (!best || e-function best-function) - best = e; } return best; } This behaviour is mandated by the spec (looking at the Intel one), though it is implemented incorrectly - should always return largest basic leaf, and ignore the kvm leaves. But the spec says that this applies only if EAX is higher than the largest supported leaf. The code as is checks whether KVM has an entry in the cpuid cache for it, which is not the same. Especially this case that hit me was a missing index entry, which should return 0. The check for too large leaf numbers should be moved into kvm_emulate_cpuid(). There is already some code in QEMU (cpu_x86_cpuid) to handle this, but that path does not apply to KVM. I will make a new version of this patch which replaces the old check with a sane version in kvm_emulate_cpuid(). Thanks for pointing this out. I think the correct behaviour is: if (e-function 1 (!best || e-function best-function)) best = e; We probably need a find_exact_cpuid_entry() that returns NULL if it doesn't find a match, for internal use. As mentioned, this behavior only applies to the actual intercept case, not to all users of kvm_find_cpuid_entry(). So I'd like to make this check in the intercept code path and not in this function. Regards, Andre. -- Andre Przywara AMD-Operating System Research Center (OSRC), Dresden, Germany -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] kvm/x86: move and fix substitue search for missing CPUID entries
If KVM cannot find an exact match for a requested CPUID leaf, the code will try to find the closest match instead of simply confessing it's failure. The implementation was meant to satisfy the CPUID specification, but did not properly check for extended and standard leaves and also didn't account for the index subleaf. Beside that this rule only applies to CPUID intercepts, which is not the only user of the kvm_find_cpuid_entry() function. So fix this algorithm and move it into kvm_emulate_cpuid(). This fixes a crash of newer Linux kernels as KVM guests on AMD Bulldozer CPUs, where bogus values were returned in response to a CPUID intercept. CC: sta...@kernel.org [2.6.38] Signed-off-by: Andre Przywara andre.przyw...@amd.com --- arch/x86/kvm/x86.c | 19 +-- 1 files changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 6e86cec..552b8f8 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4959,12 +4959,6 @@ struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu, best = e; break; } - /* -* Both basic or both extended? -*/ - if (((e-function ^ function) 0x8000) == 0) - if (!best || e-function best-function) - best = e; } return best; } @@ -4996,6 +4990,19 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) kvm_register_write(vcpu, VCPU_REGS_RCX, 0); kvm_register_write(vcpu, VCPU_REGS_RDX, 0); best = kvm_find_cpuid_entry(vcpu, function, index); + + /* if no match is found, check whether we exceed the vCPU's limit +* and return the content of the highest valid standard leaf instead. +* This is to satisfy the CPUID specification. +*/ + if (!best) { + best = kvm_find_cpuid_entry(vcpu, function 0x8000, 0); + if (best best-eax function) + best = kvm_find_cpuid_entry(vcpu, best-eax, index); + else + best = NULL; + } + if (best) { kvm_register_write(vcpu, VCPU_REGS_RAX, best-eax); kvm_register_write(vcpu, VCPU_REGS_RBX, best-ebx); -- 1.6.4 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] kvm/x86: move and fix substitue search for missing CPUID entries
Avi Kivity wrote: On 03/31/2011 03:13 PM, Andre Przywara wrote: If KVM cannot find an exact match for a requested CPUID leaf, the code will try to find the closest match instead of simply confessing it's failure. The implementation was meant to satisfy the CPUID specification, but did not properly check for extended and standard leaves and also didn't account for the index subleaf. Beside that this rule only applies to CPUID intercepts, which is not the only user of the kvm_find_cpuid_entry() function. So fix this algorithm and move it into kvm_emulate_cpuid(). This fixes a crash of newer Linux kernels as KVM guests on AMD Bulldozer CPUs, where bogus values were returned in response to a CPUID intercept. @@ -4996,6 +4990,19 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) kvm_register_write(vcpu, VCPU_REGS_RCX, 0); kvm_register_write(vcpu, VCPU_REGS_RDX, 0); best = kvm_find_cpuid_entry(vcpu, function, index); + + /* if no match is found, check whether we exceed the vCPU's limit +* and return the content of the highest valid standard leaf instead. +* This is to satisfy the CPUID specification. +*/ + if (!best) { + best = kvm_find_cpuid_entry(vcpu, function 0x8000, 0); highest valid standard leaf means the second argument should be zero, no? Weird, but somehow true. I fixed this is in a another version (following). Thanks for spotting this. Andre. + if (best best-eax function) + best = kvm_find_cpuid_entry(vcpu, best-eax, index); + else + best = NULL; + } + if (best) { kvm_register_write(vcpu, VCPU_REGS_RAX, best-eax); kvm_register_write(vcpu, VCPU_REGS_RBX, best-ebx); -- Andre Przywara AMD-Operating System Research Center (OSRC), Dresden, Germany -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2 v3] kvm/x86: move and fix substitue search for missing CPUID entries
If KVM cannot find an exact match for a requested CPUID leaf, the code will try to find the closest match instead of simply confessing it's failure. The implementation was meant to satisfy the CPUID specification, but did not properly check for extended and standard leaves and also didn't account for the index subleaf. Beside that this rule only applies to CPUID intercepts, which is not the only user of the kvm_find_cpuid_entry() function. So fix this algorithm and call it from kvm_emulate_cpuid(). This fixes a crash of newer Linux kernels as KVM guests on AMD Bulldozer CPUs, where bogus values were returned in response to a CPUID intercept. CC: sta...@kernel.org [2.6.38] Signed-off-by: Andre Przywara andre.przyw...@amd.com --- arch/x86/kvm/x86.c | 31 +-- 1 files changed, 25 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 6e86cec..a38fb9b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4959,12 +4959,6 @@ struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu, best = e; break; } - /* -* Both basic or both extended? -*/ - if (((e-function ^ function) 0x8000) == 0) - if (!best || e-function best-function) - best = e; } return best; } @@ -4984,6 +4978,27 @@ not_found: return 36; } +/* + * If no match is found, check whether we exceed the vCPU's limit + * and return the content of the highest valid _standard_ leaf instead. + * This is to satisfy the CPUID specification. + */ +static struct kvm_cpuid_entry2* check_cpuid_limit(struct kvm_vcpu *vcpu, + u32 function, u32 index) +{ + struct kvm_cpuid_entry2 *maxlevel; + + maxlevel = kvm_find_cpuid_entry(vcpu, function 0x8000, 0); + if (!maxlevel || maxlevel-eax = function) + return NULL; + if (function 0x8000) { + maxlevel = kvm_find_cpuid_entry(vcpu, 0, 0); + if (!maxlevel) + return NULL; + } + return kvm_find_cpuid_entry(vcpu, maxlevel-eax, index); +} + void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) { u32 function, index; @@ -4996,6 +5011,10 @@ void kvm_emulate_cpuid(struct kvm_vcpu *vcpu) kvm_register_write(vcpu, VCPU_REGS_RCX, 0); kvm_register_write(vcpu, VCPU_REGS_RDX, 0); best = kvm_find_cpuid_entry(vcpu, function, index); + + if (!best) + best = check_cpuid_limit(vcpu, function, index); + if (best) { kvm_register_write(vcpu, VCPU_REGS_RAX, best-eax); kvm_register_write(vcpu, VCPU_REGS_RBX, best-ebx); -- 1.6.4 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] kvm/x86: fix XSAVE bit scanning
When KVM scans the 0xD CPUID leaf for propagating the XSAVE save area leaves, it assumes that the leaves are contigious and stops at the first zero one. On AMD hardware there is a gap, though, as LWP uses leaf 62 to announce it's state save area. So lets iterate through all 64 possible leaves and simply skip zero ones to also cover later features. CC: sta...@kernel.org [2.6.38] Signed-off-by: Andre Przywara andre.przyw...@amd.com --- arch/x86/kvm/x86.c |6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index bfd7763..6e86cec 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2395,9 +2395,9 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function, int i; entry-flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; - for (i = 1; *nent maxnent; ++i) { - if (entry[i - 1].eax == 0 i != 2) - break; + for (i = 1; *nent maxnent i 64; ++i) { + if (entry[i].eax == 0) + continue; do_cpuid_1_ent(entry[i], function, i); entry[i].flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX; -- 1.6.4 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] kvm/x86: remove unneeded substitute search for missing CPUID entries
If KVM cannot find an exact match for a requested CPUID leaf, the code will try to find the closest match instead of simply confessing it's failure. The heuristic is on one hand wrong nowadays, since it does not take the KVM CPUID leaves (0x40xx) into account. On the other hand the callers of this function can all deal with the no-match situation. So lets remove this code, as it serves no purpose. This fixes a crash of newer Linux kernels as KVM guests on AMD Bulldozer CPUs, where bogus values were returned in response to a CPUID intercept. CC: sta...@kernel.org [2.6.38] Signed-off-by: Andre Przywara andre.przyw...@amd.com --- arch/x86/kvm/x86.c |6 -- 1 files changed, 0 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 6e86cec..625143f 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4959,12 +4959,6 @@ struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu, best = e; break; } - /* -* Both basic or both extended? -*/ - if (((e-function ^ function) 0x8000) == 0) - if (!best || e-function best-function) - best = e; } return best; } -- 1.6.4 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] kvm/svm: fix DR interception handling on upcoming AMD CPUs
Roedel, Joerg wrote: On Tue, Feb 08, 2011 at 07:22:29PM -0500, Andre Przywara wrote: Somehow the code line advancing the RIP and checking for exceptions got dropped between the post on the ML and the commit. Add it again to let guests boot on upcoming AMD CPUs again. Reported-by: Joerg Roedel joerg.roe...@amd.com Signed-off-by: Andre Przywara andre.przyw...@amd.com --- arch/x86/kvm/svm.c |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 25bd1bc..be06e58 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -2776,6 +2776,7 @@ static int dr_interception(struct vcpu_svm *svm) if (!err) kvm_register_write(svm-vcpu, reg, val); } + kvm_complete_insn_gp(svm-vcpu, err); Any exception check takes presedence over the intercept. So a call to skip_emulated_instruction should be sufficient here. You are right, but I think this way the implementation is cleaner and more generic. If there is no exception condition detected (err==0), then the call will just do skip_emulated_instruction anyway. But as I write this, I see that err is not initialized, so I'd propose this corrected version of the patch instead. Regards, Andre. -- From 8c1dced7b4f80e4968b03656aee2452535b2ef2f Mon Sep 17 00:00:00 2001 From: Andre Przywara andre.przyw...@amd.com Date: Wed, 9 Feb 2011 01:10:45 +0100 Subject: [PATCH] kvm/svm: fix DR interception handling on upcoming AMD CPUs Somehow the code line advancing the RIP and checking for exceptions got dropped between the mail on the ML and the commit. Add it again to let guests boot on upcoming AMD CPUs again. While at it, properly initialize the err variable to fix the write DR case. Reported-by: Joerg Roedel joerg.roe...@amd.com Signed-off-by: Andre Przywara andre.przyw...@amd.com --- arch/x86/kvm/svm.c |3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 25bd1bc..d558121 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -2760,7 +2760,7 @@ static int dr_interception(struct vcpu_svm *svm) { int reg, dr; unsigned long val; - int err; + int err = 0; if (!boot_cpu_has(X86_FEATURE_DECODEASSISTS)) return emulate_on_interception(svm); @@ -2776,6 +2776,7 @@ static int dr_interception(struct vcpu_svm *svm) if (!err) kvm_register_write(svm-vcpu, reg, val); } + kvm_complete_insn_gp(svm-vcpu, err); return 1; } -- 1.6.4 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] kvm/svm: fix DR interception handling on upcoming AMD CPUs
Somehow the code line advancing the RIP and checking for exceptions got dropped between the post on the ML and the commit. Add it again to let guests boot on upcoming AMD CPUs again. Reported-by: Joerg Roedel joerg.roe...@amd.com Signed-off-by: Andre Przywara andre.przyw...@amd.com --- arch/x86/kvm/svm.c |1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 25bd1bc..be06e58 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -2776,6 +2776,7 @@ static int dr_interception(struct vcpu_svm *svm) if (!err) kvm_register_write(svm-vcpu, reg, val); } + kvm_complete_insn_gp(svm-vcpu, err); return 1; } -- 1.6.4 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH -v3 0/8] kvm/svm: implement new DecodeAssist features
Hi, this is version 3 of the DecodeAssist patches. I added 3 clean up patches which are not SVM specific. Changes between v2 and v3: - now includes the (unchanged) CR8 handling fix - move complete_insn_gp() helper function into x86.c - remove unnecessary comment - fix handling of illegal CR accesses (inject #UD, should actually not occur) - completely rework the instruction bytes copy patch Now this propagates the addr/len pair from the interception handling into the emulator. For this I cleaned up this code path a bit (patch 3), so it does not blow up all current users of emulate_instruction. Changes between v1 and v2: - goes on top of the CR8 handling fix I sent out earlier this week (required for proper handling of CR8 exceptions) - handles exception cases properly (for mov cr and mov dr) - uses X86_FEATURE_ names instead of SVM_FEATURE names (for boot_cpu_has) (thanks to Joerg for spotting this) - use static_cpu_has where appropriate - some minor code cleanups (for instance cr register calculation) - move prefetch callback into x86_decode_insn and out of every fetch I refrained from ditching the callback at all, as I dont like extending every emulate_instruction call with NULL, 0. But if this is desperately needed, I can still change it. - rename vendor specific prefetch function names Upcoming AMD CPUs will have a SVM enhancement called DecodeAssist which will provide more information when intercepting certain events. These information allows to skip the instruction fetching and decoding and handle the intercept immediately. This patch set implements all the features which are documented in the recent AMD manual (APM vol. 2). For details see the patches. Please review and apply. Regards, Andre. -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 6/8] kvm/svm: enhance mov DR intercept handler
Newer SVM implementations provide the GPR number in the VMCB, so that the emulation path is no longer necesarry to handle debug register access intercepts. Implement the handling in svm.c and use it when the info is provided. Signed-off-by: Andre Przywara andre.przyw...@amd.com --- arch/x86/kvm/svm.c | 57 +-- 1 files changed, 41 insertions(+), 16 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index b47e2e6..eb662da 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -2745,6 +2745,31 @@ static int cr0_write_interception(struct vcpu_svm *svm) return r; } +static int dr_interception(struct vcpu_svm *svm) +{ + int reg, dr; + unsigned long val; + int err; + + if (!boot_cpu_has(X86_FEATURE_DECODEASSISTS)) + return emulate_on_interception(svm); + + reg = svm-vmcb-control.exit_info_1 SVM_EXITINFO_REG_MASK; + dr = svm-vmcb-control.exit_code - SVM_EXIT_READ_DR0; + + if (dr = 16) { /* mov to DRn */ + val = kvm_register_read(svm-vcpu, reg); + err = kvm_set_dr(svm-vcpu, dr - 16, val); + } else { + err = kvm_get_dr(svm-vcpu, dr, val); + if (!err) + kvm_register_write(svm-vcpu, reg, val); + } + kvm_complete_insn_gp(svm-vcpu, err); + + return 1; +} + static int cr8_write_interception(struct vcpu_svm *svm) { struct kvm_run *kvm_run = svm-vcpu.run; @@ -3010,22 +3035,22 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = { [SVM_EXIT_WRITE_CR3]= cr_interception, [SVM_EXIT_WRITE_CR4]= cr_interception, [SVM_EXIT_WRITE_CR8]= cr8_write_interception, - [SVM_EXIT_READ_DR0] = emulate_on_interception, - [SVM_EXIT_READ_DR1] = emulate_on_interception, - [SVM_EXIT_READ_DR2] = emulate_on_interception, - [SVM_EXIT_READ_DR3] = emulate_on_interception, - [SVM_EXIT_READ_DR4] = emulate_on_interception, - [SVM_EXIT_READ_DR5] = emulate_on_interception, - [SVM_EXIT_READ_DR6] = emulate_on_interception, - [SVM_EXIT_READ_DR7] = emulate_on_interception, - [SVM_EXIT_WRITE_DR0]= emulate_on_interception, - [SVM_EXIT_WRITE_DR1]= emulate_on_interception, - [SVM_EXIT_WRITE_DR2]= emulate_on_interception, - [SVM_EXIT_WRITE_DR3]= emulate_on_interception, - [SVM_EXIT_WRITE_DR4]= emulate_on_interception, - [SVM_EXIT_WRITE_DR5]= emulate_on_interception, - [SVM_EXIT_WRITE_DR6]= emulate_on_interception, - [SVM_EXIT_WRITE_DR7]= emulate_on_interception, + [SVM_EXIT_READ_DR0] = dr_interception, + [SVM_EXIT_READ_DR1] = dr_interception, + [SVM_EXIT_READ_DR2] = dr_interception, + [SVM_EXIT_READ_DR3] = dr_interception, + [SVM_EXIT_READ_DR4] = dr_interception, + [SVM_EXIT_READ_DR5] = dr_interception, + [SVM_EXIT_READ_DR6] = dr_interception, + [SVM_EXIT_READ_DR7] = dr_interception, + [SVM_EXIT_WRITE_DR0]= dr_interception, + [SVM_EXIT_WRITE_DR1]= dr_interception, + [SVM_EXIT_WRITE_DR2]= dr_interception, + [SVM_EXIT_WRITE_DR3]= dr_interception, + [SVM_EXIT_WRITE_DR4]= dr_interception, + [SVM_EXIT_WRITE_DR5]= dr_interception, + [SVM_EXIT_WRITE_DR6]= dr_interception, + [SVM_EXIT_WRITE_DR7]= dr_interception, [SVM_EXIT_EXCP_BASE + DB_VECTOR]= db_interception, [SVM_EXIT_EXCP_BASE + BP_VECTOR]= bp_interception, [SVM_EXIT_EXCP_BASE + UD_VECTOR]= ud_interception, -- 1.6.4 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 4/8] kvm/svm: add new SVM feature bit names
the recent APM Vol.2 and the recent AMD CPUID specification describe new CPUID features bits for SVM. Name them here for later usage. Signed-off-by: Andre Przywara andre.przyw...@amd.com --- arch/x86/kvm/svm.c |4 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index d49d73c..e2ea75f 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -51,6 +51,10 @@ MODULE_LICENSE(GPL); #define SVM_FEATURE_LBRV (1 1) #define SVM_FEATURE_SVML (1 2) #define SVM_FEATURE_NRIP (1 3) +#define SVM_FEATURE_TSC_RATE (1 4) +#define SVM_FEATURE_VMCB_CLEAN (1 5) +#define SVM_FEATURE_FLUSH_ASID (1 6) +#define SVM_FEATURE_DECODE_ASSIST (1 7) #define SVM_FEATURE_PAUSE_FILTER (1 10) #define NESTED_EXIT_HOST 0 /* Exit handled on host level */ -- 1.6.4 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 8/8] kvm/svm: copy instruction bytes from VMCB
In case of a nested page fault or an intercepted #PF newer SVM implementations provide a copy of the faulting instruction bytes in the VMCB. Use these bytes to feed the instruction emulator and avoid the costly guest instruction fetch in this case. Signed-off-by: Andre Przywara andre.przyw...@amd.com --- arch/x86/include/asm/kvm_emulate.h |2 +- arch/x86/include/asm/kvm_host.h|9 + arch/x86/include/asm/svm.h |4 +++- arch/x86/kvm/emulate.c |7 +-- arch/x86/kvm/mmu.c |5 +++-- arch/x86/kvm/svm.c |4 +++- arch/x86/kvm/vmx.c |4 ++-- arch/x86/kvm/x86.c |6 -- 8 files changed, 26 insertions(+), 15 deletions(-) diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index bf70ece..8e37deb 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h @@ -265,7 +265,7 @@ struct x86_emulate_ctxt { #define X86EMUL_MODE_HOST X86EMUL_MODE_PROT64 #endif -int x86_decode_insn(struct x86_emulate_ctxt *ctxt); +int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len); #define EMULATION_FAILED -1 #define EMULATION_OK 0 #define EMULATION_RESTART 1 diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index de00b60..6268f6c 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -634,13 +634,13 @@ enum emulation_result { #define EMULTYPE_NO_DECODE (1 0) #define EMULTYPE_TRAP_UD (1 1) #define EMULTYPE_SKIP (1 2) -int x86_emulate_instruction(struct kvm_vcpu *vcpu, - unsigned long cr2, int emulation_type); +int x86_emulate_instruction(struct kvm_vcpu *vcpu, unsigned long cr2, + int emulation_type, void *insn, int insn_len); static inline int emulate_instruction(struct kvm_vcpu *vcpu, int emulation_type) { - return x86_emulate_instruction(vcpu, 0, emulation_type); + return x86_emulate_instruction(vcpu, 0, emulation_type, NULL, 0); } void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); @@ -721,7 +721,8 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu); int kvm_fix_hypercall(struct kvm_vcpu *vcpu); -int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code); +int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code, + void *insn, int insn_len); void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva); void kvm_enable_tdp(void); diff --git a/arch/x86/include/asm/svm.h b/arch/x86/include/asm/svm.h index f0ffb81..f2b83bc 100644 --- a/arch/x86/include/asm/svm.h +++ b/arch/x86/include/asm/svm.h @@ -83,7 +83,9 @@ struct __attribute__ ((__packed__)) vmcb_control_area { u32 clean; u32 reserved_5; u64 next_rip; - u8 reserved_6[816]; + u8 insn_len; + u8 insn_bytes[15]; + u8 reserved_6[800]; }; diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 6366735..02a0041 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -2610,7 +2610,7 @@ done: } int -x86_decode_insn(struct x86_emulate_ctxt *ctxt) +x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len) { struct x86_emulate_ops *ops = ctxt-ops; struct decode_cache *c = ctxt-decode; @@ -2621,7 +2621,10 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt) struct operand memop = { .type = OP_NONE }; c-eip = ctxt-eip; - c-fetch.start = c-fetch.end = c-eip; + c-fetch.start = c-eip; + c-fetch.end = c-fetch.start + insn_len; + if (insn_len 0) + memcpy(c-fetch.data, insn, insn_len); ctxt-cs_base = seg_base(ctxt, ops, VCPU_SREG_CS); switch (mode) { diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 75334de..397a98f 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -3329,7 +3329,8 @@ void __kvm_mmu_free_some_pages(struct kvm_vcpu *vcpu) } } -int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code) +int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code, + void *insn, int insn_len) { int r; enum emulation_result er; @@ -3347,7 +3348,7 @@ int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code) if (r) goto out; - er = x86_emulate_instruction(vcpu, cr2, 0); + er = x86_emulate_instruction(vcpu, cr2, 0, insn, insn_len); switch (er) { case EMULATE_DONE: diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 7871702..00a6117 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -1527,7 +1527,9 @@ static int pf_interception(struct vcpu_svm *svm) trace_kvm_page_fault(fault_address, error_code); if (!npt_enabled
[PATCH 2/8] kvm: move complete_insn_gp() into x86.c
move the complete_insn_gp() helper function out of the VMX part into the generic x86 part to make it usable by SVM. Signed-off-by: Andre Przywara andre.przyw...@amd.com --- arch/x86/include/asm/kvm_host.h |2 ++ arch/x86/kvm/vmx.c | 16 arch/x86/kvm/x86.c |9 + 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index cb5cad2..cd4a990 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -828,4 +828,6 @@ void kvm_arch_async_page_ready(struct kvm_vcpu *vcpu, bool kvm_arch_can_inject_async_page_present(struct kvm_vcpu *vcpu); extern bool kvm_find_async_pf_gfn(struct kvm_vcpu *vcpu, gfn_t gfn); +void kvm_complete_insn_gp(struct kvm_vcpu *vcpu, int err); + #endif /* _ASM_X86_KVM_HOST_H */ diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 8e87bae..fd8ffde 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -3147,14 +3147,6 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall) hypercall[2] = 0xc1; } -static void complete_insn_gp(struct kvm_vcpu *vcpu, int err) -{ - if (err) - kvm_inject_gp(vcpu, 0); - else - skip_emulated_instruction(vcpu); -} - static int handle_cr(struct kvm_vcpu *vcpu) { unsigned long exit_qualification, val; @@ -3172,21 +3164,21 @@ static int handle_cr(struct kvm_vcpu *vcpu) switch (cr) { case 0: err = kvm_set_cr0(vcpu, val); - complete_insn_gp(vcpu, err); + kvm_complete_insn_gp(vcpu, err); return 1; case 3: err = kvm_set_cr3(vcpu, val); - complete_insn_gp(vcpu, err); + kvm_complete_insn_gp(vcpu, err); return 1; case 4: err = kvm_set_cr4(vcpu, val); - complete_insn_gp(vcpu, err); + kvm_complete_insn_gp(vcpu, err); return 1; case 8: { u8 cr8_prev = kvm_get_cr8(vcpu); u8 cr8 = kvm_register_read(vcpu, reg); err = kvm_set_cr8(vcpu, cr8); - complete_insn_gp(vcpu, err); + kvm_complete_insn_gp(vcpu, err); if (irqchip_in_kernel(vcpu-kvm)) return 1; if (cr8_prev = cr8) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2dbf68c..1d54cb7 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -334,6 +334,15 @@ void kvm_requeue_exception(struct kvm_vcpu *vcpu, unsigned nr) } EXPORT_SYMBOL_GPL(kvm_requeue_exception); +void kvm_complete_insn_gp(struct kvm_vcpu *vcpu, int err) +{ + if (err) + kvm_inject_gp(vcpu, 0); + else + kvm_x86_ops-skip_emulated_instruction(vcpu); +} +EXPORT_SYMBOL_GPL(kvm_complete_insn_gp); + void kvm_inject_page_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault) { ++vcpu-stat.pf_guest; -- 1.6.4 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 3/8] kvm: cleanup emulate_instruction
emulate_instruction had many callers, but only one used all parameters. One parameter was unused, another one is now hidden by a wrapper function (required for a future addition anyway), so most callers use now a shorter parameter list. Signed-off-by: Andre Przywara andre.przyw...@amd.com --- arch/x86/include/asm/kvm_host.h | 11 +-- arch/x86/kvm/mmu.c |2 +- arch/x86/kvm/svm.c | 14 +++--- arch/x86/kvm/vmx.c | 12 ++-- arch/x86/kvm/x86.c | 11 +-- 5 files changed, 28 insertions(+), 22 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index cd4a990..de00b60 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -634,8 +634,15 @@ enum emulation_result { #define EMULTYPE_NO_DECODE (1 0) #define EMULTYPE_TRAP_UD (1 1) #define EMULTYPE_SKIP (1 2) -int emulate_instruction(struct kvm_vcpu *vcpu, - unsigned long cr2, u16 error_code, int emulation_type); +int x86_emulate_instruction(struct kvm_vcpu *vcpu, + unsigned long cr2, int emulation_type); + +static inline int emulate_instruction(struct kvm_vcpu *vcpu, + int emulation_type) +{ + return x86_emulate_instruction(vcpu, 0, emulation_type); +} + void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address); diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index c3853d5..75334de 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -3347,7 +3347,7 @@ int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t cr2, u32 error_code) if (r) goto out; - er = emulate_instruction(vcpu, cr2, error_code, 0); + er = x86_emulate_instruction(vcpu, cr2, 0); switch (er) { case EMULATE_DONE: diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 06a0892..d49d73c 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -475,7 +475,7 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu) svm-next_rip = svm-vmcb-control.next_rip; if (!svm-next_rip) { - if (emulate_instruction(vcpu, 0, 0, EMULTYPE_SKIP) != + if (emulate_instruction(vcpu, EMULTYPE_SKIP) != EMULATE_DONE) printk(KERN_DEBUG %s: NOP\n, __func__); return; @@ -1586,7 +1586,7 @@ static int ud_interception(struct vcpu_svm *svm) { int er; - er = emulate_instruction(svm-vcpu, 0, 0, EMULTYPE_TRAP_UD); + er = emulate_instruction(svm-vcpu, EMULTYPE_TRAP_UD); if (er != EMULATE_DONE) kvm_queue_exception(svm-vcpu, UD_VECTOR); return 1; @@ -1703,7 +1703,7 @@ static int io_interception(struct vcpu_svm *svm) string = (io_info SVM_IOIO_STR_MASK) != 0; in = (io_info SVM_IOIO_TYPE_MASK) != 0; if (string || in) - return emulate_instruction(vcpu, 0, 0, 0) == EMULATE_DONE; + return emulate_instruction(vcpu, 0) == EMULATE_DONE; port = io_info 16; size = (io_info SVM_IOIO_SIZE_MASK) SVM_IOIO_SIZE_SHIFT; @@ -2648,12 +2648,12 @@ static int iret_interception(struct vcpu_svm *svm) static int invlpg_interception(struct vcpu_svm *svm) { - return emulate_instruction(svm-vcpu, 0, 0, 0) == EMULATE_DONE; + return emulate_instruction(svm-vcpu, 0) == EMULATE_DONE; } static int emulate_on_interception(struct vcpu_svm *svm) { - return emulate_instruction(svm-vcpu, 0, 0, 0) == EMULATE_DONE; + return emulate_instruction(svm-vcpu, 0) == EMULATE_DONE; } static int cr0_write_interception(struct vcpu_svm *svm) @@ -2661,7 +2661,7 @@ static int cr0_write_interception(struct vcpu_svm *svm) struct kvm_vcpu *vcpu = svm-vcpu; int r; - r = emulate_instruction(svm-vcpu, 0, 0, 0); + r = emulate_instruction(svm-vcpu, 0); if (svm-nested.vmexit_rip) { kvm_register_write(vcpu, VCPU_REGS_RIP, svm-nested.vmexit_rip); @@ -2680,7 +2680,7 @@ static int cr8_write_interception(struct vcpu_svm *svm) u8 cr8_prev = kvm_get_cr8(svm-vcpu); /* instruction emulation calls kvm_set_cr8() */ - r = emulate_instruction(svm-vcpu, 0, 0, 0); + r = emulate_instruction(svm-vcpu, 0); if (irqchip_in_kernel(svm-vcpu.kvm)) { clr_cr_intercept(svm, INTERCEPT_CR8_WRITE); return r == EMULATE_DONE; diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index fd8ffde..f3c60fb 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -2939,7 +2939,7 @@ static int handle_rmode_exception(struct kvm_vcpu *vcpu, * Cause the #SS fault with 0 error code in VM86 mode. */ if (((vec == GP_VECTOR) || (vec == SS_VECTOR)) err_code == 0
[PATCH 1/8] kvm: fix CR8 handling
The handling of CR8 writes in KVM is currently somewhat cumbersome. This patch makes it look like the other CR register handlers and fixes a possible issue in VMX, where the RIP would be incremented despite an injected #GP. Signed-off-by: Andre Przywara andre.przyw...@amd.com --- arch/x86/include/asm/kvm_host.h |2 +- arch/x86/kvm/svm.c |7 --- arch/x86/kvm/vmx.c |4 ++-- arch/x86/kvm/x86.c | 18 -- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 4461429..cb5cad2 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -661,7 +661,7 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason, int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0); int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3); int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4); -void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8); +int kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8); int kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val); int kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val); unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 24b4373..06a0892 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -2676,16 +2676,17 @@ static int cr0_write_interception(struct vcpu_svm *svm) static int cr8_write_interception(struct vcpu_svm *svm) { struct kvm_run *kvm_run = svm-vcpu.run; + int r; u8 cr8_prev = kvm_get_cr8(svm-vcpu); /* instruction emulation calls kvm_set_cr8() */ - emulate_instruction(svm-vcpu, 0, 0, 0); + r = emulate_instruction(svm-vcpu, 0, 0, 0); if (irqchip_in_kernel(svm-vcpu.kvm)) { clr_cr_intercept(svm, INTERCEPT_CR8_WRITE); - return 1; + return r == EMULATE_DONE; } if (cr8_prev = kvm_get_cr8(svm-vcpu)) - return 1; + return r == EMULATE_DONE; kvm_run-exit_reason = KVM_EXIT_SET_TPR; return 0; } diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index c195260..8e87bae 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -3185,8 +3185,8 @@ static int handle_cr(struct kvm_vcpu *vcpu) case 8: { u8 cr8_prev = kvm_get_cr8(vcpu); u8 cr8 = kvm_register_read(vcpu, reg); - kvm_set_cr8(vcpu, cr8); - skip_emulated_instruction(vcpu); + err = kvm_set_cr8(vcpu, cr8); + complete_insn_gp(vcpu, err); if (irqchip_in_kernel(vcpu-kvm)) return 1; if (cr8_prev = cr8) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f569da8..2dbf68c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -662,7 +662,7 @@ int kvm_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) } EXPORT_SYMBOL_GPL(kvm_set_cr3); -int __kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) +int kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) { if (cr8 CR8_RESERVED_BITS) return 1; @@ -672,12 +672,6 @@ int __kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) vcpu-arch.cr8 = cr8; return 0; } - -void kvm_set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) -{ - if (__kvm_set_cr8(vcpu, cr8)) - kvm_inject_gp(vcpu, 0); -} EXPORT_SYMBOL_GPL(kvm_set_cr8); unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu) @@ -4104,7 +4098,7 @@ static int emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu) res = kvm_set_cr4(vcpu, mk_cr_64(kvm_read_cr4(vcpu), val)); break; case 8: - res = __kvm_set_cr8(vcpu, val 0xfUL); + res = kvm_set_cr8(vcpu, val); break; default: vcpu_printf(vcpu, %s: unexpected cr %u\n, __func__, cr); @@ -5381,8 +5375,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) } /* re-sync apic's tpr */ - if (!irqchip_in_kernel(vcpu-kvm)) - kvm_set_cr8(vcpu, kvm_run-cr8); + if (!irqchip_in_kernel(vcpu-kvm)) { + if (kvm_set_cr8(vcpu, kvm_run-cr8) != 0) { + r = -EINVAL; + goto out; + } + } if (vcpu-arch.pio.count || vcpu-mmio_needed) { if (vcpu-mmio_needed) { -- 1.6.4 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 7/8] kvm/svm: implement enhanced INVLPG intercept
When the DecodeAssist feature is available, the linear address is provided in the VMCB on INVLPG intercepts. Use it directly to avoid any decoding and emulation. This is only useful for shadow paging, though. Signed-off-by: Andre Przywara andre.przyw...@amd.com --- arch/x86/kvm/svm.c |7 ++- 1 files changed, 6 insertions(+), 1 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index eb662da..7871702 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -2652,7 +2652,12 @@ static int iret_interception(struct vcpu_svm *svm) static int invlpg_interception(struct vcpu_svm *svm) { - return emulate_instruction(svm-vcpu, 0) == EMULATE_DONE; + if (!static_cpu_has(X86_FEATURE_DECODEASSISTS)) + return emulate_instruction(svm-vcpu, 0) == EMULATE_DONE; + + kvm_mmu_invlpg(svm-vcpu, svm-vmcb-control.exit_info_1); + skip_emulated_instruction(svm-vcpu); + return 1; } static int emulate_on_interception(struct vcpu_svm *svm) -- 1.6.4 -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html