On Thu, 2008-01-10 at 17:28 +0200, Avi Kivity wrote:
> I'll apply that patch (with a #ifdef CONFIG_PPC so other archs don't
> use it by mistake).

I don't think that's the right ifdef. For example, I believe IA64 can
run in BE mode and so will have the same issue, and there are certainly
other architectures (less relevant to the current code) that definitely
are in the same situation.

We need to plumb this through to the libkvm users anyways. Take a look
at the patch below and tell me if you think it's not the right approach.
x86 simply won't consider 'is_bigendian'. I spent a lot of time on this,
and it's by far the cleanest solution I could come up with.



diff --git a/libkvm/config-i386.mak b/libkvm/config-i386.mak
--- a/libkvm/config-i386.mak
+++ b/libkvm/config-i386.mak
@@ -2,5 +2,6 @@ LIBDIR := /lib
 LIBDIR := /lib
 CFLAGS += -m32
 CFLAGS += -D__i386__
+CFLAGS += -DARCH_MMIO_ENDIAN_LITTLE
 
 libkvm-$(ARCH)-objs := libkvm-x86.o
diff --git a/libkvm/config-ia64.mak b/libkvm/config-ia64.mak
--- a/libkvm/config-ia64.mak
+++ b/libkvm/config-ia64.mak
@@ -1,5 +1,6 @@
 
 LIBDIR := /lib
 CFLAGS += -D__ia64__
+CFLAGS += -DARCH_MMIO_ENDIAN_LITTLE -DARCH_MMIO_ENDIAN_BIG
 
 libkvm-$(ARCH)-objs := libkvm-ia64.o
diff --git a/libkvm/config-powerpc.mak b/libkvm/config-powerpc.mak
--- a/libkvm/config-powerpc.mak
+++ b/libkvm/config-powerpc.mak
@@ -2,5 +2,6 @@ LIBDIR := /lib
 LIBDIR := /lib
 CFLAGS += -m32
 CFLAGS += -D__powerpc__
+CFLAGS += -DARCH_MMIO_ENDIAN_BIG -DARCH_MMIO_ENDIAN_LITTLE
 
 libkvm-$(ARCH)-objs := libkvm-powerpc.o
diff --git a/libkvm/config-x86_64.mak b/libkvm/config-x86_64.mak
--- a/libkvm/config-x86_64.mak
+++ b/libkvm/config-x86_64.mak
@@ -2,5 +2,6 @@ LIBDIR := /lib64
 LIBDIR := /lib64
 CFLAGS += -m64
 CFLAGS += -D__x86_64__
+CFLAGS += -DARCH_MMIO_ENDIAN_LITTLE
 
 libkvm-$(ARCH)-objs := libkvm-x86.o
diff --git a/libkvm/libkvm.c b/libkvm/libkvm.c
--- a/libkvm/libkvm.c
+++ b/libkvm/libkvm.c
@@ -774,21 +774,56 @@ int kvm_set_sregs(kvm_context_t kvm, int
     return ioctl(kvm->vcpu_fd[vcpu], KVM_SET_SREGS, sregs);
 }
 
+#ifdef ARCH_MMIO_ENDIAN_BIG
+static int handle_mmio_bigendian(kvm_context_t kvm, struct kvm_run *kvm_run)
+{
+       if (kvm_run->mmio.is_write)
+               return kvm->callbacks->mmio_write_be(kvm->opaque,
+                                                    kvm_run->mmio.phys_addr,
+                                                    kvm_run->mmio.data,
+                                                    kvm_run->mmio.len);
+       else
+               return kvm->callbacks->mmio_read_be(kvm->opaque,
+                                                   kvm_run->mmio.phys_addr,
+                                                   kvm_run->mmio.data,
+                                                   kvm_run->mmio.len);
+}
+#endif
+
+#ifdef ARCH_MMIO_ENDIAN_LITTLE
+static int handle_mmio_littleendian(kvm_context_t kvm, struct kvm_run *kvm_run)
+{
+       if (kvm_run->mmio.is_write)
+               return kvm->callbacks->mmio_write_le(kvm->opaque,
+                                                    kvm_run->mmio.phys_addr,
+                                                    kvm_run->mmio.data,
+                                                    kvm_run->mmio.len);
+       else
+               return kvm->callbacks->mmio_read_le(kvm->opaque,
+                                                   kvm_run->mmio.phys_addr,
+                                                   kvm_run->mmio.data,
+                                                   kvm_run->mmio.len);
+}
+#endif
+
 static int handle_mmio(kvm_context_t kvm, struct kvm_run *kvm_run)
 {
        unsigned long addr = kvm_run->mmio.phys_addr;
-       void *data = kvm_run->mmio.data;
 
        /* hack: Red Hat 7.1 generates these weird accesses. */
        if ((addr > 0xa0000-4 && addr <= 0xa0000) && kvm_run->mmio.len == 3)
            return 0;
 
-       if (kvm_run->mmio.is_write)
-               return kvm->callbacks->mmio_write(kvm->opaque, addr, data,
-                                       kvm_run->mmio.len);
+#if defined(ARCH_MMIO_ENDIAN_BIG) && defined(ARCH_MMIO_ENDIAN_LITTLE)
+       if (kvm_run->mmio.is_bigendian)
+               return handle_mmio_bigendian(kvm, kvm_run);
        else
-               return kvm->callbacks->mmio_read(kvm->opaque, addr, data,
-                                       kvm_run->mmio.len);
+               return handle_mmio_littleendian(kvm, kvm_run);
+#elif ARCH_MMIO_ENDIAN_LITTLE
+       return handle_mmio_littleendian(kvm, kvm_run);
+#elif ARCH_MMIO_ENDIAN_BIG
+       return handle_mmio_bigendian(kvm, kvm_run);
+#endif
 }
 
 int handle_io_window(kvm_context_t kvm)
diff --git a/libkvm/libkvm.h b/libkvm/libkvm.h
--- a/libkvm/libkvm.h
+++ b/libkvm/libkvm.h
@@ -46,11 +46,11 @@ struct kvm_callbacks {
        /// For 32bit IO writes from the guest (Usually when executing 'outl')
     int (*outl)(void *opaque, uint16_t addr, uint32_t data);
        /// generic memory reads to unmapped memory (For MMIO devices)
-    int (*mmio_read)(void *opaque, uint64_t addr, uint8_t *data,
-                                       int len);
+    int (*mmio_read_be)(void *opaque, uint64_t addr, uint8_t *data, int len);
+    int (*mmio_read_le)(void *opaque, uint64_t addr, uint8_t *data, int len);
        /// generic memory writes to unmapped memory (For MMIO devices)
-    int (*mmio_write)(void *opaque, uint64_t addr, uint8_t *data,
-                                       int len);
+    int (*mmio_write_be)(void *opaque, uint64_t addr, uint8_t *data, int len);
+    int (*mmio_write_le)(void *opaque, uint64_t addr, uint8_t *data, int len);
     int (*debug)(void *opaque, int vcpu);
        /*!
         * \brief Called when the VCPU issues an 'hlt' instruction.
diff --git a/qemu/qemu-kvm.c b/qemu/qemu-kvm.c
--- a/qemu/qemu-kvm.c
+++ b/qemu/qemu-kvm.c
@@ -21,6 +21,7 @@ int kvm_irqchip = 1;
 #include <libkvm.h>
 #include <pthread.h>
 #include <sys/utsname.h>
+#include <endian.h>
 
 extern void perror(const char *s);
 
@@ -533,8 +534,13 @@ static struct kvm_callbacks qemu_kvm_ops
     .outb  = kvm_outb,
     .outw  = kvm_outw,
     .outl  = kvm_outl,
-    .mmio_read = kvm_mmio_read,
-    .mmio_write = kvm_mmio_write,
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+    .mmio_read_le = kvm_mmio_read,
+    .mmio_write_le = kvm_mmio_write,
+#else
+    .mmio_read_be = kvm_mmio_read,
+    .mmio_write_be = kvm_mmio_write,
+#endif
     .halt  = kvm_halt,
     .shutdown = kvm_shutdown,
     .io_window = kvm_io_window,
diff --git a/user/main-ppc.c b/user/main-ppc.c
--- a/user/main-ppc.c
+++ b/user/main-ppc.c
@@ -92,14 +92,14 @@ static int test_pre_kvm_run(void *opaque
        return 0;
 }
 
-static int test_mem_read(void *opaque, uint64_t addr, uint8_t *data, int len)
+static int test_mem_read_be(void *opaque, uint64_t addr, uint8_t *data, int 
len)
 {
        printf("%s: addr %"PRIx64" len %d\n", __func__, addr, len);
        memset(data, 0, len);
        return 0;
 }
 
-static int test_mem_write(void *opaque, uint64_t addr, uint8_t *data, int len)
+static int test_mem_write_be(void *opaque, uint64_t addr, uint8_t *data, int 
len)
 {
        printf("%s: addr %"PRIx64" len %d data %"PRIx64"\n",
               __func__, addr, len, *(uint64_t *)data);
@@ -120,8 +120,8 @@ static int test_dcr_write(kvm_context_t 
 }
 
 static struct kvm_callbacks test_callbacks = {
-       .mmio_read   = test_mem_read,
-       .mmio_write  = test_mem_write,
+       .mmio_read_be = test_mem_read_be,
+       .mmio_write_be = test_mem_write_be,
        .debug       = test_debug,
        .halt        = test_halt,
        .io_window = test_io_window,
diff --git a/user/main.c b/user/main.c
--- a/user/main.c
+++ b/user/main.c
@@ -389,8 +389,8 @@ static struct kvm_callbacks test_callbac
        .outb        = test_outb,
        .outw        = test_outw,
        .outl        = test_outl,
-       .mmio_read   = test_mem_read,
-       .mmio_write  = test_mem_write,
+       .mmio_read_le = test_mem_read,
+       .mmio_write_le = test_mem_write,
        .debug       = test_debug,
        .halt        = test_halt,
        .io_window = test_io_window,


-- 
Hollis Blanchard
IBM Linux Technology Center


-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel

Reply via email to