From: Christoffer Dall <cdall@cs.columbia.edu>
To: catalin.marinas@arm.com, android-virt@lists.cs.columbia.edu
Cc: s.raho@virtualopensystems.com, a.motakis@virtualopensystems.com,
c.dall@virtualopensystems.com, kvm@vger.kernel.org,
a.costa@virtualopensystems.com
Subject: [PATCH v3 8/8] ARM: KVM: Handle I/O aborts
Date: Fri, 03 Jun 2011 17:04:22 +0200 [thread overview]
Message-ID: <20110603150422.17011.44777.stgit@ubuntu> (raw)
In-Reply-To: <20110603150318.17011.82777.stgit@ubuntu>
When the guest accesses I/O memory this will create data abort
exceptions and they are handled by decoding the HSR information
(physical address, read/write, length, register) and forwarding reads
and writes to QEMU which performs the device emulation.
This requires changing the general flow somewhat since new calls to run
the VCPU must check if there's a pending MMIO load and perform the write
after QEMU has made the data available.
---
arch/arm/include/asm/kvm_host.h | 1
arch/arm/include/asm/kvm_mmu.h | 1
arch/arm/kvm/arm.c | 11 ++++
arch/arm/kvm/arm_mmu.c | 106 ++++++++++++++++++++++++++++++++++++++-
4 files changed, 115 insertions(+), 4 deletions(-)
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 7f96974..5393e25 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -86,6 +86,7 @@ struct kvm_vcpu_arch {
u32 hpfar; /* Hyp IPA Fault Address Register */
/* IO related fields */
+ bool mmio_sign_extend; /* for byte/halfword loads */
u32 mmio_rd;
/* Misc. fields */
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index a64ab2d..f06f42d 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -40,6 +40,7 @@ void free_hyp_pmds(pgd_t *hyp_pgd);
int kvm_alloc_stage2_pgd(struct kvm *kvm);
void kvm_free_stage2_pgd(struct kvm *kvm);
+int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run);
int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run);
#endif /* __ARM_KVM_MMU_H__ */
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index abed683..d01f234 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -349,6 +349,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
int ret;
for (;;) {
+ if (run->exit_reason == KVM_EXIT_MMIO) {
+ ret = kvm_handle_mmio_return(vcpu, vcpu->run);
+ if (ret)
+ break;
+ }
+
local_irq_save(flags);
ret = __kvm_vcpu_run(vcpu);
local_irq_restore(flags);
@@ -367,8 +373,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
kvm_err(ret, "Error in handle_exit");
break;
}
+
+ if (run->exit_reason == KVM_EXIT_MMIO)
+ break;
}
+ if (ret < 0)
+ run->exit_reason = KVM_EXIT_EXCEPTION;
return ret;
}
diff --git a/arch/arm/kvm/arm_mmu.c b/arch/arm/kvm/arm_mmu.c
index fe27e59..b04a211 100644
--- a/arch/arm/kvm/arm_mmu.c
+++ b/arch/arm/kvm/arm_mmu.c
@@ -16,9 +16,10 @@
#include <linux/mman.h>
#include <linux/kvm_host.h>
+#include <asm/pgalloc.h>
#include <asm/kvm_arm.h>
#include <asm/kvm_mmu.h>
-#include <asm/pgalloc.h>
+#include <asm/kvm_emulate.h>
#include "../mm/mm.h"
#include "trace.h"
@@ -297,6 +298,105 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
return 0;
}
+/**
+ * kvm_handle_mmio_return -- Handle MMIO loads after user space emulation
+ * @vcpu: The VCPU pointer
+ * @run: The VCPU run struct containing the mmio data
+ *
+ * This should only be called after returning to QEMU for MMIO load emulation.
+ */
+int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
+{
+ int *dest;
+ unsigned int len;
+ int mask;
+
+ if (!run->mmio.is_write) {
+ dest = &vcpu_reg(vcpu, vcpu->arch.mmio_rd);
+ memset(dest, 0, sizeof(int));
+
+ if (run->mmio.len > 4) {
+ kvm_err(-EINVAL, "Incorrect mmio length");
+ return -EINVAL;
+ }
+
+ len = run->mmio.len;
+ memcpy(dest, run->mmio.data, len);
+
+ if (vcpu->arch.mmio_sign_extend && len < 4) {
+ mask = 1U << ((len * 8) - 1);
+ *dest = (*dest ^ mask) - mask;
+ }
+ }
+
+ return 0;
+}
+
+static int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
+ phys_addr_t fault_ipa, struct kvm_memory_slot *memslot)
+{
+ unsigned long rd, len, instr_len;
+ bool is_write, sign_extend;
+
+ if (!((vcpu->arch.hsr >> 24) & 1) || ((vcpu->arch.hsr >> 8) & 1)) {
+ kvm_err(-EFAULT, "Invalid I/O abort");
+ return -EFAULT;
+ }
+
+ if ((vcpu->arch.hsr >> 7) & 1) {
+ kvm_err(-EFAULT, "Translation table accesses I/O memory");
+ return -EFAULT;
+ }
+
+ switch ((vcpu->arch.hsr >> 22) & 0x3) {
+ case 0: len = 1; break;
+ case 1: len = 2; break;
+ case 2: len = 4; break;
+ default:
+ kvm_err(-EFAULT, "Invalid I/O abort");
+ return -EFAULT;
+ }
+
+ is_write = ((vcpu->arch.hsr >> 6) & 1);
+ sign_extend = ((vcpu->arch.hsr >> 21) & 1);
+ rd = (vcpu->arch.hsr >> 16) & 0xf;
+ BUG_ON(rd > 15);
+
+ if (rd == 15) {
+ kvm_err(-EFAULT, "I/O memory trying to read/write pc");
+ return -EFAULT;
+ }
+
+ /* Get instruction length in bytes */
+ instr_len = ((vcpu->arch.hsr >> 25) & 1) ? 4 : 2;
+
+ if (!memslot) {
+ /* QEMU hack for missing devices - simply return 0 */
+ if (!is_write)
+ vcpu_reg(vcpu, rd) = 0;
+ vcpu_reg(vcpu, 15) += instr_len;
+ return 0;
+ }
+
+ /* Export MMIO operations to user space */
+ vcpu->run->exit_reason = KVM_EXIT_MMIO;
+ vcpu->run->mmio.is_write = is_write;
+ vcpu->run->mmio.phys_addr = fault_ipa;
+ vcpu->run->mmio.len = len;
+ vcpu->arch.mmio_sign_extend = sign_extend;
+ vcpu->arch.mmio_rd = rd;
+
+ if (is_write)
+ memcpy(run->mmio.data, &vcpu_reg(vcpu, rd), len);
+
+ /*
+ * The MMIO instruction is emulated and should not be re-executed
+ * in the guest.
+ */
+ vcpu_reg(vcpu, 15) += instr_len;
+ return 0;
+}
+
#define HSR_ABT_FS (0x3f)
#define HPFAR_MASK (~0xf)
int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run)
@@ -335,7 +435,5 @@ io_mem_abort:
return -EFAULT;
}
- kvm_msg("I/O address abort...");
- KVMARM_NOT_IMPLEMENTED();
- return -EINVAL;
+ return io_mem_abort(vcpu, run, fault_ipa, memslot);
}
next prev parent reply other threads:[~2011-06-03 15:04 UTC|newest]
Thread overview: 58+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-06-03 15:03 [PATCH v3 1/8] ARM: KVM: Initial skeleton to compile KVM support Christoffer Dall
2011-06-03 15:03 ` [PATCH v3 2/8] ARM: KVM: Hypervisor identity mapping Christoffer Dall
2011-06-03 15:03 ` [PATCH v3 3/8] ARM: KVM: Add hypervisor inititalization Christoffer Dall
2011-06-03 15:03 ` [PATCH v3 4/8] ARM: KVM: Memory virtualization setup Christoffer Dall
2011-06-05 12:41 ` Avi Kivity
2011-06-05 14:50 ` Christoffer Dall
2011-06-05 14:53 ` Avi Kivity
2011-06-05 15:14 ` Avi Kivity
2011-06-05 15:27 ` Christoffer Dall
2011-06-05 16:02 ` Avi Kivity
2011-06-03 15:03 ` [PATCH v3 5/8] ARM: KVM: World-switch implementation Christoffer Dall
2011-06-03 15:04 ` [PATCH v3 6/8] ARM: KVM: Emulation framework and CP15 emulation Christoffer Dall
2011-06-03 15:04 ` [PATCH v3 7/8] ARM: KVM: Handle guest faults in KVM Christoffer Dall
2011-06-05 12:48 ` Avi Kivity
2011-06-11 10:37 ` Christoffer Dall
2011-06-12 8:24 ` Avi Kivity
2011-06-12 8:57 ` Christoffer Dall
2011-06-03 15:04 ` Christoffer Dall [this message]
2011-06-03 15:31 ` [PATCH v3 1/8] ARM: KVM: Initial skeleton to compile KVM support Jan Kiszka
2011-06-03 15:53 ` Jan Kiszka
2011-06-03 16:19 ` Christoffer Dall
2011-06-03 16:31 ` [Android-virt] " Alexander Graf
2011-06-04 14:13 ` Alexander Graf
2011-06-05 12:21 ` Avi Kivity
2011-06-05 14:13 ` Jan Kiszka
2011-06-05 14:18 ` Avi Kivity
2011-06-05 14:58 ` Jan Kiszka
2011-06-05 15:10 ` Avi Kivity
2011-06-05 15:14 ` Jan Kiszka
2011-06-05 15:18 ` Avi Kivity
2011-06-05 16:25 ` Christoffer Dall
2011-06-05 16:28 ` Avi Kivity
2011-06-05 16:30 ` [Android-virt] " Alexander Graf
2011-06-05 16:33 ` Avi Kivity
2011-06-05 17:19 ` Alexander Graf
2011-06-05 17:48 ` Jan Kiszka
2011-06-05 17:54 ` Alexander Graf
2011-06-05 17:56 ` Jan Kiszka
2011-06-05 18:00 ` Alexander Graf
2011-06-05 18:04 ` Jan Kiszka
2011-06-05 18:12 ` Alexander Graf
2011-06-05 18:19 ` Jan Kiszka
2011-06-06 7:42 ` Avi Kivity
2011-06-06 7:41 ` Avi Kivity
2011-06-05 16:24 ` Christoffer Dall
2011-06-05 16:31 ` Avi Kivity
2011-06-05 12:36 ` Avi Kivity
2011-06-05 16:03 ` Christoffer Dall
2011-06-05 16:06 ` Avi Kivity
[not found] ` <211B3F42-9B68-41BB-B1FA-348B5500C60A@suse.de>
2011-06-10 8:40 ` [Android-virt] " Christoffer Dall
2011-06-10 9:23 ` Catalin Marinas
2011-06-10 9:53 ` Alexander Graf
2011-06-10 9:58 ` Catalin Marinas
2011-06-10 11:56 ` Christoffer Dall
2011-06-05 12:52 ` Avi Kivity
2011-06-05 14:00 ` Avi Kivity
2011-06-05 14:13 ` Christoffer Dall
2011-06-05 14:18 ` Avi Kivity
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=20110603150422.17011.44777.stgit@ubuntu \
--to=cdall@cs.columbia.edu \
--cc=a.costa@virtualopensystems.com \
--cc=a.motakis@virtualopensystems.com \
--cc=android-virt@lists.cs.columbia.edu \
--cc=c.dall@virtualopensystems.com \
--cc=catalin.marinas@arm.com \
--cc=kvm@vger.kernel.org \
--cc=s.raho@virtualopensystems.com \
/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: link
Be 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.