diff options
Diffstat (limited to 'hw')
| -rw-r--r-- | hw/alpha_pci.c | 6 | ||||
| -rw-r--r-- | hw/boards.h | 1 | ||||
| -rw-r--r-- | hw/cirrus_vga.c | 41 | ||||
| -rw-r--r-- | hw/e1000.c | 3 | ||||
| -rw-r--r-- | hw/grackle_pci.c | 17 | ||||
| -rw-r--r-- | hw/ide/pci.c | 4 | ||||
| -rw-r--r-- | hw/loader.c | 6 | ||||
| -rw-r--r-- | hw/mips_malta.c | 6 | ||||
| -rw-r--r-- | hw/pc.c | 7 | ||||
| -rw-r--r-- | hw/pc.h | 1 | ||||
| -rw-r--r-- | hw/pci.c | 20 | ||||
| -rw-r--r-- | hw/pci.h | 4 | ||||
| -rw-r--r-- | hw/ppc440.c | 106 | ||||
| -rw-r--r-- | hw/ppc440.h | 21 | ||||
| -rw-r--r-- | hw/ppc440_bamboo.c | 154 | ||||
| -rw-r--r-- | hw/ppc4xx_pci.c | 129 | ||||
| -rw-r--r-- | hw/qdev.c | 4 | ||||
| -rw-r--r-- | hw/qdev.h | 1 | ||||
| -rw-r--r-- | hw/s390-virtio.c | 1 | ||||
| -rw-r--r-- | hw/sga.c | 4 | ||||
| -rw-r--r-- | hw/spapr.c | 136 | ||||
| -rw-r--r-- | hw/spapr_pci.c | 173 | ||||
| -rw-r--r-- | hw/virtex_ml507.c | 1 | ||||
| -rw-r--r-- | hw/virtio-pci.c | 28 | ||||
| -rw-r--r-- | hw/virtio.c | 12 | ||||
| -rw-r--r-- | hw/vmware_vga.h | 8 |
26 files changed, 420 insertions, 474 deletions
diff --git a/hw/alpha_pci.c b/hw/alpha_pci.c index e9757028af..673557781e 100644 --- a/hw/alpha_pci.c +++ b/hw/alpha_pci.c @@ -121,10 +121,8 @@ void alpha_pci_vga_setup(PCIBus *pci_bus) pci_cirrus_vga_init(pci_bus); return; case VGA_VMWARE: - if (pci_vmsvga_init(pci_bus)) { - return; - } - break; + pci_vmsvga_init(pci_bus); + return; } /* If VGA is enabled at all, and one of the above didn't work, then fallback to Standard VGA. */ diff --git a/hw/boards.h b/hw/boards.h index 716fd7b1a6..f6d3784cf1 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -22,7 +22,6 @@ typedef struct QEMUMachine { unsigned int no_serial:1, no_parallel:1, use_virtcon:1, - no_vga:1, no_floppy:1, no_cdrom:1, no_sdcard:1; diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index f7b1d3d785..8506bb5777 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -250,6 +250,11 @@ typedef struct PCICirrusVGAState { CirrusVGAState cirrus_vga; } PCICirrusVGAState; +typedef struct ISACirrusVGAState { + ISADevice dev; + CirrusVGAState cirrus_vga; +} ISACirrusVGAState; + static uint8_t rop_to_index[256]; /*************************************** @@ -2883,23 +2888,35 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci, * ***************************************/ -DeviceState *isa_cirrus_vga_init(MemoryRegion *system_memory) +static int vga_initfn(ISADevice *dev) { - CirrusVGAState *s; - - s = g_malloc0(sizeof(CirrusVGAState)); - - vga_common_init(&s->vga, VGA_RAM_SIZE); - cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0, system_memory); - s->vga.ds = graphic_console_init(s->vga.update, s->vga.invalidate, - s->vga.screen_dump, s->vga.text_update, - &s->vga); - vmstate_register(NULL, 0, &vmstate_cirrus_vga, s); + ISACirrusVGAState *d = DO_UPCAST(ISACirrusVGAState, dev, dev); + VGACommonState *s = &d->cirrus_vga.vga; + + vga_common_init(s, VGA_RAM_SIZE); + cirrus_init_common(&d->cirrus_vga, CIRRUS_ID_CLGD5430, 0, + isa_address_space(dev)); + s->ds = graphic_console_init(s->update, s->invalidate, + s->screen_dump, s->text_update, + s); rom_add_vga(VGABIOS_CIRRUS_FILENAME); /* XXX ISA-LFB support */ /* FIXME not qdev yet */ - return NULL; + return 0; +} + +static ISADeviceInfo isa_cirrus_vga_info = { + .qdev.name = "isa-cirrus-vga", + .qdev.size = sizeof(ISACirrusVGAState), + .qdev.vmsd = &vmstate_cirrus_vga, + .init = vga_initfn, +}; + +static void isa_cirrus_vga_register(void) +{ + isa_qdev_register(&isa_cirrus_vga_info); } +device_init(isa_cirrus_vga_register) /*************************************** * diff --git a/hw/e1000.c b/hw/e1000.c index a29c944df4..86c5416bd1 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -466,6 +466,8 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) bytes = split_size; if (tp->size + bytes > msh) bytes = msh - tp->size; + + bytes = MIN(sizeof(tp->data) - tp->size, bytes); pci_dma_read(&s->dev, addr, tp->data + tp->size, bytes); if ((sz = tp->size + bytes) >= hdr && tp->size < hdr) memmove(tp->header, tp->data, hdr); @@ -481,6 +483,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp) // context descriptor TSE is not set, while data descriptor TSE is set DBGOUT(TXERR, "TCP segmentaion Error\n"); } else { + split_size = MIN(sizeof(tp->data) - tp->size, split_size); pci_dma_read(&s->dev, addr, tp->data + tp->size, split_size); tp->size += split_size; } diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 1e529fb5d0..be10a6d5a3 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -71,7 +71,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic, SysBusDevice *s; GrackleState *d; - dev = qdev_create(NULL, "grackle"); + dev = qdev_create(NULL, "grackle-pcihost"); qdev_init_nofail(dev); s = sysbus_from_qdev(dev); d = FROM_SYSBUS(GrackleState, s); @@ -121,9 +121,10 @@ static int grackle_pci_host_init(PCIDevice *d) return 0; } -static PCIDeviceInfo grackle_pci_host_info = { +static PCIDeviceInfo grackle_pci_info = { .qdev.name = "grackle", .qdev.size = sizeof(PCIDevice), + .qdev.no_user = 1, .init = grackle_pci_host_init, .vendor_id = PCI_VENDOR_ID_MOTOROLA, .device_id = PCI_DEVICE_ID_MOTOROLA_MPC106, @@ -131,11 +132,17 @@ static PCIDeviceInfo grackle_pci_host_info = { .class_id = PCI_CLASS_BRIDGE_HOST, }; +static SysBusDeviceInfo grackle_pci_host_info = { + .qdev.name = "grackle-pcihost", + .qdev.size = sizeof(GrackleState), + .qdev.no_user = 1, + .init = pci_grackle_init_device, +}; + static void grackle_register_devices(void) { - sysbus_register_dev("grackle", sizeof(GrackleState), - pci_grackle_init_device); - pci_qdev_register(&grackle_pci_host_info); + sysbus_register_withprop(&grackle_pci_host_info); + pci_qdev_register(&grackle_pci_info); } device_init(grackle_register_devices) diff --git a/hw/ide/pci.c b/hw/ide/pci.c index cb3de6537b..246dd5704b 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -327,7 +327,7 @@ void bmdma_cmd_writeb(BMDMAState *bm, uint32_t val) bm->cmd = val & 0x09; } -static uint64_t bmdma_addr_read(void *opaque, dma_addr_t addr, +static uint64_t bmdma_addr_read(void *opaque, target_phys_addr_t addr, unsigned width) { BMDMAState *bm = opaque; @@ -341,7 +341,7 @@ static uint64_t bmdma_addr_read(void *opaque, dma_addr_t addr, return data; } -static void bmdma_addr_write(void *opaque, dma_addr_t addr, +static void bmdma_addr_write(void *opaque, target_phys_addr_t addr, uint64_t data, unsigned width) { BMDMAState *bm = opaque; diff --git a/hw/loader.c b/hw/loader.c index 446b62874e..415cdce534 100644 --- a/hw/loader.c +++ b/hw/loader.c @@ -108,8 +108,12 @@ int load_image_targphys(const char *filename, int size; size = get_image_size(filename); - if (size > 0) + if (size > max_sz) { + return -1; + } + if (size > 0) { rom_add_file_fixed(filename, addr, -1); + } return size; } diff --git a/hw/mips_malta.c b/hw/mips_malta.c index e625ec398f..4a4f76d9f2 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -996,11 +996,7 @@ void mips_malta_init (ram_addr_t ram_size, if (cirrus_vga_enabled) { pci_cirrus_vga_init(pci_bus); } else if (vmsvga_enabled) { - if (!pci_vmsvga_init(pci_bus)) { - fprintf(stderr, "Warning: vmware_vga not available," - " using standard VGA instead\n"); - pci_vga_init(pci_bus); - } + pci_vmsvga_init(pci_bus); } else if (std_vga_enabled) { pci_vga_init(pci_bus); } diff --git a/hw/pc.c b/hw/pc.c index 85304cf115..b1fd4b004c 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -1080,16 +1080,11 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus) if (pci_bus) { dev = pci_cirrus_vga_init(pci_bus); } else { - dev = isa_cirrus_vga_init(get_system_memory()); + dev = &isa_create_simple(isa_bus, "isa-cirrus-vga")->qdev; } } else if (vmsvga_enabled) { if (pci_bus) { dev = pci_vmsvga_init(pci_bus); - if (!dev) { - fprintf(stderr, "Warning: vmware_vga not available," - " using standard VGA instead\n"); - dev = pci_vga_init(pci_bus); - } } else { fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); } diff --git a/hw/pc.h b/hw/pc.h index 13e41f101e..58a7ea910f 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -226,7 +226,6 @@ int isa_vga_mm_init(target_phys_addr_t vram_base, /* cirrus_vga.c */ DeviceState *pci_cirrus_vga_init(PCIBus *bus); -DeviceState *isa_cirrus_vga_init(MemoryRegion *address_space); /* ne2000.c */ static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd) diff --git a/hw/pci.c b/hw/pci.c index c3082bc7c6..54400ac134 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1572,21 +1572,6 @@ PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, return DO_UPCAST(PCIDevice, qdev, dev); } -PCIDevice *pci_try_create_multifunction(PCIBus *bus, int devfn, - bool multifunction, - const char *name) -{ - DeviceState *dev; - - dev = qdev_try_create(&bus->qbus, name); - if (!dev) { - return NULL; - } - qdev_prop_set_uint32(dev, "addr", devfn); - qdev_prop_set_bit(dev, "multifunction", multifunction); - return DO_UPCAST(PCIDevice, qdev, dev); -} - PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, bool multifunction, const char *name) @@ -1606,11 +1591,6 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) return pci_create_simple_multifunction(bus, devfn, false, name); } -PCIDevice *pci_try_create(PCIBus *bus, int devfn, const char *name) -{ - return pci_try_create_multifunction(bus, devfn, false, name); -} - static int pci_find_space(PCIDevice *pdev, uint8_t size) { int config_size = pci_config_size(pdev); diff --git a/hw/pci.h b/hw/pci.h index 0d2cff6fec..5501d9525d 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -469,12 +469,8 @@ PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, bool multifunction, const char *name); -PCIDevice *pci_try_create_multifunction(PCIBus *bus, int devfn, - bool multifunction, - const char *name); PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name); PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name); -PCIDevice *pci_try_create(PCIBus *bus, int devfn, const char *name); static inline int pci_is_express(const PCIDevice *d) { diff --git a/hw/ppc440.c b/hw/ppc440.c deleted file mode 100644 index cd8a95d52b..0000000000 --- a/hw/ppc440.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Qemu PowerPC 440 chip emulation - * - * Copyright 2007 IBM Corporation. - * Authors: - * Jerone Young <jyoung5@us.ibm.com> - * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> - * Hollis Blanchard <hollisb@us.ibm.com> - * - * This work is licensed under the GNU GPL license version 2 or later. - * - */ - -#include "hw.h" -#include "pc.h" -#include "isa.h" -#include "ppc.h" -#include "ppc4xx.h" -#include "ppc440.h" -#include "ppc405.h" -#include "sysemu.h" -#include "kvm.h" - -#define PPC440EP_PCI_CONFIG 0xeec00000 -#define PPC440EP_PCI_INTACK 0xeed00000 -#define PPC440EP_PCI_SPECIAL 0xeed00000 -#define PPC440EP_PCI_REGS 0xef400000 -#define PPC440EP_PCI_IO 0xe8000000 -#define PPC440EP_PCI_IOLEN 0x00010000 - -#define PPC440EP_SDRAM_NR_BANKS 4 - -static const unsigned int ppc440ep_sdram_bank_sizes[] = { - 256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0 -}; - -CPUState *ppc440ep_init(MemoryRegion *address_space_mem, ram_addr_t *ram_size, - PCIBus **pcip, const unsigned int pci_irq_nrs[4], - int do_init, const char *cpu_model) -{ - MemoryRegion *ram_memories - = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories)); - target_phys_addr_t ram_bases[PPC440EP_SDRAM_NR_BANKS]; - target_phys_addr_t ram_sizes[PPC440EP_SDRAM_NR_BANKS]; - CPUState *env; - qemu_irq *pic; - qemu_irq *irqs; - qemu_irq *pci_irqs; - - if (cpu_model == NULL) { - cpu_model = "440-Xilinx"; // XXX: should be 440EP - } - env = cpu_init(cpu_model); - if (!env) { - fprintf(stderr, "Unable to initialize CPU!\n"); - exit(1); - } - - ppc_dcr_init(env, NULL, NULL); - - /* interrupt controller */ - irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); - irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]; - irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]; - pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); - - /* SDRAM controller */ - memset(ram_bases, 0, sizeof(ram_bases)); - memset(ram_sizes, 0, sizeof(ram_sizes)); - *ram_size = ppc4xx_sdram_adjust(*ram_size, PPC440EP_SDRAM_NR_BANKS, - ram_memories, - ram_bases, ram_sizes, - ppc440ep_sdram_bank_sizes); - /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */ - ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories, - ram_bases, ram_sizes, do_init); - - /* PCI */ - pci_irqs = g_malloc(sizeof(qemu_irq) * 4); - pci_irqs[0] = pic[pci_irq_nrs[0]]; - pci_irqs[1] = pic[pci_irq_nrs[1]]; - pci_irqs[2] = pic[pci_irq_nrs[2]]; - pci_irqs[3] = pic[pci_irq_nrs[3]]; - *pcip = ppc4xx_pci_init(env, pci_irqs, - PPC440EP_PCI_CONFIG, - PPC440EP_PCI_INTACK, - PPC440EP_PCI_SPECIAL, - PPC440EP_PCI_REGS); - if (!*pcip) - printf("couldn't create PCI controller!\n"); - - isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN); - - if (serial_hds[0] != NULL) { - serial_mm_init(address_space_mem, 0xef600300, 0, pic[0], - PPC_SERIAL_MM_BAUDBASE, serial_hds[0], - DEVICE_BIG_ENDIAN); - } - if (serial_hds[1] != NULL) { - serial_mm_init(address_space_mem, 0xef600400, 0, pic[1], - PPC_SERIAL_MM_BAUDBASE, serial_hds[1], - DEVICE_BIG_ENDIAN); - } - - return env; -} diff --git a/hw/ppc440.h b/hw/ppc440.h deleted file mode 100644 index 9c27c36fd0..0000000000 --- a/hw/ppc440.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Qemu PowerPC 440 board emualtion - * - * Copyright 2007 IBM Corporation. - * Authors: Jerone Young <jyoung5@us.ibm.com> - * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> - * - * This work is licensed under the GNU GPL licence version 2 or later - * - */ - -#ifndef QEMU_PPC440_H -#define QEMU_PPC440_H - -#include "hw.h" - -CPUState *ppc440ep_init(MemoryRegion *address_space, ram_addr_t *ram_size, - PCIBus **pcip, const unsigned int pci_irq_nrs[4], - int do_init, const char *cpu_model); - -#endif diff --git a/hw/ppc440_bamboo.c b/hw/ppc440_bamboo.c index b734e3a56c..f86b16838a 100644 --- a/hw/ppc440_bamboo.c +++ b/hw/ppc440_bamboo.c @@ -3,9 +3,9 @@ * * Copyright 2007 IBM Corporation. * Authors: - * Jerone Young <jyoung5@us.ibm.com> - * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> - * Hollis Blanchard <hollisb@us.ibm.com> + * Jerone Young <jyoung5@us.ibm.com> + * Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com> + * Hollis Blanchard <hollisb@us.ibm.com> * * This work is licensed under the GNU GPL license version 2 or later. * @@ -17,13 +17,17 @@ #include "hw.h" #include "pci.h" #include "boards.h" -#include "ppc440.h" #include "kvm.h" #include "kvm_ppc.h" #include "device_tree.h" #include "loader.h" #include "elf.h" #include "exec-memory.h" +#include "pc.h" +#include "ppc.h" +#include "ppc405.h" +#include "sysemu.h" +#include "sysbus.h" #define BINARY_DEVICE_TREE_FILE "bamboo.dtb" @@ -32,6 +36,21 @@ #define FDT_ADDR 0x1800000 #define RAMDISK_ADDR 0x1900000 +#define PPC440EP_PCI_CONFIG 0xeec00000 +#define PPC440EP_PCI_INTACK 0xeed00000 +#define PPC440EP_PCI_SPECIAL 0xeed00000 +#define PPC440EP_PCI_REGS 0xef400000 +#define PPC440EP_PCI_IO 0xe8000000 +#define PPC440EP_PCI_IOLEN 0x00010000 + +#define PPC440EP_SDRAM_NR_BANKS 4 + +static const unsigned int ppc440ep_sdram_bank_sizes[] = { + 256<<20, 128<<20, 64<<20, 32<<20, 16<<20, 8<<20, 0 +}; + +static target_phys_addr_t entry; + static int bamboo_load_device_tree(target_phys_addr_t addr, uint32_t ramsize, target_phys_addr_t initrd_base, @@ -101,6 +120,42 @@ out: return ret; } +/* Create reset TLB entries for BookE, spanning the 32bit addr space. */ +static void mmubooke_create_initial_mapping(CPUState *env, + target_ulong va, + target_phys_addr_t pa) +{ + ppcemb_tlb_t *tlb = &env->tlb.tlbe[0]; + + tlb->attr = 0; + tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); + tlb->size = 1 << 31; /* up to 0x80000000 */ + tlb->EPN = va & TARGET_PAGE_MASK; + tlb->RPN = pa & TARGET_PAGE_MASK; + tlb->PID = 0; + + tlb = &env->tlb.tlbe[1]; + tlb->attr = 0; + tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4); + tlb->size = 1 << 31; /* up to 0xffffffff */ + tlb->EPN = 0x80000000 & TARGET_PAGE_MASK; + tlb->RPN = 0x80000000 & TARGET_PAGE_MASK; + tlb->PID = 0; +} + +static void main_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + + cpu_reset(env); + env->gpr[1] = (16<<20) - 8; + env->gpr[3] = FDT_ADDR; + env->nip = entry; + + /* Create a mapping for the kernel. */ + mmubooke_create_initial_mapping(env, 0, 0); +} + static void bamboo_init(ram_addr_t ram_size, const char *boot_device, const char *kernel_filename, @@ -110,19 +165,76 @@ static void bamboo_init(ram_addr_t ram_size, { unsigned int pci_irq_nrs[4] = { 28, 27, 26, 25 }; MemoryRegion *address_space_mem = get_system_memory(); + MemoryRegion *ram_memories + = g_malloc(PPC440EP_SDRAM_NR_BANKS * sizeof(*ram_memories)); + target_phys_addr_t ram_bases[PPC440EP_SDRAM_NR_BANKS]; + target_phys_addr_t ram_sizes[PPC440EP_SDRAM_NR_BANKS]; + qemu_irq *pic; + qemu_irq *irqs; PCIBus *pcibus; CPUState *env; uint64_t elf_entry; uint64_t elf_lowaddr; - target_phys_addr_t entry = 0; target_phys_addr_t loadaddr = 0; target_long initrd_size = 0; + DeviceState *dev; int success; int i; /* Setup CPU. */ - env = ppc440ep_init(address_space_mem, &ram_size, &pcibus, - pci_irq_nrs, 1, cpu_model); + if (cpu_model == NULL) { + cpu_model = "440EP"; + } + env = cpu_init(cpu_model); + if (!env) { + fprintf(stderr, "Unable to initialize CPU!\n"); + exit(1); + } + + qemu_register_reset(main_cpu_reset, env); + ppc_booke_timers_init(env, 400000000, 0); + ppc_dcr_init(env, NULL, NULL); + + /* interrupt controller */ + irqs = g_malloc0(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB); + irqs[PPCUIC_OUTPUT_INT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]; + irqs[PPCUIC_OUTPUT_CINT] = ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]; + pic = ppcuic_init(env, irqs, 0x0C0, 0, 1); + + /* SDRAM controller */ + memset(ram_bases, 0, sizeof(ram_bases)); + memset(ram_sizes, 0, sizeof(ram_sizes)); + ram_size = ppc4xx_sdram_adjust(ram_size, PPC440EP_SDRAM_NR_BANKS, + ram_memories, + ram_bases, ram_sizes, + ppc440ep_sdram_bank_sizes); + /* XXX 440EP's ECC interrupts are on UIC1, but we've only created UIC0. */ + ppc4xx_sdram_init(env, pic[14], PPC440EP_SDRAM_NR_BANKS, ram_memories, + ram_bases, ram_sizes, 1); + + /* PCI */ + dev = sysbus_create_varargs("ppc4xx-pcihost", PPC440EP_PCI_CONFIG, + pic[pci_irq_nrs[0]], pic[pci_irq_nrs[1]], + pic[pci_irq_nrs[2]], pic[pci_irq_nrs[3]], + NULL); + pcibus = (PCIBus *)qdev_get_child_bus(dev, "pci.0"); + if (!pcibus) { + fprintf(stderr, "couldn't create PCI controller!\n"); + exit(1); + } + + isa_mmio_init(PPC440EP_PCI_IO, PPC440EP_PCI_IOLEN); + + if (serial_hds[0] != NULL) { + serial_mm_init(address_space_mem, 0xef600300, 0, pic[0], + PPC_SERIAL_MM_BAUDBASE, serial_hds[0], + DEVICE_BIG_ENDIAN); + } + if (serial_hds[1] != NULL) { + serial_mm_init(address_space_mem, 0xef600400, 0, pic[1], + PPC_SERIAL_MM_BAUDBASE, serial_hds[1], + DEVICE_BIG_ENDIAN); + } if (pcibus) { /* Register network interfaces. */ @@ -169,12 +281,6 @@ static void bamboo_init(ram_addr_t ram_size, fprintf(stderr, "couldn't load device tree\n"); exit(1); } - - /* Set initial guest state. */ - env->gpr[1] = (16<<20) - 8; - env->gpr[3] = FDT_ADDR; - env->nip = entry; - /* XXX we currently depend on KVM to create some initial TLB entries. */ } if (kvm_enabled()) @@ -182,34 +288,14 @@ static void bamboo_init(ram_addr_t ram_size, } static QEMUMachine bamboo_machine = { - .name = "bamboo-0.13", - .alias = "bamboo", - .desc = "bamboo", - .init = bamboo_init, -}; - -static QEMUMachine bamboo_machine_v0_12 = { - .name = "bamboo-0.12", + .name = "bamboo", .desc = "bamboo", .init = bamboo_init, - .compat_props = (GlobalProperty[]) { - { - .driver = "virtio-serial-pci", - .property = "max_ports", - .value = stringify(1), - },{ - .driver = "virtio-serial-pci", - .property = "vectors", - .value = stringify(0), - }, - { /* end of list */ } - }, }; static void bamboo_machine_init(void) { qemu_register_machine(&bamboo_machine); - qemu_register_machine(&bamboo_machine_v0_12); } machine_init(bamboo_machine_init); diff --git a/hw/ppc4xx_pci.c b/hw/ppc4xx_pci.c index 2c69210225..26de007c0f 100644 --- a/hw/ppc4xx_pci.c +++ b/hw/ppc4xx_pci.c @@ -49,13 +49,14 @@ struct PCITargetMap { #define PPC4xx_PCI_NR_PTMS 2 struct PPC4xxPCIState { + PCIHostState pci_state; + struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS]; struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS]; + qemu_irq irq[4]; - PCIHostState pci_state; - PCIDevice *pci_dev; - MemoryRegion iomem_addr; - MemoryRegion iomem_regs; + MemoryRegion container; + MemoryRegion iomem; }; typedef struct PPC4xxPCIState PPC4xxPCIState; @@ -83,8 +84,10 @@ typedef struct PPC4xxPCIState PPC4xxPCIState; #define PCIL0_PTM1LA 0x34 #define PCIL0_PTM2MS 0x38 #define PCIL0_PTM2LA 0x3c +#define PCI_REG_BASE 0x800000 #define PCI_REG_SIZE 0x40 +#define PCI_ALL_SIZE (PCI_REG_BASE + PCI_REG_SIZE) static uint64_t pci4xx_cfgaddr_read(void *opaque, target_phys_addr_t addr, unsigned size) @@ -275,6 +278,10 @@ static void ppc4xx_pci_set_irq(void *opaque, int irq_num, int level) qemu_irq *pci_irqs = opaque; DPRINTF("%s: PCI irq %d\n", __func__, irq_num); + if (irq_num < 0) { + fprintf(stderr, "%s: PCI irq %d\n", __func__, irq_num); + return; + } qemu_set_irq(pci_irqs[irq_num], level); } @@ -310,7 +317,6 @@ static const VMStateDescription vmstate_ppc4xx_pci = { .minimum_version_id = 1, .minimum_version_id_old = 1, .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE_POINTER(pci_dev, PPC4xxPCIState), VMSTATE_STRUCT_ARRAY(pmm, PPC4xxPCIState, PPC4xx_PCI_NR_PMMS, 1, vmstate_pci_master_map, struct PCIMasterMap), @@ -322,60 +328,63 @@ static const VMStateDescription vmstate_ppc4xx_pci = { }; /* XXX Interrupt acknowledge cycles not supported. */ -PCIBus *ppc4xx_pci_init(CPUState *env, qemu_irq pci_irqs[4], - target_phys_addr_t config_space, - target_phys_addr_t int_ack, - target_phys_addr_t special_cycle, - target_phys_addr_t registers) +static int ppc4xx_pcihost_initfn(SysBusDevice *dev) +{ + PPC4xxPCIState *s; + PCIHostState *h; + PCIBus *b; + int i; + + h = FROM_SYSBUS(PCIHostState, sysbus_from_qdev(dev)); + s = DO_UPCAST(PPC4xxPCIState, pci_state, h); + + for (i = 0; i < ARRAY_SIZE(s->irq); i++) { + sysbus_init_irq(dev, &s->irq[i]); + } + + b = pci_register_bus(&s->pci_state.busdev.qdev, NULL, ppc4xx_pci_set_irq, + ppc4xx_pci_map_irq, s->irq, get_system_memory(), + get_system_io(), 0, 4); + s->pci_state.bus = b; + + pci_create_simple(b, 0, "ppc4xx-host-bridge"); + + /* XXX split into 2 memory regions, one for config space, one for regs */ + memory_region_init(&s->container, "pci-container", PCI_ALL_SIZE); + memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops, h, + "pci-conf-idx", 4); + memory_region_init_io(&h->data_mem, &pci_host_data_le_ops, h, + "pci-conf-data", 4); + memory_region_init_io(&s->iomem, &pci_reg_ops, s, + "pci.reg", PCI_REG_SIZE); + memory_region_add_subregion(&s->container, PCIC0_CFGADDR, &h->conf_mem); + memory_region_add_subregion(&s->container, PCIC0_CFGDATA, &h->data_mem); + memory_region_add_subregion(&s->container, PCI_REG_BASE, &s->iomem); + sysbus_init_mmio(dev, &s->container); + qemu_register_reset(ppc4xx_pci_reset, s); + + return 0; +} + +static PCIDeviceInfo ppc4xx_host_bridge_info = { + .qdev.name = "ppc4xx-host-bridge", + .qdev.desc = "Host bridge", + .qdev.size = sizeof(PCIDevice), + .vendor_id = PCI_VENDOR_ID_IBM, + .device_id = PCI_DEVICE_ID_IBM_440GX, + .class_id = PCI_CLASS_BRIDGE_OTHER, +}; + +static SysBusDeviceInfo ppc4xx_pcihost_info = { + .init = ppc4xx_pcihost_initfn, + .qdev.name = "ppc4xx-pcihost", + .qdev.size = sizeof(PPC4xxPCIState), + .qdev.vmsd = &vmstate_ppc4xx_pci, +}; + +static void ppc4xx_pci_register(void) { - PPC4xxPCIState *controller; - static int ppc4xx_pci_id; - uint8_t *pci_conf; - - controller = g_malloc0(sizeof(PPC4xxPCIState)); - - controller->pci_state.bus = pci_register_bus(NULL, "pci", - ppc4xx_pci_set_irq, - ppc4xx_pci_map_irq, - pci_irqs, - get_system_memory(), - get_system_io(), - 0, 4); - - controller->pci_dev = pci_register_device(controller->pci_state.bus, - "host bridge", sizeof(PCIDevice), - 0, NULL, NULL); - pci_conf = controller->pci_dev->config; - pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM); - pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_440GX); - pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER); - - /* CFGADDR */ - memory_region_init_io(&controller->iomem_addr, &pci4xx_cfgaddr_ops, - controller, "pci.cfgaddr", 4); - memory_region_add_subregion(get_system_memory(), - config_space + PCIC0_CFGADDR, - &controller->iomem_addr); - - /* CFGDATA */ - memory_region_init_io(&controller->pci_state.data_mem, - &pci_host_data_be_ops, - &controller->pci_state, "pci-conf-data", 4); - memory_region_add_subregion(get_system_memory(), - config_space + PCIC0_CFGDATA, - &controller->pci_state.data_mem); - - /* Internal registers */ - memory_region_init_io(&controller->iomem_regs, &pci_reg_ops, controller, - "pci.regs", PCI_REG_SIZE); - memory_region_add_subregion(get_system_memory(), registers, - &controller->iomem_regs); - - qemu_register_reset(ppc4xx_pci_reset, controller); - - /* XXX load/save code not tested. */ - vmstate_register(&controller->pci_dev->qdev, ppc4xx_pci_id++, - &vmstate_ppc4xx_pci, controller); - - return controller->pci_state.bus; + sysbus_register_withprop(&ppc4xx_pcihost_info); + pci_qdev_register(&ppc4xx_host_bridge_info); } +device_init(ppc4xx_pci_register); diff --git a/hw/qdev.c b/hw/qdev.c index e59f3455d7..5a7566850a 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -80,6 +80,10 @@ static DeviceInfo *qdev_find_info(BusInfo *bus_info, const char *name) return NULL; } +bool qdev_exists(const char *name) +{ + return !!qdev_find_info(NULL, name); +} static void qdev_property_add_legacy(DeviceState *dev, Property *prop, Error **errp); diff --git a/hw/qdev.h b/hw/qdev.h index 2abb767389..6b58dd8aeb 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -179,6 +179,7 @@ typedef struct GlobalProperty { DeviceState *qdev_create(BusState *bus, const char *name); DeviceState *qdev_try_create(BusState *bus, const char *name); +bool qdev_exists(const char *name); int qdev_device_help(QemuOpts *opts); DeviceState *qdev_device_add(QemuOpts *opts); int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT; diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c index 2210b8ac7e..51123a7535 100644 --- a/hw/s390-virtio.c +++ b/hw/s390-virtio.c @@ -317,7 +317,6 @@ static QEMUMachine s390_machine = { .no_serial = 1, .no_parallel = 1, .use_virtcon = 1, - .no_vga = 1, .max_cpus = 255, .is_default = 1, }; diff --git a/hw/sga.c b/hw/sga.c index 7ef750adf6..ea1193749a 100644 --- a/hw/sga.c +++ b/hw/sga.c @@ -35,7 +35,7 @@ typedef struct ISAGAState { ISADevice dev; } ISASGAState; -static int isa_cirrus_vga_initfn(ISADevice *dev) +static int sga_initfn(ISADevice *dev) { rom_add_vga(SGABIOS_FILENAME); return 0; @@ -45,7 +45,7 @@ static ISADeviceInfo sga_info = { .qdev.name = "sga", .qdev.desc = "Serial Graphics Adapter", .qdev.size = sizeof(ISASGAState), - .init = isa_cirrus_vga_initfn, + .init = sga_initfn, }; static void sga_register(void) diff --git a/hw/spapr.c b/hw/spapr.c index 0e1f80dfdc..dffb6a2a50 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -50,19 +50,29 @@ #include <libfdt.h> -#define KERNEL_LOAD_ADDR 0x00000000 -#define INITRD_LOAD_ADDR 0x02800000 +/* SLOF memory layout: + * + * SLOF raw image loaded at 0, copies its romfs right below the flat + * device-tree, then position SLOF itself 31M below that + * + * So we set FW_OVERHEAD to 40MB which should account for all of that + * and more + * + * We load our kernel at 4M, leaving space for SLOF initial image + */ #define FDT_MAX_SIZE 0x10000 #define RTAS_MAX_SIZE 0x10000 #define FW_MAX_SIZE 0x400000 #define FW_FILE_NAME "slof.bin" +#define FW_OVERHEAD 0x2800000 +#define KERNEL_LOAD_ADDR FW_MAX_SIZE -#define MIN_RMA_SLOF 128UL +#define MIN_RMA_SLOF 128UL #define TIMEBASE_FREQ 512000000ULL #define MAX_CPUS 256 -#define XICS_IRQS 1024 +#define XICS_IRQS 1024 #define SPAPR_PCI_BUID 0x800000020000001ULL #define SPAPR_PCI_MEM_WIN_ADDR (0x10000000000ULL + 0xA0000000) @@ -139,6 +149,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model, target_phys_addr_t rma_size, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, + target_phys_addr_t kernel_size, const char *boot_device, const char *kernel_cmdline, long hash_shift) @@ -176,6 +187,12 @@ static void *spapr_create_fdt_skel(const char *cpu_model, fdt = g_malloc0(FDT_MAX_SIZE); _FDT((fdt_create(fdt, FDT_MAX_SIZE))); + if (kernel_size) { + _FDT((fdt_add_reservemap_entry(fdt, KERNEL_LOAD_ADDR, kernel_size))); + } + if (initrd_size) { + _FDT((fdt_add_reservemap_entry(fdt, initrd_base, initrd_size))); + } _FDT((fdt_finish_reservemap(fdt))); /* Root node */ @@ -197,15 +214,13 @@ static void *spapr_create_fdt_skel(const char *cpu_model, &start_prop, sizeof(start_prop)))); _FDT((fdt_property(fdt, "linux,initrd-end", &end_prop, sizeof(end_prop)))); - _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device))); + if (kernel_size) { + uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR), + cpu_to_be64(kernel_size) }; - /* - * Because we don't always invoke any firmware, we can't rely on - * that to do BAR allocation. Long term, we should probably do - * that ourselves, but for now, this setting (plus advertising the - * current BARs as 0) causes sufficiently recent kernels to to the - * BAR assignment themselves */ - _FDT((fdt_property_cell(fdt, "linux,pci-probe-only", 0))); + _FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop)))); + } + _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device))); _FDT((fdt_end_node(fdt))); @@ -445,6 +460,12 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, _FDT((fdt_pack(fdt))); + if (fdt_totalsize(fdt) > FDT_MAX_SIZE) { + hw_error("FDT too big ! 0x%x bytes (max is 0x%x)\n", + fdt_totalsize(fdt), FDT_MAX_SIZE); + exit(1); + } + cpu_physical_memory_write(fdt_addr, fdt, fdt_totalsize(fdt)); g_free(fdt); @@ -494,8 +515,9 @@ static void ppc_spapr_init(ram_addr_t ram_size, MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); target_phys_addr_t rma_alloc_size, rma_size; - uint32_t initrd_base; - long kernel_size, initrd_size, fw_size; + uint32_t initrd_base = 0; + long kernel_size = 0, initrd_size = 0; + long load_limit, rtas_limit, fw_size; long pteg_shift = 17; char *filename; @@ -517,11 +539,13 @@ static void ppc_spapr_init(ram_addr_t ram_size, rma_size = ram_size; } - /* We place the device tree just below either the top of the RMA, + /* We place the device tree and RTAS just below either the top of the RMA, * or just below 2GB, whichever is lowere, so that it can be * processed with 32-bit real mode code if necessary */ - spapr->fdt_addr = MIN(rma_size, 0x80000000) - FDT_MAX_SIZE; - spapr->rtas_addr = spapr->fdt_addr - RTAS_MAX_SIZE; + rtas_limit = MIN(rma_size, 0x80000000); + spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE; + spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE; + load_limit = spapr->fdt_addr - FW_OVERHEAD; /* init CPUs */ if (cpu_model == NULL) { @@ -577,13 +601,19 @@ static void ppc_spapr_init(ram_addr_t ram_size, filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr, - ram_size - spapr->rtas_addr); + rtas_limit - spapr->rtas_addr); if (spapr->rtas_size < 0) { hw_error("qemu: could not load LPAR rtas '%s'\n", filename); exit(1); } + if (spapr->rtas_size > RTAS_MAX_SIZE) { + hw_error("RTAS too big ! 0x%lx bytes (max is 0x%x)\n", + spapr->rtas_size, RTAS_MAX_SIZE); + exit(1); + } g_free(filename); + /* Set up Interrupt Controller */ spapr->icp = xics_system_init(XICS_IRQS); spapr->next_irq = 16; @@ -622,6 +652,20 @@ static void ppc_spapr_init(ram_addr_t ram_size, spapr_vscsi_create(spapr->vio_bus, 0x2000 + i); } + if (rma_size < (MIN_RMA_SLOF << 20)) { + fprintf(stderr, "qemu: pSeries SLOF firmware requires >= " + "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF); + exit(1); + } + + fprintf(stderr, "sPAPR memory map:\n"); + fprintf(stderr, "RTAS : 0x%08lx..%08lx\n", + (unsigned long)spapr->rtas_addr, + (unsigned long)(spapr->rtas_addr + spapr->rtas_size - 1)); + fprintf(stderr, "FDT : 0x%08lx..%08lx\n", + (unsigned long)spapr->fdt_addr, + (unsigned long)(spapr->fdt_addr + FDT_MAX_SIZE - 1)); + if (kernel_filename) { uint64_t lowaddr = 0; @@ -630,57 +674,60 @@ static void ppc_spapr_init(ram_addr_t ram_size, if (kernel_size < 0) { kernel_size = load_image_targphys(kernel_filename, KERNEL_LOAD_ADDR, - ram_size - KERNEL_LOAD_ADDR); + load_limit - KERNEL_LOAD_ADDR); } if (kernel_size < 0) { fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename); exit(1); } + fprintf(stderr, "Kernel : 0x%08x..%08lx\n", + KERNEL_LOAD_ADDR, KERNEL_LOAD_ADDR + kernel_size - 1); /* load initrd */ if (initrd_filename) { - initrd_base = INITRD_LOAD_ADDR; + /* Try to locate the initrd in the gap between the kernel + * and the firmware. Add a bit of space just in case + */ + initrd_base = (KERNEL_LOAD_ADDR + kernel_size + 0x1ffff) & ~0xffff; initrd_size = load_image_targphys(initrd_filename, initrd_base, - ram_size - initrd_base); + load_limit - initrd_base); if (initrd_size < 0) { fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", initrd_filename); exit(1); } + fprintf(stderr, "Ramdisk : 0x%08lx..%08lx\n", + (long)initrd_base, (long)(initrd_base + initrd_size - 1)); } else { initrd_base = 0; initrd_size = 0; } + } - spapr->entry_point = KERNEL_LOAD_ADDR; - } else { - if (rma_size < (MIN_RMA_SLOF << 20)) { - fprintf(stderr, "qemu: pSeries SLOF firmware requires >= " - "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF); - exit(1); - } - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME); - fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE); - if (fw_size < 0) { - hw_error("qemu: could not load LPAR rtas '%s'\n", filename); - exit(1); - } - g_free(filename); - spapr->entry_point = 0x100; - initrd_base = 0; - initrd_size = 0; - - /* SLOF will startup the secondary CPUs using RTAS, - rather than expecting a kexec() style entry */ - for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->halted = 1; - } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME); + fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE); + if (fw_size < 0) { + hw_error("qemu: could not load LPAR rtas '%s'\n", filename); + exit(1); + } + g_free(filename); + fprintf(stderr, "Firmware load : 0x%08x..%08lx\n", + 0, fw_size); + fprintf(stderr, "Firmware runtime : 0x%08lx..%08lx\n", + load_limit, (unsigned long)spapr->fdt_addr); + + spapr->entry_point = 0x100; + + /* SLOF will startup the secondary CPUs using RTAS */ + for (env = first_cpu; env != NULL; env = env->next_cpu) { + env->halted = 1; } /* Prepare the device tree */ spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, rma_size, initrd_base, initrd_size, + kernel_size, boot_device, kernel_cmdline, pteg_shift + 7); assert(spapr->fdt_skel != NULL); @@ -693,7 +740,6 @@ static QEMUMachine spapr_machine = { .desc = "pSeries Logical Partition (PAPR compliant)", .init = ppc_spapr_init, .max_cpus = MAX_CPUS, - .no_vga = 1, .no_parallel = 1, .use_scsi = 1, }; diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index 9b6a032cce..2c95faa8c1 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -62,6 +62,30 @@ static PCIDevice *find_dev(sPAPREnvironment *spapr, return NULL; } +static uint32_t rtas_pci_cfgaddr(uint32_t arg) +{ + return ((arg >> 20) & 0xf00) | (arg & 0xff); +} + +static uint32_t rtas_read_pci_config_do(PCIDevice *pci_dev, uint32_t addr, + uint32_t limit, uint32_t len) +{ + if ((addr + len) <= limit) { + return pci_host_config_read_common(pci_dev, addr, limit, len); + } else { + return ~0x0; + } +} + +static void rtas_write_pci_config_do(PCIDevice *pci_dev, uint32_t addr, + uint32_t limit, uint32_t val, + uint32_t len) +{ + if ((addr + len) <= limit) { + pci_host_config_write_common(pci_dev, addr, limit, val, len); + } +} + static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, target_ulong args, @@ -76,8 +100,8 @@ static void rtas_ibm_read_pci_config(sPAPREnvironment *spapr, return; } size = rtas_ld(args, 3); - addr = rtas_ld(args, 0) & 0xFF; - val = pci_default_read_config(dev, addr, size); + addr = rtas_pci_cfgaddr(rtas_ld(args, 0)); + val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size); rtas_st(rets, 0, 0); rtas_st(rets, 1, val); } @@ -95,8 +119,8 @@ static void rtas_read_pci_config(sPAPREnvironment *spapr, return; } size = rtas_ld(args, 1); - addr = rtas_ld(args, 0) & 0xFF; - val = pci_default_read_config(dev, addr, size); + addr = rtas_pci_cfgaddr(rtas_ld(args, 0)); + val = rtas_read_pci_config_do(dev, addr, pci_config_size(dev), size); rtas_st(rets, 0, 0); rtas_st(rets, 1, val); } @@ -116,8 +140,8 @@ static void rtas_ibm_write_pci_config(sPAPREnvironment *spapr, } val = rtas_ld(args, 4); size = rtas_ld(args, 3); - addr = rtas_ld(args, 0) & 0xFF; - pci_default_write_config(dev, addr, val, size); + addr = rtas_pci_cfgaddr(rtas_ld(args, 0)); + rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size); rtas_st(rets, 0, 0); } @@ -135,8 +159,8 @@ static void rtas_write_pci_config(sPAPREnvironment *spapr, } val = rtas_ld(args, 2); size = rtas_ld(args, 1); - addr = rtas_ld(args, 0) & 0xFF; - pci_default_write_config(dev, addr, val, size); + addr = rtas_pci_cfgaddr(rtas_ld(args, 0)); + rtas_write_pci_config_do(dev, addr, pci_config_size(dev), val, size); rtas_st(rets, 0, 0); } @@ -319,31 +343,13 @@ void spapr_create_phb(sPAPREnvironment *spapr, #define b_fff(x) b_x((x), 8, 3) /* function number */ #define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */ -static uint32_t regtype_to_ss(uint8_t type) -{ - if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) { - return 3; - } - if (type == PCI_BASE_ADDRESS_SPACE_IO) { - return 1; - } - return 2; -} - int spapr_populate_pci_devices(sPAPRPHBState *phb, uint32_t xics_phandle, void *fdt) { PCIBus *bus = phb->host_state.bus; - int bus_off, node_off = 0, devid, fn, i, n, devices; - DeviceState *qdev; + int bus_off, i; char nodename[256]; - struct { - uint32_t hi; - uint64_t addr; - uint64_t size; - } __attribute__((packed)) reg[PCI_NUM_REGIONS + 1], - assigned_addresses[PCI_NUM_REGIONS]; uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) }; struct { uint32_t hi; @@ -364,7 +370,7 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb, }; uint64_t bus_reg[] = { cpu_to_be64(phb->buid), 0 }; uint32_t interrupt_map_mask[] = { - cpu_to_be32(b_ddddd(-1)|b_fff(-1)), 0x0, 0x0, 0x0}; + cpu_to_be32(b_ddddd(-1)|b_fff(0)), 0x0, 0x0, 0x0}; uint32_t interrupt_map[bus->nirq][7]; /* Start populating the FDT */ @@ -392,117 +398,26 @@ int spapr_populate_pci_devices(sPAPRPHBState *phb, _FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range))); _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges))); _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg))); + _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1)); + + /* Build the interrupt-map, this must matches what is done + * in pci_spapr_map_irq + */ _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask", &interrupt_map_mask, sizeof(interrupt_map_mask))); - - /* Populate PCI devices and allocate IRQs */ - devices = 0; - QTAILQ_FOREACH(qdev, &bus->qbus.children, sibling) { - PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev); - int irq_index = pci_spapr_map_irq(dev, 0); - uint32_t *irqmap = interrupt_map[devices]; - uint8_t *config = dev->config; - - devid = dev->devfn >> 3; - fn = dev->devfn & 7; - - sprintf(nodename, "pci@%u,%u", devid, fn); - - /* Allocate interrupt from the map */ - if (devid > bus->nirq) { - printf("Unexpected behaviour in spapr_populate_pci_devices," - "wrong devid %u\n", devid); - exit(-1); - } - irqmap[0] = cpu_to_be32(b_ddddd(devid)|b_fff(fn)); + for (i = 0; i < 7; i++) { + uint32_t *irqmap = interrupt_map[i]; + irqmap[0] = cpu_to_be32(b_ddddd(i)|b_fff(0)); irqmap[1] = 0; irqmap[2] = 0; irqmap[3] = 0; irqmap[4] = cpu_to_be32(xics_phandle); - irqmap[5] = cpu_to_be32(phb->lsi_table[irq_index].dt_irq); + irqmap[5] = cpu_to_be32(phb->lsi_table[i % SPAPR_PCI_NUM_LSI].dt_irq); irqmap[6] = cpu_to_be32(0x8); - - /* Add node to FDT */ - node_off = fdt_add_subnode(fdt, bus_off, nodename); - if (node_off < 0) { - return node_off; - } - - _FDT(fdt_setprop_cell(fdt, node_off, "vendor-id", - pci_get_word(&config[PCI_VENDOR_ID]))); - _FDT(fdt_setprop_cell(fdt, node_off, "device-id", - pci_get_word(&config[PCI_DEVICE_ID]))); - _FDT(fdt_setprop_cell(fdt, node_off, "revision-id", - pci_get_byte(&config[PCI_REVISION_ID]))); - _FDT(fdt_setprop_cell(fdt, node_off, "class-code", - pci_get_long(&config[PCI_CLASS_REVISION]) >> 8)); - _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-id", - pci_get_word(&config[PCI_SUBSYSTEM_ID]))); - _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-vendor-id", - pci_get_word(&config[PCI_SUBSYSTEM_VENDOR_ID]))); - - /* Config space region comes first */ - reg[0].hi = cpu_to_be32( - b_n(0) | - b_p(0) | - b_t(0) | - b_ss(0/*config*/) | - b_bbbbbbbb(0) | - b_ddddd(devid) | - b_fff(fn)); - reg[0].addr = 0; - reg[0].size = 0; - - n = 0; - for (i = 0; i < ARRAY_SIZE(bars); ++i) { - if (0 == dev->io_regions[i].size) { - continue; - } - - reg[n+1].hi = cpu_to_be32( - b_n(0) | - b_p(0) | - b_t(0) | - b_ss(regtype_to_ss(dev->io_regions[i].type)) | - b_bbbbbbbb(0) | - b_ddddd(devid) | - b_fff(fn) | - b_rrrrrrrr(bars[i])); - reg[n+1].addr = 0; - reg[n+1].size = cpu_to_be64(dev->io_regions[i].size); - - assigned_addresses[n].hi = cpu_to_be32( - b_n(1) | - b_p(0) | - b_t(0) | - b_ss(regtype_to_ss(dev->io_regions[i].type)) | - b_bbbbbbbb(0) | - b_ddddd(devid) | - b_fff(fn) | - b_rrrrrrrr(bars[i])); - - /* - * Writing zeroes to assigned_addresses causes the guest kernel to - * reassign BARs - */ - assigned_addresses[n].addr = cpu_to_be64(dev->io_regions[i].addr); - assigned_addresses[n].size = reg[n+1].size; - - ++n; - } - _FDT(fdt_setprop(fdt, node_off, "reg", reg, sizeof(reg[0])*(n+1))); - _FDT(fdt_setprop(fdt, node_off, "assigned-addresses", - assigned_addresses, - sizeof(assigned_addresses[0])*(n))); - _FDT(fdt_setprop_cell(fdt, node_off, "interrupts", - pci_get_byte(&config[PCI_INTERRUPT_PIN]))); - - ++devices; } - /* Write interrupt map */ _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map, - devices * sizeof(interrupt_map[0]))); + 7 * sizeof(interrupt_map[0]))); return 0; } diff --git a/hw/virtex_ml507.c b/hw/virtex_ml507.c index bd16b97934..f8d2b1be04 100644 --- a/hw/virtex_ml507.c +++ b/hw/virtex_ml507.c @@ -38,7 +38,6 @@ #include "ppc.h" #include "ppc4xx.h" -#include "ppc440.h" #include "ppc405.h" #include "blockdev.h" diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index caff0aa2eb..c93889a2ab 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); } diff --git a/hw/virtio.c b/hw/virtio.c index 81ecc40b31..74cc038af9 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -539,7 +539,7 @@ uint32_t virtio_config_readb(VirtIODevice *vdev, uint32_t addr) if (addr > (vdev->config_len - sizeof(val))) return (uint32_t)-1; - memcpy(&val, vdev->config + addr, sizeof(val)); + val = ldub_p(vdev->config + addr); return val; } @@ -552,7 +552,7 @@ uint32_t virtio_config_readw(VirtIODevice *vdev, uint32_t addr) if (addr > (vdev->config_len - sizeof(val))) return (uint32_t)-1; - memcpy(&val, vdev->config + addr, sizeof(val)); + val = lduw_p(vdev->config + addr); return val; } @@ -565,7 +565,7 @@ uint32_t virtio_config_readl(VirtIODevice *vdev, uint32_t addr) if (addr > (vdev->config_len - sizeof(val))) return (uint32_t)-1; - memcpy(&val, vdev->config + addr, sizeof(val)); + val = ldl_p(vdev->config + addr); return val; } @@ -576,7 +576,7 @@ void virtio_config_writeb(VirtIODevice *vdev, uint32_t addr, uint32_t data) if (addr > (vdev->config_len - sizeof(val))) return; - memcpy(vdev->config + addr, &val, sizeof(val)); + stb_p(vdev->config + addr, val); if (vdev->set_config) vdev->set_config(vdev, vdev->config); @@ -589,7 +589,7 @@ void virtio_config_writew(VirtIODevice *vdev, uint32_t addr, uint32_t data) if (addr > (vdev->config_len - sizeof(val))) return; - memcpy(vdev->config + addr, &val, sizeof(val)); + stw_p(vdev->config + addr, val); if (vdev->set_config) vdev->set_config(vdev, vdev->config); @@ -602,7 +602,7 @@ void virtio_config_writel(VirtIODevice *vdev, uint32_t addr, uint32_t data) if (addr > (vdev->config_len - sizeof(val))) return; - memcpy(vdev->config + addr, &val, sizeof(val)); + stl_p(vdev->config + addr, val); if (vdev->set_config) vdev->set_config(vdev, vdev->config); diff --git a/hw/vmware_vga.h b/hw/vmware_vga.h index db11cbfac8..000fbddc0f 100644 --- a/hw/vmware_vga.h +++ b/hw/vmware_vga.h @@ -8,12 +8,8 @@ static inline DeviceState *pci_vmsvga_init(PCIBus *bus) { PCIDevice *dev; - dev = pci_try_create(bus, -1, "vmware-svga"); - if (!dev || qdev_init(&dev->qdev) < 0) { - return NULL; - } else { - return &dev->qdev; - } + dev = pci_create_simple(bus, -1, "vmware-svga"); + return &dev->qdev; } #endif |