[PATCH 11/13] KVM: arm64: implement ITS command queue command handlers
The connection between a device, an event ID, the LPI number and the allocated CPU is stored in in-memory tables in a GICv3, but their format is not specified by the spec. Instead software uses a command queue to let the ITS implementation use their own format. Implement handlers for the various ITS commands and let them store the requested relation into our own data structures. Error handling is very basic at this point, as we don't have a good way of communicating errors to the guest (usually a SError). Signed-off-by: Andre Przywara andre.przyw...@arm.com --- include/linux/irqchip/arm-gic-v3.h | 1 + virt/kvm/arm/its-emul.c| 422 - virt/kvm/arm/its-emul.h| 11 + 3 files changed, 433 insertions(+), 1 deletion(-) diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index 0b450c7..651aacc 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -254,6 +254,7 @@ #define GITS_CMD_MAPD 0x08 #define GITS_CMD_MAPC 0x09 #define GITS_CMD_MAPVI 0x0a +#define GITS_CMD_MAPI 0x0b #define GITS_CMD_MOVI 0x01 #define GITS_CMD_DISCARD 0x0f #define GITS_CMD_INV 0x0c diff --git a/virt/kvm/arm/its-emul.c b/virt/kvm/arm/its-emul.c index afd440e..574cf05 100644 --- a/virt/kvm/arm/its-emul.c +++ b/virt/kvm/arm/its-emul.c @@ -22,6 +22,7 @@ #include linux/kvm_host.h #include linux/interrupt.h #include linux/list.h +#include linux/slab.h #include linux/irqchip/arm-gic-v3.h #include kvm/arm_vgic.h @@ -55,6 +56,34 @@ struct its_itte { unsigned long *pending; }; +static struct its_device *find_its_device(struct kvm *kvm, u32 device_id) +{ + struct vgic_its *its = kvm-arch.vgic.its; + struct its_device *device; + + list_for_each_entry(device, its-device_list, dev_list) + if (device_id == device-device_id) + return device; + + return NULL; +} + +static struct its_itte *find_itte(struct kvm *kvm, u32 device_id, u32 event_id) +{ + struct its_device *device; + struct its_itte *itte; + + device = find_its_device(kvm, device_id); + if (device == NULL) + return NULL; + + list_for_each_entry(itte, device-itt, itte_list) + if (itte-event_id == event_id) + return itte; + + return NULL; +} + #define for_each_lpi(dev, itte, kvm) \ list_for_each_entry(dev, (kvm)-arch.vgic.its.device_list, dev_list) \ list_for_each_entry(itte, (dev)-itt, itte_list) @@ -71,6 +100,19 @@ static struct its_itte *find_itte_by_lpi(struct kvm *kvm, int lpi) return NULL; } +static struct its_collection *find_collection(struct kvm *kvm, int coll_id) +{ + struct its_collection *collection; + + list_for_each_entry(collection, kvm-arch.vgic.its.collection_list, + coll_list) { + if (coll_id == collection-collection_id) + return collection; + } + + return NULL; +} + #define LPI_PROP_ENABLE_BIT(p) ((p) LPI_PROP_ENABLED) #define LPI_PROP_PRIORITY(p) ((p) 0xfc) @@ -345,9 +387,386 @@ void vits_unqueue_lpi(struct kvm_vcpu *vcpu, int lpi) spin_unlock(its-lock); } +static u64 its_cmd_mask_field(u64 *its_cmd, int word, int shift, int size) +{ + return (le64_to_cpu(its_cmd[word]) shift) (BIT_ULL(size) - 1); +} + +#define its_cmd_get_command(cmd) its_cmd_mask_field(cmd, 0, 0, 8) +#define its_cmd_get_deviceid(cmd) its_cmd_mask_field(cmd, 0, 32, 32) +#define its_cmd_get_id(cmd)its_cmd_mask_field(cmd, 1, 0, 32) +#define its_cmd_get_physical_id(cmd) its_cmd_mask_field(cmd, 1, 32, 32) +#define its_cmd_get_collection(cmd)its_cmd_mask_field(cmd, 2, 0, 16) +#define its_cmd_get_target_addr(cmd) its_cmd_mask_field(cmd, 2, 16, 32) +#define its_cmd_get_validbit(cmd) its_cmd_mask_field(cmd, 2, 63, 1) + +/* + * Handles the DISCARD command, which frees an ITTE. + * Must be called with the ITS lock held. + */ +static int vits_cmd_handle_discard(struct kvm *kvm, u64 *its_cmd) +{ + u32 device_id; + u32 event_id; + struct its_itte *itte; + + device_id = its_cmd_get_deviceid(its_cmd); + event_id = its_cmd_get_id(its_cmd); + + itte = find_itte(kvm, device_id, event_id); + if (!itte || !itte-collection) + return E_ITS_DISCARD_UNMAPPED_INTERRUPT; + + clear_bit(itte-collection-target_addr, itte-pending); + + list_del(itte-itte_list); + kfree(itte); + return 0; +} + +/* + * Handles the MOVI command, which moves an ITTE to a different collection. + * Must be called with the ITS lock held. + */ +static int vits_cmd_handle_movi(struct kvm *kvm, u64 *its_cmd) +{ + u32 device_id = its_cmd_get_deviceid(its_cmd); + u32 event_id =
[PATCH 05/13] KVM: arm64: handle ITS related GICv3 redistributor registers
In the GICv3 redistributor there are the PENDBASER and PROPBASER registers which we did not emulate so far, as they only make sense when having an ITS. In preparation for that emulate those MMIO accesses by storing the 64-bit data written into it into a variable which we later read in the ITS emulation. Signed-off-by: Andre Przywara andre.przyw...@arm.com --- include/kvm/arm_vgic.h | 4 virt/kvm/arm/vgic-v3-emul.c | 43 +++ virt/kvm/arm/vgic.c | 35 +++ virt/kvm/arm/vgic.h | 4 4 files changed, 86 insertions(+) diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 37725bb..9ea0b3b 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -256,6 +256,10 @@ struct vgic_dist { struct vgic_vm_ops vm_ops; struct vgic_io_device dist_iodev; struct vgic_io_device *redist_iodevs; + + u64 propbaser; + u64 *pendbaser; + boollpis_enabled; }; struct vgic_v2_cpu_if { diff --git a/virt/kvm/arm/vgic-v3-emul.c b/virt/kvm/arm/vgic-v3-emul.c index 16c6d8a..04f3aed 100644 --- a/virt/kvm/arm/vgic-v3-emul.c +++ b/virt/kvm/arm/vgic-v3-emul.c @@ -607,6 +607,37 @@ static bool handle_mmio_cfg_reg_redist(struct kvm_vcpu *vcpu, return vgic_handle_cfg_reg(reg, mmio, offset); } +/* We don't trigger any actions here, just store the register value */ +static bool handle_mmio_propbaser_redist(struct kvm_vcpu *vcpu, +struct kvm_exit_mmio *mmio, +phys_addr_t offset) +{ + struct vgic_dist *dist = vcpu-kvm-arch.vgic; + int mode = ACCESS_READ_VALUE; + + mode |= dist-lpis_enabled ? ACCESS_WRITE_IGNORED : ACCESS_WRITE_VALUE; + vgic_handle_base_register(vcpu, mmio, offset, dist-propbaser, mode); + + return false; +} + +/* We don't trigger any actions here, just store the register value */ +static bool handle_mmio_pendbaser_redist(struct kvm_vcpu *vcpu, +struct kvm_exit_mmio *mmio, +phys_addr_t offset) +{ + struct kvm_vcpu *rdvcpu = mmio-private; + struct vgic_dist *dist = vcpu-kvm-arch.vgic; + int mode = ACCESS_READ_VALUE; + + /* Storing a value with LPIs already enabled is undefined */ + mode |= dist-lpis_enabled ? ACCESS_WRITE_IGNORED : ACCESS_WRITE_VALUE; + vgic_handle_base_register(vcpu, mmio, offset, + dist-pendbaser[rdvcpu-vcpu_id], mode); + + return false; +} + #define SGI_base(x) ((x) + SZ_64K) static const struct vgic_io_range vgic_redist_ranges[] = { @@ -635,6 +666,18 @@ static const struct vgic_io_range vgic_redist_ranges[] = { .handle_mmio= handle_mmio_raz_wi, }, { + .base = GICR_PENDBASER, + .len= 0x08, + .bits_per_irq = 0, + .handle_mmio= handle_mmio_pendbaser_redist, + }, + { + .base = GICR_PROPBASER, + .len= 0x08, + .bits_per_irq = 0, + .handle_mmio= handle_mmio_propbaser_redist, + }, + { .base = GICR_IDREGS, .len= 0x30, .bits_per_irq = 0, diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 2e9723aa..0a9236d 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -448,6 +448,41 @@ void vgic_reg_access(struct kvm_exit_mmio *mmio, u32 *reg, } } +/* handle a 64-bit register access */ +void vgic_handle_base_register(struct kvm_vcpu *vcpu, + struct kvm_exit_mmio *mmio, + phys_addr_t offset, u64 *basereg, + int mode) +{ + u32 reg; + u64 breg; + + switch (offset ~3) { + case 0x00: + breg = *basereg; + reg = lower_32_bits(breg); + vgic_reg_access(mmio, reg, offset 3, mode); + if (mmio-is_write (mode ACCESS_WRITE_VALUE)) { + breg = GENMASK_ULL(63, 32); + breg |= reg; + *basereg = breg; + } + break; + case 0x04: + breg = *basereg; + reg = upper_32_bits(breg); + vgic_reg_access(mmio, reg, offset 3, mode); + if (mmio-is_write (mode ACCESS_WRITE_VALUE)) { + breg = lower_32_bits(breg); + breg |= (u64)reg 32; + *basereg = breg; + } + break; + } +} + + + bool handle_mmio_raz_wi(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, phys_addr_t offset) { diff --git
[PATCH v5 09/12] KVM: arm64: introduce vcpu-arch.debug_ptr
This introduces a level of indirection for the debug registers. Instead of using the sys_regs[] directly we store registers in a structure in the vcpu. As we are no longer tied to the layout of the sys_regs[] we can make the copies size appropriate for control and value registers. This also entails updating the sys_regs code to access this new structure. Instead of passing a register index we now pass an offset into the kvm_guest_debug_arch structure. We also need to ensure the GET/SET_ONE_REG ioctl operations store the registers in their correct location. Signed-off-by: Alex Bennée alex.ben...@linaro.org --- arch/arm/kvm/arm.c| 3 + arch/arm64/include/asm/kvm_asm.h | 24 +++- arch/arm64/include/asm/kvm_host.h | 12 +++- arch/arm64/kernel/asm-offsets.c | 6 ++ arch/arm64/kvm/hyp.S | 107 +--- arch/arm64/kvm/sys_regs.c | 126 +++--- 6 files changed, 188 insertions(+), 90 deletions(-) diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 9b3ed6d..0d17c7b 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -279,6 +279,9 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) /* Set up the timer */ kvm_timer_vcpu_init(vcpu); + /* Set the debug registers to be the guests */ + vcpu-arch.debug_ptr = vcpu-arch.vcpu_debug_state; + return 0; } diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index d6b507e..e997404 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -46,24 +46,16 @@ #defineCNTKCTL_EL1 20 /* Timer Control Register (EL1) */ #definePAR_EL1 21 /* Physical Address Register */ #define MDSCR_EL1 22 /* Monitor Debug System Control Register */ -#define DBGBCR0_EL123 /* Debug Breakpoint Control Registers (0-15) */ -#define DBGBCR15_EL1 38 -#define DBGBVR0_EL139 /* Debug Breakpoint Value Registers (0-15) */ -#define DBGBVR15_EL1 54 -#define DBGWCR0_EL155 /* Debug Watchpoint Control Registers (0-15) */ -#define DBGWCR15_EL1 70 -#define DBGWVR0_EL171 /* Debug Watchpoint Value Registers (0-15) */ -#define DBGWVR15_EL1 86 -#define MDCCINT_EL187 /* Monitor Debug Comms Channel Interrupt Enable Reg */ +#define MDCCINT_EL123 /* Monitor Debug Comms Channel Interrupt Enable Reg */ /* 32bit specific registers. Keep them at the end of the range */ -#defineDACR32_EL2 88 /* Domain Access Control Register */ -#defineIFSR32_EL2 89 /* Instruction Fault Status Register */ -#defineFPEXC32_EL2 90 /* Floating-Point Exception Control Register */ -#defineDBGVCR32_EL291 /* Debug Vector Catch Register */ -#defineTEECR32_EL1 92 /* ThumbEE Configuration Register */ -#defineTEEHBR32_EL193 /* ThumbEE Handler Base Register */ -#defineNR_SYS_REGS 94 +#defineDACR32_EL2 24 /* Domain Access Control Register */ +#defineIFSR32_EL2 25 /* Instruction Fault Status Register */ +#defineFPEXC32_EL2 26 /* Floating-Point Exception Control Register */ +#defineDBGVCR32_EL227 /* Debug Vector Catch Register */ +#defineTEECR32_EL1 28 /* ThumbEE Configuration Register */ +#defineTEEHBR32_EL129 /* ThumbEE Handler Base Register */ +#defineNR_SYS_REGS 30 /* 32bit mapping */ #define c0_MPIDR (MPIDR_EL1 * 2) /* MultiProcessor ID Register */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index e2db6a6..e5040b6 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -108,11 +108,21 @@ struct kvm_vcpu_arch { /* Exception Information */ struct kvm_vcpu_fault_info fault; - /* Debug state */ + /* Guest debug state */ u64 debug_flags; + /* +* For debugging the guest we need to keep a set of debug +* registers which can override the guests own debug state +* while being used. These are set via the KVM_SET_GUEST_DEBUG +* ioctl. +*/ + struct kvm_guest_debug_arch *debug_ptr; + struct kvm_guest_debug_arch vcpu_debug_state; + /* Pointer to host CPU context */ kvm_cpu_context_t *host_cpu_context; + struct kvm_guest_debug_arch host_debug_state; /* VGIC state */ struct vgic_cpu vgic_cpu; diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index dfb25a2..1a8e97c 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -116,10 +116,16 @@ int main(void) DEFINE(VCPU_FAR_EL2, offsetof(struct kvm_vcpu, arch.fault.far_el2)); DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2)); DEFINE(VCPU_DEBUG_FLAGS,
[PATCH v5 01/12] KVM: add comments for kvm_debug_exit_arch struct
Bring into line with the comments for the other structures and their KVM_EXIT_* cases. Also update api.txt to reflect use in kvm_run documentation. Signed-off-by: Alex Bennée alex.ben...@linaro.org Reviewed-by: David Hildenbrand d...@linux.vnet.ibm.com Reviewed-by: Andrew Jones drjo...@redhat.com Acked-by: Christoffer Dall christoffer.d...@linaro.org --- v2 - add comments for other exit types v3 - s/commentary/comments/ - add rb tags - update api.txt kvm_run to include KVM_EXIT_DEBUG desc v4 - sp fixes - add a-b --- Documentation/virtual/kvm/api.txt | 4 +++- include/uapi/linux/kvm.h | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 9fa2bf8..c34c32d 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3070,11 +3070,13 @@ data_offset describes where the data is located (KVM_EXIT_IO_OUT) or where kvm expects application code to place the data for the next KVM_RUN invocation (KVM_EXIT_IO_IN). Data format is a packed array. + /* KVM_EXIT_DEBUG */ struct { struct kvm_debug_exit_arch arch; } debug; -Unused. +If the exit_reason is KVM_EXIT_DEBUG, then a vcpu is processing a debug event +for which architecture specific information is returned. /* KVM_EXIT_MMIO */ struct { diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 4b60056..70ac641 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -237,6 +237,7 @@ struct kvm_run { __u32 count; __u64 data_offset; /* relative to kvm_run start */ } io; + /* KVM_EXIT_DEBUG */ struct { struct kvm_debug_exit_arch arch; } debug; @@ -285,6 +286,7 @@ struct kvm_run { __u32 data; __u8 is_write; } dcr; + /* KVM_EXIT_INTERNAL_ERROR */ struct { __u32 suberror; /* Available with KVM_CAP_INTERNAL_ERROR_DATA: */ @@ -295,6 +297,7 @@ struct kvm_run { struct { __u64 gprs[32]; } osi; + /* KVM_EXIT_PAPR_HCALL */ struct { __u64 nr; __u64 ret; -- 2.4.1 ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
[PATCH v5 05/12] KVM: arm: introduce kvm_arm_init/setup/clear_debug
This is a precursor for later patches which will need to do more to setup debug state before entering the hyp.S switch code. The existing functionality for setting mdcr_el2 has been moved out of hyp.S and now uses the value kept in vcpu-arch.mdcr_el2. As the assembler used to previously mask and preserve MDCR_EL2.HPMN I've had to add a mechanism to save the value of mdcr_el2 as a per-cpu variable during the initialisation code. The kernel never sets this number so we are assuming the bootcode has set up the correct value here. This also moves the conditional setting of the TDA bit from the hyp code into the C code which is currently used for the lazy debug register context switch code. Signed-off-by: Alex Bennée alex.ben...@linaro.org --- v3 - rename fns from arch-arm - preserve MDCR_EL2.HPMN setting - re-word some of the comments - fix some minor grammar nits - merge setting of mdcr_el2 - introduce trap_debug flag - move setup/clear within the irq lock section v4 - fix TDOSA desc - rm un-needed else leg - s/arch/arm/ --- arch/arm/include/asm/kvm_host.h | 4 ++ arch/arm/kvm/arm.c| 9 - arch/arm64/include/asm/kvm_asm.h | 2 + arch/arm64/include/asm/kvm_host.h | 5 +++ arch/arm64/kernel/asm-offsets.c | 1 + arch/arm64/kvm/Makefile | 2 +- arch/arm64/kvm/debug.c| 81 +++ arch/arm64/kvm/hyp.S | 19 - 8 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 arch/arm64/kvm/debug.c diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index d71607c..746c0c69 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -236,4 +236,8 @@ static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} +static inline void kvm_arm_init_debug(void) {} +static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} +static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {} + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 52a1d4d38..4a274e1 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -570,6 +570,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) continue; } + kvm_arm_setup_debug(vcpu); + /** * Enter the guest */ @@ -582,7 +584,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) vcpu-mode = OUTSIDE_GUEST_MODE; kvm_guest_exit(); trace_kvm_exit(kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu)); - /* + + kvm_arm_clear_debug(vcpu); + +/* * We may have taken a host interrupt in HYP mode (ie * while executing the guest). This interrupt is still * pending, as we haven't serviced it yet! @@ -930,6 +935,8 @@ static void cpu_init_hyp_mode(void *dummy) vector_ptr = (unsigned long)__kvm_hyp_vector; __cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr); + + kvm_arm_init_debug(); } static int hyp_init_cpu_notify(struct notifier_block *self, diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index 4f7310f..d6b507e 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -137,6 +137,8 @@ extern char __restore_vgic_v2_state[]; extern char __save_vgic_v3_state[]; extern char __restore_vgic_v3_state[]; +extern u32 __kvm_get_mdcr_el2(void); + #endif #endif /* __ARM_KVM_ASM_H__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index f0f58c9..7cb99b5 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -103,6 +103,7 @@ struct kvm_vcpu_arch { /* HYP configuration */ u64 hcr_el2; + u32 mdcr_el2; /* Exception Information */ struct kvm_vcpu_fault_info fault; @@ -250,4 +251,8 @@ static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} +void kvm_arm_init_debug(void); +void kvm_arm_setup_debug(struct kvm_vcpu *vcpu); +void kvm_arm_clear_debug(struct kvm_vcpu *vcpu); + #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index da675cc..dfb25a2 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -117,6 +117,7 @@ int main(void) DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2)); DEFINE(VCPU_DEBUG_FLAGS,
[PATCH v5 10/12] KVM: arm64: guest debug, HW assisted debug support
This adds support for userspace to control the HW debug registers for guest debug. In the debug ioctl we copy the IMPDEF defined number of registers into a new register set called host_debug_state. There is now a new vcpu parameter called debug_ptr which selects which register set is to copied into the real registers when world switch occurs. I've moved some helper functions into the hw_breakpoint.h header for re-use. As with single step we need to tweak the guest registers to enable the exceptions so we need to save and restore those bits. Two new capabilities have been added to the KVM_EXTENSION ioctl to allow userspace to query the number of hardware break and watch points available on the host hardware. Signed-off-by: Alex Bennée alex.ben...@linaro.org --- v2 - switched to C setup - replace host debug registers directly into context - minor tweak to api docs - setup right register for debug - add FAR_EL2 to debug exit structure - add support for trapping debug register access v3 - remove stray trace statement - fix spacing around operators (various) - clean-up usage of trap_debug - introduce debug_ptr, replace excessive memcpy stuff - don't use memcpy in ioctl, just assign - update cap ioctl documentation - reword a number comments - rename host_debug_state-external_debug_state v4 - use the new u32/u64 split debug_ptr approach - fix some wording/comments v5 - don't set MDSCR_EL1.KDE (not needed) --- Documentation/virtual/kvm/api.txt | 7 ++- arch/arm/kvm/arm.c | 7 +++ arch/arm64/include/asm/hw_breakpoint.h | 12 +++ arch/arm64/include/asm/kvm_host.h | 3 ++- arch/arm64/include/uapi/asm/kvm.h | 2 +- arch/arm64/kernel/hw_breakpoint.c | 12 --- arch/arm64/kvm/debug.c | 37 +- arch/arm64/kvm/handle_exit.c | 6 ++ arch/arm64/kvm/reset.c | 12 +++ include/uapi/linux/kvm.h | 2 ++ 10 files changed, 80 insertions(+), 20 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 33c8143..ada57df 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2668,7 +2668,7 @@ The top 16 bits of the control field are architecture specific control flags which can include the following: - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86, arm64] - - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390] + - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390, arm64] - KVM_GUESTDBG_INJECT_DB: inject DB type exception [x86] - KVM_GUESTDBG_INJECT_BP: inject BP type exception [x86] - KVM_GUESTDBG_EXIT_PENDING: trigger an immediate guest exit [s390] @@ -2683,6 +2683,11 @@ updated to the correct (supplied) values. The second part of the structure is architecture specific and typically contains a set of debug registers. +For arm64 the number of debug registers is implementation defined and +can be determined by querying the KVM_CAP_GUEST_DEBUG_HW_BPS and +KVM_CAP_GUEST_DEBUG_HW_WPS capabilities which return a positive number +indicating the number of supported registers. + When debug events exit the main run loop with the reason KVM_EXIT_DEBUG with the kvm_debug_exit_arch part of the kvm_run structure containing architecture specific debug information. diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 0d17c7b..6df47c1 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -307,6 +307,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) #define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE |\ KVM_GUESTDBG_USE_SW_BP | \ + KVM_GUESTDBG_USE_HW_BP | \ KVM_GUESTDBG_SINGLESTEP) /** @@ -327,6 +328,12 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, if (dbg-control KVM_GUESTDBG_ENABLE) { vcpu-guest_debug = dbg-control; + + /* Hardware assisted Break and Watch points */ + if (vcpu-guest_debug KVM_GUESTDBG_USE_HW_BP) { + vcpu-arch.external_debug_state = dbg-arch; + } + } else { /* If not enabled clear all flags */ vcpu-guest_debug = 0; diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h index 52b484b..c450552 100644 --- a/arch/arm64/include/asm/hw_breakpoint.h +++ b/arch/arm64/include/asm/hw_breakpoint.h @@ -130,6 +130,18 @@ static inline void ptrace_hw_copy_thread(struct task_struct *task) } #endif +/* Determine number of BRP registers available. */ +static inline int get_num_brps(void) +{ + return ((read_cpuid(ID_AA64DFR0_EL1) 12) 0xf) + 1; +} + +/* Determine number of WRP registers available. */ +static inline int get_num_wrps(void) +{ + return
[PATCH v4 0/4] Add support for for GICv2m and MSIs to arm-virt
Now when we have a host generic PCIe controller in the virt board, it would be nice to be able to use MSIs so that we can eventually enable VHOST with KVM. With these patches you can use MSIs with TCG and with KVM, but you still need some fixes for the mapping of the IRQ index to the GSI number for IRQFD to work. A separate series that enables IRQFD and vhost is available: ARM adaptations for vhost irqfd setup https://lists.gnu.org/archive/html/qemu-devel/2015-04/msg01054.html) Tested with KVM on XGene and with TCG by configuring a virtio-pci network adapter for the guest and verifying MSIs going through as expected. Rebased on target-arm.next, see the individual patches for detailed changelogs. Christoffer Dall (4): target-arm: Add GIC phandle to VirtBoardInfo arm_gicv2m: Add GICv2m widget to support MSIs target-arm: Extend the gic node properties target-arm: Add the GICv2m to the virt board hw/arm/virt.c | 73 ++- hw/intc/Makefile.objs | 1 + hw/intc/arm_gicv2m.c | 190 ++ include/hw/arm/virt.h | 2 + 4 files changed, 248 insertions(+), 18 deletions(-) create mode 100644 hw/intc/arm_gicv2m.c -- 2.1.2.330.g565301e.dirty ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
[PATCH v5 12/12] KVM: arm64: add trace points for guest_debug debug
This includes trace points for: kvm_arch_setup_guest_debug kvm_arch_clear_guest_debug I've also added some generic register setting trace events and also a trace point to dump the array of hardware registers. Signed-off-by: Alex Bennée alex.ben...@linaro.org --- v3 - add trace event for debug access. - remove short trace #define, rename trace events - use __print_array with fixed array instead of own func - rationalise trace points (only one per register changed) - add vcpu ptr to the debug_setup trace - remove :: in prints v4 - u32/u64 split on debug registers - fix for renames - add tracing of traps/set_guest_debug - remove handle_guest_debug trace v5 - minor print fmt fix - rm pstate traces --- arch/arm/kvm/arm.c| 2 + arch/arm/kvm/trace.h | 17 arch/arm64/kvm/debug.c| 35 +++- arch/arm64/kvm/sys_regs.c | 10 + arch/arm64/kvm/trace.h| 105 ++ 5 files changed, 168 insertions(+), 1 deletion(-) diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 6df47c1..a939a4e 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -323,6 +323,8 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) { + trace_kvm_set_guest_debug(vcpu, dbg-control); + if (dbg-control ~KVM_GUESTDBG_VALID_MASK) return -EINVAL; diff --git a/arch/arm/kvm/trace.h b/arch/arm/kvm/trace.h index 0ec3539..3e346a6 100644 --- a/arch/arm/kvm/trace.h +++ b/arch/arm/kvm/trace.h @@ -317,6 +317,23 @@ TRACE_EVENT(kvm_toggle_cache, __entry-now ? on : off) ); +TRACE_EVENT(kvm_set_guest_debug, + TP_PROTO(struct kvm_vcpu *vcpu, __u32 guest_debug), + TP_ARGS(vcpu, guest_debug), + + TP_STRUCT__entry( + __field(struct kvm_vcpu *, vcpu) + __field(__u32, guest_debug) + ), + + TP_fast_assign( + __entry-vcpu = vcpu; + __entry-guest_debug = guest_debug; + ), + + TP_printk(vcpu: %p, flags: 0x%08x, __entry-vcpu, __entry-guest_debug) +); + #endif /* _TRACE_KVM_H */ #undef TRACE_INCLUDE_PATH diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index 3c0daae..97204b5 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -24,6 +24,8 @@ #include asm/kvm_arm.h #include asm/kvm_emulate.h +#include trace.h + /* These are the bits of MDSCR_EL1 we may manipulate */ #define MDSCR_EL1_DEBUG_MASK (DBG_MDSCR_SS | \ DBG_MDSCR_KDE | \ @@ -46,11 +48,17 @@ static DEFINE_PER_CPU(u32, mdcr_el2); static void save_guest_debug_regs(struct kvm_vcpu *vcpu) { vcpu-arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1); + + trace_kvm_arm_set_dreg32(Saved MDSCR_EL1, + vcpu-arch.guest_debug_preserved.mdscr_el1); } static void restore_guest_debug_regs(struct kvm_vcpu *vcpu) { vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu-arch.guest_debug_preserved.mdscr_el1; + + trace_kvm_arm_set_dreg32(Restored MDSCR_EL1, + vcpu_sys_reg(vcpu, MDSCR_EL1)); } /** @@ -92,6 +100,8 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) { bool trap_debug = !(vcpu-arch.debug_flags KVM_ARM64_DEBUG_DIRTY); + trace_kvm_arm_setup_debug(vcpu, vcpu-guest_debug); + vcpu-arch.mdcr_el2 = __this_cpu_read(mdcr_el2) MDCR_EL2_HPMN_MASK; vcpu-arch.mdcr_el2 |= (MDCR_EL2_TPM | MDCR_EL2_TPMCR | @@ -121,6 +131,8 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) vcpu_sys_reg(vcpu, MDSCR_EL1) = ~DBG_MDSCR_SS; } + trace_kvm_arm_set_dreg32(SPSR_EL2, *vcpu_cpsr(vcpu)); + /* * HW Break/Watch points * @@ -137,16 +149,29 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) vcpu-arch.debug_ptr = vcpu-arch.external_debug_state; vcpu-arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; trap_debug = true; + + trace_kvm_arm_set_regset(BKPTS, get_num_brps(), + vcpu-arch.debug_ptr-dbg_bcr[0], + vcpu-arch.debug_ptr-dbg_bvr[0]); + + trace_kvm_arm_set_regset(WAPTS, get_num_wrps(), + vcpu-arch.debug_ptr-dbg_wcr[0], + vcpu-arch.debug_ptr-dbg_wvr[0]); } } /* Trap debug register access */ if (trap_debug) vcpu-arch.mdcr_el2 |= MDCR_EL2_TDA; + + trace_kvm_arm_set_dreg32(MDCR_EL2, vcpu-arch.mdcr_el2); + trace_kvm_arm_set_dreg32(MDSCR_EL1, vcpu_sys_reg(vcpu,
[PATCH v5 11/12] KVM: arm64: enable KVM_CAP_SET_GUEST_DEBUG
Finally advertise the KVM capability for SET_GUEST_DEBUG. Once arm support is added this check can be moved to the common kvm_vm_ioctl_check_extension() code. Signed-off-by: Alex Bennée alex.ben...@linaro.org Acked-by: Christoffer Dall christoffer.d...@linaro.org --- v3: - separated capability check from previous patches - moved into arm64 specific ioctl handler. v4: - add a-b-tag --- arch/arm64/kvm/reset.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 21d5a62..88e5331 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -76,6 +76,9 @@ int kvm_arch_dev_ioctl_check_extension(long ext) case KVM_CAP_GUEST_DEBUG_HW_WPS: r = get_num_wrps(); break; + case KVM_CAP_SET_GUEST_DEBUG: + r = 1; + break; default: r = 0; } -- 2.4.1 ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
[PATCH v5 00/12] KVM Guest Debug support for arm64
Here is V5 of the KVM Guest Debug support for arm64. The changes are fairly minimal from the last round: - dropped KVM_GUESTDBG_USE_SW/HW_BP unifying patch (ABI break) - new comment patch to fix comments in hyp.S (also sent separately) - simplified singlestep code (no longer needs to preserve pstate) - don't set MDSCR_EL1.KDE (not needed) For full details see the changelog on each of the patches. GIT Repos: The patches for this series are based off v4.1-rc5 and can be found at: https://git.linaro.org/people/alex.bennee/linux.git branch: guest-debug/4.1-rc5-v5 While adding debug exception injection support into QEMU I ran into problem with GDB in the guest which relies on working single step support. So while guest SW BKPTs get delivered (and HW BKPTs if the host is not using them) GDB tends to get confused as it tries to single step. If the host isn't doing any debugging of the guest then everything works as normal. The actual solution would be to fully emulate single step in QEMU by creating a new debug event when the guest sets MDSCR_EL1.SS. QEMU would then need to ensure the correct position is reached while honouring the guests setting of MDSCR_EL1.KDE. However this would be a bunch of potentially hairy new code so I've left this as an exercise for a future patch series. https://github.com/stsquad/qemu branch: kvm/guest-debug-v5 Alex Bennée (12): KVM: add comments for kvm_debug_exit_arch struct KVM: arm64: fix misleading comments in save/restore KVM: arm64: guest debug, define API headers KVM: arm: guest debug, add stub KVM_SET_GUEST_DEBUG ioctl KVM: arm: introduce kvm_arm_init/setup/clear_debug KVM: arm64: guest debug, add SW break point support KVM: arm64: guest debug, add support for single-step KVM: arm64: re-factor hyp.S debug register code KVM: arm64: introduce vcpu-arch.debug_ptr KVM: arm64: guest debug, HW assisted debug support KVM: arm64: enable KVM_CAP_SET_GUEST_DEBUG KVM: arm64: add trace points for guest_debug debug Documentation/virtual/kvm/api.txt | 15 +- arch/arm/include/asm/kvm_host.h| 4 + arch/arm/kvm/arm.c | 46 ++- arch/arm/kvm/trace.h | 17 + arch/arm64/include/asm/hw_breakpoint.h | 12 + arch/arm64/include/asm/kvm_asm.h | 26 +- arch/arm64/include/asm/kvm_host.h | 29 +- arch/arm64/include/uapi/asm/kvm.h | 20 ++ arch/arm64/kernel/asm-offsets.c| 7 + arch/arm64/kernel/hw_breakpoint.c | 12 - arch/arm64/kvm/Makefile| 2 +- arch/arm64/kvm/debug.c | 194 arch/arm64/kvm/handle_exit.c | 44 +++ arch/arm64/kvm/hyp.S | 551 ++--- arch/arm64/kvm/reset.c | 15 + arch/arm64/kvm/sys_regs.c | 136 ++-- arch/arm64/kvm/trace.h | 105 +++ include/uapi/linux/kvm.h | 5 + 18 files changed, 788 insertions(+), 452 deletions(-) create mode 100644 arch/arm64/kvm/debug.c -- 2.4.1 ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
[PATCH v5 04/12] KVM: arm: guest debug, add stub KVM_SET_GUEST_DEBUG ioctl
This commit adds a stub function to support the KVM_SET_GUEST_DEBUG ioctl. Any unsupported flag will return -EINVAL. For now, only KVM_GUESTDBG_ENABLE is supported, although it won't have any effects. Signed-off-by: Alex Bennée alex.ben...@linaro.org. Reviewed-by: Christoffer Dall christoffer.d...@linaro.org --- v2 - simplified form of the ioctl (stuff will go into setup_debug) v3 - KVM_GUESTDBG_VALID-KVM_GUESTDBG_VALID_MASK - move mask check to the top of function - add ioctl doc header - split capability into separate patch - tweaked commit wording w.r.t return of -EINVAL v4 - add r-b-tag --- Documentation/virtual/kvm/api.txt | 2 +- arch/arm/kvm/arm.c| 23 ++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index c34c32d..ba635c7 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2645,7 +2645,7 @@ handled. 4.87 KVM_SET_GUEST_DEBUG Capability: KVM_CAP_SET_GUEST_DEBUG -Architectures: x86, s390, ppc +Architectures: x86, s390, ppc, arm64 Type: vcpu ioctl Parameters: struct kvm_guest_debug (in) Returns: 0 on success; -1 on error diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index d9631ec..52a1d4d38 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -302,10 +302,31 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) kvm_arm_set_running_vcpu(NULL); } +#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE) + +/** + * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging + * @kvm: pointer to the KVM struct + * @kvm_guest_debug: the ioctl data buffer + * + * This sets up and enables the VM for guest debugging. Userspace + * passes in a control flag to enable different debug types and + * potentially other architecture specific information in the rest of + * the structure. + */ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) { - return -EINVAL; + if (dbg-control ~KVM_GUESTDBG_VALID_MASK) + return -EINVAL; + + if (dbg-control KVM_GUESTDBG_ENABLE) { + vcpu-guest_debug = dbg-control; + } else { + /* If not enabled clear all flags */ + vcpu-guest_debug = 0; + } + return 0; } -- 2.4.1 ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
[PATCH v5 07/12] KVM: arm64: guest debug, add support for single-step
This adds support for single-stepping the guest. To do this we need to manipulate the guests PSTATE.SS and MDSCR_EL1.SS bits which we do in the kvm_arm_setup/clear_debug() so we don't affect the apparent state of the guest. Additionally while the host is debugging the guest we suppress the ability of the guest to single-step itself. Signed-off-by: Alex Bennée alex.ben...@linaro.org --- v2 - Move pstate/mdscr manipulation into C - don't export guest_debug to assembly - add accessor for saved_debug regs - tweak save/restore of mdscr_el1 v3 - don't save PC in debug information struct - rename debug_saved_regs-guest_debug_state - save whole value, only use bits in restore - add save/restore_guest-debug_regs helper functions - simplify commit message for clarity - rm vcpu_debug_saved_reg access fn v4 - added more comments based on suggestions - guest_debug_state-guest_debug_preserved - no point masking restore, we will trap out v5 - more comments - don't bother preserving pstate.ss --- arch/arm/kvm/arm.c| 4 ++- arch/arm64/include/asm/kvm_host.h | 11 arch/arm64/kvm/debug.c| 58 --- arch/arm64/kvm/handle_exit.c | 2 ++ 4 files changed, 70 insertions(+), 5 deletions(-) diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 064c105..9b3ed6d 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -302,7 +302,9 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) kvm_arm_set_running_vcpu(NULL); } -#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP) +#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE |\ + KVM_GUESTDBG_USE_SW_BP | \ + KVM_GUESTDBG_SINGLESTEP) /** * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 7cb99b5..e2db6a6 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -123,6 +123,17 @@ struct kvm_vcpu_arch { * here. */ + /* +* Guest registers we preserve during guest debugging. +* +* These shadow registers are updated by the kvm_handle_sys_reg +* trap handler if the guest accesses or updates them while we +* are using guest debug. +*/ + struct { + u32 mdscr_el1; + } guest_debug_preserved; + /* Don't run the guest */ bool pause; diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index 8d1bfa4..10a6baa 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -19,11 +19,41 @@ #include linux/kvm_host.h +#include asm/debug-monitors.h +#include asm/kvm_asm.h #include asm/kvm_arm.h +#include asm/kvm_emulate.h + +/* These are the bits of MDSCR_EL1 we may manipulate */ +#define MDSCR_EL1_DEBUG_MASK (DBG_MDSCR_SS | \ + DBG_MDSCR_KDE | \ + DBG_MDSCR_MDE) static DEFINE_PER_CPU(u32, mdcr_el2); /** + * save/restore_guest_debug_regs + * + * For some debug operations we need to tweak some guest registers. As + * a result we need to save the state of those registers before we + * make those modifications. This does get confused if the guest + * attempts to control single step while being debugged. It will start + * working again once it is no longer being debugged by the host. + * + * Guest access to MDSCR_EL1 is trapped by the hypervisor and handled + * after we have restored the preserved value to the main context. + */ +static void save_guest_debug_regs(struct kvm_vcpu *vcpu) +{ + vcpu-arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1); +} + +static void restore_guest_debug_regs(struct kvm_vcpu *vcpu) +{ + vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu-arch.guest_debug_preserved.mdscr_el1; +} + +/** * kvm_arm_init_debug - grab what we need for debug * * Currently the sole task of this function is to retrieve the initial @@ -38,7 +68,6 @@ void kvm_arm_init_debug(void) __this_cpu_write(mdcr_el2, kvm_call_hyp(__kvm_get_mdcr_el2)); } - /** * kvm_arm_setup_debug - set up debug related stuff * @@ -73,12 +102,33 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) if (trap_debug) vcpu-arch.mdcr_el2 |= MDCR_EL2_TDA; - /* Trap breakpoints? */ - if (vcpu-guest_debug KVM_GUESTDBG_USE_SW_BP) + /* Is Guest debugging in effect? */ + if (vcpu-guest_debug) { vcpu-arch.mdcr_el2 |= MDCR_EL2_TDE; + + /* Save guest debug state */ + save_guest_debug_regs(vcpu); + + /* +* Single Step (ARM ARM D2.12.3 The software step state +* machine) +* +* If we are doing Single Step we need to manipulate +* MDSCR_EL1.SS and PSTATE.SS. If not we need to +
[PATCH v5 02/12] KVM: arm64: fix misleading comments in save/restore
The elr_el2 and spsr_el2 registers in fact contain the processor state before entry into the hypervisor code. In the case of guest state it could be in either el0 or el1. Signed-off-by: Alex Bennée alex.ben...@linaro.org --- arch/arm64/kvm/hyp.S | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index 5befd01..cb9bdd8 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -50,8 +50,8 @@ stp x29, lr, [x3, #80] mrs x19, sp_el0 - mrs x20, elr_el2// EL1 PC - mrs x21, spsr_el2 // EL1 pstate + mrs x20, elr_el2// PC before hyp entry + mrs x21, spsr_el2 // pstate before hyp entry stp x19, x20, [x3, #96] str x21, [x3, #112] @@ -82,8 +82,8 @@ ldr x21, [x3, #16] msr sp_el0, x19 - msr elr_el2, x20// EL1 PC - msr spsr_el2, x21 // EL1 pstate + msr elr_el2, x20// PC to restore + msr spsr_el2, x21 // pstate to restore add x3, x2, #CPU_XREG_OFFSET(19) ldp x19, x20, [x3] -- 2.4.1 ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
[PATCH v5 06/12] KVM: arm64: guest debug, add SW break point support
This adds support for SW breakpoints inserted by userspace. We do this by trapping all guest software debug exceptions to the hypervisor (MDCR_EL2.TDE). The exit handler sets an exit reason of KVM_EXIT_DEBUG with the kvm_debug_exit_arch structure holding the exception syndrome information. It will be up to userspace to extract the PC (via GET_ONE_REG) and determine if the debug event was for a breakpoint it inserted. If not userspace will need to re-inject the correct exception restart the hypervisor to deliver the debug exception to the guest. Any other guest software debug exception (e.g. single step or HW assisted breakpoints) will cause an error and the VM to be killed. This is addressed by later patches which add support for the other debug types. Signed-off-by: Alex Bennée alex.ben...@linaro.org Reviewed-by: Christoffer Dall christoffer.d...@linaro.org --- v2 - update to use new exit struct - tweak for C setup - do our setup in debug_setup/clear code - fixed up comments v3: - fix spacing in KVM_GUESTDBG_VALID_MASK - fix and clarify wording on kvm_handle_guest_debug - handle error case in kvm_handle_guest_debug - re-word the commit message v4 - rm else leg - add r-b-tag --- Documentation/virtual/kvm/api.txt | 2 +- arch/arm/kvm/arm.c| 2 +- arch/arm64/kvm/debug.c| 3 +++ arch/arm64/kvm/handle_exit.c | 36 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index ba635c7..33c8143 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2667,7 +2667,7 @@ when running. Common control bits are: The top 16 bits of the control field are architecture specific control flags which can include the following: - - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86] + - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86, arm64] - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390] - KVM_GUESTDBG_INJECT_DB: inject DB type exception [x86] - KVM_GUESTDBG_INJECT_BP: inject BP type exception [x86] diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 4a274e1..064c105 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -302,7 +302,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) kvm_arm_set_running_vcpu(NULL); } -#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE) +#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP) /** * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index faf0e1f..8d1bfa4 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -73,6 +73,9 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) if (trap_debug) vcpu-arch.mdcr_el2 |= MDCR_EL2_TDA; + /* Trap breakpoints? */ + if (vcpu-guest_debug KVM_GUESTDBG_USE_SW_BP) + vcpu-arch.mdcr_el2 |= MDCR_EL2_TDE; } void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 524fa25..27f38a9 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -82,6 +82,40 @@ static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run) return 1; } +/** + * kvm_handle_guest_debug - handle a debug exception instruction + * + * @vcpu: the vcpu pointer + * @run: access to the kvm_run structure for results + * + * We route all debug exceptions through the same handler. If both the + * guest and host are using the same debug facilities it will be up to + * userspace to re-inject the correct exception for guest delivery. + * + * @return: 0 (while setting run-exit_reason), -1 for error + */ +static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + u32 hsr = kvm_vcpu_get_hsr(vcpu); + int ret = 0; + + run-exit_reason = KVM_EXIT_DEBUG; + run-debug.arch.hsr = hsr; + + switch (hsr ESR_ELx_EC_SHIFT) { + case ESR_ELx_EC_BKPT32: + case ESR_ELx_EC_BRK64: + break; + default: + kvm_err(%s: un-handled case hsr: %#08x\n, + __func__, (unsigned int) hsr); + ret = -1; + break; + } + + return ret; +} + static exit_handle_fn arm_exit_handlers[] = { [ESR_ELx_EC_WFx]= kvm_handle_wfx, [ESR_ELx_EC_CP15_32]= kvm_handle_cp15_32, @@ -96,6 +130,8 @@ static exit_handle_fn arm_exit_handlers[] = { [ESR_ELx_EC_SYS64] = kvm_handle_sys_reg, [ESR_ELx_EC_IABT_LOW] = kvm_handle_guest_abort, [ESR_ELx_EC_DABT_LOW] = kvm_handle_guest_abort, + [ESR_ELx_EC_BKPT32] = kvm_handle_guest_debug, + [ESR_ELx_EC_BRK64] = kvm_handle_guest_debug, }; static exit_handle_fn kvm_get_exit_handler(struct
[PATCH v4 4/4] target-arm: Add the GICv2m to the virt board
Add a GICv2m device to the virt board to enable MSIs on the generic PCI host controller. We allocate 64 SPIs in the IRQ space for now (this can be increased/decreased later) and map the GICv2m right after the GIC in the memory map. Reviewed-by: Eric Auger eric.au...@linaro.org Signed-off-by: Christoffer Dall christoffer.d...@linaro.org --- Changes since v3: - Rebased on target-arm.next, so moved some definitions to virt.h - Added reviewed-by tag Changes since v2: - Factored out changes to GIC DT node to previous patch. - Renamed QOM type name to arm-gicv2m Changes since v1: - Remove stray merge conflict line - Reworded commmit message. hw/arm/virt.c | 40 +++- include/hw/arm/virt.h | 2 ++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 387dac8..4bb7175 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -70,6 +70,7 @@ typedef struct VirtBoardInfo { int fdt_size; uint32_t clock_phandle; uint32_t gic_phandle; +uint32_t v2m_phandle; } VirtBoardInfo; typedef struct { @@ -109,6 +110,7 @@ static const MemMapEntry a15memmap[] = { /* GIC distributor and CPU interfaces sit inside the CPU peripheral space */ [VIRT_GIC_DIST] = { 0x0800, 0x0001 }, [VIRT_GIC_CPU] ={ 0x0801, 0x0001 }, +[VIRT_GIC_V2M] ={ 0x0802, 0x1000 }, [VIRT_UART] = { 0x0900, 0x1000 }, [VIRT_RTC] ={ 0x0901, 0x1000 }, [VIRT_FW_CFG] = { 0x0902, 0x000a }, @@ -125,6 +127,7 @@ static const int a15irqmap[] = { [VIRT_RTC] = 2, [VIRT_PCIE] = 3, /* ... to 6 */ [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */ +[VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */ }; static VirtBoardInfo machines[] = { @@ -300,9 +303,21 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) } } -static void fdt_add_gic_node(VirtBoardInfo *vbi) +static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi) { +vbi-v2m_phandle = qemu_fdt_alloc_phandle(vbi-fdt); +qemu_fdt_add_subnode(vbi-fdt, /intc/v2m); +qemu_fdt_setprop_string(vbi-fdt, /intc/v2m, compatible, +arm,gic-v2m-frame); +qemu_fdt_setprop(vbi-fdt, /intc/v2m, msi-controller, NULL, 0); +qemu_fdt_setprop_sized_cells(vbi-fdt, /intc/v2m, reg, + 2, vbi-memmap[VIRT_GIC_V2M].base, + 2, vbi-memmap[VIRT_GIC_V2M].size); +qemu_fdt_setprop_cell(vbi-fdt, /intc/v2m, phandle, vbi-v2m_phandle); +} +static void fdt_add_gic_node(VirtBoardInfo *vbi) +{ vbi-gic_phandle = qemu_fdt_alloc_phandle(vbi-fdt); qemu_fdt_setprop_cell(vbi-fdt, /, interrupt-parent, vbi-gic_phandle); @@ -323,6 +338,25 @@ static void fdt_add_gic_node(VirtBoardInfo *vbi) qemu_fdt_setprop_cell(vbi-fdt, /intc, phandle, vbi-gic_phandle); } +static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic) +{ +int i; +int irq = vbi-irqmap[VIRT_GIC_V2M]; +DeviceState *dev; + +dev = qdev_create(NULL, arm-gicv2m); +sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vbi-memmap[VIRT_GIC_V2M].base); +qdev_prop_set_uint32(dev, base-spi, irq); +qdev_prop_set_uint32(dev, num-spi, NUM_GICV2M_SPIS); +qdev_init_nofail(dev); + +for (i = 0; i NUM_GICV2M_SPIS; i++) { +sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, pic[irq + i]); +} + +fdt_add_v2m_gic_node(vbi); +} + static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic) { /* We create a standalone GIC v2 */ @@ -373,6 +407,8 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic) } fdt_add_gic_node(vbi); + +create_v2m(vbi, pic); } static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic) @@ -676,6 +712,8 @@ static void create_pcie(const VirtBoardInfo *vbi, qemu_irq *pic) qemu_fdt_setprop_cells(vbi-fdt, nodename, bus-range, 0, nr_pcie_buses - 1); +qemu_fdt_setprop_cells(vbi-fdt, nodename, msi-parent, vbi-v2m_phandle); + qemu_fdt_setprop_sized_cells(vbi-fdt, nodename, reg, 2, base_ecam, 2, size_ecam); qemu_fdt_setprop_sized_cells(vbi-fdt, nodename, ranges, diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h index ceec8b3..003ef29 100644 --- a/include/hw/arm/virt.h +++ b/include/hw/arm/virt.h @@ -32,6 +32,7 @@ #include qemu-common.h +#define NUM_GICV2M_SPIS 64 #define NUM_VIRTIO_TRANSPORTS 32 #define ARCH_TIMER_VIRT_IRQ 11 @@ -53,6 +54,7 @@ enum { VIRT_PCIE_MMIO, VIRT_PCIE_PIO, VIRT_PCIE_ECAM, +VIRT_GIC_V2M, }; typedef struct MemMapEntry { -- 2.1.2.330.g565301e.dirty ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
[PATCH v4 3/4] target-arm: Extend the gic node properties
In preparation for adding the GICv2m which requires address specifiers and is a subnode of the gic, we extend the gic DT definition to specify the #address-cells and #size-cells properties and add an empty ranges property properties of the DT node, since this is required to add the v2m node as a child of the gic node. Note that we must also expand the irq-map to reference the gic with the right address-cells as a consequence of this change. Reviewed-by: Eric Auger eric.au...@linaro.org Suggested-by: Shanker Donthineni shank...@codeaurora.org Signed-off-by: Christoffer Dall christoffer.d...@linaro.org --- Changes since v3: - Rewrote patch and changed authorship and tags accordingly - Fixed spelling in commit message Changes since v2: - New separate patch factoring out changes to existing code for eased bisectability in case we broke something - The above fixes the issue with non-MSI compatible guests. hw/arm/virt.c | 11 +++ 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index e5235ef..387dac8 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -317,6 +317,9 @@ static void fdt_add_gic_node(VirtBoardInfo *vbi) 2, vbi-memmap[VIRT_GIC_DIST].size, 2, vbi-memmap[VIRT_GIC_CPU].base, 2, vbi-memmap[VIRT_GIC_CPU].size); +qemu_fdt_setprop_cell(vbi-fdt, /intc, #address-cells, 0x2); +qemu_fdt_setprop_cell(vbi-fdt, /intc, #size-cells, 0x2); +qemu_fdt_setprop(vbi-fdt, /intc, ranges, NULL, 0); qemu_fdt_setprop_cell(vbi-fdt, /intc, phandle, vbi-gic_phandle); } @@ -585,7 +588,7 @@ static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle, int first_irq, const char *nodename) { int devfn, pin; -uint32_t full_irq_map[4 * 4 * 8] = { 0 }; +uint32_t full_irq_map[4 * 4 * 10] = { 0 }; uint32_t *irq_map = full_irq_map; for (devfn = 0; devfn = 0x18; devfn += 0x8) { @@ -598,13 +601,13 @@ static void create_pcie_irq_map(const VirtBoardInfo *vbi, uint32_t gic_phandle, uint32_t map[] = { devfn 8, 0, 0, /* devfn */ pin + 1,/* PCI pin */ -gic_phandle, irq_type, irq_nr, irq_level }; /* GIC irq */ +gic_phandle, 0, 0, irq_type, irq_nr, irq_level }; /* GIC irq */ /* Convert map to big endian */ -for (i = 0; i 8; i++) { +for (i = 0; i 10; i++) { irq_map[i] = cpu_to_be32(map[i]); } -irq_map += 8; +irq_map += 10; } } -- 2.1.2.330.g565301e.dirty ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
[PATCH v4 2/4] arm_gicv2m: Add GICv2m widget to support MSIs
The ARM GICv2m widget is a little device that handles MSI interrupt writes to a trigger register and ties them to a range of interrupt lines wires to the GIC. It has a few status/id registers and the interrupt wires, and that's about it. A board instantiates the device by setting the base SPI number and number SPIs for the frame. The base-spi parameter is indexed in the SPI number space only, so base-spi == 0, means IRQ number 32. When a device (the PCI host controller) writes to the trigger register, the payload is the GIC IRQ number, so we have to subtract 32 from that and then index into our frame of SPIs. When instantiating a GICv2m device, tell PCI that we have instantiated something that can deal with MSIs. We rely on the board actually wiring up the GICv2m to the PCI host controller. Reviewed-by: Eric Auger eric.au...@linaro.org Signed-off-by: Christoffer Dall christoffer.d...@linaro.org --- Changes since v3: - Added reviewed-by tag Changes since v2: - Renamed QOM type to arm-gicv2m Changes since v1: - Check that writes to MSI_SETSPI are within the lower boundary as well - Move gicv2m to common-obj in Makefile - Separate switch case and comment for impdef regs - Clearly document what is emulated - Allow 16 bit lower accesses to MSI_SETSPI regs - Fix commit grammar error - Remove stray pixman commit hw/intc/Makefile.objs | 1 + hw/intc/arm_gicv2m.c | 190 ++ 2 files changed, 191 insertions(+) create mode 100644 hw/intc/arm_gicv2m.c diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 843864a..092d8a8 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -11,6 +11,7 @@ common-obj-$(CONFIG_SLAVIO) += slavio_intctl.o common-obj-$(CONFIG_IOAPIC) += ioapic_common.o common-obj-$(CONFIG_ARM_GIC) += arm_gic_common.o common-obj-$(CONFIG_ARM_GIC) += arm_gic.o +common-obj-$(CONFIG_ARM_GIC) += arm_gicv2m.o common-obj-$(CONFIG_OPENPIC) += openpic.o obj-$(CONFIG_APIC) += apic.o apic_common.o diff --git a/hw/intc/arm_gicv2m.c b/hw/intc/arm_gicv2m.c new file mode 100644 index 000..9f84f72 --- /dev/null +++ b/hw/intc/arm_gicv2m.c @@ -0,0 +1,190 @@ +/* + * GICv2m extension for MSI/MSI-x support with a GICv2-based system + * + * Copyright (C) 2015 Linaro, All rights reserved. + * + * Author: Christoffer Dall christoffer.d...@linaro.org + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see http://www.gnu.org/licenses/. + */ + +/* This file implements an emulated GICv2m widget as described in the ARM + * Server Base System Architecture (SBSA) specification Version 2.2 + * (ARM-DEN-0029 v2.2) pages 35-39 without any optional implementation defined + * identification registers and with a single non-secure MSI register frame. + */ + +#include hw/sysbus.h +#include hw/pci/msi.h + +#define TYPE_ARM_GICV2M arm-gicv2m +#define ARM_GICV2M(obj) OBJECT_CHECK(ARMGICv2mState, (obj), TYPE_ARM_GICV2M) + +#define GICV2M_NUM_SPI_MAX 128 + +#define V2M_MSI_TYPER 0x008 +#define V2M_MSI_SETSPI_NS 0x040 +#define V2M_MSI_IIDR0xFCC +#define V2M_IIDR0 0xFD0 +#define V2M_IIDR11 0xFFC + +#define PRODUCT_ID_QEMU 0x51 /* ASCII code Q */ + +typedef struct ARMGICv2mState { +SysBusDevice parent_obj; + +MemoryRegion iomem; +qemu_irq spi[GICV2M_NUM_SPI_MAX]; + +uint32_t base_spi; +uint32_t num_spi; +} ARMGICv2mState; + +static void gicv2m_set_irq(void *opaque, int irq) +{ +ARMGICv2mState *s = (ARMGICv2mState *)opaque; + +qemu_irq_pulse(s-spi[irq]); +} + +static uint64_t gicv2m_read(void *opaque, hwaddr offset, +unsigned size) +{ +ARMGICv2mState *s = (ARMGICv2mState *)opaque; +uint32_t val; + +if (size != 4) { +qemu_log_mask(LOG_GUEST_ERROR, gicv2m_read: bad size %u\n, size); +return 0; +} + +switch (offset) { +case V2M_MSI_TYPER: +val = (s-base_spi + 32) 16; +val |= s-num_spi; +return val; +case V2M_MSI_IIDR: +/* We don't have any valid implementor so we leave that field as zero + * and we return 0 in the arch revision as per the spec. + */ +return (PRODUCT_ID_QEMU 20); +case V2M_IIDR0 ... V2M_IIDR11: +/* We do not implement any optional identification registers and the + * mandatory MSI_PIDR2 register reads as 0x0, so we
Re: [PATCH V1 4/5] kvm: arm64: Implement ACPI probing code for GICv2
On Thu, May 28, 2015 at 01:34:33AM -0400, Wei Huang wrote: This patches enables ACPI support for KVM virtual GICv2. KVM parses ACPI table for virt GIC related information and initializes resources. Signed-off-by: Alexander Spyridaki a.spyrida...@virtualopensystems.com Signed-off-by: Wei Huang w...@redhat.com --- virt/kvm/arm/vgic-v2.c | 49 - 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c index 711de82..01ce8a3 100644 --- a/virt/kvm/arm/vgic-v2.c +++ b/virt/kvm/arm/vgic-v2.c @@ -264,6 +264,53 @@ int vgic_v2_acpi_probe(struct acpi_madt_generic_interrupt *vgic_acpi, const struct vgic_ops **ops, const struct vgic_params **params) { - return -EINVAL; + struct vgic_params *vgic = vgic_v2_params; + int irq_mode, ret; + + /* IRQ trigger mode */ + irq_mode = (vgic_acpi-flags ACPI_MADT_VGIC_IRQ_MODE) ? + ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE; + vgic-maint_irq = acpi_register_gsi(NULL, vgic_acpi-vgic_interrupt, + irq_mode, ACPI_ACTIVE_HIGH); + if (!vgic-maint_irq) { + kvm_err(Cannot register VGIC ACPI maintenance irq\n); + ret = -ENXIO; + goto out; + } + + /* GICH resource */ + vgic-vctrl_base = ioremap(vgic_acpi-gich_base_address, SZ_8K); + if (!vgic-vctrl_base) { + kvm_err(cannot ioremap GICH memory\n); + ret = -ENOMEM; + goto out; + } + + vgic-nr_lr = readl_relaxed(vgic-vctrl_base + GICH_VTR); + vgic-nr_lr = (vgic-nr_lr 0x3f) + 1; + + ret = create_hyp_io_mappings(vgic-vctrl_base, + vgic-vctrl_base + SZ_8K, + vgic_acpi-gich_base_address); + if (ret) { + kvm_err(Cannot map GICH into hyp\n); + goto out; + } + + vgic-vcpu_base = vgic_acpi-gicv_base_address; + vgic-can_emulate_gicv2 = true; + kvm_register_device_ops(kvm_arm_vgic_v2_ops, KVM_DEV_TYPE_ARM_VGIC_V2); + + kvm_info(GICH base=0x%llx, GICV base=0x%llx, IRQ=%d\n, + (unsigned long long)vgic_acpi-gich_base_address, + (unsigned long long)vgic_acpi-gicv_base_address, + vgic-maint_irq); + + vgic-type = VGIC_V2; we're missing max_gic_vcpus here vgic-max_gic_vcpus = VGIC_V2_MAX_CPUS; + *ops = vgic_v2_ops; + *params = vgic; + +out: + return ret; } #endif /* CONFIG_ACPI */ -- 1.8.3.1 -- 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 ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Re: [PATCH V1 4/5] kvm: arm64: Implement ACPI probing code for GICv2
On 05/29/2015 09:06 AM, Andrew Jones wrote: On Thu, May 28, 2015 at 01:34:33AM -0400, Wei Huang wrote: This patches enables ACPI support for KVM virtual GICv2. KVM parses ACPI table for virt GIC related information and initializes resources. Signed-off-by: Alexander Spyridaki a.spyrida...@virtualopensystems.com Signed-off-by: Wei Huang w...@redhat.com --- virt/kvm/arm/vgic-v2.c | 49 - 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c index 711de82..01ce8a3 100644 --- a/virt/kvm/arm/vgic-v2.c +++ b/virt/kvm/arm/vgic-v2.c @@ -264,6 +264,53 @@ int vgic_v2_acpi_probe(struct acpi_madt_generic_interrupt *vgic_acpi, const struct vgic_ops **ops, const struct vgic_params **params) { -return -EINVAL; +struct vgic_params *vgic = vgic_v2_params; +int irq_mode, ret; + +/* IRQ trigger mode */ +irq_mode = (vgic_acpi-flags ACPI_MADT_VGIC_IRQ_MODE) ? +ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE; +vgic-maint_irq = acpi_register_gsi(NULL, vgic_acpi-vgic_interrupt, +irq_mode, ACPI_ACTIVE_HIGH); +if (!vgic-maint_irq) { +kvm_err(Cannot register VGIC ACPI maintenance irq\n); +ret = -ENXIO; +goto out; +} + +/* GICH resource */ +vgic-vctrl_base = ioremap(vgic_acpi-gich_base_address, SZ_8K); +if (!vgic-vctrl_base) { +kvm_err(cannot ioremap GICH memory\n); +ret = -ENOMEM; +goto out; +} + +vgic-nr_lr = readl_relaxed(vgic-vctrl_base + GICH_VTR); +vgic-nr_lr = (vgic-nr_lr 0x3f) + 1; + +ret = create_hyp_io_mappings(vgic-vctrl_base, + vgic-vctrl_base + SZ_8K, + vgic_acpi-gich_base_address); +if (ret) { +kvm_err(Cannot map GICH into hyp\n); +goto out; +} + +vgic-vcpu_base = vgic_acpi-gicv_base_address; +vgic-can_emulate_gicv2 = true; +kvm_register_device_ops(kvm_arm_vgic_v2_ops, KVM_DEV_TYPE_ARM_VGIC_V2); + +kvm_info(GICH base=0x%llx, GICV base=0x%llx, IRQ=%d\n, + (unsigned long long)vgic_acpi-gich_base_address, + (unsigned long long)vgic_acpi-gicv_base_address, + vgic-maint_irq); + +vgic-type = VGIC_V2; we're missing max_gic_vcpus here vgic-max_gic_vcpus = VGIC_V2_MAX_CPUS; Yes. Will fix in the next spin. -Wei +*ops = vgic_v2_ops; +*params = vgic; + +out: +return ret; } #endif /* CONFIG_ACPI */ -- 1.8.3.1 -- 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 ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
[PATCH v5 3/6] target-arm: kvm - implement software breakpoints
These don't involve messing around with debug registers, just setting the breakpoint instruction in memory. GDB will not use this mechanism if it can't access the memory to write the breakpoint. All the kernel has to do is ensure the hypervisor traps the breakpoint exceptions and returns to userspace. Signed-off-by: Alex Bennée alex.ben...@linaro.org -- v2 - handle debug exit with new hsr exception info - add verbosity to UNIMP message v3 - sync with kvm_cpu_synchronize_state() before checking PC. - use internals.h defines - use env-pc - use proper format types --- target-arm/kvm.c | 88 1 file changed, 76 insertions(+), 12 deletions(-) diff --git a/target-arm/kvm.c b/target-arm/kvm.c index fdd9ba3..c3bad6f 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -510,9 +510,60 @@ void kvm_arch_post_run(CPUState *cs, struct kvm_run *run) { } +/* See v8 ARM ARM D7.2.27 ESR_ELx, Exception Syndrome Register + * + * To minimise translating between kernel and user-space the kernel + * ABI just provides user-space with the full exception syndrome + * register value to be decoded in QEMU. + */ + +static int kvm_handle_debug(CPUState *cs, struct kvm_run *run) +{ +struct kvm_debug_exit_arch *arch_info = run-debug.arch; +int hsr_ec = arch_info-hsr ARM_EL_EC_SHIFT; +ARMCPU *cpu = ARM_CPU(cs); +CPUARMState *env = cpu-env; + +/* Ensure PC is synchronised */ +kvm_cpu_synchronize_state(cs); + +switch (hsr_ec) { +case EC_AA64_BKPT: +if (kvm_find_sw_breakpoint(cs, env-pc)) { +return true; +} +break; +default: +error_report(%s: unhandled debug exit (%PRIx32, %PRIx64)\n, + __func__, arch_info-hsr, env-pc); +} + +/* If we don't handle this it could be it really is for the + guest to handle */ +qemu_log_mask(LOG_UNIMP, + %s: re-injecting exception not yet implemented + (0x%PRIx32, %PRIx64)\n, + __func__, hsr_ec, env-pc); + +return false; +} + int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) { -return 0; +int ret = 0; + +switch (run-exit_reason) { +case KVM_EXIT_DEBUG: +if (kvm_handle_debug(cs, run)) { +ret = EXCP_DEBUG; +} /* otherwise return to guest */ +break; +default: +qemu_log_mask(LOG_UNIMP, %s: un-handled exit reason %d\n, + __func__, run-exit_reason); +break; +} +return ret; } bool kvm_arch_stop_on_emulation_error(CPUState *cs) @@ -537,14 +588,33 @@ int kvm_arch_on_sigbus(int code, void *addr) void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg) { -qemu_log_mask(LOG_UNIMP, %s: not implemented\n, __func__); +if (kvm_sw_breakpoints_active(cs)) { +dbg-control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP; +} } -int kvm_arch_insert_sw_breakpoint(CPUState *cs, - struct kvm_sw_breakpoint *bp) +/* C6.6.29 BRK instruction */ +int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) { -qemu_log_mask(LOG_UNIMP, %s: not implemented\n, __func__); -return -EINVAL; +static const uint32_t brk = 0xd420; + +if (cpu_memory_rw_debug(cs, bp-pc, (uint8_t *)bp-saved_insn, 4, 0) || +cpu_memory_rw_debug(cs, bp-pc, (uint8_t *)brk, 4, 1)) { +return -EINVAL; +} +return 0; +} + +int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp) +{ +static uint32_t brk; + +if (cpu_memory_rw_debug(cs, bp-pc, (uint8_t *)brk, 4, 0) || +brk != 0xd420 || +cpu_memory_rw_debug(cs, bp-pc, (uint8_t *)bp-saved_insn, 4, 1)) { +return -EINVAL; +} +return 0; } int kvm_arch_insert_hw_breakpoint(target_ulong addr, @@ -561,12 +631,6 @@ int kvm_arch_remove_hw_breakpoint(target_ulong addr, return -EINVAL; } -int kvm_arch_remove_sw_breakpoint(CPUState *cs, - struct kvm_sw_breakpoint *bp) -{ -qemu_log_mask(LOG_UNIMP, %s: not implemented\n, __func__); -return -EINVAL; -} void kvm_arch_remove_all_hw_breakpoints(void) { -- 2.4.1 ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
[PATCH v5 1/6] linux-headers: sync from my kernel tree (DEV)
I assume I'll properly merge the KVM Headers direct from Linux when the kernel side is upstream. These headers came from: https://git.linaro.org/people/alex.bennee/linux.git/shortlog/refs/heads/guest-debug/4.1-rc5-v5 Signed-off-by: Alex Bennée alex.ben...@linaro.org --- v2 - update ABI to include -far v3 - update with latest 4.1-rc1 headers v4 - update to v4 headers v5 - update to v5 headers --- include/standard-headers/linux/virtio_balloon.h | 28 +++- include/standard-headers/linux/virtio_blk.h | 8 +- include/standard-headers/linux/virtio_ids.h | 1 + include/standard-headers/linux/virtio_input.h | 76 +++ include/standard-headers/linux/virtio_ring.h| 2 +- linux-headers/asm-arm/kvm.h | 9 +- linux-headers/asm-arm64/kvm.h | 29 - linux-headers/asm-mips/kvm.h| 164 +++- linux-headers/asm-s390/kvm.h| 4 + linux-headers/asm-x86/hyperv.h | 2 + linux-headers/linux/kvm.h | 71 +- linux-headers/linux/vfio.h | 2 + 12 files changed, 325 insertions(+), 71 deletions(-) create mode 100644 include/standard-headers/linux/virtio_input.h diff --git a/include/standard-headers/linux/virtio_balloon.h b/include/standard-headers/linux/virtio_balloon.h index 799376d..88ada1d 100644 --- a/include/standard-headers/linux/virtio_balloon.h +++ b/include/standard-headers/linux/virtio_balloon.h @@ -25,6 +25,7 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ +#include standard-headers/linux/types.h #include standard-headers/linux/virtio_ids.h #include standard-headers/linux/virtio_config.h @@ -51,9 +52,32 @@ struct virtio_balloon_config { #define VIRTIO_BALLOON_S_MEMTOT 5 /* Total amount of memory */ #define VIRTIO_BALLOON_S_NR 6 +/* + * Memory statistics structure. + * Driver fills an array of these structures and passes to device. + * + * NOTE: fields are laid out in a way that would make compiler add padding + * between and after fields, so we have to use compiler-specific attributes to + * pack it, to disable this padding. This also often causes compiler to + * generate suboptimal code. + * + * We maintain this statistics structure format for backwards compatibility, + * but don't follow this example. + * + * If implementing a similar structure, do something like the below instead: + * struct virtio_balloon_stat { + * __virtio16 tag; + * uint8_t reserved[6]; + * __virtio64 val; + * }; + * + * In other words, add explicit reserved fields to align field and + * structure boundaries at field size, avoiding compiler padding + * without the packed attribute. + */ struct virtio_balloon_stat { - uint16_t tag; - uint64_t val; + __virtio16 tag; + __virtio64 val; } QEMU_PACKED; #endif /* _LINUX_VIRTIO_BALLOON_H */ diff --git a/include/standard-headers/linux/virtio_blk.h b/include/standard-headers/linux/virtio_blk.h index 12016b4..cd601f4 100644 --- a/include/standard-headers/linux/virtio_blk.h +++ b/include/standard-headers/linux/virtio_blk.h @@ -58,7 +58,7 @@ struct virtio_blk_config { uint32_t size_max; /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */ uint32_t seg_max; - /* geometry the device (if VIRTIO_BLK_F_GEOMETRY) */ + /* geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */ struct virtio_blk_geometry { uint16_t cylinders; uint8_t heads; @@ -117,7 +117,11 @@ struct virtio_blk_config { #define VIRTIO_BLK_T_BARRIER 0x8000 #endif /* !VIRTIO_BLK_NO_LEGACY */ -/* This is the first element of the read scatter-gather list. */ +/* + * This comes first in the read scatter-gather list. + * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated, + * this is the first element of the read scatter-gather list. + */ struct virtio_blk_outhdr { /* VIRTIO_BLK_T* */ __virtio32 type; diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard-headers/linux/virtio_ids.h index 284fc3a..5f60aa4 100644 --- a/include/standard-headers/linux/virtio_ids.h +++ b/include/standard-headers/linux/virtio_ids.h @@ -39,5 +39,6 @@ #define VIRTIO_ID_9P 9 /* 9p virtio console */ #define VIRTIO_ID_RPROC_SERIAL 11 /* virtio remoteproc serial link */ #define VIRTIO_ID_CAIF12 /* Virtio caif */ +#define VIRTIO_ID_INPUT18 /* virtio input */ #endif /* _LINUX_VIRTIO_IDS_H */ diff --git a/include/standard-headers/linux/virtio_input.h b/include/standard-headers/linux/virtio_input.h new file mode 100644 index 000..a98a797 --- /dev/null +++ b/include/standard-headers/linux/virtio_input.h @@ -0,0 +1,76 @@ +#ifndef _LINUX_VIRTIO_INPUT_H +#define _LINUX_VIRTIO_INPUT_H +/* This header
[PATCH v5 2/6] target-arm: kvm64: introduce kvm_arm_init_debug()
As we haven't always had guest debug support we need to probe for it. Additionally we don't do this in the start-up capability code so we don't fall over on old kernels. Signed-off-by: Alex Bennée alex.ben...@linaro.org --- target-arm/kvm64.c | 18 ++ 1 file changed, 18 insertions(+) diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c index 93c1ca8..61592d2 100644 --- a/target-arm/kvm64.c +++ b/target-arm/kvm64.c @@ -25,6 +25,22 @@ #include internals.h #include hw/arm/arm.h +static bool have_guest_debug; + +/** + * kvm_arm_init_debug() + * @cs: CPUState + * + * Check for guest debug capabilities. + * + */ +static void kvm_arm_init_debug(CPUState *cs) +{ +have_guest_debug = kvm_check_extension(cs-kvm_state, + KVM_CAP_SET_GUEST_DEBUG); +return; +} + static inline void set_feature(uint64_t *features, int feature) { *features |= 1ULL feature; @@ -107,6 +123,8 @@ int kvm_arch_init_vcpu(CPUState *cs) return ret; } +kvm_arm_init_debug(cs); + return kvm_arm_init_cpreg_list(cpu); } -- 2.4.1 ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
[PATCH v5 0/6] QEMU support for KVM Guest Debug on arm64
Hi, You may be wondering what happened to v3 and v4. They do exist but they didn't change much from the the original patches as I've been mostly looking the kernel side of the equation. So in summary the changes are: - updates to the kernel ABI - don't fall over on kernels without debug support - better logging, syncing and use of internals.h - debug exception re-injection for guest events* More detailed changelogs are attached to each patch. * see https://lists.cs.columbia.edu/pipermail/kvmarm/2015-May/014807.html GIT Repos: The patch series is based off a recent master and can be found at: https://github.com/stsquad/qemu branch: kvm/guest-debug-v5 The kernel patches for this series are based off a v4.1-rc5-v5 and can be found at: https://git.linaro.org/people/alex.bennee/linux.git branch: guest-debug/4.1-rc5-v5 Alex Bennée (6): linux-headers: sync from my kernel tree (DEV) target-arm: kvm64: introduce kvm_arm_init_debug() target-arm: kvm - implement software breakpoints target-arm: kvm - support for single step target-arm: kvm - add support for HW assisted debug target-arm: kvm - re-inject guest debug exceptions include/standard-headers/linux/virtio_balloon.h | 28 ++- include/standard-headers/linux/virtio_blk.h | 8 +- include/standard-headers/linux/virtio_ids.h | 1 + include/standard-headers/linux/virtio_input.h | 76 ++ include/standard-headers/linux/virtio_ring.h| 2 +- linux-headers/asm-arm/kvm.h | 9 +- linux-headers/asm-arm64/kvm.h | 29 ++- linux-headers/asm-mips/kvm.h| 164 +++- linux-headers/asm-s390/kvm.h| 4 + linux-headers/asm-x86/hyperv.h | 2 + linux-headers/linux/kvm.h | 71 +- linux-headers/linux/vfio.h | 2 + target-arm/cpu.h| 1 + target-arm/helper-a64.c | 17 +- target-arm/internals.h | 1 + target-arm/kvm.c| 137 -- target-arm/kvm64.c | 318 target-arm/kvm_arm.h| 21 ++ 18 files changed, 790 insertions(+), 101 deletions(-) create mode 100644 include/standard-headers/linux/virtio_input.h -- 2.4.1 ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Re: [PATCH v2] arm/arm64: KVM: Properly account for guest CPU time
On 05/28/2015 11:49 AM, Christoffer Dall wrote: Until now we have been calling kvm_guest_exit after re-enabling interrupts when we come back from the guest, but this has the unfortunate effect that CPU time accounting done in the context of timer interrupts occurring while the guest is running doesn't properly notice that the time since the last tick was spent in the guest. Inspired by the comment in the x86 code, move the kvm_guest_exit() call below the local_irq_enable() call and change __kvm_guest_exit() to kvm_guest_exit(), because we are now calling this function with interrupts enabled. We have to now explicitly disable preemption and not enable preemption before we've called kvm_guest_exit(), since otherwise we could be preempted and everything happening before we eventually get scheduled again would be accounted for as guest time. At the same time, move the trace_kvm_exit() call outside of the atomic section, since there is no reason for us to do that with interrupts disabled. Signed-off-by: Christoffer Dall christoffer.d...@linaro.org --- This patch is based on kvm/queue, because it has the kvm_guest_enter/exit rework recently posted by Christian Borntraeger. I hope I got the logic of this right, there were 2 slightly worrying facts about this: First, we now enable and disable and enable interrupts on each exit path, but I couldn't see any performance overhead on hackbench - yes the only benchmark we care about. Second, looking at the ppc and mips code, they seem to also call kvm_guest_exit() before enabling interrupts, so I don't understand how guest CPU time accounting works on those architectures. Changes since v1: - Tweak comment and commit text based on Marc's feedback. - Explicitly disable preemption and enable it only after kvm_guest_exit(). arch/arm/kvm/arm.c | 21 + 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index e41cb11..fe8028d 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -532,6 +532,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) kvm_vgic_flush_hwstate(vcpu); kvm_timer_flush_hwstate(vcpu); + preempt_disable(); local_irq_disable(); /* @@ -544,6 +545,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) if (ret = 0 || need_new_vmid_gen(vcpu-kvm)) { local_irq_enable(); + preempt_enable(); kvm_timer_sync_hwstate(vcpu); kvm_vgic_sync_hwstate(vcpu); continue; @@ -559,8 +561,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) ret = kvm_call_hyp(__kvm_vcpu_run, vcpu); vcpu-mode = OUTSIDE_GUEST_MODE; - __kvm_guest_exit(); - trace_kvm_exit(kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu)); + /* + * Back from guest + */ + /* * We may have taken a host interrupt in HYP mode (ie * while executing the guest). This interrupt is still @@ -574,8 +578,17 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) local_irq_enable(); /* - * Back from guest - */ + * We do local_irq_enable() before calling kvm_guest_exit() so + * that if a timer interrupt hits while running the guest we + * account that tick as being spent in the guest. We enable + * preemption after calling kvm_guest_exit() so that if we get + * preempted we make sure ticks after that is not counted as + * guest time. + */ + kvm_guest_exit(); + trace_kvm_exit(kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu)); + preempt_enable(); + kvm_timer_sync_hwstate(vcpu); kvm_vgic_sync_hwstate(vcpu); Hi Christoffer, so currently we take a snap shot when we enter the guest (tsk-vtime_snap) and upon exit add the time we spent in the guest and update accrued time, which appears correct. With this patch it appears that interrupts running in host mode are accrued to Guest time, and additional preemption latency is added. Thanks, - Mario ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm