vesa, pci-shmem and virtio-pci devices need to set up config space with little-endian conversions (as config space is LE). The pci_config_address bitfield also needs to be reversed when building on BE systems. Signed-off-by: Matt Evans <matt@xxxxxxxxxx> --- tools/kvm/hw/pci-shmem.c | 23 +++++++++++---------- tools/kvm/hw/vesa.c | 15 +++++++------ tools/kvm/include/kvm/ioport.h | 11 +++++---- tools/kvm/include/kvm/pci.h | 40 ++++++++++++++++++++++++++------------ tools/kvm/pci.c | 4 +- tools/kvm/virtio/pci.c | 41 +++++++++++++++++++++------------------ 6 files changed, 77 insertions(+), 57 deletions(-) diff --git a/tools/kvm/hw/pci-shmem.c b/tools/kvm/hw/pci-shmem.c index 780a377..fd954c5 100644 --- a/tools/kvm/hw/pci-shmem.c +++ b/tools/kvm/hw/pci-shmem.c @@ -8,21 +8,22 @@ #include "kvm/ioeventfd.h" #include <linux/kvm.h> +#include <linux/byteorder.h> #include <sys/ioctl.h> #include <fcntl.h> #include <sys/mman.h> static struct pci_device_header pci_shmem_pci_device = { - .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, - .device_id = 0x1110, + .vendor_id = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET), + .device_id = cpu_to_le16(0x1110), .header_type = PCI_HEADER_TYPE_NORMAL, - .class = 0xFF0000, /* misc pci device */ - .status = PCI_STATUS_CAP_LIST, + .class[2] = 0xFF, /* misc pci device */ + .status = cpu_to_le16(PCI_STATUS_CAP_LIST), .capabilities = (void *)&pci_shmem_pci_device.msix - (void *)&pci_shmem_pci_device, .msix.cap = PCI_CAP_ID_MSIX, - .msix.ctrl = 1, - .msix.table_offset = 1, /* Use BAR 1 */ - .msix.pba_offset = 0x1001, /* Use BAR 1 */ + .msix.ctrl = cpu_to_le16(1), + .msix.table_offset = cpu_to_le32(1), /* Use BAR 1 */ + .msix.pba_offset = cpu_to_le32(0x1001), /* Use BAR 1 */ }; /* registers for the Inter-VM shared memory device */ @@ -123,7 +124,7 @@ int pci_shmem__get_local_irqfd(struct kvm *kvm) if (fd < 0) return fd; - if (pci_shmem_pci_device.msix.ctrl & PCI_MSIX_FLAGS_ENABLE) { + if (pci_shmem_pci_device.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_ENABLE)) { gsi = irq__add_msix_route(kvm, &msix_table[0].msg); } else { gsi = pci_shmem_pci_device.irq_line; @@ -241,11 +242,11 @@ int pci_shmem__init(struct kvm *kvm) * 1 - MSI-X MMIO space * 2 - Shared memory block */ - pci_shmem_pci_device.bar[0] = ivshmem_registers | PCI_BASE_ADDRESS_SPACE_IO; + pci_shmem_pci_device.bar[0] = cpu_to_le32(ivshmem_registers | PCI_BASE_ADDRESS_SPACE_IO); pci_shmem_pci_device.bar_size[0] = shmem_region->size; - pci_shmem_pci_device.bar[1] = msix_block | PCI_BASE_ADDRESS_SPACE_MEMORY; + pci_shmem_pci_device.bar[1] = cpu_to_le32(msix_block | PCI_BASE_ADDRESS_SPACE_MEMORY); pci_shmem_pci_device.bar_size[1] = 0x1010; - pci_shmem_pci_device.bar[2] = shmem_region->phys_addr | PCI_BASE_ADDRESS_SPACE_MEMORY; + pci_shmem_pci_device.bar[2] = cpu_to_le32(shmem_region->phys_addr | PCI_BASE_ADDRESS_SPACE_MEMORY); pci_shmem_pci_device.bar_size[2] = shmem_region->size; pci__register(&pci_shmem_pci_device, dev); diff --git a/tools/kvm/hw/vesa.c b/tools/kvm/hw/vesa.c index 22b1652..63f1082 100644 --- a/tools/kvm/hw/vesa.c +++ b/tools/kvm/hw/vesa.c @@ -8,6 +8,7 @@ #include "kvm/irq.h" #include "kvm/kvm.h" #include "kvm/pci.h" +#include <linux/byteorder.h> #include <sys/mman.h> #include <sys/types.h> @@ -31,14 +32,14 @@ static struct ioport_operations vesa_io_ops = { }; static struct pci_device_header vesa_pci_device = { - .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, - .device_id = PCI_DEVICE_ID_VESA, + .vendor_id = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET), + .device_id = cpu_to_le16(PCI_DEVICE_ID_VESA), .header_type = PCI_HEADER_TYPE_NORMAL, .revision_id = 0, - .class = 0x030000, - .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, - .subsys_id = PCI_SUBSYSTEM_ID_VESA, - .bar[1] = VESA_MEM_ADDR | PCI_BASE_ADDRESS_SPACE_MEMORY, + .class[2] = 0x03, + .subsys_vendor_id = cpu_to_le16(PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET), + .subsys_id = cpu_to_le16(PCI_SUBSYSTEM_ID_VESA), + .bar[1] = cpu_to_le32(VESA_MEM_ADDR | PCI_BASE_ADDRESS_SPACE_MEMORY), .bar_size[1] = VESA_MEM_SIZE, }; @@ -56,7 +57,7 @@ struct framebuffer *vesa__init(struct kvm *kvm) vesa_pci_device.irq_pin = pin; vesa_pci_device.irq_line = line; vesa_base_addr = ioport__register(IOPORT_EMPTY, &vesa_io_ops, IOPORT_SIZE, NULL); - vesa_pci_device.bar[0] = vesa_base_addr | PCI_BASE_ADDRESS_SPACE_IO; + vesa_pci_device.bar[0] = cpu_to_le32(vesa_base_addr | PCI_BASE_ADDRESS_SPACE_IO); pci__register(&vesa_pci_device, dev); mem = mmap(NULL, VESA_MEM_SIZE, PROT_RW, MAP_ANON_NORESERVE, -1, 0); diff --git a/tools/kvm/include/kvm/ioport.h b/tools/kvm/include/kvm/ioport.h index 61a70ec..09bf876 100644 --- a/tools/kvm/include/kvm/ioport.h +++ b/tools/kvm/include/kvm/ioport.h @@ -7,6 +7,7 @@ #include <limits.h> #include <asm/types.h> #include <linux/types.h> +#include <linux/byteorder.h> /* some ports we reserve for own use */ #define IOPORT_DBG 0xe0 @@ -36,15 +37,15 @@ static inline u8 ioport__read8(u8 *data) { return *data; } - +/* On BE platforms, PCI I/O is byteswapped, i.e. LE, so swap back. */ static inline u16 ioport__read16(u16 *data) { - return *data; + return le16_to_cpu(*data); } static inline u32 ioport__read32(u32 *data) { - return *data; + return le32_to_cpu(*data); } static inline void ioport__write8(u8 *data, u8 value) @@ -54,12 +55,12 @@ static inline void ioport__write8(u8 *data, u8 value) static inline void ioport__write16(u16 *data, u16 value) { - *data = value; + *data = cpu_to_le16(value); } static inline void ioport__write32(u32 *data, u32 value) { - *data = value; + *data = cpu_to_le32(value); } #endif /* KVM__IOPORT_H */ diff --git a/tools/kvm/include/kvm/pci.h b/tools/kvm/include/kvm/pci.h index b578ad7..21f93d0 100644 --- a/tools/kvm/include/kvm/pci.h +++ b/tools/kvm/include/kvm/pci.h @@ -5,6 +5,7 @@ #include <linux/kvm.h> #include <linux/pci_regs.h> #include <linux/msi.h> +#include <endian.h> #define PCI_MAX_DEVICES 256 /* @@ -17,14 +18,27 @@ #define PCI_CONFIG_BUS_FORWARD 0xcfa #define PCI_IO_SIZE 0x100 -struct pci_config_address { - unsigned zeros : 2; /* 1 .. 0 */ - unsigned register_number : 6; /* 7 .. 2 */ - unsigned function_number : 3; /* 10 .. 8 */ - unsigned device_number : 5; /* 15 .. 11 */ - unsigned bus_number : 8; /* 23 .. 16 */ - unsigned reserved : 7; /* 30 .. 24 */ - unsigned enable_bit : 1; /* 31 */ +union pci_config_address { + struct { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned zeros : 2; /* 1 .. 0 */ + unsigned register_number : 6; /* 7 .. 2 */ + unsigned function_number : 3; /* 10 .. 8 */ + unsigned device_number : 5; /* 15 .. 11 */ + unsigned bus_number : 8; /* 23 .. 16 */ + unsigned reserved : 7; /* 30 .. 24 */ + unsigned enable_bit : 1; /* 31 */ +#else + unsigned enable_bit : 1; /* 31 */ + unsigned reserved : 7; /* 30 .. 24 */ + unsigned bus_number : 8; /* 23 .. 16 */ + unsigned device_number : 5; /* 15 .. 11 */ + unsigned function_number : 3; /* 10 .. 8 */ + unsigned register_number : 6; /* 7 .. 2 */ + unsigned zeros : 2; /* 1 .. 0 */ +#endif + }; + u32 w; }; struct msix_table { @@ -45,8 +59,8 @@ struct pci_device_header { u16 device_id; u16 command; u16 status; - u16 revision_id : 8; - u32 class : 24; + u8 revision_id; + u8 class[3]; u8 cacheline_size; u8 latency_timer; u8 header_type; @@ -56,8 +70,8 @@ struct pci_device_header { u16 subsys_vendor_id; u16 subsys_id; u32 exp_rom_bar; - u32 capabilities : 8; - u32 reserved1 : 24; + u8 capabilities; + u8 reserved1[3]; u32 reserved2; u8 irq_line; u8 irq_pin; @@ -66,7 +80,7 @@ struct pci_device_header { struct msix_cap msix; u8 empty[136]; /* Rest of PCI config space */ u32 bar_size[6]; -}; +} __attribute__((packed)); void pci__init(void); void pci__register(struct pci_device_header *dev, u8 dev_num); diff --git a/tools/kvm/pci.c b/tools/kvm/pci.c index 920e13e..5bbcbc7 100644 --- a/tools/kvm/pci.c +++ b/tools/kvm/pci.c @@ -9,7 +9,7 @@ static struct pci_device_header *pci_devices[PCI_MAX_DEVICES]; -static struct pci_config_address pci_config_address; +static union pci_config_address pci_config_address; /* This is within our PCI gap - in an unused area */ static u32 io_space_blocks = KVM_32BIT_GAP_START + 0x1000000; @@ -105,7 +105,7 @@ static bool pci_config_data_out(struct ioport *ioport, struct kvm *kvm, u16 port * When the kernel got the size it would write the address * back. */ - if (ioport__read32(p + offset)) { + if (*(u32 *)(p + offset)) { /* See if kernel tries to mask one of the BARs */ if ((offset >= PCI_BAR_OFFSET(0)) && (offset <= PCI_BAR_OFFSET(6)) && diff --git a/tools/kvm/virtio/pci.c b/tools/kvm/virtio/pci.c index d9fc3a5..acb7d96 100644 --- a/tools/kvm/virtio/pci.c +++ b/tools/kvm/virtio/pci.c @@ -9,6 +9,7 @@ #include "kvm/virtio-trans.h" #include <linux/virtio_pci.h> +#include <linux/byteorder.h> #include <string.h> struct virtio_trans_ops *virtio_pci__get_trans_ops(void) @@ -59,7 +60,7 @@ static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_trans *vtra static inline bool virtio_pci__msix_enabled(struct virtio_pci *vpci) { - return vpci->pci_hdr.msix.ctrl & PCI_MSIX_FLAGS_ENABLE; + return vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_ENABLE); } static bool virtio_pci__specific_io_in(struct kvm *kvm, struct virtio_trans *vtrans, u16 port, @@ -244,8 +245,8 @@ int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_trans *vtrans, u32 vq) int tbl = vpci->vq_vector[vq]; if (virtio_pci__msix_enabled(vpci)) { - if (vpci->pci_hdr.msix.ctrl & PCI_MSIX_FLAGS_MASKALL || - vpci->msix_table[tbl].ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT) { + if (vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_MASKALL) || + vpci->msix_table[tbl].ctrl & cpu_to_le16(PCI_MSIX_ENTRY_CTRL_MASKBIT)) { vpci->msix_pba |= 1 << tbl; return 0; @@ -265,8 +266,8 @@ int virtio_pci__signal_config(struct kvm *kvm, struct virtio_trans *vtrans) int tbl = vpci->config_vector; if (virtio_pci__msix_enabled(vpci)) { - if (vpci->pci_hdr.msix.ctrl & PCI_MSIX_FLAGS_MASKALL || - vpci->msix_table[tbl].ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT) { + if (vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_MASKALL) || + vpci->msix_table[tbl].ctrl & cpu_to_le16(PCI_MSIX_ENTRY_CTRL_MASKBIT)) { vpci->msix_pba |= 1 << tbl; return 0; @@ -296,19 +297,21 @@ int virtio_pci__init(struct kvm *kvm, struct virtio_trans *vtrans, void *dev, kvm__register_mmio(kvm, vpci->msix_pba_block, 0x100, callback_mmio_pba, vpci); vpci->pci_hdr = (struct pci_device_header) { - .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, - .device_id = device_id, + .vendor_id = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET), + .device_id = cpu_to_le16(device_id), .header_type = PCI_HEADER_TYPE_NORMAL, .revision_id = 0, - .class = class, - .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, - .subsys_id = subsys_id, - .bar[0] = vpci->base_addr | PCI_BASE_ADDRESS_SPACE_IO, - .bar[1] = vpci->msix_io_block | PCI_BASE_ADDRESS_SPACE_MEMORY - | PCI_BASE_ADDRESS_MEM_TYPE_64, - .bar[3] = vpci->msix_pba_block | PCI_BASE_ADDRESS_SPACE_MEMORY - | PCI_BASE_ADDRESS_MEM_TYPE_64, - .status = PCI_STATUS_CAP_LIST, + .class[0] = class & 0xff, + .class[1] = (class >> 8) & 0xff, + .class[2] = (class >> 16) & 0xff, + .subsys_vendor_id = cpu_to_le16(PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET), + .subsys_id = cpu_to_le16(subsys_id), + .bar[0] = cpu_to_le32(vpci->base_addr | PCI_BASE_ADDRESS_SPACE_IO), + .bar[1] = cpu_to_le32(vpci->msix_io_block | PCI_BASE_ADDRESS_SPACE_MEMORY + | PCI_BASE_ADDRESS_MEM_TYPE_64), + .bar[3] = cpu_to_le32(vpci->msix_pba_block | PCI_BASE_ADDRESS_SPACE_MEMORY + | PCI_BASE_ADDRESS_MEM_TYPE_64), + .status = cpu_to_le16(PCI_STATUS_CAP_LIST), .capabilities = (void *)&vpci->pci_hdr.msix - (void *)&vpci->pci_hdr, }; @@ -325,14 +328,14 @@ int virtio_pci__init(struct kvm *kvm, struct virtio_trans *vtrans, void *dev, * For example, a returned value of "00000000011" * indicates a table size of 4. */ - vpci->pci_hdr.msix.ctrl = (VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG - 1); + vpci->pci_hdr.msix.ctrl = cpu_to_le16(VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG - 1); /* * Both table and PBA could be mapped on the same BAR, but for now * we're not in short of BARs */ - vpci->pci_hdr.msix.table_offset = 1; /* Use BAR 1 */ - vpci->pci_hdr.msix.pba_offset = 3; /* Use BAR 3 */ + vpci->pci_hdr.msix.table_offset = cpu_to_le32(1); /* Use BAR 1 */ + vpci->pci_hdr.msix.pba_offset = cpu_to_le32(3); /* Use BAR 3 */ vpci->config_vector = 0; if (irq__register_device(subsys_id, &ndev, &pin, &line) < 0) -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html