Merge remote branch 'mst/for_anthony' into staging
This commit is contained in:
commit
9edf5051f3
@ -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
|
||||
|
6
bswap.h
6
bswap.h
@ -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 */
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
1
hw/pci.h
1
hw/pci.h
@ -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,
|
||||
|
196
hw/pci_host.c
196
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 void pci_host_config_write_noswap(ReadWriteHandler *handler,
|
||||
pcibus_t addr, uint32_t val, int len)
|
||||
{
|
||||
PCIHostState *s = container_of(handler, PCIHostState, conf_noswap_handler);
|
||||
|
||||
static CPUReadMemoryFunc * const pci_host_config_read[] = {
|
||||
&pci_host_config_readl,
|
||||
&pci_host_config_readl,
|
||||
&pci_host_config_readl,
|
||||
};
|
||||
PCI_DPRINTF("%s addr %" FMT_PCIBUS " %d val %"PRIx32"\n",
|
||||
__func__, addr, len, val);
|
||||
s->config_reg = val;
|
||||
}
|
||||
|
||||
static uint32_t pci_host_config_read_noswap(ReadWriteHandler *handler,
|
||||
pcibus_t addr, int len)
|
||||
{
|
||||
PCIHostState *s = container_of(handler, PCIHostState, conf_noswap_handler);
|
||||
uint32_t val = s->config_reg;
|
||||
|
||||
PCI_DPRINTF("%s addr %" FMT_PCIBUS " len %d val %"PRIx32"\n",
|
||||
__func__, addr, len, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pci_host_data_write(ReadWriteHandler *handler,
|
||||
pcibus_t addr, uint32_t val, int len)
|
||||
{
|
||||
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 uint32_t pci_host_data_read(ReadWriteHandler *handler,
|
||||
pcibus_t addr, int len)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int pci_host_conf_register_mmio(PCIHostState *s)
|
||||
{
|
||||
return cpu_register_io_memory(pci_host_config_read,
|
||||
pci_host_config_write, s);
|
||||
pci_host_init(s);
|
||||
return cpu_register_io_memory_simple(&s->conf_handler);
|
||||
}
|
||||
|
||||
static void pci_host_config_writel_noswap(void *opaque,
|
||||
target_phys_addr_t addr,
|
||||
uint32_t val)
|
||||
{
|
||||
PCIHostState *s = opaque;
|
||||
|
||||
PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n",
|
||||
__func__, addr, val);
|
||||
s->config_reg = val;
|
||||
}
|
||||
|
||||
static uint32_t pci_host_config_readl_noswap(void *opaque,
|
||||
target_phys_addr_t addr)
|
||||
{
|
||||
PCIHostState *s = opaque;
|
||||
uint32_t val = s->config_reg;
|
||||
|
||||
PCI_DPRINTF("%s addr " TARGET_FMT_plx " val %"PRIx32"\n",
|
||||
__func__, addr, 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)
|
||||
{
|
||||
return cpu_register_io_memory(pci_host_config_read_noswap,
|
||||
pci_host_config_write_noswap, s);
|
||||
}
|
||||
|
||||
static void pci_host_config_writel_ioport(void *opaque,
|
||||
uint32_t addr, uint32_t val)
|
||||
{
|
||||
PCIHostState *s = opaque;
|
||||
|
||||
PCI_DPRINTF("%s addr %"PRIx32 " val %"PRIx32"\n", __func__, addr, val);
|
||||
s->config_reg = val;
|
||||
}
|
||||
|
||||
static uint32_t pci_host_config_readl_ioport(void *opaque, uint32_t addr)
|
||||
{
|
||||
PCIHostState *s = opaque;
|
||||
uint32_t val = s->config_reg;
|
||||
|
||||
PCI_DPRINTF("%s addr %"PRIx32" val %"PRIx32"\n", __func__, addr, val);
|
||||
return val;
|
||||
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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
2
hw/ppc.h
2
hw/ppc.h
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
151
hw/unin_pci.c
151
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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
91
rwhandler.c
Normal file
91
rwhandler.c
Normal file
@ -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
|
27
rwhandler.h
Normal file
27
rwhandler.h
Normal file
@ -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
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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__ */
|
||||
|
Loading…
Reference in New Issue
Block a user