I hope I've explained in the other mail I just sent why Qemu assuming
little-endian for everything is not OK.

One other important clarification: kvm_run->mmio.is_bigendian is about
*one* *particular* *MMIO* *access*. It has only coincidental
relationship to the "endianness mode" of the guest.

-- 
Hollis Blanchard
IBM Linux Technology Center

On Mon, 2008-01-14 at 13:42 +0800, Xu, Anthony wrote:
> >         kvm_run->mmio.is_bigendian = vcpu->arch.some_register &
> From your example code, I can know is_bigendian indicate whether guest
> is in bigendian mode when accessing MMIO.
> 
> Qemu is responsible for handling MMIO emulation, Qemus always assume it
> is running on littleendian mode.
> So if guest accesses MMIO in bigendian mode,
>       kvm need to transform it to littleendian before delivering this
> MMIO request to Qemu.
> 
> 
> This works for IA64 side.
> 
> 
> Thanks,
> - Anthony
> 
> 
> Hollis Blanchard wrote:
> > We're just talking about a flag in the kvm_run.mmio structure, so it
> > does not represent the state of any software, guest or host, other
> > than that single MMIO access.
> > 
> > This flag is only used for communication between host kernel and host
> > userland, so the host kernel is always responsible for setting it.
> > 
> > "is_bigendian" is just one more necessary piece of information for
> > MMIO emulation. kvm_run already tells you that you are loading 4
> > bytes from address 0. What you don't know today is if byte 0 is the
> > least significant or most significant byte. If "is_bigendian" is set,
> > you know that byte 0 is the MSB and byte 3 is the LSB. If not, the
> > opposite is true.
> > 
> > In the simplest case, IA64's in-kernel MMIO emulation code could look
> > something like:
> >         kvm_run->mmio.phys_addr = addr;
> >         kvm_run->mmio.len = len;
> >         ...
> >         kvm_run->mmio.is_bigendian = vcpu->arch.some_register &
> >         BIGENDIAN;
> > 
> > If IA64 has reverse-endian load/store instructions like PowerPC, then
> > you would also need to consider the particular instruction used as
> > well as the guest state.
> > 
> > 
> > On Fri, 2008-01-11 at 10:02 +0800, Xu, Anthony wrote:
> >> Hi all,
> >> 
> >> That's a good start to consider BE.
> >> Yes, IA64 support BE and LE.
> >> 
> >> I have below comments.
> >> 
> >> What does is_bigendian mean?
> >> Host is runing with BE or guest is running with BE.
> >> Who will set is_bigendian?
> >> 
> >> For supporing BE,
> >> We need to consider host BE and guest BE.
> >> For IA64,  most OS is running with LE, and
> >> Application can run with BE or LE,
> >> For example, Qemu can run with BE or LE.
> >> 
> >> IMHO, we need two flags,
> >> host_is_bigendian indicates Qemu is running with BE
> >> Guest_is_bigendian indecates the guest application who is accessing
> >> MMIO 
> >> 
> >> Is running with LE.
> >> 
> >> 
> >> - Anthony
> >> 
> >> 
> >> 
> >> 
> >> 
> >> 
> >> Hollis Blanchard wrote:
> >>> 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,
> >> 
> >>
> ------------------------------------------------------------------------
> -
> >> 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/marketp
> lace
> >> _______________________________________________
> >> kvm-devel mailing list
> >> kvm-devel@lists.sourceforge.net
> >> https://lists.sourceforge.net/lists/listinfo/kvm-devel


-------------------------------------------------------------------------
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