mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-09-09 00:07:57 -06:00

When running a fully emulated device in cross-endian conditions, including a virtio 1.0 device offered to a big endian guest, we need to fix the vnet headers. This is currently handled by the virtio_net_hdr_swap() function in the core virtio-net code but it should actually be handled by the net backend. With this patch, virtio-net now tries to configure the backend to do the endian fixing when the device starts (i.e. drivers sets the CONFIG_OK bit). If the backend cannot support the requested endiannes, we have to fallback onto virtio_net_hdr_swap(): this is recorded in the needs_vnet_hdr_swap flag, to be used in the TX and RX paths. Note that we reset the backend to the default behaviour (guest native endianness) when the device stops (i.e. device status had CONFIG_OK bit and driver unsets it). This is needed, with the linux tap backend at least, otherwise the guest may lose network connectivity if rebooted into a different endianness. The current vhost-net code also tries to configure net backends. This will be no more needed and will be reverted in a subsequent patch. Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com> Reviewed-by: Laurent Vivier <lvivier@redhat.com> Signed-off-by: Greg Kurz <gkurz@linux.vnet.ibm.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Reviewed-by: Laurent Vivier <lvivier@redhat.com>
187 lines
4.6 KiB
C
187 lines
4.6 KiB
C
/*
|
|
* Virtio Accessor Support: In case your target can change endian.
|
|
*
|
|
* Copyright IBM, Corp. 2013
|
|
*
|
|
* Authors:
|
|
* Rusty Russell <rusty@au.ibm.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
*/
|
|
#ifndef _QEMU_VIRTIO_ACCESS_H
|
|
#define _QEMU_VIRTIO_ACCESS_H
|
|
#include "hw/virtio/virtio.h"
|
|
#include "exec/address-spaces.h"
|
|
|
|
static inline bool virtio_access_is_big_endian(VirtIODevice *vdev)
|
|
{
|
|
if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) {
|
|
/* Devices conforming to VIRTIO 1.0 or later are always LE. */
|
|
return false;
|
|
}
|
|
#if defined(TARGET_IS_BIENDIAN)
|
|
return virtio_is_big_endian(vdev);
|
|
#elif defined(TARGET_WORDS_BIGENDIAN)
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
static inline bool virtio_legacy_is_cross_endian(VirtIODevice *vdev)
|
|
{
|
|
#ifdef TARGET_IS_BIENDIAN
|
|
#ifdef HOST_WORDS_BIGENDIAN
|
|
return !virtio_is_big_endian(vdev);
|
|
#else
|
|
return virtio_is_big_endian(vdev);
|
|
#endif
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
static inline uint16_t virtio_lduw_phys(VirtIODevice *vdev, hwaddr pa)
|
|
{
|
|
if (virtio_access_is_big_endian(vdev)) {
|
|
return lduw_be_phys(&address_space_memory, pa);
|
|
}
|
|
return lduw_le_phys(&address_space_memory, pa);
|
|
}
|
|
|
|
static inline uint32_t virtio_ldl_phys(VirtIODevice *vdev, hwaddr pa)
|
|
{
|
|
if (virtio_access_is_big_endian(vdev)) {
|
|
return ldl_be_phys(&address_space_memory, pa);
|
|
}
|
|
return ldl_le_phys(&address_space_memory, pa);
|
|
}
|
|
|
|
static inline uint64_t virtio_ldq_phys(VirtIODevice *vdev, hwaddr pa)
|
|
{
|
|
if (virtio_access_is_big_endian(vdev)) {
|
|
return ldq_be_phys(&address_space_memory, pa);
|
|
}
|
|
return ldq_le_phys(&address_space_memory, pa);
|
|
}
|
|
|
|
static inline void virtio_stw_phys(VirtIODevice *vdev, hwaddr pa,
|
|
uint16_t value)
|
|
{
|
|
if (virtio_access_is_big_endian(vdev)) {
|
|
stw_be_phys(&address_space_memory, pa, value);
|
|
} else {
|
|
stw_le_phys(&address_space_memory, pa, value);
|
|
}
|
|
}
|
|
|
|
static inline void virtio_stl_phys(VirtIODevice *vdev, hwaddr pa,
|
|
uint32_t value)
|
|
{
|
|
if (virtio_access_is_big_endian(vdev)) {
|
|
stl_be_phys(&address_space_memory, pa, value);
|
|
} else {
|
|
stl_le_phys(&address_space_memory, pa, value);
|
|
}
|
|
}
|
|
|
|
static inline void virtio_stw_p(VirtIODevice *vdev, void *ptr, uint16_t v)
|
|
{
|
|
if (virtio_access_is_big_endian(vdev)) {
|
|
stw_be_p(ptr, v);
|
|
} else {
|
|
stw_le_p(ptr, v);
|
|
}
|
|
}
|
|
|
|
static inline void virtio_stl_p(VirtIODevice *vdev, void *ptr, uint32_t v)
|
|
{
|
|
if (virtio_access_is_big_endian(vdev)) {
|
|
stl_be_p(ptr, v);
|
|
} else {
|
|
stl_le_p(ptr, v);
|
|
}
|
|
}
|
|
|
|
static inline void virtio_stq_p(VirtIODevice *vdev, void *ptr, uint64_t v)
|
|
{
|
|
if (virtio_access_is_big_endian(vdev)) {
|
|
stq_be_p(ptr, v);
|
|
} else {
|
|
stq_le_p(ptr, v);
|
|
}
|
|
}
|
|
|
|
static inline int virtio_lduw_p(VirtIODevice *vdev, const void *ptr)
|
|
{
|
|
if (virtio_access_is_big_endian(vdev)) {
|
|
return lduw_be_p(ptr);
|
|
} else {
|
|
return lduw_le_p(ptr);
|
|
}
|
|
}
|
|
|
|
static inline int virtio_ldl_p(VirtIODevice *vdev, const void *ptr)
|
|
{
|
|
if (virtio_access_is_big_endian(vdev)) {
|
|
return ldl_be_p(ptr);
|
|
} else {
|
|
return ldl_le_p(ptr);
|
|
}
|
|
}
|
|
|
|
static inline uint64_t virtio_ldq_p(VirtIODevice *vdev, const void *ptr)
|
|
{
|
|
if (virtio_access_is_big_endian(vdev)) {
|
|
return ldq_be_p(ptr);
|
|
} else {
|
|
return ldq_le_p(ptr);
|
|
}
|
|
}
|
|
|
|
static inline uint16_t virtio_tswap16(VirtIODevice *vdev, uint16_t s)
|
|
{
|
|
#ifdef HOST_WORDS_BIGENDIAN
|
|
return virtio_access_is_big_endian(vdev) ? s : bswap16(s);
|
|
#else
|
|
return virtio_access_is_big_endian(vdev) ? bswap16(s) : s;
|
|
#endif
|
|
}
|
|
|
|
static inline void virtio_tswap16s(VirtIODevice *vdev, uint16_t *s)
|
|
{
|
|
*s = virtio_tswap16(vdev, *s);
|
|
}
|
|
|
|
static inline uint32_t virtio_tswap32(VirtIODevice *vdev, uint32_t s)
|
|
{
|
|
#ifdef HOST_WORDS_BIGENDIAN
|
|
return virtio_access_is_big_endian(vdev) ? s : bswap32(s);
|
|
#else
|
|
return virtio_access_is_big_endian(vdev) ? bswap32(s) : s;
|
|
#endif
|
|
}
|
|
|
|
static inline void virtio_tswap32s(VirtIODevice *vdev, uint32_t *s)
|
|
{
|
|
*s = virtio_tswap32(vdev, *s);
|
|
}
|
|
|
|
static inline uint64_t virtio_tswap64(VirtIODevice *vdev, uint64_t s)
|
|
{
|
|
#ifdef HOST_WORDS_BIGENDIAN
|
|
return virtio_access_is_big_endian(vdev) ? s : bswap64(s);
|
|
#else
|
|
return virtio_access_is_big_endian(vdev) ? bswap64(s) : s;
|
|
#endif
|
|
}
|
|
|
|
static inline void virtio_tswap64s(VirtIODevice *vdev, uint64_t *s)
|
|
{
|
|
*s = virtio_tswap64(vdev, *s);
|
|
}
|
|
#endif /* _QEMU_VIRTIO_ACCESS_H */
|