diff options
-rw-r--r-- | Makefile.target | 1 | ||||
-rw-r--r-- | bswap.h | 6 | ||||
-rw-r--r-- | hw/mac_dbdma.c | 10 | ||||
-rw-r--r-- | hw/pci.h | 1 | ||||
-rw-r--r-- | hw/pci_host.c | 172 | ||||
-rw-r--r-- | hw/pci_host.h | 4 | ||||
-rw-r--r-- | hw/pci_host_template.h | 109 | ||||
-rw-r--r-- | hw/pci_ids.h | 1 | ||||
-rw-r--r-- | hw/ppc.h | 2 | ||||
-rw-r--r-- | hw/ppc_mac.h | 1 | ||||
-rw-r--r-- | hw/ppc_newworld.c | 73 | ||||
-rw-r--r-- | hw/ppc_oldworld.c | 9 | ||||
-rw-r--r-- | hw/unin_pci.c | 151 | ||||
-rw-r--r-- | hw/versatile_pci.c | 10 | ||||
-rw-r--r-- | qemu-common.h | 2 | ||||
-rw-r--r-- | rwhandler.c | 91 | ||||
-rw-r--r-- | rwhandler.h | 27 | ||||
-rw-r--r-- | target-ppc/helper.c | 9 | ||||
-rw-r--r-- | target-ppc/kvm.c | 69 | ||||
-rw-r--r-- | target-ppc/kvm_ppc.h | 2 |
20 files changed, 511 insertions, 239 deletions
diff --git a/Makefile.target b/Makefile.target index f498574696..068408f70b 100644 --- a/Makefile.target +++ b/Makefile.target @@ -46,6 +46,7 @@ all: $(PROGS) # cpu emulator library libobj-y = exec.o translate-all.o cpu-exec.o translate.o libobj-y += tcg/tcg.o +libobj-y += rwhandler.o libobj-$(CONFIG_SOFTFLOAT) += fpu/softfloat.o libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o libobj-y += op_helper.o helper.o @@ -214,4 +214,10 @@ static inline void cpu_to_be32wu(uint32_t *p, uint32_t v) #undef le_bswaps #undef be_bswaps +/* len must be one of 1, 2, 4 */ +static inline uint32_t qemu_bswap_len(uint32_t value, int len) +{ + return bswap32(value) >> (32 - 8 * len); +} + #endif /* BSWAP_H */ diff --git a/hw/mac_dbdma.c b/hw/mac_dbdma.c index 8ec3d99314..8f94c35ac3 100644 --- a/hw/mac_dbdma.c +++ b/hw/mac_dbdma.c @@ -402,7 +402,9 @@ static void start_output(DBDMA_channel *ch, int key, uint32_t addr, ch->io.dma_end = dbdma_end; ch->io.is_dma_out = 1; ch->processing = 1; - ch->rw(&ch->io); + if (ch->rw) { + ch->rw(&ch->io); + } } static void start_input(DBDMA_channel *ch, int key, uint32_t addr, @@ -425,7 +427,9 @@ static void start_input(DBDMA_channel *ch, int key, uint32_t addr, ch->io.dma_end = dbdma_end; ch->io.is_dma_out = 0; ch->processing = 1; - ch->rw(&ch->io); + if (ch->rw) { + ch->rw(&ch->io); + } } static void load_word(DBDMA_channel *ch, int key, uint32_t addr, @@ -688,7 +692,7 @@ dbdma_control_write(DBDMA_channel *ch) if (status & ACTIVE) qemu_bh_schedule(dbdma_bh); - if (status & FLUSH) + if ((status & FLUSH) && ch->flush) ch->flush(&ch->io); } @@ -70,7 +70,6 @@ #define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 #define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 -typedef uint64_t pcibus_t; #define FMT_PCIBUS PRIx64 typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, diff --git a/hw/pci_host.c b/hw/pci_host.c index 6289ead3b3..b15d5faef7 100644 --- a/hw/pci_host.c +++ b/hw/pci_host.c @@ -79,152 +79,120 @@ uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len) return val; } -static void pci_host_config_writel(void *opaque, target_phys_addr_t addr, - uint32_t val) +static void pci_host_config_write(ReadWriteHandler *handler, + pcibus_t addr, uint32_t val, int len) { - PCIHostState *s = opaque; + PCIHostState *s = container_of(handler, PCIHostState, conf_handler); + PCI_DPRINTF("%s addr %" FMT_PCIBUS " %d val %"PRIx32"\n", + __func__, addr, len, val); #ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); + val = qemu_bswap_len(val, len); #endif - PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n", - __func__, addr, val); s->config_reg = val; } -static uint32_t pci_host_config_readl(void *opaque, target_phys_addr_t addr) +static uint32_t pci_host_config_read(ReadWriteHandler *handler, + pcibus_t addr, int len) { - PCIHostState *s = opaque; + PCIHostState *s = container_of(handler, PCIHostState, conf_handler); uint32_t val = s->config_reg; - #ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); + val = qemu_bswap_len(val, len); #endif - PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n", - __func__, addr, val); + PCI_DPRINTF("%s addr %" FMT_PCIBUS " len %d val %"PRIx32"\n", + __func__, addr, len, val); return val; } -static CPUWriteMemoryFunc * const pci_host_config_write[] = { - &pci_host_config_writel, - &pci_host_config_writel, - &pci_host_config_writel, -}; - -static CPUReadMemoryFunc * const pci_host_config_read[] = { - &pci_host_config_readl, - &pci_host_config_readl, - &pci_host_config_readl, -}; - -int pci_host_conf_register_mmio(PCIHostState *s) -{ - return cpu_register_io_memory(pci_host_config_read, - pci_host_config_write, s); -} - -static void pci_host_config_writel_noswap(void *opaque, - target_phys_addr_t addr, - uint32_t val) +static void pci_host_config_write_noswap(ReadWriteHandler *handler, + pcibus_t addr, uint32_t val, int len) { - PCIHostState *s = opaque; + PCIHostState *s = container_of(handler, PCIHostState, conf_noswap_handler); - PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n", - __func__, addr, val); + PCI_DPRINTF("%s addr %" FMT_PCIBUS " %d val %"PRIx32"\n", + __func__, addr, len, val); s->config_reg = val; } -static uint32_t pci_host_config_readl_noswap(void *opaque, - target_phys_addr_t addr) +static uint32_t pci_host_config_read_noswap(ReadWriteHandler *handler, + pcibus_t addr, int len) { - PCIHostState *s = opaque; + PCIHostState *s = container_of(handler, PCIHostState, conf_noswap_handler); uint32_t val = s->config_reg; - PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n", - __func__, addr, val); + PCI_DPRINTF("%s addr %" FMT_PCIBUS " len %d val %"PRIx32"\n", + __func__, addr, len, val); return val; } -static CPUWriteMemoryFunc * const pci_host_config_write_noswap[] = { - &pci_host_config_writel_noswap, - &pci_host_config_writel_noswap, - &pci_host_config_writel_noswap, -}; - -static CPUReadMemoryFunc * const pci_host_config_read_noswap[] = { - &pci_host_config_readl_noswap, - &pci_host_config_readl_noswap, - &pci_host_config_readl_noswap, -}; - -int pci_host_conf_register_mmio_noswap(PCIHostState *s) +static void pci_host_data_write(ReadWriteHandler *handler, + pcibus_t addr, uint32_t val, int len) { - return cpu_register_io_memory(pci_host_config_read_noswap, - pci_host_config_write_noswap, s); + PCIHostState *s = container_of(handler, PCIHostState, data_handler); +#ifdef TARGET_WORDS_BIGENDIAN + val = qemu_bswap_len(val, len); +#endif + PCI_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n", + addr, len, val); + if (s->config_reg & (1u << 31)) + pci_data_write(s->bus, s->config_reg | (addr & 3), val, len); } -static void pci_host_config_writel_ioport(void *opaque, - uint32_t addr, uint32_t val) +static uint32_t pci_host_data_read(ReadWriteHandler *handler, + pcibus_t addr, int len) { - PCIHostState *s = opaque; + PCIHostState *s = container_of(handler, PCIHostState, data_handler); + uint32_t val; + if (!(s->config_reg & (1 << 31))) + return 0xffffffff; + val = pci_data_read(s->bus, s->config_reg | (addr & 3), len); + PCI_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n", + addr, len, val); +#ifdef TARGET_WORDS_BIGENDIAN + val = qemu_bswap_len(val, len); +#endif + return val; +} - PCI_DPRINTF("%s addr %"PRIx32 " val %"PRIx32"\n", __func__, addr, val); - s->config_reg = val; +static void pci_host_init(PCIHostState *s) +{ + s->conf_handler.write = pci_host_config_write; + s->conf_handler.read = pci_host_config_read; + s->conf_noswap_handler.write = pci_host_config_write_noswap; + s->conf_noswap_handler.read = pci_host_config_read_noswap; + s->data_handler.write = pci_host_data_write; + s->data_handler.read = pci_host_data_read; } -static uint32_t pci_host_config_readl_ioport(void *opaque, uint32_t addr) +int pci_host_conf_register_mmio(PCIHostState *s) { - PCIHostState *s = opaque; - uint32_t val = s->config_reg; + pci_host_init(s); + return cpu_register_io_memory_simple(&s->conf_handler); +} - PCI_DPRINTF("%s addr %"PRIx32" val %"PRIx32"\n", __func__, addr, val); - return val; +int pci_host_conf_register_mmio_noswap(PCIHostState *s) +{ + pci_host_init(s); + return cpu_register_io_memory_simple(&s->conf_noswap_handler); } void pci_host_conf_register_ioport(pio_addr_t ioport, PCIHostState *s) { - register_ioport_write(ioport, 4, 4, pci_host_config_writel_ioport, s); - register_ioport_read(ioport, 4, 4, pci_host_config_readl_ioport, s); + pci_host_init(s); + register_ioport_simple(&s->conf_noswap_handler, ioport, 4, 4); } -#define PCI_ADDR_T target_phys_addr_t -#define PCI_HOST_SUFFIX _mmio - -#include "pci_host_template.h" - -static CPUWriteMemoryFunc * const pci_host_data_write_mmio[] = { - pci_host_data_writeb_mmio, - pci_host_data_writew_mmio, - pci_host_data_writel_mmio, -}; - -static CPUReadMemoryFunc * const pci_host_data_read_mmio[] = { - pci_host_data_readb_mmio, - pci_host_data_readw_mmio, - pci_host_data_readl_mmio, -}; - int pci_host_data_register_mmio(PCIHostState *s) { - return cpu_register_io_memory(pci_host_data_read_mmio, - pci_host_data_write_mmio, - s); + pci_host_init(s); + return cpu_register_io_memory_simple(&s->data_handler); } -#undef PCI_ADDR_T -#undef PCI_HOST_SUFFIX - -#define PCI_ADDR_T uint32_t -#define PCI_HOST_SUFFIX _ioport - -#include "pci_host_template.h" - void pci_host_data_register_ioport(pio_addr_t ioport, PCIHostState *s) { - register_ioport_write(ioport, 4, 1, pci_host_data_writeb_ioport, s); - register_ioport_write(ioport, 4, 2, pci_host_data_writew_ioport, s); - register_ioport_write(ioport, 4, 4, pci_host_data_writel_ioport, s); - register_ioport_read(ioport, 4, 1, pci_host_data_readb_ioport, s); - register_ioport_read(ioport, 4, 2, pci_host_data_readw_ioport, s); - register_ioport_read(ioport, 4, 4, pci_host_data_readl_ioport, s); + pci_host_init(s); + register_ioport_simple(&s->data_handler, ioport, 4, 1); + register_ioport_simple(&s->data_handler, ioport, 4, 2); + register_ioport_simple(&s->data_handler, ioport, 4, 4); } diff --git a/hw/pci_host.h b/hw/pci_host.h index a006687f8b..5ff64430ed 100644 --- a/hw/pci_host.h +++ b/hw/pci_host.h @@ -29,9 +29,13 @@ #define PCI_HOST_H #include "sysbus.h" +#include "rwhandler.h" struct PCIHostState { SysBusDevice busdev; + ReadWriteHandler conf_noswap_handler; + ReadWriteHandler conf_handler; + ReadWriteHandler data_handler; uint32_t config_reg; PCIBus *bus; }; diff --git a/hw/pci_host_template.h b/hw/pci_host_template.h deleted file mode 100644 index 11e6c88fd7..0000000000 --- a/hw/pci_host_template.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * QEMU Common PCI Host bridge configuration data space access routines. - * - * Copyright (c) 2006 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* Worker routines for a PCI host controller that uses an {address,data} - register pair to access PCI configuration space. */ - -static void glue(pci_host_data_writeb, PCI_HOST_SUFFIX)( - void* opaque, PCI_ADDR_T addr, uint32_t val) -{ - PCIHostState *s = opaque; - - PCI_DPRINTF("writeb addr " TARGET_FMT_plx " val %x\n", - (target_phys_addr_t)addr, val); - if (s->config_reg & (1u << 31)) - pci_data_write(s->bus, s->config_reg | (addr & 3), val, 1); -} - -static void glue(pci_host_data_writew, PCI_HOST_SUFFIX)( - void* opaque, PCI_ADDR_T addr, uint32_t val) -{ - PCIHostState *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - PCI_DPRINTF("writew addr " TARGET_FMT_plx " val %x\n", - (target_phys_addr_t)addr, val); - if (s->config_reg & (1u << 31)) - pci_data_write(s->bus, s->config_reg | (addr & 3), val, 2); -} - -static void glue(pci_host_data_writel, PCI_HOST_SUFFIX)( - void* opaque, PCI_ADDR_T addr, uint32_t val) -{ - PCIHostState *s = opaque; -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - PCI_DPRINTF("writel addr " TARGET_FMT_plx " val %x\n", - (target_phys_addr_t)addr, val); - if (s->config_reg & (1u << 31)) - pci_data_write(s->bus, s->config_reg, val, 4); -} - -static uint32_t glue(pci_host_data_readb, PCI_HOST_SUFFIX)( - void* opaque, PCI_ADDR_T addr) -{ - PCIHostState *s = opaque; - uint32_t val; - - if (!(s->config_reg & (1 << 31))) - return 0xff; - val = pci_data_read(s->bus, s->config_reg | (addr & 3), 1); - PCI_DPRINTF("readb addr " TARGET_FMT_plx " val %x\n", - (target_phys_addr_t)addr, val); - return val; -} - -static uint32_t glue(pci_host_data_readw, PCI_HOST_SUFFIX)( - void* opaque, PCI_ADDR_T addr) -{ - PCIHostState *s = opaque; - uint32_t val; - if (!(s->config_reg & (1 << 31))) - return 0xffff; - val = pci_data_read(s->bus, s->config_reg | (addr & 3), 2); - PCI_DPRINTF("readw addr " TARGET_FMT_plx " val %x\n", - (target_phys_addr_t)addr, val); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap16(val); -#endif - return val; -} - -static uint32_t glue(pci_host_data_readl, PCI_HOST_SUFFIX)( - void* opaque, PCI_ADDR_T addr) -{ - PCIHostState *s = opaque; - uint32_t val; - if (!(s->config_reg & (1 << 31))) - return 0xffffffff; - val = pci_data_read(s->bus, s->config_reg | (addr & 3), 4); - PCI_DPRINTF("readl addr " TARGET_FMT_plx " val %x\n", - (target_phys_addr_t)addr, val); -#ifdef TARGET_WORDS_BIGENDIAN - val = bswap32(val); -#endif - return val; -} diff --git a/hw/pci_ids.h b/hw/pci_ids.h index 63379c234a..fe7a121562 100644 --- a/hw/pci_ids.h +++ b/hw/pci_ids.h @@ -63,6 +63,7 @@ #define PCI_VENDOR_ID_APPLE 0x106b #define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020 +#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b #define PCI_VENDOR_ID_SUN 0x108e #define PCI_DEVICE_ID_SUN_EBUS 0x1000 @@ -40,10 +40,12 @@ enum { ARCH_PREP = 0, ARCH_MAC99, ARCH_HEATHROW, + ARCH_MAC99_U3, }; #define FW_CFG_PPC_WIDTH (FW_CFG_ARCH_LOCAL + 0x00) #define FW_CFG_PPC_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01) #define FW_CFG_PPC_DEPTH (FW_CFG_ARCH_LOCAL + 0x02) +#define FW_CFG_PPC_TBFREQ (FW_CFG_ARCH_LOCAL + 0x03) #define PPC_SERIAL_MM_BAUDBASE 399193 diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h index a04dffea84..89f96bbc34 100644 --- a/hw/ppc_mac.h +++ b/hw/ppc_mac.h @@ -58,6 +58,7 @@ PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic); /* UniNorth PCI */ PCIBus *pci_pmac_init(qemu_irq *pic); +PCIBus *pci_pmac_u3_init(qemu_irq *pic); /* Mac NVRAM */ typedef struct MacIONVRAMState MacIONVRAMState; diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c index a4c714ae7f..bc86c851e7 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc_newworld.c @@ -21,6 +21,30 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. + * + * PCI bus layout on a real G5 (U3 based): + * + * 0000:f0:0b.0 Host bridge [0600]: Apple Computer Inc. U3 AGP [106b:004b] + * 0000:f0:10.0 VGA compatible controller [0300]: ATI Technologies Inc RV350 AP [Radeon 9600] [1002:4150] + * 0001:00:00.0 Host bridge [0600]: Apple Computer Inc. CPC945 HT Bridge [106b:004a] + * 0001:00:01.0 PCI bridge [0604]: Advanced Micro Devices [AMD] AMD-8131 PCI-X Bridge [1022:7450] (rev 12) + * 0001:00:02.0 PCI bridge [0604]: Advanced Micro Devices [AMD] AMD-8131 PCI-X Bridge [1022:7450] (rev 12) + * 0001:00:03.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0045] + * 0001:00:04.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0046] + * 0001:00:05.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0047] + * 0001:00:06.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0048] + * 0001:00:07.0 PCI bridge [0604]: Apple Computer Inc. K2 HT-PCI Bridge [106b:0049] + * 0001:01:07.0 Class [ff00]: Apple Computer Inc. K2 KeyLargo Mac/IO [106b:0041] (rev 20) + * 0001:01:08.0 USB Controller [0c03]: Apple Computer Inc. K2 KeyLargo USB [106b:0040] + * 0001:01:09.0 USB Controller [0c03]: Apple Computer Inc. K2 KeyLargo USB [106b:0040] + * 0001:02:0b.0 USB Controller [0c03]: NEC Corporation USB [1033:0035] (rev 43) + * 0001:02:0b.1 USB Controller [0c03]: NEC Corporation USB [1033:0035] (rev 43) + * 0001:02:0b.2 USB Controller [0c03]: NEC Corporation USB 2.0 [1033:00e0] (rev 04) + * 0001:03:0d.0 Class [ff00]: Apple Computer Inc. K2 ATA/100 [106b:0043] + * 0001:03:0e.0 FireWire (IEEE 1394) [0c00]: Apple Computer Inc. K2 FireWire [106b:0042] + * 0001:04:0f.0 Ethernet controller [0200]: Apple Computer Inc. K2 GMAC (Sun GEM) [106b:004c] + * 0001:05:0c.0 IDE interface [0101]: Broadcom K2 SATA [1166:0240] + * */ #include "hw.h" #include "ppc.h" @@ -40,6 +64,8 @@ #include "loader.h" #include "elf.h" #include "kvm.h" +#include "kvm_ppc.h" +#include "hw/usb.h" #define MAX_IDE_BUS 2 #define VGA_BIOS_SIZE 65536 @@ -109,11 +135,13 @@ static void ppc_core99_init (ram_addr_t ram_size, int nvram_mem_index; int vga_bios_size, bios_size; int pic_mem_index, dbdma_mem_index, cuda_mem_index, escc_mem_index; + int ide_mem_index[3]; int ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; void *fw_cfg; void *dbdma; uint8_t *vga_bios_ptr; + int machine_arch; linux_boot = (kernel_filename != NULL); @@ -317,7 +345,14 @@ static void ppc_core99_init (ram_addr_t ram_size, } } pic = openpic_init(NULL, &pic_mem_index, smp_cpus, openpic_irqs, NULL); - pci_bus = pci_pmac_init(pic); + if (PPC_INPUT(env) == PPC_FLAGS_INPUT_970) { + /* 970 gets a U3 bus */ + pci_bus = pci_pmac_u3_init(pic); + machine_arch = ARCH_MAC99_U3; + } else { + pci_bus = pci_pmac_init(pic); + machine_arch = ARCH_MAC99; + } /* init basic PC hardware */ pci_vga_init(pci_bus, vga_bios_offset, vga_bios_size); @@ -331,27 +366,41 @@ static void ppc_core99_init (ram_addr_t ram_size, fprintf(stderr, "qemu: too many IDE bus\n"); exit(1); } - for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) { - hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS); - } dbdma = DBDMA_init(&dbdma_mem_index); - pci_cmd646_ide_init(pci_bus, hd, 0); + + /* We only emulate 2 out of 3 IDE controllers for now */ + ide_mem_index[0] = -1; + hd[0] = drive_get(IF_IDE, 0, 0); + hd[1] = drive_get(IF_IDE, 0, 1); + ide_mem_index[1] = pmac_ide_init(hd, pic[0x0d], dbdma, 0x16, pic[0x02]); + hd[0] = drive_get(IF_IDE, 1, 0); + hd[1] = drive_get(IF_IDE, 1, 1); + ide_mem_index[2] = pmac_ide_init(hd, pic[0x0e], dbdma, 0x1a, pic[0x02]); /* cuda also initialize ADB */ + if (machine_arch == ARCH_MAC99_U3) { + usb_enabled = 1; + } cuda_init(&cuda_mem_index, pic[0x19]); adb_kbd_init(&adb_bus); adb_mouse_init(&adb_bus); - macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem_index, - dbdma_mem_index, cuda_mem_index, NULL, 0, NULL, + dbdma_mem_index, cuda_mem_index, NULL, 3, ide_mem_index, escc_mem_index); if (usb_enabled) { usb_ohci_init_pci(pci_bus, -1); } + /* U3 needs to use USB for input because Linux doesn't support via-cuda + on PPC64 */ + if (machine_arch == ARCH_MAC99_U3) { + usbdevice_create("keyboard"); + usbdevice_create("mouse"); + } + if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8) graphic_depth = 15; @@ -364,7 +413,7 @@ static void ppc_core99_init (ram_addr_t ram_size, fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); - fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, ARCH_MAC99); + fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, machine_arch); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_base); fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size); if (kernel_cmdline) { @@ -381,6 +430,14 @@ static void ppc_core99_init (ram_addr_t ram_size, fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height); fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth); + if (kvm_enabled()) { +#ifdef CONFIG_KVM + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq()); +#endif + } else { + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec()); + } + qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); } diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c index 7ccc6a1471..04a78358dd 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc_oldworld.c @@ -40,6 +40,7 @@ #include "loader.h" #include "elf.h" #include "kvm.h" +#include "kvm_ppc.h" #define MAX_IDE_BUS 2 #define VGA_BIOS_SIZE 65536 @@ -401,6 +402,14 @@ static void ppc_heathrow_init (ram_addr_t ram_size, fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_HEIGHT, graphic_height); fw_cfg_add_i16(fw_cfg, FW_CFG_PPC_DEPTH, graphic_depth); + if (kvm_enabled()) { +#ifdef CONFIG_KVM + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, kvmppc_get_tbfreq()); +#endif + } else { + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec()); + } + qemu_register_boot_set(fw_cfg_boot_set, fw_cfg); } diff --git a/hw/unin_pci.c b/hw/unin_pci.c index 19eb5e0ad7..7bdf430346 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -36,22 +36,31 @@ #define UNIN_DPRINTF(fmt, ...) #endif +static const int unin_irq_line[] = { 0x1b, 0x1c, 0x1d, 0x1e }; + typedef struct UNINState { SysBusDevice busdev; PCIHostState host_state; + ReadWriteHandler data_handler; } UNINState; -/* Don't know if this matches real hardware, but it agrees with OHW. */ static int pci_unin_map_irq(PCIDevice *pci_dev, int irq_num) { - return (irq_num + (pci_dev->devfn >> 3)) & 3; + int retval; + int devfn = pci_dev->devfn & 0x00FFFFFF; + + retval = (((devfn >> 11) & 0x1F) + irq_num) & 3; + + return retval; } static void pci_unin_set_irq(void *opaque, int irq_num, int level) { qemu_irq *pic = opaque; - qemu_set_irq(pic[irq_num + 8], level); + UNIN_DPRINTF("%s: setting INT %d = %d\n", __func__, + unin_irq_line[irq_num], level); + qemu_set_irq(pic[unin_irq_line[irq_num]], level); } static void pci_unin_save(QEMUFile* f, void *opaque) @@ -75,6 +84,68 @@ static void pci_unin_reset(void *opaque) { } +static uint32_t unin_get_config_reg(uint32_t reg, uint32_t addr) +{ + uint32_t retval; + + if (reg & (1u << 31)) { + /* XXX OpenBIOS compatibility hack */ + retval = reg | (addr & 3); + } else if (reg & 1) { + /* CFA1 style */ + retval = (reg & ~7u) | (addr & 7); + } else { + uint32_t slot, func; + + /* Grab CFA0 style values */ + slot = ffs(reg & 0xfffff800) - 1; + func = (reg >> 8) & 7; + + /* ... and then convert them to x86 format */ + /* config pointer */ + retval = (reg & (0xff - 7)) | (addr & 7); + /* slot */ + retval |= slot << 11; + /* fn */ + retval |= func << 8; + } + + + UNIN_DPRINTF("Converted config space accessor %08x/%08x -> %08x\n", + reg, addr, retval); + + return retval; +} + +static void unin_data_write(ReadWriteHandler *handler, + pcibus_t addr, uint32_t val, int len) +{ + UNINState *s = container_of(handler, UNINState, data_handler); +#ifdef TARGET_WORDS_BIGENDIAN + val = qemu_bswap_len(val, len); +#endif + UNIN_DPRINTF("write addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val); + pci_data_write(s->host_state.bus, + unin_get_config_reg(s->host_state.config_reg, addr), + val, len); +} + +static uint32_t unin_data_read(ReadWriteHandler *handler, + pcibus_t addr, int len) +{ + UNINState *s = container_of(handler, UNINState, data_handler); + uint32_t val; + + val = pci_data_read(s->host_state.bus, + unin_get_config_reg(s->host_state.config_reg, addr), + len); + UNIN_DPRINTF("read addr %" FMT_PCIBUS " len %d val %x\n", addr, len, val); +#ifdef TARGET_WORDS_BIGENDIAN + val = qemu_bswap_len(val, len); +#endif + return val; +} + static int pci_unin_main_init_device(SysBusDevice *dev) { UNINState *s; @@ -85,7 +156,9 @@ static int pci_unin_main_init_device(SysBusDevice *dev) s = FROM_SYSBUS(UNINState, dev); pci_mem_config = pci_host_conf_register_mmio(&s->host_state); - pci_mem_data = pci_host_data_register_mmio(&s->host_state); + s->data_handler.read = unin_data_read; + s->data_handler.write = unin_data_write; + pci_mem_data = cpu_register_io_memory_simple(&s->data_handler); sysbus_init_mmio(dev, 0x1000, pci_mem_config); sysbus_init_mmio(dev, 0x1000, pci_mem_data); @@ -94,6 +167,27 @@ static int pci_unin_main_init_device(SysBusDevice *dev) return 0; } +static int pci_u3_agp_init_device(SysBusDevice *dev) +{ + UNINState *s; + int pci_mem_config, pci_mem_data; + + /* Uninorth U3 AGP bus */ + s = FROM_SYSBUS(UNINState, dev); + + pci_mem_config = pci_host_conf_register_mmio(&s->host_state); + s->data_handler.read = unin_data_read; + s->data_handler.write = unin_data_write; + pci_mem_data = cpu_register_io_memory_simple(&s->data_handler); + sysbus_init_mmio(dev, 0x1000, pci_mem_config); + sysbus_init_mmio(dev, 0x1000, pci_mem_data); + + register_savevm("uninorth", 0, 1, pci_unin_save, pci_unin_load, &s->host_state); + qemu_register_reset(pci_unin_reset, &s->host_state); + + return 0; +} + static int pci_unin_agp_init_device(SysBusDevice *dev) { UNINState *s; @@ -175,6 +269,31 @@ PCIBus *pci_pmac_init(qemu_irq *pic) return d->host_state.bus; } +PCIBus *pci_pmac_u3_init(qemu_irq *pic) +{ + DeviceState *dev; + SysBusDevice *s; + UNINState *d; + + /* Uninorth AGP bus */ + + dev = qdev_create(NULL, "u3-agp"); + qdev_init_nofail(dev); + s = sysbus_from_qdev(dev); + d = FROM_SYSBUS(UNINState, s); + + d->host_state.bus = pci_register_bus(&d->busdev.qdev, "pci", + pci_unin_set_irq, pci_unin_map_irq, + pic, 11 << 3, 4); + + sysbus_mmio_map(s, 0, 0xf0800000); + sysbus_mmio_map(s, 1, 0xf0c00000); + + pci_create_simple(d->host_state.bus, 11 << 3, "u3-agp"); + + return d->host_state.bus; +} + static int unin_main_pci_host_init(PCIDevice *d) { pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE); @@ -201,6 +320,21 @@ static int unin_agp_pci_host_init(PCIDevice *d) return 0; } +static int u3_agp_pci_host_init(PCIDevice *d) +{ + pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE); + pci_config_set_device_id(d->config, PCI_DEVICE_ID_APPLE_U3_AGP); + /* revision */ + d->config[0x08] = 0x00; + pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST); + /* cache line size */ + d->config[0x0C] = 0x08; + /* latency timer */ + d->config[0x0D] = 0x10; + d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; + return 0; +} + static int unin_internal_pci_host_init(PCIDevice *d) { pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_APPLE); @@ -220,6 +354,12 @@ static PCIDeviceInfo unin_main_pci_host_info = { .init = unin_main_pci_host_init, }; +static PCIDeviceInfo u3_agp_pci_host_info = { + .qdev.name = "u3-agp", + .qdev.size = sizeof(PCIDevice), + .init = u3_agp_pci_host_init, +}; + static PCIDeviceInfo unin_agp_pci_host_info = { .qdev.name = "uni-north-agp", .qdev.size = sizeof(PCIDevice), @@ -237,6 +377,9 @@ static void unin_register_devices(void) sysbus_register_dev("uni-north", sizeof(UNINState), pci_unin_main_init_device); pci_qdev_register(&unin_main_pci_host_info); + sysbus_register_dev("u3-agp", sizeof(UNINState), + pci_u3_agp_init_device); + pci_qdev_register(&u3_agp_pci_host_info); sysbus_register_dev("uni-north-agp", sizeof(UNINState), pci_unin_agp_init_device); pci_qdev_register(&unin_agp_pci_host_info); diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c index 153c6514f7..7048fb84d0 100644 --- a/hw/versatile_pci.c +++ b/hw/versatile_pci.c @@ -147,14 +147,10 @@ static int versatile_pci_host_init(PCIDevice *d) pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_XILINX); /* Both boards have the same device ID. Oh well. */ pci_config_set_device_id(d->config, PCI_DEVICE_ID_XILINX_XC2VP30); - d->config[0x04] = 0x00; - d->config[0x05] = 0x00; - d->config[0x06] = 0x20; - d->config[0x07] = 0x02; - d->config[0x08] = 0x00; // revision - d->config[0x09] = 0x00; // programming i/f + pci_set_word(d->config + PCI_STATUS, + PCI_STATUS_66MHZ | PCI_STATUS_DEVSEL_MEDIUM); pci_config_set_class(d->config, PCI_CLASS_PROCESSOR_CO); - d->config[0x0D] = 0x10; // latency_timer + pci_set_byte(d->config + PCI_LATENCY_TIMER, 0x10); return 0; } diff --git a/qemu-common.h b/qemu-common.h index a98fccd214..fc32d8df95 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -227,6 +227,8 @@ typedef struct I2SCodec I2SCodec; typedef struct DeviceState DeviceState; typedef struct SSIBus SSIBus; +typedef uint64_t pcibus_t; + /* CPU save/load. */ void cpu_save(QEMUFile *f, void *opaque); int cpu_load(QEMUFile *f, void *opaque, int version_id); diff --git a/rwhandler.c b/rwhandler.c new file mode 100644 index 0000000000..c50c4bf603 --- /dev/null +++ b/rwhandler.c @@ -0,0 +1,91 @@ +#include "rwhandler.h" +#include "ioport.h" +#include "cpu-all.h" + +#if !defined(CONFIG_USER_ONLY) + +#define RWHANDLER_WRITE(name, len, type) \ +static void name(void *opaque, type addr, uint32_t value) \ +{\ + struct ReadWriteHandler *handler = opaque;\ + handler->write(handler, addr, value, len);\ +} + +#define RWHANDLER_READ(name, len, type) \ +static uint32_t name(void *opaque, type addr) \ +{ \ + struct ReadWriteHandler *handler = opaque; \ + return handler->read(handler, addr, len); \ +} + +RWHANDLER_WRITE(cpu_io_memory_simple_writeb, 1, target_phys_addr_t); +RWHANDLER_READ(cpu_io_memory_simple_readb, 1, target_phys_addr_t); +RWHANDLER_WRITE(cpu_io_memory_simple_writew, 2, target_phys_addr_t); +RWHANDLER_READ(cpu_io_memory_simple_readw, 2, target_phys_addr_t); +RWHANDLER_WRITE(cpu_io_memory_simple_writel, 4, target_phys_addr_t); +RWHANDLER_READ(cpu_io_memory_simple_readl, 4, target_phys_addr_t); + +static CPUWriteMemoryFunc * const cpu_io_memory_simple_write[] = { + &cpu_io_memory_simple_writeb, + &cpu_io_memory_simple_writew, + &cpu_io_memory_simple_writel, +}; + +static CPUReadMemoryFunc * const cpu_io_memory_simple_read[] = { + &cpu_io_memory_simple_readb, + &cpu_io_memory_simple_readw, + &cpu_io_memory_simple_readl, +}; + +int cpu_register_io_memory_simple(struct ReadWriteHandler *handler) +{ + if (!handler->read || !handler->write) { + return -1; + } + return cpu_register_io_memory(cpu_io_memory_simple_read, + cpu_io_memory_simple_write, + handler); +} + +RWHANDLER_WRITE(ioport_simple_writeb, 1, uint32_t); +RWHANDLER_READ(ioport_simple_readb, 1, uint32_t); +RWHANDLER_WRITE(ioport_simple_writew, 2, uint32_t); +RWHANDLER_READ(ioport_simple_readw, 2, uint32_t); +RWHANDLER_WRITE(ioport_simple_writel, 4, uint32_t); +RWHANDLER_READ(ioport_simple_readl, 4, uint32_t); + +int register_ioport_simple(ReadWriteHandler* handler, + pio_addr_t start, int length, int size) +{ + IOPortWriteFunc *write; + IOPortReadFunc *read; + int r; + switch (size) { + case 1: + write = ioport_simple_writeb; + read = ioport_simple_readb; + break; + case 2: + write = ioport_simple_writew; + read = ioport_simple_readw; + break; + default: + write = ioport_simple_writel; + read = ioport_simple_readl; + } + if (handler->write) { + r = register_ioport_write(start, length, size, write, handler); + if (r < 0) { + return r; + } + } + if (handler->read) { + r = register_ioport_read(start, length, size, read, handler); + if (r < 0) { + return r; + } + } + return 0; +} + +#endif diff --git a/rwhandler.h b/rwhandler.h new file mode 100644 index 0000000000..bc11849572 --- /dev/null +++ b/rwhandler.h @@ -0,0 +1,27 @@ +#ifndef READ_WRITE_HANDLER_H +#define READ_WRITE_HANDLER_H + +#include "qemu-common.h" +#include "ioport.h" + +typedef struct ReadWriteHandler ReadWriteHandler; + +/* len is guaranteed to be one of 1, 2 or 4, addr is guaranteed to fit in an + * appropriate type (io/memory/etc). They do not need to be range checked. */ +typedef void WriteHandlerFunc(ReadWriteHandler *, pcibus_t addr, + uint32_t value, int len); +typedef uint32_t ReadHandlerFunc(ReadWriteHandler *, pcibus_t addr, int len); + +struct ReadWriteHandler { + WriteHandlerFunc *write; + ReadHandlerFunc *read; +}; + +/* Helpers for when we want to use a single routine with length. */ +/* CPU memory handler: both read and write must be present. */ +int cpu_register_io_memory_simple(ReadWriteHandler *); +/* io port handler: can supply only read or write handlers. */ +int register_ioport_simple(ReadWriteHandler *, + pio_addr_t start, int length, int size); + +#endif diff --git a/target-ppc/helper.c b/target-ppc/helper.c index a4fae31e38..cd1c9fea0e 100644 --- a/target-ppc/helper.c +++ b/target-ppc/helper.c @@ -736,14 +736,13 @@ static inline int slb_lookup(CPUPPCState *env, target_ulong eaddr, PRIx32 "\n", __func__, n, slb->tmp64, slb->tmp); if (slb_is_valid(slb)) { /* SLB entry is valid */ + mask = 0xFFFFFFFFF0000000ULL; if (slb->tmp & 0x8) { - /* 1 TB Segment */ - mask = 0xFFFF000000000000ULL; + /* 16 MB PTEs */ if (target_page_bits) - *target_page_bits = 24; // XXX 16M pages? + *target_page_bits = 24; } else { - /* 256MB Segment */ - mask = 0xFFFFFFFFF0000000ULL; + /* 4 KB PTEs */ if (target_page_bits) *target_page_bits = TARGET_PAGE_BITS; } diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 0424a78422..8ad003799c 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -37,6 +37,22 @@ do { } while (0) #endif +/* XXX For some odd reason we sometimes hang inside KVM forever. I'd guess it's + * a race condition where we actually have a level triggered interrupt, but + * the infrastructure can't expose that yet, so the guest ACKs it, goes to + * sleep and never gets notified that there's still an interrupt pending. + * + * As a quick workaround, let's just wake up every 500 ms. That way we can + * assure that we're always reinjecting interrupts in time. + */ +static QEMUTimer *idle_timer; + +static void do_nothing(void *opaque) +{ + qemu_mod_timer(idle_timer, qemu_get_clock(vm_clock) + + (get_ticks_per_sec() / 2)); +} + int kvm_arch_init(KVMState *s, int smp_cpus) { return 0; @@ -173,6 +189,12 @@ int kvm_arch_pre_run(CPUState *env, struct kvm_run *run) int r; unsigned irq; + if (!idle_timer) { + idle_timer = qemu_new_timer(vm_clock, do_nothing, NULL); + qemu_mod_timer(idle_timer, qemu_get_clock(vm_clock) + + (get_ticks_per_sec() / 2)); + } + /* PowerPC Qemu tracks the various core input pins (interrupt, critical * interrupt, reset, etc) in PPC-specific env->irq_input_state. */ if (run->ready_for_interrupt_injection && @@ -252,3 +274,50 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run) return ret; } +static int read_cpuinfo(const char *field, char *value, int len) +{ + FILE *f; + int ret = -1; + int field_len = strlen(field); + char line[512]; + + f = fopen("/proc/cpuinfo", "r"); + if (!f) { + return -1; + } + + do { + if(!fgets(line, sizeof(line), f)) { + break; + } + if (!strncmp(line, field, field_len)) { + strncpy(value, line, len); + ret = 0; + break; + } + } while(*line); + + fclose(f); + + return ret; +} + +uint32_t kvmppc_get_tbfreq(void) +{ + char line[512]; + char *ns; + uint32_t retval = get_ticks_per_sec(); + + if (read_cpuinfo("timebase", line, sizeof(line))) { + return retval; + } + + if (!(ns = strchr(line, ':'))) { + return retval; + } + + ns++; + + retval = atoi(ns); + return retval; +} diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 3792ef7251..e8d66e88e4 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -14,4 +14,6 @@ void kvmppc_fdt_update(void *fdt); int kvmppc_read_host_property(const char *node_path, const char *prop, void *val, size_t len); +uint32_t kvmppc_get_tbfreq(void); + #endif /* __KVM_PPC_H__ */ |