Merge remote branch 'mst/for_anthony' into staging

This commit is contained in:
Anthony Liguori 2010-02-19 13:02:10 -06:00
commit 9edf5051f3
20 changed files with 523 additions and 251 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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);
}

View File

@ -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,

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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
View 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
View 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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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__ */