From: Christoffer Dall <christoffer.dall@arm.com> To: kvmarm@lists.cs.columbia.edu Cc: "Daniel P. Berrangé" <berrange@redhat.com>, "Marc Zyngier" <maz@kernel.org>, "Stefan Hajnoczi" <stefanha@redhat.com>, "Heinrich Schuchardt" <xypron.glpk@gmx.de>, linux-arm-kernel@lists.infradead.org Subject: [kvmtool v3 4/5] arm: Handle exits from undecoded load/store instructions Date: Fri, 11 Oct 2019 13:07:08 +0200 [thread overview] Message-ID: <20191011110709.2764-5-christoffer.dall@arm.com> (raw) In-Reply-To: <20191011110709.2764-1-christoffer.dall@arm.com> KVM occasionally encounters guests that attempt to access memory outside the registered RAM memory slots using instructions that don't provide decoding information in the ESR_EL2 (the ISV bit is not set), and historically this has led to the kernel printing a confusing error message in dmesg and returning -ENOYSYS from KVM_RUN. KVM/Arm now has KVM_CAP_ARM_NISV_TO_USER, which can be enabled from userspace, and which allows us to handle this with a little bit more helpful information to the user. For example, we can at least tell the user if the guest just hit a hole in the guest's memory map, or if this appeared to be an attempt at doing MMIO. Signed-off-by: Christoffer Dall <christoffer.dall@arm.com> --- arm/kvm-cpu.c | 20 +++++++++++++++++++- arm/kvm.c | 8 ++++++++ include/kvm/kvm.h | 1 + kvm.c | 1 + mmio.c | 11 +++++++++++ 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/arm/kvm-cpu.c b/arm/kvm-cpu.c index 7780251..25bd3ed 100644 --- a/arm/kvm-cpu.c +++ b/arm/kvm-cpu.c @@ -136,7 +136,25 @@ void kvm_cpu__delete(struct kvm_cpu *vcpu) bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu) { - return false; + switch (vcpu->kvm_run->exit_reason) { + case KVM_EXIT_ARM_NISV: { + u64 phys_addr = vcpu->kvm_run->arm_nisv.fault_ipa; + + if (!arm_addr_in_ioport_region(phys_addr) && + !kvm__mmio_exists(vcpu, phys_addr)) + die("Guest accessed memory outside RAM and IO ranges"); + + /* + * We cannot fetch and decode instructions from a KVM guest, + * which used a load/store instruction that doesn't get + * decoded in the ESR towards an I/O device, so we have no + * choice but to exit to the user with an error. + */ + die("Guest accessed I/O device with unsupported load/store instruction"); + } + default: + return false; + } } void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu) diff --git a/arm/kvm.c b/arm/kvm.c index 1f85fc6..2572ac2 100644 --- a/arm/kvm.c +++ b/arm/kvm.c @@ -59,6 +59,8 @@ void kvm__arch_set_cmdline(char *cmdline, bool video) void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size) { + struct kvm_enable_cap enable_cap = { .flags = 0 }; + /* * Allocate guest memory. We must align our buffer to 64K to * correlate with the maximum guest page size for virtio-mmio. @@ -83,6 +85,12 @@ void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size) madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size, MADV_HUGEPAGE); + if (kvm__supports_extension(kvm, KVM_CAP_ARM_NISV_TO_USER)) { + enable_cap.cap = KVM_CAP_ARM_NISV_TO_USER; + if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &enable_cap) < 0) + die("unable to enable NISV_TO_USER capability"); + } + /* Create the virtual GIC. */ if (gic__create(kvm, kvm->cfg.arch.irqchip)) die("Failed to create virtual GIC"); diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h index 7a73818..05d90ee 100644 --- a/include/kvm/kvm.h +++ b/include/kvm/kvm.h @@ -107,6 +107,7 @@ bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u8 is_write); int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr, enum kvm_mem_type type); +bool kvm__mmio_exists(struct kvm_cpu *vcpu, u64 phys_addr); static inline int kvm__register_ram(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr) { diff --git a/kvm.c b/kvm.c index 57c4ff9..03ec43f 100644 --- a/kvm.c +++ b/kvm.c @@ -55,6 +55,7 @@ const char *kvm_exit_reasons[] = { #ifdef CONFIG_PPC64 DEFINE_KVM_EXIT_REASON(KVM_EXIT_PAPR_HCALL), #endif + DEFINE_KVM_EXIT_REASON(KVM_EXIT_ARM_NISV), }; static int pause_event; diff --git a/mmio.c b/mmio.c index 61e1d47..2ab7fa7 100644 --- a/mmio.c +++ b/mmio.c @@ -139,3 +139,14 @@ bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u return true; } + +bool kvm__mmio_exists(struct kvm_cpu *vcpu, u64 phys_addr) +{ + struct mmio_mapping *mmio; + + br_read_lock(vcpu->kvm); + mmio = mmio_search(&mmio_tree, phys_addr, 1); + br_read_unlock(vcpu->kvm); + + return mmio != NULL; +} -- 2.18.0 _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
WARNING: multiple messages have this Message-ID (diff)
From: Christoffer Dall <christoffer.dall@arm.com> To: kvmarm@lists.cs.columbia.edu Cc: "Peter Maydell" <peter.maydell@linaro.org>, "Daniel P. Berrangé" <berrange@redhat.com>, "Suzuki K Poulose" <suzuki.poulose@arm.com>, "Marc Zyngier" <maz@kernel.org>, "Christoffer Dall" <christoffer.dall@arm.com>, "James Morse" <james.morse@arm.com>, "Julien Thierry" <julien.thierry.kdev@gmail.com>, "Stefan Hajnoczi" <stefanha@redhat.com>, "Heinrich Schuchardt" <xypron.glpk@gmx.de>, "Alexander Graf" <graf@amazon.com>, linux-arm-kernel@lists.infradead.org Subject: [kvmtool v3 4/5] arm: Handle exits from undecoded load/store instructions Date: Fri, 11 Oct 2019 13:07:08 +0200 [thread overview] Message-ID: <20191011110709.2764-5-christoffer.dall@arm.com> (raw) In-Reply-To: <20191011110709.2764-1-christoffer.dall@arm.com> KVM occasionally encounters guests that attempt to access memory outside the registered RAM memory slots using instructions that don't provide decoding information in the ESR_EL2 (the ISV bit is not set), and historically this has led to the kernel printing a confusing error message in dmesg and returning -ENOYSYS from KVM_RUN. KVM/Arm now has KVM_CAP_ARM_NISV_TO_USER, which can be enabled from userspace, and which allows us to handle this with a little bit more helpful information to the user. For example, we can at least tell the user if the guest just hit a hole in the guest's memory map, or if this appeared to be an attempt at doing MMIO. Signed-off-by: Christoffer Dall <christoffer.dall@arm.com> --- arm/kvm-cpu.c | 20 +++++++++++++++++++- arm/kvm.c | 8 ++++++++ include/kvm/kvm.h | 1 + kvm.c | 1 + mmio.c | 11 +++++++++++ 5 files changed, 40 insertions(+), 1 deletion(-) diff --git a/arm/kvm-cpu.c b/arm/kvm-cpu.c index 7780251..25bd3ed 100644 --- a/arm/kvm-cpu.c +++ b/arm/kvm-cpu.c @@ -136,7 +136,25 @@ void kvm_cpu__delete(struct kvm_cpu *vcpu) bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu) { - return false; + switch (vcpu->kvm_run->exit_reason) { + case KVM_EXIT_ARM_NISV: { + u64 phys_addr = vcpu->kvm_run->arm_nisv.fault_ipa; + + if (!arm_addr_in_ioport_region(phys_addr) && + !kvm__mmio_exists(vcpu, phys_addr)) + die("Guest accessed memory outside RAM and IO ranges"); + + /* + * We cannot fetch and decode instructions from a KVM guest, + * which used a load/store instruction that doesn't get + * decoded in the ESR towards an I/O device, so we have no + * choice but to exit to the user with an error. + */ + die("Guest accessed I/O device with unsupported load/store instruction"); + } + default: + return false; + } } void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu) diff --git a/arm/kvm.c b/arm/kvm.c index 1f85fc6..2572ac2 100644 --- a/arm/kvm.c +++ b/arm/kvm.c @@ -59,6 +59,8 @@ void kvm__arch_set_cmdline(char *cmdline, bool video) void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size) { + struct kvm_enable_cap enable_cap = { .flags = 0 }; + /* * Allocate guest memory. We must align our buffer to 64K to * correlate with the maximum guest page size for virtio-mmio. @@ -83,6 +85,12 @@ void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size) madvise(kvm->arch.ram_alloc_start, kvm->arch.ram_alloc_size, MADV_HUGEPAGE); + if (kvm__supports_extension(kvm, KVM_CAP_ARM_NISV_TO_USER)) { + enable_cap.cap = KVM_CAP_ARM_NISV_TO_USER; + if (ioctl(kvm->vm_fd, KVM_ENABLE_CAP, &enable_cap) < 0) + die("unable to enable NISV_TO_USER capability"); + } + /* Create the virtual GIC. */ if (gic__create(kvm, kvm->cfg.arch.irqchip)) die("Failed to create virtual GIC"); diff --git a/include/kvm/kvm.h b/include/kvm/kvm.h index 7a73818..05d90ee 100644 --- a/include/kvm/kvm.h +++ b/include/kvm/kvm.h @@ -107,6 +107,7 @@ bool kvm__emulate_io(struct kvm_cpu *vcpu, u16 port, void *data, int direction, bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u8 is_write); int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr, enum kvm_mem_type type); +bool kvm__mmio_exists(struct kvm_cpu *vcpu, u64 phys_addr); static inline int kvm__register_ram(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr) { diff --git a/kvm.c b/kvm.c index 57c4ff9..03ec43f 100644 --- a/kvm.c +++ b/kvm.c @@ -55,6 +55,7 @@ const char *kvm_exit_reasons[] = { #ifdef CONFIG_PPC64 DEFINE_KVM_EXIT_REASON(KVM_EXIT_PAPR_HCALL), #endif + DEFINE_KVM_EXIT_REASON(KVM_EXIT_ARM_NISV), }; static int pause_event; diff --git a/mmio.c b/mmio.c index 61e1d47..2ab7fa7 100644 --- a/mmio.c +++ b/mmio.c @@ -139,3 +139,14 @@ bool kvm__emulate_mmio(struct kvm_cpu *vcpu, u64 phys_addr, u8 *data, u32 len, u return true; } + +bool kvm__mmio_exists(struct kvm_cpu *vcpu, u64 phys_addr) +{ + struct mmio_mapping *mmio; + + br_read_lock(vcpu->kvm); + mmio = mmio_search(&mmio_tree, phys_addr, 1); + br_read_unlock(vcpu->kvm); + + return mmio != NULL; +} -- 2.18.0 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2019-10-11 11:07 UTC|newest] Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-10-11 11:07 [PATCH v3 0/2] Improve handling of stage 2 aborts without instruction decode Christoffer Dall 2019-10-11 11:07 ` Christoffer Dall 2019-10-11 11:07 ` [PATCH v3 1/2] KVM: arm/arm64: Allow reporting non-ISV data aborts to userspace Christoffer Dall 2019-10-11 11:07 ` Christoffer Dall 2019-10-11 11:07 ` [PATCH v3 2/2] KVM: arm/arm64: Allow user injection of external data aborts Christoffer Dall 2019-10-11 11:07 ` Christoffer Dall 2019-10-21 20:21 ` Alexander Graf 2019-10-21 20:21 ` Alexander Graf 2019-10-11 11:07 ` [kvmtool v3 3/5] update headers: Update the KVM headers for new Arm fault reporting features Christoffer Dall 2019-10-11 11:07 ` Christoffer Dall 2019-10-11 11:07 ` Christoffer Dall [this message] 2019-10-11 11:07 ` [kvmtool v3 4/5] arm: Handle exits from undecoded load/store instructions Christoffer Dall 2019-10-11 11:07 ` [kvmtool v3 5/5] arm: Inject external data aborts when accessing holes in the memory map Christoffer Dall 2019-10-11 11:07 ` Christoffer Dall 2019-10-20 10:25 ` [PATCH v3 0/2] Improve handling of stage 2 aborts without instruction decode Marc Zyngier 2019-10-20 10:25 ` Marc Zyngier 2019-10-21 13:37 ` Christoffer Dall 2019-10-21 13:37 ` Christoffer Dall 2019-10-21 13:59 ` Marc Zyngier 2019-10-21 13:59 ` Marc Zyngier
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20191011110709.2764-5-christoffer.dall@arm.com \ --to=christoffer.dall@arm.com \ --cc=berrange@redhat.com \ --cc=kvmarm@lists.cs.columbia.edu \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=maz@kernel.org \ --cc=stefanha@redhat.com \ --cc=xypron.glpk@gmx.de \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.