From patchwork Sat Jan 21 04:18:58 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Graf X-Patchwork-Id: 137173 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 99FA51007D4 for ; Sat, 21 Jan 2012 16:29:33 +1100 (EST) Received: from localhost ([::1]:56374 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RoSRC-00009F-Co for incoming@patchwork.ozlabs.org; Fri, 20 Jan 2012 23:20:22 -0500 Received: from eggs.gnu.org ([140.186.70.92]:43123) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RoSQ8-0006to-G4 for qemu-devel@nongnu.org; Fri, 20 Jan 2012 23:19:25 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1RoSQ5-0001R6-P3 for qemu-devel@nongnu.org; Fri, 20 Jan 2012 23:19:16 -0500 Received: from cantor2.suse.de ([195.135.220.15]:57123 helo=mx2.suse.de) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1RoSQ5-0001Q8-Dn; Fri, 20 Jan 2012 23:19:13 -0500 Received: from relay2.suse.de (unknown [195.135.220.254]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx2.suse.de (Postfix) with ESMTP id 876A89043F; Sat, 21 Jan 2012 05:19:12 +0100 (CET) From: Alexander Graf To: qemu-ppc@nongnu.org Date: Sat, 21 Jan 2012 05:18:58 +0100 Message-Id: <1327119551-29674-14-git-send-email-agraf@suse.de> X-Mailer: git-send-email 1.7.3.4 In-Reply-To: <1327119551-29674-1-git-send-email-agraf@suse.de> References: <1327119551-29674-1-git-send-email-agraf@suse.de> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4-2.6 X-Received-From: 195.135.220.15 Cc: Blue Swirl , qemu-devel Developers , Aurelien Jarno Subject: [Qemu-devel] [PATCH 13/26] virtio-pci: Fix endianness of virtio config X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Benjamin Herrenschmidt The virtio config area in PIO space is a bit special. The initial header is little endian but the rest (device specific) is guest native endian. The PIO accessors for PCI on machines that don't have native IO ports assume that all PIO is little endian, which works fine for everything except the above. A complicated way to fix it would be to split the BAR into two memory regions with different endianess settings, but this isn't practical to do, besides, the PIO code doesn't honor region endianness anyway (I have a patch for that too but it isn't necessary at this stage). So I decided to go for the quick fix instead which consists of reverting the swap in virtio-pci in selected places, hoping that when we eventually do a "v2" of the virtio protocols, we sort that out once and for all using a fixed endian setting for everything. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Alexander Graf [agraf: keep virtio in libhw and determine endianness through a helper function in exec.c] Reviewed-by: Anthony Liguori --- exec.c | 14 ++++++++++++++ hw/virtio-pci.c | 28 ++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/exec.c b/exec.c index 7f9f730..5b9eb9a 100644 --- a/exec.c +++ b/exec.c @@ -4390,6 +4390,20 @@ tb_page_addr_t get_page_addr_code(CPUState *env1, target_ulong addr) return qemu_ram_addr_from_host_nofail(p); } +/* + * A helper function for the _utterly broken_ virtio device model to find out if + * it's running on a big endian machine. Don't do this at home kids! + */ +bool virtio_is_big_endian(void); +bool virtio_is_big_endian(void) +{ +#if defined(TARGET_WORDS_BIGENDIAN) + return true; +#else + return false; +#endif +} + #define MMUSUFFIX _cmmu #undef GETPC #define GETPC() NULL diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index caff0aa..c93889a 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -91,6 +91,9 @@ */ #define wmb() do { } while (0) +/* HACK for virtio to determine if it's running a big endian guest */ +bool virtio_is_big_endian(void); + /* virtio device */ static void virtio_pci_notify(void *opaque, uint16_t vector) @@ -414,20 +417,35 @@ static uint32_t virtio_pci_config_readw(void *opaque, uint32_t addr) { VirtIOPCIProxy *proxy = opaque; uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); + uint16_t val; if (addr < config) return virtio_ioport_read(proxy, addr); addr -= config; - return virtio_config_readw(proxy->vdev, addr); + val = virtio_config_readw(proxy->vdev, addr); + if (virtio_is_big_endian()) { + /* + * virtio is odd, ioports are LE but config space is target native + * endian. However, in qemu, all PIO is LE, so we need to re-swap + * on BE targets + */ + val = bswap16(val); + } + return val; } static uint32_t virtio_pci_config_readl(void *opaque, uint32_t addr) { VirtIOPCIProxy *proxy = opaque; uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); + uint32_t val; if (addr < config) return virtio_ioport_read(proxy, addr); addr -= config; - return virtio_config_readl(proxy->vdev, addr); + val = virtio_config_readl(proxy->vdev, addr); + if (virtio_is_big_endian()) { + val = bswap32(val); + } + return val; } static void virtio_pci_config_writeb(void *opaque, uint32_t addr, uint32_t val) @@ -451,6 +469,9 @@ static void virtio_pci_config_writew(void *opaque, uint32_t addr, uint32_t val) return; } addr -= config; + if (virtio_is_big_endian()) { + val = bswap16(val); + } virtio_config_writew(proxy->vdev, addr, val); } @@ -463,6 +484,9 @@ static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val) return; } addr -= config; + if (virtio_is_big_endian()) { + val = bswap32(val); + } virtio_config_writel(proxy->vdev, addr, val); }